fork(): preliminary version (no wait()/waitpid() support yet)

This commit is contained in:
Balazs Gerofi bgerofi@riken.jp
2014-04-02 14:07:38 +09:00
parent 391b69e8c4
commit cf442e6a14
7 changed files with 321 additions and 42 deletions

View File

@@ -47,6 +47,10 @@
#define KERNEL_STACK_NR_PAGES 24
extern long do_arch_prctl(unsigned long code, unsigned long address);
static void insert_vm_range_list(struct process_vm *vm,
struct vm_range *newrange);
static int copy_user_ranges(struct process *proc, struct process *org);
enum ihk_mc_pt_attribute vrflag_to_ptattr(unsigned long flag);
static int init_process_vm(struct process *owner, struct process_vm *vm)
{
@@ -105,6 +109,7 @@ struct process *create_process(unsigned long user_pc)
proc->vm = (struct process_vm *)(proc + 1);
if(init_process_vm(proc, proc->vm) != 0){
kfree(proc->sigshared);
kfree(proc->sighandler);
ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES);
return NULL;
@@ -117,11 +122,12 @@ struct process *create_process(unsigned long user_pc)
}
struct process *clone_process(struct process *org, unsigned long pc,
unsigned long sp)
unsigned long sp, int clone_flags)
{
struct process *proc;
if((proc = ihk_mc_alloc_pages(KERNEL_STACK_NR_PAGES, IHK_MC_AP_NOWAIT)) == NULL){
if ((proc = ihk_mc_alloc_pages(KERNEL_STACK_NR_PAGES,
IHK_MC_AP_NOWAIT)) == NULL) {
return NULL;
}
@@ -136,24 +142,199 @@ struct process *clone_process(struct process *org, unsigned long pc,
memcpy(proc->uctx, org->uctx, sizeof(*org->uctx));
ihk_mc_modify_user_context(proc->uctx, IHK_UCR_STACK_POINTER, sp);
ihk_mc_modify_user_context(proc->uctx, IHK_UCR_PROGRAM_COUNTER, pc);
ihk_atomic_inc(&org->vm->refcount);
proc->vm = org->vm;
proc->rlimit_stack = org->rlimit_stack;
proc->sighandler = org->sighandler;
ihk_atomic_inc(&org->sighandler->use);
/* TODO: do this check properly!
* fork() */
if (clone_flags == 0x1200011) {
dkprintf("fork(): sighandler\n");
proc->sighandler = kmalloc(sizeof(struct sig_handler),
IHK_MC_AP_NOWAIT);
if (!proc->sighandler) {
goto err_free_proc;
}
proc->sigshared = org->sigshared;
ihk_atomic_inc(&org->sigshared->use);
dkprintf("fork(): sigshared\n");
proc->sigshared = kmalloc(sizeof(struct sig_shared), IHK_MC_AP_NOWAIT);
if (!proc->sigshared) {
goto err_free_sighandler;
}
ihk_mc_spinlock_init(&proc->sigpendinglock);
INIT_LIST_HEAD(&proc->sigpending);
memset(proc->sighandler, '\0', sizeof(struct sig_handler));
ihk_atomic_set(&proc->sighandler->use, 1);
ihk_mc_spinlock_init(&proc->sighandler->lock);
ihk_atomic_set(&proc->sigshared->use, 1);
ihk_mc_spinlock_init(&proc->sigshared->lock);
INIT_LIST_HEAD(&proc->sigshared->sigpending);
ihk_mc_spinlock_init(&proc->sigpendinglock);
INIT_LIST_HEAD(&proc->sigpending);
proc->vm = (struct process_vm *)(proc + 1);
dkprintf("fork(): init_process_vm()\n");
if (init_process_vm(proc, proc->vm) != 0) {
goto err_free_sigshared;
}
memcpy(&proc->vm->region, &org->vm->region, sizeof(struct vm_regions));
dkprintf("fork(): copy_user_ranges()\n");
/* Copy user-space mappings.
* TODO: do this with COW later? */
if (copy_user_ranges(proc, org) != 0) {
goto err_free_sigshared;
}
dkprintf("fork(): copy_user_ranges() OK\n");
}
/* clone() */
else {
ihk_atomic_inc(&org->vm->refcount);
proc->vm = org->vm;
proc->sighandler = org->sighandler;
ihk_atomic_inc(&org->sighandler->use);
proc->sigshared = org->sigshared;
ihk_atomic_inc(&org->sigshared->use);
ihk_mc_spinlock_init(&proc->sigpendinglock);
INIT_LIST_HEAD(&proc->sigpending);
}
ihk_mc_spinlock_init(&proc->spin_sleep_lock);
proc->spin_sleep = 0;
return proc;
err_free_sigshared:
kfree(proc->sigshared);
err_free_sighandler:
ihk_mc_free_pages(proc->sighandler, KERNEL_STACK_NR_PAGES);
err_free_proc:
ihk_mc_free_pages(proc, KERNEL_STACK_NR_PAGES);
return NULL;
}
static int copy_user_ranges(struct process *proc, struct process *org)
{
struct vm_range *src_range;
struct vm_range *range;
ihk_mc_spinlock_lock_noirq(&org->vm->memory_range_lock);
/* Iterate original process' vm_range list and take a copy one-by-one */
list_for_each_entry(src_range, &org->vm->vm_range_list, list) {
void *ptepgaddr;
size_t ptepgsize;
int ptep2align;
void *pg_vaddr;
size_t pgsize;
void *vaddr;
int p2align;
enum ihk_mc_pt_attribute attr;
pte_t *ptep;
range = kmalloc(sizeof(struct vm_range), IHK_MC_AP_NOWAIT);
if (!range) {
goto err_rollback;
}
INIT_LIST_HEAD(&range->list);
range->start = src_range->start;
range->end = src_range->end;
range->flag = src_range->flag;
range->memobj = src_range->memobj;
range->objoff = src_range->objoff;
if (range->memobj) {
memobj_ref(range->memobj);
}
/* Copy actual mappings */
vaddr = (void *)range->start;
while ((unsigned long)vaddr < range->end) {
/* Get source PTE */
ptep = ihk_mc_pt_lookup_pte(org->vm->page_table, vaddr,
&ptepgaddr, &ptepgsize, &ptep2align);
if (!ptep || pte_is_null(ptep) || !pte_is_present(ptep)) {
vaddr += PAGE_SIZE;
continue;
}
dkprintf("copy_user_ranges(): 0x%lx PTE found\n", vaddr);
/* Page size */
if (arch_get_smaller_page_size(NULL, -1, &ptepgsize,
&ptep2align)) {
kprintf("ERROR: copy_user_ranges() "
"(%p,%lx-%lx %lx,%lx):"
"get pgsize failed\n", org->vm,
range->start, range->end,
range->flag, vaddr);
goto err_free_range_rollback;
}
pgsize = ptepgsize;
p2align = ptep2align;
dkprintf("copy_user_ranges(): page size: %d\n", pgsize);
/* Get physical page */
pg_vaddr = ihk_mc_alloc_aligned_pages(1, p2align, IHK_MC_AP_NOWAIT);
if (!pg_vaddr) {
kprintf("ERROR: copy_user_ranges() allocating new page\n");
goto err_free_range_rollback;
}
dkprintf("copy_user_ranges(): phys page allocated\n", pgsize);
/* Copy content */
memcpy(pg_vaddr, vaddr, pgsize);
dkprintf("copy_user_ranges(): memcpy OK\n", pgsize);
/* Set up new PTE */
attr = vrflag_to_ptattr(range->flag);
if (ihk_mc_pt_set_range(proc->vm->page_table, vaddr,
vaddr + pgsize, virt_to_phys(pg_vaddr), attr)) {
kprintf("ERROR: copy_user_ranges() "
"(%p,%lx-%lx %lx,%lx):"
"set range failed.\n",
org->vm, range->start, range->end,
range->flag, vaddr);
goto err_free_range_rollback;
}
dkprintf("copy_user_ranges(): new PTE set\n", pgsize);
vaddr += pgsize;
}
insert_vm_range_list(proc->vm, range);
}
ihk_mc_spinlock_unlock_noirq(&org->vm->memory_range_lock);
return 0;
err_free_range_rollback:
kfree(range);
err_rollback:
/* TODO: implement rollback */
ihk_mc_spinlock_unlock_noirq(&org->vm->memory_range_lock);
return -1;
}
int update_process_page_table(struct process *process,
@@ -549,10 +730,9 @@ int add_process_memory_range(struct process *process,
range->start, range->end, range->end - range->start,
range->flag);
} else {
dkprintf("range: 0x%lX - 0x%lX => 0x%lX - 0x%lX (%ld) [%lx]\n",
range->start, range->end, range->phys, range->phys +
range->end - range->start, range->end - range->start,
range->flag);
dkprintf("range: 0x%lX - 0x%lX (%ld) [%lx]\n",
range->start, range->end, range->end - range->start,
range->flag);
}
if (flag & VR_REMOTE) {