diff --git a/tasks/fs0/include/lib/bit.h b/tasks/fs0/include/lib/bit.h index bccc5df..7d6f8a7 100644 --- a/tasks/fs0/include/lib/bit.h +++ b/tasks/fs0/include/lib/bit.h @@ -10,6 +10,7 @@ int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, int check_and_clear_bit(u32 *word, int bit); int check_and_clear_contig_bits(u32 *word, int first, int nbits); +int check_and_set_bit(u32 *word, int bit); /* Set */ static inline void setbit(unsigned int *w, unsigned int flags) diff --git a/tasks/fs0/include/lib/idpool.h b/tasks/fs0/include/lib/idpool.h index 34d8349..2650e75 100644 --- a/tasks/fs0/include/lib/idpool.h +++ b/tasks/fs0/include/lib/idpool.h @@ -22,6 +22,7 @@ static inline void id_pool_copy(struct id_pool *to, struct id_pool *from, int to 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); +int id_get(struct id_pool *pool, int id); int ids_new_contiguous(struct id_pool *pool, int numids); int ids_del_contiguous(struct id_pool *pool, int first, int numids); diff --git a/tasks/fs0/include/syscalls.h b/tasks/fs0/include/syscalls.h index 61aba51..fe4ec20 100644 --- a/tasks/fs0/include/syscalls.h +++ b/tasks/fs0/include/syscalls.h @@ -27,8 +27,9 @@ int pager_sys_close(struct tcb *sender, l4id_t closer, int fd); int pager_update_stats(struct tcb *sender, unsigned long vnum, unsigned long newsize); -int pager_notify_fork(struct tcb *sender, l4id_t parid, - l4id_t chid, unsigned long utcb_address); +int pager_notify_fork(struct tcb *sender, l4id_t parentid, + l4id_t childid, unsigned long utcb_address, + unsigned int flags); int pager_notify_exit(struct tcb *sender, l4id_t tid); #endif /* __FS0_SYSCALLS_H__ */ diff --git a/tasks/fs0/include/task.h b/tasks/fs0/include/task.h index 2ef0eb2..e58b4f1 100644 --- a/tasks/fs0/include/task.h +++ b/tasks/fs0/include/task.h @@ -10,18 +10,32 @@ #define __TASKNAME__ __VFSNAME__ +#define TCB_NO_SHARING 0 +#define TCB_SHARED_VM (1 << 0) +#define TCB_SHARED_FILES (1 << 1) +#define TCB_SHARED_FS (1 << 2) + #define TASK_FILES_MAX 32 +struct task_fd_head { + int fd[TASK_FILES_MAX]; + struct id_pool *fdpool; + int tcb_refs; +}; + +struct task_fs_data { + struct vnode *curdir; + struct vnode *rootdir; + int tcb_refs; +}; + /* Thread control block, fs0 portion */ struct tcb { l4id_t tid; - unsigned long utcb_address; - int utcb_mapped; /* Set if we mapped their utcb */ struct list_head list; - int fd[TASK_FILES_MAX]; - struct id_pool *fdpool; - struct vnode *curdir; - struct vnode *rootdir; + unsigned long utcb_address; + struct task_fd_head *files; + struct task_fs_data *fs_data; }; /* Structures used when receiving new task info from pager */ @@ -35,11 +49,6 @@ struct task_data_head { struct task_data tdata[]; }; -static inline int task_is_utcb_mapped(struct tcb *t) -{ - return t->utcb_mapped; -} - struct tcb *find_task(int tid); int init_task_data(void); diff --git a/tasks/fs0/main.c b/tasks/fs0/main.c index 70cb6c5..830bcee 100644 --- a/tasks/fs0/main.c +++ b/tasks/fs0/main.c @@ -111,7 +111,7 @@ void handle_fs_requests(void) break; case L4_IPC_TAG_NOTIFY_FORK: ret = pager_notify_fork(sender, (l4id_t)mr[0], (l4id_t)mr[1], - (unsigned long)mr[2]); + (unsigned long)mr[2], (unsigned int)mr[3]); break; case L4_IPC_TAG_NOTIFY_EXIT: ret = pager_notify_exit(sender, (l4id_t)mr[0]); diff --git a/tasks/fs0/src/lib/bit.c b/tasks/fs0/src/lib/bit.c index 7190e5b..7b1dee4 100644 --- a/tasks/fs0/src/lib/bit.c +++ b/tasks/fs0/src/lib/bit.c @@ -96,3 +96,16 @@ int check_and_clear_contig_bits(u32 *word, int first, int nbits) return 0; } +int check_and_set_bit(u32 *word, int bit) +{ + /* Check that bit was clear */ + if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) { + word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit); + return 0; + } else { + //printf("Trying to set already set bit\n"); + return -1; + } +} + + diff --git a/tasks/fs0/src/lib/idpool.c b/tasks/fs0/src/lib/idpool.c index 76e5970..0cb826e 100644 --- a/tasks/fs0/src/lib/idpool.c +++ b/tasks/fs0/src/lib/idpool.c @@ -9,12 +9,15 @@ #include #include INC_GLUE(memory.h) #include +#include struct id_pool *id_pool_new_init(int totalbits) { int nwords = BITWISE_GETWORD(totalbits); struct id_pool *new = kzalloc((nwords * SZ_WORD) + sizeof(struct id_pool)); + if (!new) + return PTR_ERR(-ENOMEM); new->nwords = nwords; return new; } @@ -63,3 +66,16 @@ int id_del(struct id_pool *pool, int id) return ret; } +/* Return a specific id, if available */ +int id_get(struct id_pool *pool, int id) +{ + int ret; + + ret = check_and_set_bit(pool->bitmap, id); + + if (ret < 0) + return ret; + else + return id; +} + diff --git a/tasks/fs0/src/path.c b/tasks/fs0/src/path.c index 48d5122..f011429 100644 --- a/tasks/fs0/src/path.c +++ b/tasks/fs0/src/path.c @@ -91,7 +91,7 @@ struct pathdata *pathdata_parse(const char *pathname, list_add_tail(&comp->list, &pdata->list); /* Lookup start vnode is root vnode */ - pdata->vstart = task->rootdir; + pdata->vstart = task->fs_data->rootdir; /* Otherwise start from current directory */ } else { @@ -104,7 +104,7 @@ struct pathdata *pathdata_parse(const char *pathname, INIT_LIST_HEAD(&comp->list); /* Get current dentry for this task */ - curdir = list_entry(task->curdir->dentries.next, + curdir = list_entry(task->fs_data->curdir->dentries.next, struct dentry, vref); /* Use its name in path component */ @@ -112,7 +112,7 @@ struct pathdata *pathdata_parse(const char *pathname, list_add_tail(&comp->list, &pdata->list); /* Lookup start vnode is current dir vnode */ - pdata->vstart = task->curdir; + pdata->vstart = task->fs_data->curdir; } /* Add every other path component */ diff --git a/tasks/fs0/src/syscalls.c b/tasks/fs0/src/syscalls.c index 6f5c047..63a3367 100644 --- a/tasks/fs0/src/syscalls.c +++ b/tasks/fs0/src/syscalls.c @@ -46,12 +46,12 @@ int pager_sys_open(struct tcb *pager, l4id_t opener, int fd) return -ESRCH; /* Check if that fd has been opened */ - if (task->fd[fd] == NILFD) + if (task->files->fd[fd] == NILFD) return -EBADF; /* Search the vnode by that vnum */ if (IS_ERR(v = vfs_lookup_byvnum(vfs_root.pivot->sb, - task->fd[fd]))) + task->files->fd[fd]))) return (int)v; /* @@ -119,12 +119,12 @@ int pager_sys_close(struct tcb *sender, l4id_t closer, int fd) BUG_ON(!(task = find_task(closer))); - if ((err = id_del(task->fdpool, fd)) < 0) { + if ((err = id_del(task->files->fdpool, fd)) < 0) { printf("%s: Error releasing fd identifier.\n", __FUNCTION__); return err; } - task->fd[fd] = NILFD; + task->files->fd[fd] = NILFD; return 0; } @@ -166,11 +166,11 @@ int sys_open(struct tcb *task, const char *pathname, int flags, unsigned int mod } /* Get a new fd */ - BUG_ON((fd = id_new(task->fdpool)) < 0); + BUG_ON((fd = id_new(task->files->fdpool)) < 0); retval = fd; /* Assign the new fd with the vnode's number */ - task->fd[fd] = v->vnum; + task->files->fd[fd] = v->vnum; out: pathdata_destroy(pdata); @@ -226,7 +226,7 @@ int sys_chdir(struct tcb *task, const char *pathname) } /* Assign the current directory pointer */ - task->curdir = v; + task->fs_data->curdir = v; out: /* Destroy extracted path data */ @@ -254,10 +254,10 @@ int sys_fstat(struct tcb *task, int fd, void *statbuf) unsigned long vnum; /* Get the vnum */ - if (fd < 0 || fd > TASK_FILES_MAX || task->fd[fd] == NILFD) + if (fd < 0 || fd > TASK_FILES_MAX || task->files->fd[fd] == NILFD) return -EBADF; - vnum = task->fd[fd]; + vnum = task->files->fd[fd]; /* Lookup vnode */ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) @@ -437,10 +437,10 @@ int sys_readdir(struct tcb *t, int fd, void *buf, int count) (unsigned long)buf > t->utcb_address + PAGE_SIZE) return -EINVAL; - if (fd < 0 || fd > TASK_FILES_MAX || t->fd[fd] == NILFD) + if (fd < 0 || fd > TASK_FILES_MAX || t->files->fd[fd] == NILFD) return -EBADF; - vnum = t->fd[fd]; + vnum = t->files->fd[fd]; /* Lookup vnode */ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) diff --git a/tasks/fs0/src/task.c b/tasks/fs0/src/task.c index aa2517d..75f9f5c 100644 --- a/tasks/fs0/src/task.c +++ b/tasks/fs0/src/task.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ void global_add_task(struct tcb *task) list_add_tail(&task->list, &global_tasks.list); global_tasks.total++; } + void global_remove_task(struct tcb *task) { BUG_ON(list_empty(&task->list)); @@ -37,7 +39,6 @@ void global_remove_task(struct tcb *task) BUG_ON(--global_tasks.total < 0); } - struct tcb *find_task(int tid) { struct tcb *t; @@ -48,31 +49,112 @@ struct tcb *find_task(int tid) return 0; } -/* Allocate a task struct and initialise it */ -struct tcb *create_tcb(void) +/* Allocate a vfs task structure according to given flags */ +struct tcb *tcb_alloc_init(unsigned int flags) { - struct tcb *t; + struct tcb *task; - if (!(t = kmalloc(sizeof(*t)))) + if (!(task = kzalloc(sizeof(struct tcb)))) return PTR_ERR(-ENOMEM); - t->fdpool = id_pool_new_init(TASK_FILES_MAX); - INIT_LIST_HEAD(&t->list); + /* Allocate new fs data struct if its not shared */ + if (!(flags & TCB_SHARED_FS)) { + if (!(task->fs_data = + kzalloc(sizeof(*task->fs_data)))) { + kfree(task); + return PTR_ERR(-ENOMEM); + } + task->fs_data->tcb_refs = 1; + } - return t; + /* Allocate file structures if not shared */ + if (!(flags & TCB_SHARED_FILES)) { + if (!(task->files = + kzalloc(sizeof(*task->files)))) { + kfree(task->fs_data); + kfree(task); + return PTR_ERR(-ENOMEM); + } + if (IS_ERR(task->files->fdpool = + id_pool_new_init(TASK_FILES_MAX))) { + void *err = task->files->fdpool; + + kfree(task->files); + kfree(task->fs_data); + kfree(task); + return err; + } + task->files->tcb_refs = 1; + } + + /* Ids will be set up later */ + task->tid = TASK_ID_INVALID; + + /* Initialise list structure */ + INIT_LIST_HEAD(&task->list); + + return task; } -void destroy_tcb(struct tcb *t) +void copy_tcb(struct tcb *to, struct tcb *from, unsigned int share_flags) { - kfree(t->fdpool); + if (share_flags & TCB_SHARED_FILES) { + to->files = from->files; + to->files->tcb_refs++; + } else { + /* Copy all file descriptors */ + memcpy(to->files->fd, from->files->fd, + TASK_FILES_MAX * sizeof(to->files->fd[0])); - global_remove_task(t); - kfree(t); + /* Copy the idpool */ + id_pool_copy(to->files->fdpool, from->files->fdpool, TASK_FILES_MAX); + } + + if (share_flags & TCB_SHARED_FS) { + to->fs_data = from->fs_data; + to->fs_data->tcb_refs++; + } else + memcpy(to->fs_data, from->fs_data, sizeof(*to->fs_data)); +} + +/* Allocate a task struct and initialise it */ +struct tcb *tcb_create(struct tcb *orig, l4id_t tid, unsigned long utcb, + unsigned int share_flags) +{ + struct tcb *task; + + /* Can't have some share flags with no original task */ + BUG_ON(!orig && share_flags); + + /* Create a task and use given space and thread ids. */ + if (IS_ERR(task = tcb_alloc_init(share_flags))) + return task; + + task->tid = tid; + task->utcb_address = utcb; + + /* + * If there's an original task that means this will be a full + * or partial copy of it. We copy depending on share_flags. + */ + if (orig) + copy_tcb(task, orig, share_flags); + + return task; +} + +/* FIXME: Modify it to work with shared structures!!! */ +void tcb_destroy(struct tcb *task) +{ + global_remove_task(task); + + kfree(task); } /* - * Attaches to task's utcb. FIXME: Add SHM_RDONLY and test it. + * Attaches to task's utcb. TODO: Add SHM_RDONLY and test it. * FIXME: This calls the pager and is a potential for deadlock + * it only doesn't lock because it is called during initialisation. */ int task_utcb_attach(struct tcb *t) { @@ -106,32 +188,19 @@ out_err: * Receives ipc from pager about a new fork event and * the information on the resulting child task. */ -int pager_notify_fork(struct tcb *sender, l4id_t parid, - l4id_t chid, unsigned long utcb_address) +int pager_notify_fork(struct tcb *sender, l4id_t parentid, + l4id_t childid, unsigned long utcb_address, + unsigned int flags) { struct tcb *child, *parent; // printf("%s/%s\n", __TASKNAME__, __FUNCTION__); - BUG_ON(!(parent = find_task(parid))); + BUG_ON(!(parent = find_task(parentid))); - if (IS_ERR(child = create_tcb())) + /* Create a child vfs tcb using given parent and copy flags */ + if (IS_ERR(child = tcb_create(parent, childid, utcb_address, flags))) return (int)child; - /* 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)); - global_add_task(child); // printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__); @@ -149,7 +218,7 @@ int pager_notify_exit(struct tcb *sender, l4id_t tid) // printf("%s/%s\n", __TASKNAME__, __FUNCTION__); BUG_ON(!(task = find_task(tid))); - destroy_tcb(task); + tcb_destroy(task); // printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__); @@ -188,16 +257,15 @@ int init_task_structs(struct task_data_head *tdata_head) struct tcb *t; for (int i = 0; i < tdata_head->total; i++) { - if (IS_ERR(t = create_tcb())) + /* New tcb with fields sent by pager */ + if (IS_ERR(t = tcb_create(0, tdata_head->tdata[i].tid, + tdata_head->tdata[i].utcb_address, + 0))) return (int)t; - /* Initialise fields sent by pager */ - t->tid = tdata_head->tdata[i].tid; - t->utcb_address = tdata_head->tdata[i].utcb_address; - /* Initialise vfs specific fields. */ - t->rootdir = vfs_root.pivot; - t->curdir = vfs_root.pivot; + t->fs_data->rootdir = vfs_root.pivot; + t->fs_data->curdir = vfs_root.pivot; /* Print task information */ //printf("%s: Task info received from mm0:\n", __TASKNAME__); diff --git a/tasks/mm0/include/task.h b/tasks/mm0/include/task.h index 275aa80..4783307 100644 --- a/tasks/mm0/include/task.h +++ b/tasks/mm0/include/task.h @@ -15,7 +15,7 @@ #include #include -#define __TASKNAME__ __PAGERNAME__ +#define __TASKNAME__ __PAGERNAME__ #define TASK_FILES_MAX 32 @@ -24,12 +24,10 @@ #define DEFAULT_STACK_SIZE SZ_16K #define DEFAULT_UTCB_SIZE PAGE_SIZE - -enum tcb_create_flags { - TCB_NO_SHARING = 0, - TCB_SHARED_VM = 1, - TCB_SHARED_FILES = 2, -}; +#define TCB_NO_SHARING 0 +#define TCB_SHARED_VM (1 << 0) +#define TCB_SHARED_FILES (1 << 1) +#define TCB_SHARED_FS (1 << 2) struct vm_file; diff --git a/tasks/mm0/src/clone.c b/tasks/mm0/src/clone.c index 695698a..f81beeb 100644 --- a/tasks/mm0/src/clone.c +++ b/tasks/mm0/src/clone.c @@ -18,7 +18,7 @@ /* * Sends vfs task information about forked child, and its utcb */ -int vfs_notify_fork(struct tcb *child, struct tcb *parent) +int vfs_notify_fork(struct tcb *child, struct tcb *parent, unsigned int flags) { int err = 0; @@ -30,6 +30,7 @@ int vfs_notify_fork(struct tcb *child, struct tcb *parent) write_mr(L4SYS_ARG0, parent->tid); write_mr(L4SYS_ARG1, child->tid); write_mr(L4SYS_ARG2, (unsigned int)child->utcb); + write_mr(L4SYS_ARG3, flags); if ((err = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_NOTIFY_FORK)) < 0) { @@ -86,7 +87,7 @@ int sys_fork(struct tcb *parent) // printf("Mapped 0x%p to vfs as utcb of %d\n", child->utcb, child->tid); /* We can now notify vfs about forked process */ - vfs_notify_fork(child, parent); + vfs_notify_fork(child, parent, TCB_NO_SHARING); /* Add child to global task list */ global_add_task(child); @@ -120,7 +121,7 @@ int sys_clone(struct tcb *parent, void *child_stack, unsigned int flags) child->stack_start = 0; /* We can now notify vfs about forked process */ - vfs_notify_fork(child, parent); + vfs_notify_fork(child, parent, TCB_SHARED_FILES); /* Add child to global task list */ global_add_task(child); diff --git a/tasks/mm0/src/munmap.c b/tasks/mm0/src/munmap.c index 18b97cb..5d1b572 100644 --- a/tasks/mm0/src/munmap.c +++ b/tasks/mm0/src/munmap.c @@ -167,6 +167,9 @@ int vma_flush_pages(struct vm_area *vma) * Unmaps the given virtual address range from the task, the region * may span into zero or more vmas, and may involve shrinking, splitting * and destruction of multiple vmas. + * + * NOTE: Shared object addresses are returned back to their pools when + * such objects are deleted, and not via this function. */ int do_munmap(struct tcb *task, unsigned long vaddr, unsigned long npages) {