diff -NurpP --minimal linux-2.6.16-rc4-vs2.1.1-rc7/include/linux/vs_context.h linux-2.6.16-rc4-vs2.1.1-rc9.2/include/linux/vs_context.h --- linux-2.6.16-rc4-vs2.1.1-rc7/include/linux/vs_context.h 2006-02-17 23:26:33 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc9.2/include/linux/vs_context.h 2006-02-27 16:45:55 +0100 @@ -213,6 +213,11 @@ static inline void __leave_vx_admin(stru extern void exit_vx_info(struct task_struct *); + +#define vx_child_reaper(p) \ + ((p->vx_info) ? p->vx_info->vx_reaper : child_reaper) + + #else #warning duplicate inclusion #endif diff -NurpP --minimal linux-2.6.16-rc4-vs2.1.1-rc7/include/linux/vserver/context.h linux-2.6.16-rc4-vs2.1.1-rc9.2/include/linux/vserver/context.h --- linux-2.6.16-rc4-vs2.1.1-rc7/include/linux/vserver/context.h 2006-02-17 23:26:33 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc9.2/include/linux/vserver/context.h 2006-02-27 16:48:26 +0100 @@ -113,7 +113,8 @@ struct vx_info { uint64_t vx_bcaps; /* bounding caps (system) */ uint64_t vx_ccaps; /* context caps (vserver) */ - pid_t vx_initpid; /* PID of fake init process */ + struct task_struct *vx_reaper; /* guest reaper process */ + pid_t vx_initpid; /* PID of guest init */ wait_queue_head_t vx_wait; /* context exit waitqueue */ diff -NurpP --minimal linux-2.6.16-rc4-vs2.1.1-rc7/kernel/exit.c linux-2.6.16-rc4-vs2.1.1-rc9.2/kernel/exit.c --- linux-2.6.16-rc4-vs2.1.1-rc7/kernel/exit.c 2006-02-18 18:06:47 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc9.2/kernel/exit.c 2006-02-27 15:59:33 +0100 @@ -542,7 +542,7 @@ static void exit_mm(struct task_struct * mmput(mm); } -static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_reaper) +static inline void choose_new_parent(task_t *p, task_t *reaper) { /* * Make sure we're not reparenting to ourselves and that @@ -626,7 +626,7 @@ static void forget_original_parent(struc do { reaper = next_thread(reaper); if (reaper == father) { - reaper = child_reaper; + reaper = vx_child_reaper(father); break; } } while (reaper->exit_state); @@ -650,7 +650,7 @@ static void forget_original_parent(struc if (father == p->real_parent) { /* reparent with a reaper, real father it's us */ - choose_new_parent(p, reaper, child_reaper); + choose_new_parent(p, vx_child_reaper(p)); reparent_thread(p, father, 0); } else { /* reparent ptraced task to its real parent */ @@ -671,7 +671,11 @@ static void forget_original_parent(struc } list_for_each_safe(_p, _n, &father->ptrace_children) { p = list_entry(_p,struct task_struct,ptrace_list); - choose_new_parent(p, reaper, child_reaper); + + /* check for reaper context */ + BUG_ON(p->xid != reaper->xid); + + choose_new_parent(p, reaper); reparent_thread(p, father, 1); } } diff -NurpP --minimal linux-2.6.16-rc4-vs2.1.1-rc7/kernel/vserver/context.c linux-2.6.16-rc4-vs2.1.1-rc9.2/kernel/vserver/context.c --- linux-2.6.16-rc4-vs2.1.1-rc7/kernel/vserver/context.c 2006-02-17 23:26:33 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc9.2/kernel/vserver/context.c 2006-02-27 16:53:32 +0100 @@ -87,6 +87,10 @@ static struct vx_info *__alloc_vx_info(x new->vx_state = 0; init_waitqueue_head(&new->vx_wait); + /* prepare reaper */ + get_task_struct(child_reaper); + new->vx_reaper = child_reaper; + /* rest of init goes here */ vx_info_init_limit(&new->limit); vx_info_init_sched(&new->sched); @@ -548,21 +552,6 @@ out: } #endif - -/* task must me current or locked */ - -void exit_vx_info(struct task_struct *p) -{ - struct vx_info *vxi = p->vx_info; - - if (vxi) { - atomic_dec(&vxi->cvirt.nr_threads); - vx_nproc_dec(p); - release_vx_info(vxi, p); - } -} - - #ifdef CONFIG_VSERVER_DEBUG void dump_vx_info_inactive(int level) @@ -690,12 +679,29 @@ out: return ret; } +int vx_set_reaper(struct vx_info *vxi, struct task_struct *p) +{ + if (!vxi) + return -EINVAL; + + vxdprintk(VXD_CBIT(xid, 6), + "vx_set_reaper(%p[#%d],%p[#%d,%d])", + vxi, vxi->vx_id, p, p->xid, p->pid); + + if (vxi->vx_reaper == p) + return 0; + + /* set new child reaper */ + get_task_struct(p); + xchg(&vxi->vx_reaper, &p); + put_task_struct(p); + return 0; +} + int vx_set_init(struct vx_info *vxi, struct task_struct *p) { if (!vxi) return -EINVAL; - if (vxi->vx_initpid) - return -EPERM; vxdprintk(VXD_CBIT(xid, 6), "vx_set_init(%p[#%d],%p[#%d,%d,%d])", @@ -705,6 +711,15 @@ int vx_set_init(struct vx_info *vxi, str return 0; } +void vx_exit_init(struct vx_info *vxi, struct task_struct *p) +{ + vxdprintk(VXD_CBIT(xid, 6), + "vx_exit_init(%p[#%d],%p[#%d,%d,%d])", + vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid); + + vxi->vx_initpid = 0; +} + void vx_set_persistant(struct vx_info *vxi) { vxdprintk(VXD_CBIT(xid, 6), @@ -720,6 +735,25 @@ void vx_set_persistant(struct vx_info *v } +/* task must be current or locked */ + +void exit_vx_info(struct task_struct *p) +{ + struct vx_info *vxi = p->vx_info; + + if (vxi) { + atomic_dec(&vxi->cvirt.nr_threads); + vx_nproc_dec(p); + + if (vxi->vx_initpid == p->tgid) + vx_exit_init(vxi, p); + if (vxi->vx_reaper == p) + vx_set_reaper(vxi, child_reaper); + release_vx_info(vxi, p); + } +} + + /* vserver syscall commands below here */ /* taks xid and vx_info functions */