struct_cpy(childregs, regs);
childregs->eax = 0;
childregs->esp = esp;
+ p->user_vm_lock = NULL;
p->thread.esp = (unsigned long) childregs;
p->thread.esp0 = (unsigned long) (childregs+1);
unlazy_fpu(tsk);
struct_cpy(&p->thread.i387, &tsk->thread.i387);
+ if (unlikely(NULL != tsk->thread.ts_io_bitmap)) {
+ p->thread.ts_io_bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
+ if (!p->thread.ts_io_bitmap)
+ return -ENOMEM;
+ memcpy(p->thread.ts_io_bitmap, tsk->thread.ts_io_bitmap,
+ IO_BITMAP_BYTES);
+ }
+
+ /*
+ * The common fastpath:
+ */
+ if (!(clone_flags & (CLONE_SETTLS | CLONE_SETTID | CLONE_RELEASE_VM)))
+ return 0;
/*
* Set a new TLS for the child thread?
*/
if (put_user(p->pid, (pid_t *)childregs->edx))
return -EFAULT;
- if (unlikely(NULL != tsk->thread.ts_io_bitmap)) {
- p->thread.ts_io_bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
- if (!p->thread.ts_io_bitmap)
- return -ENOMEM;
- memcpy(p->thread.ts_io_bitmap, tsk->thread.ts_io_bitmap,
- IO_BITMAP_BYTES);
+ /*
+ * Does the userspace VM want any unlock on mm_release()?
+ */
+ if (clone_flags & CLONE_RELEASE_VM) {
+ childregs->esp -= sizeof(0UL);
+ p->user_vm_lock = (long *) esp;
}
-
return 0;
}
#define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */
#define CLONE_SETTID 0x00100000 /* write the TID back to userspace */
#define CLONE_DETACHED 0x00200000 /* parent wants no child-exit signal */
+#define CLONE_RELEASE_VM 0x00400000 /* release the userspace VM */
#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
wait_queue_head_t wait_chldexit; /* for wait4() */
struct completion *vfork_done; /* for vfork() */
+ long *user_vm_lock; /* for CLONE_RELEASE_VM */
unsigned long rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
tsk->vfork_done = NULL;
complete(vfork_done);
}
+ if (tsk->user_vm_lock)
+ /*
+ * We dont check the error code - if userspace has
+ * not set up a proper pointer then tough luck.
+ */
+ put_user(0UL, tsk->user_vm_lock);
}
static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)