X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fvserver%2Fcontext.c;h=d24d0144be8e0c7a74858f31b1a68b69afed04a9;hb=567f20a20be06ad546b5962340c4be268462055b;hp=87bf17e0da073eaf5eb76e2adf56cb4f15efed7c;hpb=cace1c4618b6c6442b7dc973e935e7f3268e4aa7;p=linux-2.6.git diff --git a/kernel/vserver/context.c b/kernel/vserver/context.c index 87bf17e0d..d24d0144b 100644 --- a/kernel/vserver/context.c +++ b/kernel/vserver/context.c @@ -16,21 +16,23 @@ * V0.09 revert to non RCU for now * V0.10 and back to working RCU hash * V0.11 and back to locking again + * V0.12 have __create claim() the vxi * */ -#include #include #include #include #include +#include +#include +#include #include #include #include #include - -#include +#include #include #include @@ -66,6 +68,10 @@ static struct vx_info *__alloc_vx_info(xid_t xid) 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); @@ -76,6 +82,9 @@ static struct vx_info *__alloc_vx_info(xid_t xid) new->vx_bcaps = CAP_INIT_EFF_SET; new->vx_ccaps = 0; + new->reboot_cmd = 0; + new->exit_code = 0; + vxdprintk(VXD_CBIT(xid, 0), "alloc_vx_info(%d) = %p", xid, new); vxh_alloc_vx_info(new); @@ -187,9 +196,9 @@ static inline void __hash_vx_info(struct vx_info *vxi) static inline void __unhash_vx_info(struct vx_info *vxi) { - vxd_assert_lock(&vx_info_hash_lock); vxdprintk(VXD_CBIT(xid, 4), "__unhash_vx_info: %p[#%d]", vxi, vxi->vx_id); + spin_lock(&vx_info_hash_lock); vxh_unhash_vx_info(vxi); /* context must be hashed */ @@ -197,6 +206,7 @@ static inline void __unhash_vx_info(struct vx_info *vxi) vxi->vx_state &= ~VXS_HASHED; hlist_del(&vxi->vx_hlist); + spin_unlock(&vx_info_hash_lock); } @@ -318,7 +328,7 @@ out_unlock: /* __create_vx_info() * create the requested context - * get() and hash it */ + * get(), claim() and hash it */ static struct vx_info * __create_vx_info(int id) { @@ -363,6 +373,7 @@ static struct vx_info * __create_vx_info(int id) /* new context */ vxdprintk(VXD_CBIT(xid, 0), "create_vx_info(%d) = %p (new)", id, new); + claim_vx_info(new, NULL); __hash_vx_info(get_vx_info(new)); vxi = new, new = NULL; @@ -381,19 +392,17 @@ out_unlock: void unhash_vx_info(struct vx_info *vxi) { __shutdown_vx_info(vxi); - spin_lock(&vx_info_hash_lock); __unhash_vx_info(vxi); - spin_unlock(&vx_info_hash_lock); __wakeup_vx_info(vxi); } -/* locate_vx_info() +/* lookup_vx_info() * search for a vx_info and get() it * negative id means current */ -struct vx_info *locate_vx_info(int id) +struct vx_info *lookup_vx_info(int id) { struct vx_info *vxi = NULL; @@ -423,7 +432,7 @@ int xid_is_hashed(xid_t xid) #ifdef CONFIG_VSERVER_LEGACY -struct vx_info *locate_or_create_vx_info(int id) +struct vx_info *lookup_or_create_vx_info(int id) { int err; @@ -485,10 +494,8 @@ int vx_migrate_user(struct task_struct *p, struct vx_info *vxi) return 0; } -void vx_mask_bcaps(struct task_struct *p) +void vx_mask_bcaps(struct vx_info *vxi, struct task_struct *p) { - struct vx_info *vxi = p->vx_info; - p->cap_effective &= vxi->vx_bcaps; p->cap_inheritable &= vxi->vx_bcaps; p->cap_permitted &= vxi->vx_bcaps; @@ -500,12 +507,15 @@ void vx_mask_bcaps(struct task_struct *p) static int vx_openfd_task(struct task_struct *tsk) { struct files_struct *files = tsk->files; + struct fdtable *fdt; const unsigned long *bptr; int count, total; + /* no rcu_read_lock() because of spin_lock() */ spin_lock(&files->file_lock); - bptr = files->open_fds->fds_bits; - count = files->max_fds / (sizeof(unsigned long) * 8); + fdt = files_fdtable(files); + bptr = fdt->open_fds->fds_bits; + count = fdt->max_fds / (sizeof(unsigned long) * 8); for (total = 0; count > 0; count--) { if (*bptr) total += hweight_long(*bptr); @@ -567,7 +577,7 @@ int vx_migrate_task(struct task_struct *p, struct vx_info *vxi) "moved task %p into vxi:%p[#%d]", p, vxi, vxi->vx_id); - vx_mask_bcaps(p); + vx_mask_bcaps(vxi, p); task_unlock(p); } out: @@ -575,21 +585,106 @@ out: return ret; } +int vx_set_reaper(struct vx_info *vxi, struct task_struct *p) +{ + struct task_struct *old_reaper; + + 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); + + old_reaper = vxi->vx_reaper; + if (old_reaper == p) + return 0; + + /* set new child reaper */ + get_task_struct(p); + vxi->vx_reaper = p; + put_task_struct(old_reaper); + 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])", vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid); + vxi->vx_flags &= ~VXF_STATE_INIT; vxi->vx_initpid = p->tgid; return 0; } +void vx_exit_init(struct vx_info *vxi, struct task_struct *p, int code) +{ + 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->exit_code = code; + vxi->vx_initpid = 0; +} + +void vx_set_persistent(struct vx_info *vxi) +{ + vxdprintk(VXD_CBIT(xid, 6), + "vx_set_persistent(%p[#%d])", vxi, vxi->vx_id); + + get_vx_info(vxi); + claim_vx_info(vxi, NULL); +} + +void vx_clear_persistent(struct vx_info *vxi) +{ + vxdprintk(VXD_CBIT(xid, 6), + "vx_clear_persistent(%p[#%d])", vxi, vxi->vx_id); + + release_vx_info(vxi, NULL); + put_vx_info(vxi); +} + +void vx_update_persistent(struct vx_info *vxi) +{ + if (vx_info_flags(vxi, VXF_PERSISTENT, 0)) + vx_set_persistent(vxi); + else + vx_clear_persistent(vxi); +} + + +/* task must be current or locked */ + +void exit_vx_info(struct task_struct *p, int code) +{ + struct vx_info *vxi = p->vx_info; + + if (vxi) { + atomic_dec(&vxi->cvirt.nr_threads); + vx_nproc_dec(p); + + vxi->exit_code = code; + release_vx_info(vxi, p); + } +} + +void exit_vx_info_early(struct task_struct *p, int code) +{ + struct vx_info *vxi = p->vx_info; + + if (vxi) { + if (vxi->vx_initpid == p->tgid) + vx_exit_init(vxi, p, code); + if (vxi->vx_reaper == p) + vx_set_reaper(vxi, child_reaper); + } +} + /* vserver syscall commands below here */ @@ -629,7 +724,7 @@ int vc_vx_info(uint32_t id, void __user *data) if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) return -EPERM; - vxi = locate_vx_info(id); + vxi = lookup_vx_info(id); if (!vxi) return -ESRCH; @@ -668,10 +763,22 @@ int vc_ctx_create(uint32_t xid, void __user *data) /* initial flags */ new_vxi->vx_flags = vc_data.flagword; - vs_state_change(new_vxi, VSC_STARTUP); + ret = -ENOEXEC; + if (vs_state_change(new_vxi, VSC_STARTUP)) + goto out; + + ret = vx_migrate_task(current, new_vxi); + if (ret) + goto out; + + /* return context id on success */ ret = new_vxi->vx_id; - vx_migrate_task(current, new_vxi); - /* if this fails, we might end up with a hashed vx_info */ + + /* get a reference for persistent contexts */ + if ((vc_data.flagword & VXF_PERSISTENT)) + vx_set_persistent(new_vxi); +out: + release_vx_info(new_vxi, NULL); put_vx_info(new_vxi); return ret; } @@ -679,10 +786,13 @@ int vc_ctx_create(uint32_t xid, void __user *data) int vc_ctx_migrate(uint32_t id, void __user *data) { + struct vcmd_ctx_migrate vc_data = { .flagword = 0 }; struct vx_info *vxi; if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (data && copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; /* dirty hack until Spectator becomes a cap */ if (id == 1) { @@ -690,10 +800,14 @@ int vc_ctx_migrate(uint32_t id, void __user *data) return 0; } - vxi = locate_vx_info(id); + vxi = lookup_vx_info(id); if (!vxi) return -ESRCH; vx_migrate_task(current, vxi); + if (vc_data.flagword & VXM_SET_INIT) + vx_set_init(vxi, current); + if (vc_data.flagword & VXM_SET_REAPER) + vx_set_reaper(vxi, current); put_vx_info(vxi); return 0; } @@ -707,7 +821,7 @@ int vc_get_cflags(uint32_t id, void __user *data) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - vxi = locate_vx_info(id); + vxi = lookup_vx_info(id); if (!vxi) return -ESRCH; @@ -734,7 +848,7 @@ int vc_set_cflags(uint32_t id, void __user *data) if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - vxi = locate_vx_info(id); + vxi = lookup_vx_info(id); if (!vxi) return -ESRCH; @@ -742,14 +856,20 @@ int vc_set_cflags(uint32_t id, void __user *data) mask = vx_mask_mask(vc_data.mask, vxi->vx_flags, VXF_ONE_TIME); trigger = (mask & vxi->vx_flags) ^ (mask & vc_data.flagword); - if (trigger & VXF_STATE_SETUP) - vx_mask_bcaps(current); - if (trigger & VXF_STATE_INIT) - if (vxi == current->vx_info) + if (vxi == current->vx_info) { + if (trigger & VXF_STATE_SETUP) + vx_mask_bcaps(vxi, current); + if (trigger & VXF_STATE_INIT) { vx_set_init(vxi, current); + vx_set_reaper(vxi, current); + } + } vxi->vx_flags = vx_mask_flags(vxi->vx_flags, vc_data.flagword, mask); + if (trigger & VXF_PERSISTENT) + vx_update_persistent(vxi); + put_vx_info(vxi); return 0; } @@ -762,7 +882,7 @@ int vc_get_ccaps(uint32_t id, void __user *data) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - vxi = locate_vx_info(id); + vxi = lookup_vx_info(id); if (!vxi) return -ESRCH; @@ -786,7 +906,7 @@ int vc_set_ccaps(uint32_t id, void __user *data) if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - vxi = locate_vx_info(id); + vxi = lookup_vx_info(id); if (!vxi) return -ESRCH;