--- linux-2.6.16-rc1/fs/namei.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namei.c 2006-01-25 05:34:51 +0100 @@ -700,7 +724,8 @@ static __always_inline void follow_dotdo if (nd->dentry == current->fs->root && nd->mnt == current->fs->rootmnt) { read_unlock(¤t->fs->lock); - break; + /* for sane '/' avoid follow_mount() */ + return; } read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -241,6 +243,7 @@ static struct vfsmount *clone_mnt(struct mnt->mnt_root = dget(root); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; + mnt->mnt_tag = old->mnt_tag; if (flag & CL_SLAVE) { list_add(&mnt->mnt_slave, &old->mnt_slave_list); --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -349,6 +352,32 @@ static inline void mangle(struct seq_fil seq_escape(m, s, " \t\n\\"); } +static int mnt_is_reachable(struct vfsmount *mnt) +{ + struct vfsmount *root_mnt; + struct dentry *root, *point; + int ret; + + if (mnt == mnt->mnt_namespace->root) + return 1; + + spin_lock(&dcache_lock); + root_mnt = current->fs->rootmnt; + root = current->fs->root; + point = root; + + while ((mnt != mnt->mnt_parent) && (mnt != root_mnt)) { + point = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + } + + ret = (mnt == root_mnt) && is_subdir(point, root); + + spin_unlock(&dcache_lock); + + return ret; +} + static int show_vfsmnt(struct seq_file *m, void *v) { struct vfsmount *mnt = v; --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -475,7 +520,8 @@ void release_mounts(struct list_head *he } } -void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) +static inline void __umount_list(struct vfsmount *mnt, + int propagate, struct list_head *kill) { struct vfsmount *p; --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -479,11 +525,6 @@ ***** { struct vfsmount *p; - for (p = mnt; p; p = next_mnt(p, mnt)) { - list_del(&p->mnt_hash); - list_add(&p->mnt_hash, kill); - } - if (propagate) propagate_umount(kill); --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -499,6 +540,33 @@ void umount_tree(struct vfsmount *mnt, i } } +void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) +{ + struct vfsmount *p; + + for (p = mnt; p; p = next_mnt(p, mnt)) { + list_del(&p->mnt_hash); + list_add(&p->mnt_hash, kill); + // p->mnt_namespace = NULL; + } + __umount_list(mnt, propagate, kill); +} + +void umount_unused(struct vfsmount *mnt, struct fs_struct *fs) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + if (p == fs->rootmnt || p == fs->pwdmnt) + continue; + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + p->mnt_namespace = NULL; + } + __umount_list(mnt, 0, &kill); +} + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block *sb = mnt->mnt_sb; --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -559,7 +627,7 @@ static int do_umount(struct vfsmount *mn down_write(&sb->s_umount); if (!(sb->s_flags & MS_RDONLY)) { lock_kernel(); - DQUOT_OFF(sb); + DQUOT_OFF(sb->s_dqh); retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); unlock_kernel(); } --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -861,7 +931,8 @@ static int do_change_type(struct nameida /* * do loopback mount. */ -static int do_loopback(struct nameidata *nd, char *old_name, int recurse) +static int do_loopback(struct nameidata *nd, char *old_name, tag_t tag, + unsigned long flags, int mnt_flags) { struct nameidata old_nd; struct vfsmount *mnt = NULL; --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -866,6 +937,7 @@ ***** struct nameidata old_nd; struct vfsmount *mnt = NULL; int err = mount_is_safe(nd); + int recurse = flags & MS_REC; if (err) return err; if (!old_name || !*old_name) --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -891,6 +963,12 @@ static int do_loopback(struct nameidata if (!mnt) goto out; + mnt->mnt_flags = mnt_flags; + if (flags & MS_TAGID) { + mnt->mnt_tag = tag; + mnt->mnt_flags |= MNT_TAGID; + } + err = graft_tree(mnt, nd); if (err) { LIST_HEAD(umount_list); --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -912,7 +991,7 @@ out: * on it - tough luck. */ static int do_remount(struct nameidata *nd, int flags, int mnt_flags, - void *data) + void *data, xid_t xid) { int err; struct super_block *sb = nd->mnt->mnt_sb; --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -951,7 +1030,7 @@ static int do_move_mount(struct nameidat struct nameidata old_nd, parent_nd; struct vfsmount *p; int err = 0; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -1031,7 +1110,7 @@ static int do_new_mount(struct nameidata return -EINVAL; /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -1269,6 +1348,7 @@ long do_mount(char *dev_name, char *dir_ struct nameidata nd; int retval = 0; int mnt_flags = 0; + tag_t tag = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -1284,7 +1364,19 @@ long do_mount(char *dev_name, char *dir_ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; +#ifdef CONFIG_PROPAGATE + retval = dx_parse_tag(data_page, &tag, 1); + if (retval) { + mnt_flags |= MNT_TAGID; + /* bind and re-mounts get the tag flag */ + if (flags & (MS_BIND|MS_REMOUNT)) + flags |= MS_TAGID; + } +#endif + /* Separate the per-mountpoint flags */ + if (flags & MS_RDONLY) + mnt_flags |= MNT_RDONLY; if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; if (flags & MS_NODEV) --- linux-2.6.16-rc1/fs/namespace.c 2006-01-26 22:35:12 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/fs/namespace.c 2006-01-25 05:34:51 +0100 @@ -1310,9 +1402,9 @@ long do_mount(char *dev_name, char *dir_ if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, - data_page); + data_page, tag); else if (flags & MS_BIND) - retval = do_loopback(&nd, dev_name, flags & MS_REC); + retval = do_loopback(&nd, dev_name, tag, flags, mnt_flags); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) --- linux-2.6.16-rc1/include/linux/namespace.h 2006-01-03 17:30:09 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/include/linux/namespace.h 2006-01-21 18:28:03 +0100 @@ -15,6 +15,7 @@ struct namespace { extern int copy_namespace(int, struct task_struct *); extern void __put_namespace(struct namespace *namespace); +extern void umount_unused(struct vfsmount *, struct fs_struct *); static inline void put_namespace(struct namespace *namespace) { --- linux-2.6.16-rc1/include/linux/vserver/namespace.h 1970-01-01 01:00:00 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/include/linux/vserver/namespace.h 2006-01-27 20:41:31 +0100 @@ -0,0 +1,15 @@ +#ifndef _VX_NAMESPACE_H +#define _VX_NAMESPACE_H + + +#include + +struct vx_info; +struct namespace; +struct fs_struct; + +extern int vx_set_namespace(struct vx_info *, struct namespace *, struct fs_struct *); + +#else /* _VX_NAMESPACE_H */ +#warning duplicate inclusion +#endif /* _VX_NAMESPACE_H */ --- linux-2.6.16-rc1/kernel/vserver/namespace.c 1970-01-01 01:00:00 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/kernel/vserver/namespace.c 2006-01-27 22:04:09 +0100 @@ -0,0 +1,123 @@ +/* + * linux/kernel/vserver/namespace.c + * + * Virtual Server: Context Namespace Support + * + * Copyright (C) 2003-2005 Herbert Pötzl + * + * V0.01 broken out from context.c 0.07 + * V0.02 added task locking for namespace + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* namespace functions */ + +#include + +int vx_set_namespace(struct vx_info *vxi, struct namespace *ns, struct fs_struct *fs) +{ + struct fs_struct *fs_copy; + + if (vxi->vx_namespace) + return -EPERM; + if (!ns || !fs) + return -EINVAL; + + fs_copy = copy_fs_struct(fs); + if (!fs_copy) + return -ENOMEM; + + get_namespace(ns); + vxi->vx_namespace = ns; + vxi->vx_fs = fs_copy; + return 0; +} + +int vc_enter_namespace(uint32_t id, void *data) +{ + struct vx_info *vxi; + struct fs_struct *old_fs, *fs; + struct namespace *old_ns; + int ret = 0; + + if (!vx_check(0, VX_ADMIN)) + return -ENOSYS; + + vxi = lookup_vx_info(id); + if (!vxi) + return -ESRCH; + + ret = -EINVAL; + if (!vxi->vx_namespace) + goto out_put; + + ret = -ENOMEM; + fs = copy_fs_struct(vxi->vx_fs); + if (!fs) + goto out_put; + + ret = 0; + task_lock(current); + old_ns = current->namespace; + old_fs = current->fs; + get_namespace(vxi->vx_namespace); + current->namespace = vxi->vx_namespace; + current->fs = fs; + task_unlock(current); + + put_namespace(old_ns); + put_fs_struct(old_fs); +out_put: + put_vx_info(vxi); + return ret; +} + +int vc_cleanup_namespace(uint32_t id, void *data) +{ + // down_write(¤t->namespace->sem); + spin_lock(&vfsmount_lock); + umount_unused(current->namespace->root, current->fs); + spin_unlock(&vfsmount_lock); + // up_write(¤t->namespace->sem); + return 0; +} + +int vc_set_namespace(uint32_t id, void __user *data) +{ + struct fs_struct *fs; + struct namespace *ns; + struct vx_info *vxi; + int ret; + + vxi = lookup_vx_info(id); + if (!vxi) + return -ESRCH; + + task_lock(current); + fs = current->fs; + atomic_inc(&fs->count); + ns = current->namespace; + get_namespace(current->namespace); + task_unlock(current); + + ret = vx_set_namespace(vxi, ns, fs); + + put_namespace(ns); + put_fs_struct(fs); + put_vx_info(vxi); + return ret; +} + --- linux-2.6.16-rc1/mm/slab_vs.h 1970-01-01 01:00:00 +0100 +++ linux-2.6.16-rc1-vs2.1.0.9.4/mm/slab_vs.h 2006-01-21 18:28:03 +0100 @@ -0,0 +1,23 @@ + +static inline +void vx_slab_alloc(struct kmem_cache *cachep, gfp_t flags) +{ + int what = cachep->gfpflags & GFP_ZONEMASK; + + if (!current->vx_info) + return; + + atomic_add(cachep->objsize, ¤t->vx_info->cacct.slab[what]); +} + +static inline +void vx_slab_free(struct kmem_cache *cachep) +{ + int what = cachep->gfpflags & GFP_ZONEMASK; + + if (!current->vx_info) + return; + + atomic_sub(cachep->objsize, ¤t->vx_info->cacct.slab[what]); +} +