diff -NurpP linux-2.6.19.2-vs2.2.0-rc8.7/include/linux/nsproxy.h linux-2.6.19.2-vs2.2.0-rc8.9/include/linux/nsproxy.h --- linux-2.6.19.2-vs2.2.0-rc8.7/include/linux/nsproxy.h 2007-01-26 13:28:15 +0100 +++ linux-2.6.19.2-vs2.2.0-rc8.9/include/linux/nsproxy.h 2007-01-29 04:49:52 +0100 @@ -35,6 +35,12 @@ void get_task_namespaces(struct task_str void free_nsproxy(struct nsproxy *ns); struct nsproxy *put_nsproxy(struct nsproxy *ns); +static inline void vs_put_nsproxy(struct nsproxy *ns) +{ + if (atomic_dec_and_test(&ns->count)) + free_nsproxy(ns); +} + static inline void finalize_put_nsproxy(struct nsproxy *ns) { if (ns) diff -NurpP linux-2.6.19.2-vs2.2.0-rc8.7/kernel/nsproxy.c linux-2.6.19.2-vs2.2.0-rc8.9/kernel/nsproxy.c --- linux-2.6.19.2-vs2.2.0-rc8.7/kernel/nsproxy.c 2007-01-26 13:34:12 +0100 +++ linux-2.6.19.2-vs2.2.0-rc8.9/kernel/nsproxy.c 2007-01-29 16:58:37 +0100 @@ -144,3 +144,4 @@ void free_nsproxy(struct nsproxy *ns) put_ipc_ns(ns->ipc_ns); kfree(ns); } + diff -NurpP linux-2.6.19.2-vs2.2.0-rc8.7/kernel/vserver/context.c linux-2.6.19.2-vs2.2.0-rc8.9/kernel/vserver/context.c --- linux-2.6.19.2-vs2.2.0-rc8.7/kernel/vserver/context.c 2007-01-26 02:13:49 +0100 +++ linux-2.6.19.2-vs2.2.0-rc8.9/kernel/vserver/context.c 2007-01-29 16:50:06 +0100 @@ -175,10 +175,10 @@ static void __shutdown_vx_info(struct vx vs_state_change(vxi, VSC_SHUTDOWN); nsproxy = xchg(&vxi->vx_nsproxy, NULL); - if (nsproxy) - put_nsproxy(nsproxy); - fs = xchg(&vxi->vx_fs, NULL); + + if (nsproxy) + vs_put_nsproxy(nsproxy); if (fs) put_fs_struct(fs); } diff -NurpP linux-2.6.19.2-vs2.2.0-rc8.7/kernel/vserver/space.c linux-2.6.19.2-vs2.2.0-rc8.9/kernel/vserver/space.c --- linux-2.6.19.2-vs2.2.0-rc8.7/kernel/vserver/space.c 2006-12-17 19:29:27 +0100 +++ linux-2.6.19.2-vs2.2.0-rc8.9/kernel/vserver/space.c 2007-01-29 16:51:40 +0100 @@ -41,6 +41,7 @@ const struct vcmd_space_mask space_mask * build a new nsproxy mix * assumes that both proxies are 'const' * does not touch nsproxy refcounts + * will take a reference on the result. */ struct nsproxy *vs_mix_nsproxy(struct nsproxy *old_nsproxy, @@ -51,15 +52,12 @@ struct nsproxy *vs_mix_nsproxy(struct ns struct ipc_namespace *old_ipc; struct nsproxy *nsproxy; - old_ns = old_nsproxy->namespace; - old_uts = old_nsproxy->uts_ns; - old_ipc = old_nsproxy->ipc_ns; - nsproxy = dup_namespaces(old_nsproxy); if (!nsproxy) goto out; if (mask & CLONE_NEWNS) { + old_ns = nsproxy->namespace; nsproxy->namespace = new_nsproxy->namespace; if (nsproxy->namespace) get_namespace(nsproxy->namespace); @@ -67,6 +65,7 @@ struct nsproxy *vs_mix_nsproxy(struct ns old_ns = NULL; if (mask & CLONE_NEWUTS) { + old_uts = nsproxy->uts_ns; nsproxy->uts_ns = new_nsproxy->uts_ns; if (nsproxy->uts_ns) get_uts_ns(nsproxy->uts_ns); @@ -74,6 +73,7 @@ struct nsproxy *vs_mix_nsproxy(struct ns old_uts = NULL; if (mask & CLONE_NEWIPC) { + old_ipc = nsproxy->ipc_ns; nsproxy->ipc_ns = new_nsproxy->ipc_ns; if (nsproxy->ipc_ns) get_ipc_ns(nsproxy->ipc_ns); @@ -90,42 +90,51 @@ out: return nsproxy; } + +/* + * merge two nsproxy structs into a new one. + * will take a reference on the result. + */ + static inline -void __vs_merge_nsproxy(struct nsproxy **ptr, - struct nsproxy *nsproxy, unsigned long mask) +struct nsproxy * __vs_merge_nsproxy(struct nsproxy *old, + struct nsproxy *proxy, unsigned long mask) { - struct nsproxy *old = *ptr; struct nsproxy null_proxy = { .namespace = NULL }; - BUG_ON(!nsproxy); + if (!proxy) + return NULL; if (mask) - *ptr = vs_mix_nsproxy(old ? old : &null_proxy, - nsproxy, mask); - else { - *ptr = nsproxy; - get_nsproxy(nsproxy); - } - if (old) - put_nsproxy(old); + return vs_mix_nsproxy(old ? old : &null_proxy, + proxy, mask); + return proxy; } +/* + * merge two fs structs into a new one. + * will take a reference on the result. + */ + static inline -void __vs_merge_fs(struct fs_struct **ptr, struct fs_struct *fs) +struct fs_struct * __vs_merge_fs(struct fs_struct *old, + struct fs_struct *fs, unsigned long mask) { - struct fs_struct *old = *ptr; + if (!(mask & CLONE_FS)) + return old; - *ptr = fs; - atomic_inc(&fs->count); - if (old) - put_fs_struct(old); + if (!fs) + return NULL; + + return copy_fs_struct(fs); } int vx_enter_space(struct vx_info *vxi, unsigned long mask) { - struct fs_struct *fs = NULL; - struct nsproxy *nsproxy; + struct nsproxy *proxy, *proxy_cur, *proxy_new; + struct fs_struct *fs, *fs_cur, *fs_new; + int ret; if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0)) return -EACCES; @@ -136,28 +145,50 @@ int vx_enter_space(struct vx_info *vxi, if ((mask & vxi->vx_nsmask) != mask) return -EINVAL; - nsproxy = vxi->vx_nsproxy; - if ((mask & CLONE_FS)) { - BUG_ON(!vxi->vx_fs); - fs = copy_fs_struct(vxi->vx_fs); - if (!fs) - return -ENOMEM; - } + proxy = vxi->vx_nsproxy; + fs = vxi->vx_fs; task_lock(current); - if (nsproxy) - __vs_merge_nsproxy(¤t->nsproxy, nsproxy, mask); - if (fs) - __vs_merge_fs(¤t->fs, fs); + fs_cur = current->fs; + atomic_inc(&fs_cur->count); + proxy_cur = current->nsproxy; + get_nsproxy(proxy_cur); task_unlock(current); - return 0; + + fs_new = __vs_merge_fs(fs_cur, fs, mask); + if (IS_ERR(fs_new)) { + ret = PTR_ERR(fs_new); + goto out_put; + } + + proxy_new = __vs_merge_nsproxy(proxy_cur, proxy, mask); + if (IS_ERR(proxy_new)) { + ret = PTR_ERR(proxy_new); + goto out_put_fs; + } + + fs_new = xchg(¤t->fs, fs_new); + proxy_new = xchg(¤t->nsproxy, proxy_new); + ret = 0; + + if (proxy_new) + vs_put_nsproxy(proxy_new); +out_put_fs: + if (fs_new) + put_fs_struct(fs_new); +out_put: + if (fs_cur) + put_fs_struct(fs_cur); + if (proxy_cur) + vs_put_nsproxy(proxy_cur); + return ret; } int vx_set_space(struct vx_info *vxi, unsigned long mask) { - struct fs_struct *fs, *fs_copy = NULL; - struct nsproxy *nsproxy; + struct nsproxy *proxy, *proxy_cur, *proxy_new; + struct fs_struct *fs, *fs_cur, *fs_new; int ret; if (!mask) @@ -166,30 +197,45 @@ int vx_set_space(struct vx_info *vxi, un if ((mask & space_mask.mask) != mask) return -EINVAL; + proxy = vxi->vx_nsproxy; + fs = vxi->vx_fs; + task_lock(current); - fs = current->fs; - atomic_inc(&fs->count); - nsproxy = current->nsproxy; - get_nsproxy(nsproxy); + fs_cur = current->fs; + atomic_inc(&fs_cur->count); + proxy_cur = current->nsproxy; + get_nsproxy(proxy_cur); task_unlock(current); - ret = -ENOMEM; - if ((mask & CLONE_FS)) { - fs_copy = copy_fs_struct(fs); - if (!fs_copy) - goto out_put; + fs_new = __vs_merge_fs(fs, fs_cur, mask); + if (IS_ERR(fs_new)) { + ret = PTR_ERR(fs_new); + goto out_put; } - if (nsproxy) - __vs_merge_nsproxy(&vxi->vx_nsproxy, nsproxy, mask); - if (fs_copy) - __vs_merge_fs(&vxi->vx_fs, fs_copy); - vxi->vx_nsmask |= mask; + proxy_new = __vs_merge_nsproxy(proxy, proxy_cur, mask); + if (IS_ERR(proxy_new)) { + ret = PTR_ERR(proxy_new); + goto out_put_fs; + } + fs = xchg(&vxi->vx_fs, fs_new); + proxy = xchg(&vxi->vx_nsproxy, proxy_new); + vxi->vx_nsmask |= mask; + fs_new = fs; + proxy_new = proxy; ret = 0; + + if (proxy_new) + vs_put_nsproxy(proxy_new); +out_put_fs: + if (fs_new) + put_fs_struct(fs_new); out_put: - put_fs_struct(fs); - put_nsproxy(nsproxy); + if (fs) + put_fs_struct(fs); + if (proxy) + vs_put_nsproxy(proxy); return ret; }