mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 19:03:15 +01:00
Added ipc to notify vfs about a forked child.
TODO: Need to ensure child shmat()s its own utcb after a fork (possibly in libposix/fork.c)
This commit is contained in:
@@ -128,10 +128,6 @@ int thread_create(struct task_ids *ids, unsigned int flags)
|
||||
/* Allocate new pgd and copy all kernel areas */
|
||||
new->pgd = alloc_pgd();
|
||||
copy_pgd_kern_all(new->pgd);
|
||||
|
||||
/* New space id, or requested id if available */
|
||||
if ((ids->spid = id_get(space_id_pool, ids->spid)) < 0)
|
||||
ids->spid = id_new(space_id_pool);
|
||||
} else {
|
||||
/* Existing space will be used, find it from all tasks */
|
||||
list_for_each_entry(task, &global_task_list, task_list) {
|
||||
@@ -149,10 +145,22 @@ int thread_create(struct task_ids *ids, unsigned int flags)
|
||||
BUG();
|
||||
}
|
||||
out:
|
||||
/* New thread id, or requested id if available */
|
||||
/* Allocate requested id if it's available, else a new one */
|
||||
if ((ids->tid = id_get(thread_id_pool, ids->tid)) < 0)
|
||||
ids->tid = id_new(thread_id_pool);
|
||||
|
||||
/* If thread space is new or copied, it gets a new space id */
|
||||
if (flags == THREAD_CREATE_NEWSPC ||
|
||||
flags == THREAD_CREATE_COPYSPC) {
|
||||
/*
|
||||
* Allocate requested id if
|
||||
* it's available, else a new one
|
||||
*/
|
||||
if ((ids->spid = id_get(space_id_pool,
|
||||
ids->spid)) < 0)
|
||||
ids->spid = id_new(space_id_pool);
|
||||
}
|
||||
|
||||
/* Set all ids */
|
||||
set_task_ids(new, ids);
|
||||
|
||||
|
||||
@@ -8,6 +8,14 @@ struct id_pool {
|
||||
u32 bitmap[];
|
||||
};
|
||||
|
||||
/* Copy one id pool to another by calculating its size */
|
||||
static inline void id_pool_copy(struct idpool *to, struct idpool *from, int totalbits)
|
||||
{
|
||||
int nwords = BITWISE_GETWORD(totalbits);
|
||||
|
||||
memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool));
|
||||
}
|
||||
|
||||
struct id_pool *id_pool_new_init(int mapsize);
|
||||
int id_new(struct id_pool *pool);
|
||||
int id_del(struct id_pool *pool, int id);
|
||||
|
||||
@@ -24,6 +24,17 @@ struct tcb {
|
||||
struct vnode *rootdir;
|
||||
};
|
||||
|
||||
/* Structures used when receiving new task info from pager */
|
||||
struct task_data {
|
||||
unsigned long tid;
|
||||
unsigned long utcb_address;
|
||||
};
|
||||
|
||||
struct task_data_head {
|
||||
unsigned long total;
|
||||
struct task_data tdata[];
|
||||
};
|
||||
|
||||
static inline int task_is_utcb_mapped(struct tcb *t)
|
||||
{
|
||||
return t->utcb_mapped;
|
||||
|
||||
@@ -99,6 +99,10 @@ void handle_fs_requests(void)
|
||||
pager_update_stats(sender, (unsigned long)mr[0],
|
||||
(unsigned long)mr[1]);
|
||||
break;
|
||||
case L4_IPC_TAG_NOTIFY_FORK:
|
||||
pager_notify_fork(sender, (l4id_t)mr[0], (l4id_t)mr[1],
|
||||
(unsigned long)mr[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: Unrecognised ipc tag (%d) "
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <stdio.h>
|
||||
|
||||
static inline void id_pool_copy(struct idpool *to, struct idpool *from, int totalbits)
|
||||
{
|
||||
int nwords = BITWISE_GETWORD(totalbits);
|
||||
|
||||
memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool));
|
||||
}
|
||||
struct id_pool *id_pool_new_init(int totalbits)
|
||||
{
|
||||
int nwords = BITWISE_GETWORD(totalbits);
|
||||
|
||||
@@ -72,15 +72,44 @@ int receive_pager_taskdata_orig(l4id_t *tdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct task_data {
|
||||
unsigned long tid;
|
||||
unsigned long utcb_address;
|
||||
};
|
||||
/*
|
||||
* Receives ipc from pager about a new fork event and
|
||||
* the information on the resulting child task.
|
||||
*/
|
||||
int pager_notify_fork(l4id_t sender, l4id_t parid,
|
||||
l4id_t chid, unsigned long utcb_address)
|
||||
{
|
||||
struct tcb *child, *parent;
|
||||
int err;
|
||||
|
||||
// printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
||||
BUG_ON(!(parent = find_task(parid)));
|
||||
|
||||
if (IS_ERR(child = create_tcb())) {
|
||||
l4_ipc_return((int)child);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialise fields sent by pager */
|
||||
child->tid = chid;
|
||||
child->utcb_address = utcb_address;
|
||||
|
||||
/*
|
||||
* Initialise vfs specific fields.
|
||||
* FIXME: Or copy from parent???
|
||||
*/
|
||||
child->rootdir = vfs_root.pivot;
|
||||
child->curdir = vfs_root.pivot;
|
||||
|
||||
/* Copy file descriptors from parent */
|
||||
id_pool_copy(child->fdpool, parent->fdpool, TASK_FILES_MAX);
|
||||
memcpy(child->fd, parent->fd, TASK_FILES_MAX * sizeof(int));
|
||||
|
||||
l4_ipc_return(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct task_data_head {
|
||||
unsigned long total;
|
||||
struct task_data tdata[];
|
||||
};
|
||||
|
||||
/* Read task information into the utcb page, since it won't fit into mrs. */
|
||||
struct task_data_head *receive_pager_taskdata(void)
|
||||
|
||||
@@ -55,5 +55,6 @@
|
||||
#define L4_IPC_TAG_PAGER_WRITE 43 /* Pager writes file contents to vfs */
|
||||
#define L4_IPC_TAG_PAGER_CLOSE 44 /* Pager notifies vfs of file close */
|
||||
#define L4_IPC_TAG_PAGER_UPDATE_STATS 45 /* Pager updates file stats in vfs */
|
||||
#define L4_IPC_TAG_NOTIFY_FORK 46 /* Pager notifies vfs of process fork */
|
||||
|
||||
#endif /* __IPCDEFS_H__ */
|
||||
|
||||
@@ -82,6 +82,17 @@ struct tcb {
|
||||
struct file_descriptor fd[TASK_FILES_MAX];
|
||||
};
|
||||
|
||||
/* Structures to use when sending new task information to vfs */
|
||||
struct task_data {
|
||||
unsigned long tid;
|
||||
unsigned long utcb_address;
|
||||
};
|
||||
|
||||
struct task_data_head {
|
||||
unsigned long total;
|
||||
struct task_data tdata[];
|
||||
};
|
||||
|
||||
struct tcb *find_task(int tid);
|
||||
|
||||
struct initdata;
|
||||
|
||||
@@ -72,7 +72,6 @@ int copy_tcb(struct tcb *to, struct tcb *from)
|
||||
to->map_start = from->map_start;
|
||||
to->map_end = from->map_end;
|
||||
|
||||
|
||||
/* Copy all vm areas */
|
||||
copy_vmas(to, from);
|
||||
|
||||
@@ -81,24 +80,48 @@ int copy_tcb(struct tcb *to, struct tcb *from)
|
||||
TASK_FILES_MAX * sizeof(struct file_descriptor));
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends vfs task information about forked child, and its utcb
|
||||
*/
|
||||
void vfs_notify_fork(struct tcb *child, struct tcb *parent)
|
||||
{
|
||||
int err;
|
||||
struct task_data_head *tdata_head;
|
||||
struct tcb *vfs;
|
||||
|
||||
printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
|
||||
|
||||
l4_save_ipcregs();
|
||||
|
||||
/* Write parent and child information */
|
||||
write_mr(L4SYS_ARG0, parent->tid);
|
||||
write_mr(L4SYS_ARG1, child->tid);
|
||||
write_mr(L4SYS_ARG2, child->utcb);
|
||||
|
||||
if ((err = l4_sendrecv(VFS_TID, VFS_TID,
|
||||
L4_IPC_TAG_NOTIFY_FORK)) < 0) {
|
||||
printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Check if syscall was successful */
|
||||
if ((err = l4_get_retval()) < 0) {
|
||||
printf("%s: Pager from VFS read error: %d.\n",
|
||||
__FUNCTION__, err);
|
||||
return err;
|
||||
}
|
||||
l4_restore_ipcregs();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int do_fork(struct tcb *parent)
|
||||
{
|
||||
struct task_ids ids = { .tid = TASK_ID_INVALID, .spid = parent->spid };
|
||||
struct tcb *child;
|
||||
|
||||
/*
|
||||
* Allocate and copy parent pgd + all pmds to child.
|
||||
*
|
||||
* When a write fault occurs on any of the frozen shadows,
|
||||
* fault handler creates a new shadow on top, if it hasn't,
|
||||
* and then starts adding writeable pages to the new shadow.
|
||||
* Every forked task will fault on every page of the frozen shadow,
|
||||
* until all pages have been made copy-on-write'ed, in which case
|
||||
* the underlying frozen shadow is collapsed.
|
||||
*
|
||||
* Every forked task must have its own copy of pgd + pmds because
|
||||
* every one of them will have to fault on frozen shadows individually.
|
||||
*/
|
||||
struct task_ids ids = {
|
||||
.tid = TASK_ID_INVALID,
|
||||
.spid = parent->spid,
|
||||
};
|
||||
|
||||
/* Make all shadows in this task read-only */
|
||||
vm_freeze_shadows(parent);
|
||||
@@ -115,18 +138,22 @@ int do_fork(struct tcb *parent)
|
||||
/* Create new utcb for child since it can't use its parent's */
|
||||
child->utcb = utcb_vaddr_new();
|
||||
|
||||
/* Create the utcb shared memory segment available for child to shmat() */
|
||||
if (IS_ERR(shm = shm_new((key_t)child->utcb, __pfn(DEFAULT_UTCB_SIZE)))) {
|
||||
/*
|
||||
* Create the utcb shared memory segment
|
||||
* available for child to shmat()
|
||||
*/
|
||||
if (IS_ERR(shm = shm_new((key_t)child->utcb,
|
||||
__pfn(DEFAULT_UTCB_SIZE)))) {
|
||||
l4_ipc_return((int)shm);
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: We should munmap() parent's utcb page from child */
|
||||
|
||||
/* Notify fs0 about forked process */
|
||||
vfs_send_fork(parent, child);
|
||||
vfs_notify_fork(child, parent);
|
||||
|
||||
/* Start forked child. FIXME: Return ipc to child as well ??? */
|
||||
l4_thread_control(THREAD_START, child);
|
||||
/* Start forked child. */
|
||||
l4_thread_control(THREAD_RUN, ids);
|
||||
|
||||
/* Return back to parent */
|
||||
l4_ipc_return(0);
|
||||
|
||||
@@ -481,16 +481,6 @@ void init_pm(struct initdata *initdata)
|
||||
start_boot_tasks(initdata);
|
||||
}
|
||||
|
||||
struct task_data {
|
||||
unsigned long tid;
|
||||
unsigned long utcb_address;
|
||||
};
|
||||
|
||||
struct task_data_head {
|
||||
unsigned long total;
|
||||
struct task_data tdata[];
|
||||
};
|
||||
|
||||
/*
|
||||
* During its initialisation FS0 wants to learn how many boot tasks
|
||||
* are running, and their tids, which includes itself. This function
|
||||
|
||||
Reference in New Issue
Block a user