Made changes to have shared tcb parts in fs0 in preparation for clone()

fs_data and files structures can now be shared in the vfs task.
Currently no means to free shared structures in tcb destruction. Need to add that.
This commit is contained in:
Bahadir Balban
2008-11-09 10:07:24 +02:00
parent 5468c1833d
commit 63fb907cd0
13 changed files with 189 additions and 78 deletions

View File

@@ -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)

View File

@@ -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);

View File

@@ -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__ */

View File

@@ -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);

View File

@@ -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]);

View File

@@ -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;
}
}

View File

@@ -9,12 +9,15 @@
#include <l4/macros.h>
#include INC_GLUE(memory.h)
#include <stdio.h>
#include <l4/api/errno.h>
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;
}

View File

@@ -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 */

View File

@@ -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)))

View File

@@ -10,6 +10,7 @@
#include <l4lib/arch/syslib.h>
#include <l4lib/ipcdefs.h>
#include <lib/malloc.h>
#include <lib/idpool.h>
#include <task.h>
#include <vfs.h>
#include <sys/ipc.h>
@@ -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__);

View File

@@ -15,7 +15,7 @@
#include <lib/addr.h>
#include <l4/api/kip.h>
#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;

View File

@@ -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);

View File

@@ -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)
{