--- linux-2.6.16-rc4/fs/namei.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namei.c 2006-02-17 23:26:32 +0100 @@ -702,7 +726,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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +0100 @@ -1310,9 +1404,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-rc4/include/linux/namespace.h 2006-02-18 14:40:34 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/include/linux/namespace.h 2006-02-17 23:27:06 +0100 @@ -16,6 +16,7 @@ struct namespace { extern int copy_namespace(int, struct task_struct *); extern void __put_namespace(struct namespace *namespace); extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *); +extern void umount_unused(struct vfsmount *, struct fs_struct *); static inline void put_namespace(struct namespace *namespace) { --- linux-2.6.16-rc4/include/linux/vserver/namespace.h 1970-01-01 01:00:00 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/include/linux/vserver/namespace.h 2006-02-17 23:26:33 +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-rc4/kernel/vserver/namespace.c 1970-01-01 01:00:00 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/kernel/vserver/namespace.c 2006-02-17 23:26:33 +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-rc4/fs/namespace.c 2006-02-18 14:40:22 +0100 +++ linux-2.6.16-rc4-vs2.1.1-rc8/fs/namespace.c 2006-02-17 23:28:12 +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);