diff -urN FS-shared_umount/fs/namespace.c FS-slave_mount/fs/namespace.c --- FS-shared_umount/fs/namespace.c 2005-11-03 07:22:03.000000000 -0500 +++ FS-slave_mount/fs/namespace.c 2005-11-03 07:22:35.000000000 -0500 @@ -67,6 +67,8 @@ INIT_LIST_HEAD(&mnt->mnt_list); INIT_LIST_HEAD(&mnt->mnt_expire); INIT_LIST_HEAD(&mnt->mnt_share); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + INIT_LIST_HEAD(&mnt->mnt_slave); if (name) { int size = strlen(name) + 1; char *newname = kmalloc(size, GFP_KERNEL); @@ -1243,7 +1245,7 @@ data_page); else if (flags & MS_BIND) retval = do_loopback(&nd, dev_name, flags & MS_REC); - else if (flags & (MS_SHARED | MS_PRIVATE)) + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE)) retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) retval = do_move_mount(&nd, dev_name); diff -urN FS-shared_umount/fs/pnode.c FS-slave_mount/fs/pnode.c --- FS-shared_umount/fs/pnode.c 2005-11-03 06:59:26.000000000 -0500 +++ FS-slave_mount/fs/pnode.c 2005-11-03 06:59:27.000000000 -0500 @@ -17,13 +17,61 @@ return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); } +static int do_make_slave(struct vfsmount *mnt) +{ + struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; + struct vfsmount *slave_mnt; + + /* + * slave 'mnt' to a peer mount that has the + * same root dentry. If none is available than + * slave it to anything that is available. + */ + while ((peer_mnt = next_peer(peer_mnt)) != mnt && + peer_mnt->mnt_root != mnt->mnt_root) ; + + if (peer_mnt == mnt) { + peer_mnt = next_peer(mnt); + if (peer_mnt == mnt) + peer_mnt = NULL; + } + list_del_init(&mnt->mnt_share); + + if (peer_mnt) + master = peer_mnt; + + if (master) { + list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) + slave_mnt->mnt_master = master; + list_del(&mnt->mnt_slave); + list_add(&mnt->mnt_slave, &master->mnt_slave_list); + list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + } else { + struct list_head *p = &mnt->mnt_slave_list; + while (!list_empty(p)) { + slave_mnt = list_entry(p->next, + struct vfsmount, mnt_slave); + list_del_init(&slave_mnt->mnt_slave); + slave_mnt->mnt_master = NULL; + } + } + mnt->mnt_master = master; + CLEAR_MNT_SHARED(mnt); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + return 0; +} + void change_mnt_propagation(struct vfsmount *mnt, int type) { if (type == MS_SHARED) { set_mnt_shared(mnt); - } else { - list_del_init(&mnt->mnt_share); - mnt->mnt_flags &= ~MNT_PNODE_MASK; + return; + } + do_make_slave(mnt); + if (type != MS_SLAVE) { + list_del_init(&mnt->mnt_slave); + mnt->mnt_master = NULL; } } diff -urN FS-shared_umount/fs/pnode.h FS-slave_mount/fs/pnode.h --- FS-shared_umount/fs/pnode.h 2005-11-03 06:59:26.000000000 -0500 +++ FS-slave_mount/fs/pnode.h 2005-11-03 06:59:27.000000000 -0500 @@ -12,10 +12,12 @@ #include #define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED) +#define IS_MNT_SLAVE(mnt) (mnt->mnt_master) #define IS_MNT_NEW(mnt) (!mnt->mnt_namespace) #define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) #define CL_EXPIRE 0x01 +#define CL_SLAVE 0x02 #define CL_COPY_ALL 0x04 #define CL_MAKE_SHARED 0x08 #define CL_PROPAGATION 0x10 diff -urN FS-shared_umount/include/linux/fs.h FS-slave_mount/include/linux/fs.h --- FS-shared_umount/include/linux/fs.h 2005-11-03 06:59:26.000000000 -0500 +++ FS-slave_mount/include/linux/fs.h 2005-11-03 06:59:27.000000000 -0500 @@ -105,6 +105,7 @@ #define MS_REC 16384 #define MS_VERBOSE 32768 #define MS_PRIVATE (1<<18) /* change to private */ +#define MS_SLAVE (1<<19) /* change to slave */ #define MS_SHARED (1<<20) /* change to shared */ #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_ACTIVE (1<<30) diff -urN FS-shared_umount/include/linux/mount.h FS-slave_mount/include/linux/mount.h --- FS-shared_umount/include/linux/mount.h 2005-11-03 06:59:23.000000000 -0500 +++ FS-slave_mount/include/linux/mount.h 2005-11-03 06:59:27.000000000 -0500 @@ -38,6 +38,9 @@ struct list_head mnt_list; struct list_head mnt_expire; /* link in fs-specific expiry list */ struct list_head mnt_share; /* circular list of shared mounts */ + struct list_head mnt_slave_list;/* list of slave mounts */ + struct list_head mnt_slave; /* slave list entry */ + struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ struct namespace *mnt_namespace; /* containing namespace */ int mnt_pinned; };