diff --git a/src/api/thread.c b/src/api/thread.c index e58184c..1681033 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -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); diff --git a/tasks/fs0/include/lib/idpool.h b/tasks/fs0/include/lib/idpool.h index 3400849..fe2a047 100644 --- a/tasks/fs0/include/lib/idpool.h +++ b/tasks/fs0/include/lib/idpool.h @@ -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); diff --git a/tasks/fs0/include/task.h b/tasks/fs0/include/task.h index c82b527..2ef0eb2 100644 --- a/tasks/fs0/include/task.h +++ b/tasks/fs0/include/task.h @@ -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; diff --git a/tasks/fs0/main.c b/tasks/fs0/main.c index ea56714..d269f6b 100644 --- a/tasks/fs0/main.c +++ b/tasks/fs0/main.c @@ -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) " diff --git a/tasks/fs0/src/lib/idpool.c b/tasks/fs0/src/lib/idpool.c index 76e5970..0c4639b 100644 --- a/tasks/fs0/src/lib/idpool.c +++ b/tasks/fs0/src/lib/idpool.c @@ -10,6 +10,12 @@ #include INC_GLUE(memory.h) #include +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); diff --git a/tasks/fs0/src/task.c b/tasks/fs0/src/task.c index e3415a3..0a09d13 100644 --- a/tasks/fs0/src/task.c +++ b/tasks/fs0/src/task.c @@ -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) diff --git a/tasks/libl4/include/l4lib/ipcdefs.h b/tasks/libl4/include/l4lib/ipcdefs.h index b6ac159..1bd50ac 100644 --- a/tasks/libl4/include/l4lib/ipcdefs.h +++ b/tasks/libl4/include/l4lib/ipcdefs.h @@ -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__ */ diff --git a/tasks/mm0/include/task.h b/tasks/mm0/include/task.h index d7aaac1..111b282 100644 --- a/tasks/mm0/include/task.h +++ b/tasks/mm0/include/task.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; diff --git a/tasks/mm0/src/clone.c b/tasks/mm0/src/clone.c index a7abc6a..6e0dfa8 100755 --- a/tasks/mm0/src/clone.c +++ b/tasks/mm0/src/clone.c @@ -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); diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index 5b21ea6..4ad3a73 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -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