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:
Bahadir Balban
2008-08-22 00:11:06 +03:00
parent 3ce220f062
commit 1d15821acb
10 changed files with 139 additions and 44 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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