diff options
| author | Ram Pai <linuxram@us.ibm.com> | 2005-11-07 17:21:20 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 21:18:11 -0500 |
| commit | 9676f0c6389b62bd6b24d77d4b3abdbcfa32d0f2 (patch) | |
| tree | fd7d965c6d646cf7e4cfd35e866723927f6cfe8b | |
| parent | 5afe00221389998a25d611dc7941c06580c29eb6 (diff) | |
[PATCH] unbindable mounts
An unbindable mount does not forward or receive propagation. Also
unbindable mount disallows bind mounts. The semantics is as follows.
Bind semantics:
It is invalid to bind mount an unbindable mount.
Move semantics:
It is invalid to move an unbindable mount under shared mount.
Clone-namespace semantics:
If a mount is unbindable in the parent namespace, the corresponding
cloned mount in the child namespace becomes unbindable too. Note:
there is subtle difference, unbindable mounts cannot be bind mounted
but can be cloned during clone-namespace.
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | fs/namespace.c | 88 | ||||
| -rw-r--r-- | fs/pnode.c | 2 | ||||
| -rw-r--r-- | fs/pnode.h | 1 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 | ||||
| -rw-r--r-- | include/linux/mount.h | 1 |
5 files changed, 67 insertions, 26 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 089670363704..caa9187f67e5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -213,6 +213,16 @@ static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) | |||
| 213 | return list_entry(next, struct vfsmount, mnt_child); | 213 | return list_entry(next, struct vfsmount, mnt_child); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | static struct vfsmount *skip_mnt_tree(struct vfsmount *p) | ||
| 217 | { | ||
| 218 | struct list_head *prev = p->mnt_mounts.prev; | ||
| 219 | while (prev != &p->mnt_mounts) { | ||
| 220 | p = list_entry(prev, struct vfsmount, mnt_child); | ||
| 221 | prev = p->mnt_mounts.prev; | ||
| 222 | } | ||
| 223 | return p; | ||
| 224 | } | ||
| 225 | |||
| 216 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | 226 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, |
| 217 | int flag) | 227 | int flag) |
| 218 | { | 228 | { |
| @@ -650,6 +660,9 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, | |||
| 650 | struct vfsmount *res, *p, *q, *r, *s; | 660 | struct vfsmount *res, *p, *q, *r, *s; |
| 651 | struct nameidata nd; | 661 | struct nameidata nd; |
| 652 | 662 | ||
| 663 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) | ||
| 664 | return NULL; | ||
| 665 | |||
| 653 | res = q = clone_mnt(mnt, dentry, flag); | 666 | res = q = clone_mnt(mnt, dentry, flag); |
| 654 | if (!q) | 667 | if (!q) |
| 655 | goto Enomem; | 668 | goto Enomem; |
| @@ -661,6 +674,10 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, | |||
| 661 | continue; | 674 | continue; |
| 662 | 675 | ||
| 663 | for (s = r; s; s = next_mnt(s, r)) { | 676 | for (s = r; s; s = next_mnt(s, r)) { |
| 677 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) { | ||
| 678 | s = skip_mnt_tree(s); | ||
| 679 | continue; | ||
| 680 | } | ||
| 664 | while (p != s->mnt_parent) { | 681 | while (p != s->mnt_parent) { |
| 665 | p = p->mnt_parent; | 682 | p = p->mnt_parent; |
| 666 | q = q->mnt_parent; | 683 | q = q->mnt_parent; |
| @@ -698,18 +715,18 @@ Enomem: | |||
| 698 | * | 715 | * |
| 699 | * NOTE: in the table below explains the semantics when a source mount | 716 | * NOTE: in the table below explains the semantics when a source mount |
| 700 | * of a given type is attached to a destination mount of a given type. | 717 | * of a given type is attached to a destination mount of a given type. |
| 701 | * ------------------------------------------------------------- | 718 | * --------------------------------------------------------------------------- |
| 702 | * | BIND MOUNT OPERATION | | 719 | * | BIND MOUNT OPERATION | |
| 703 | * |************************************************************* | 720 | * |************************************************************************** |
| 704 | * | source-->| shared | private | slave | | 721 | * | source-->| shared | private | slave | unbindable | |
| 705 | * | dest | | | | | 722 | * | dest | | | | | |
| 706 | * | | | | | | | 723 | * | | | | | | | |
| 707 | * | v | | | | | 724 | * | v | | | | | |
| 708 | * |************************************************************* | 725 | * |************************************************************************** |
| 709 | * | shared | shared (++) | shared (+) | shared(+++)| | 726 | * | shared | shared (++) | shared (+) | shared(+++)| invalid | |
| 710 | * | | | | | | 727 | * | | | | | | |
| 711 | * |non-shared| shared (+) | private | slave (*) | | 728 | * |non-shared| shared (+) | private | slave (*) | invalid | |
| 712 | * ************************************************************** | 729 | * *************************************************************************** |
| 713 | * A bind operation clones the source mount and mounts the clone on the | 730 | * A bind operation clones the source mount and mounts the clone on the |
| 714 | * destination mount. | 731 | * destination mount. |
| 715 | * | 732 | * |
| @@ -726,18 +743,18 @@ Enomem: | |||
| 726 | * (*) the cloned mount is made a slave of the same master as that of the | 743 | * (*) the cloned mount is made a slave of the same master as that of the |
| 727 | * source mount. | 744 | * source mount. |
| 728 | * | 745 | * |
| 729 | * -------------------------------------------------------------- | 746 | * --------------------------------------------------------------------------- |
| 730 | * | MOVE MOUNT OPERATION | | 747 | * | MOVE MOUNT OPERATION | |
| 731 | * |************************************************************* | 748 | * |************************************************************************** |
| 732 | * | source-->| shared | private | slave | | 749 | * | source-->| shared | private | slave | unbindable | |
| 733 | * | dest | | | | | 750 | * | dest | | | | | |
| 734 | * | | | | | | | 751 | * | | | | | | | |
| 735 | * | v | | | | | 752 | * | v | | | | | |
| 736 | * |************************************************************* | 753 | * |************************************************************************** |
| 737 | * | shared | shared (+) | shared (+) | shared(+++) | | 754 | * | shared | shared (+) | shared (+) | shared(+++) | invalid | |
| 738 | * | | | | | | 755 | * | | | | | | |
| 739 | * |non-shared| shared (+*) | private | slave (*) | | 756 | * |non-shared| shared (+*) | private | slave (*) | unbindable | |
| 740 | * ************************************************************** | 757 | * *************************************************************************** |
| 741 | * | 758 | * |
| 742 | * (+) the mount is moved to the destination. And is then propagated to | 759 | * (+) the mount is moved to the destination. And is then propagated to |
| 743 | * all the mounts in the propagation tree of the destination mount. | 760 | * all the mounts in the propagation tree of the destination mount. |
| @@ -854,6 +871,9 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) | |||
| 854 | 871 | ||
| 855 | down_write(&namespace_sem); | 872 | down_write(&namespace_sem); |
| 856 | err = -EINVAL; | 873 | err = -EINVAL; |
| 874 | if (IS_MNT_UNBINDABLE(old_nd.mnt)) | ||
| 875 | goto out; | ||
| 876 | |||
| 857 | if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) | 877 | if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) |
| 858 | goto out; | 878 | goto out; |
| 859 | 879 | ||
| @@ -911,6 +931,16 @@ static int do_remount(struct nameidata *nd, int flags, int mnt_flags, | |||
| 911 | return err; | 931 | return err; |
| 912 | } | 932 | } |
| 913 | 933 | ||
| 934 | static inline int tree_contains_unbindable(struct vfsmount *mnt) | ||
| 935 | { | ||
| 936 | struct vfsmount *p; | ||
| 937 | for (p = mnt; p; p = next_mnt(p, mnt)) { | ||
| 938 | if (IS_MNT_UNBINDABLE(p)) | ||
| 939 | return 1; | ||
| 940 | } | ||
| 941 | return 0; | ||
| 942 | } | ||
| 943 | |||
| 914 | static int do_move_mount(struct nameidata *nd, char *old_name) | 944 | static int do_move_mount(struct nameidata *nd, char *old_name) |
| 915 | { | 945 | { |
| 916 | struct nameidata old_nd, parent_nd; | 946 | struct nameidata old_nd, parent_nd; |
| @@ -954,6 +984,12 @@ static int do_move_mount(struct nameidata *nd, char *old_name) | |||
| 954 | */ | 984 | */ |
| 955 | if (old_nd.mnt->mnt_parent && IS_MNT_SHARED(old_nd.mnt->mnt_parent)) | 985 | if (old_nd.mnt->mnt_parent && IS_MNT_SHARED(old_nd.mnt->mnt_parent)) |
| 956 | goto out1; | 986 | goto out1; |
| 987 | /* | ||
| 988 | * Don't move a mount tree containing unbindable mounts to a destination | ||
| 989 | * mount which is shared. | ||
| 990 | */ | ||
| 991 | if (IS_MNT_SHARED(nd->mnt) && tree_contains_unbindable(old_nd.mnt)) | ||
| 992 | goto out1; | ||
| 957 | err = -ELOOP; | 993 | err = -ELOOP; |
| 958 | for (p = nd->mnt; p->mnt_parent != p; p = p->mnt_parent) | 994 | for (p = nd->mnt; p->mnt_parent != p; p = p->mnt_parent) |
| 959 | if (p == old_nd.mnt) | 995 | if (p == old_nd.mnt) |
| @@ -1266,7 +1302,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
| 1266 | data_page); | 1302 | data_page); |
| 1267 | else if (flags & MS_BIND) | 1303 | else if (flags & MS_BIND) |
| 1268 | retval = do_loopback(&nd, dev_name, flags & MS_REC); | 1304 | retval = do_loopback(&nd, dev_name, flags & MS_REC); |
| 1269 | else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE)) | 1305 | else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) |
| 1270 | retval = do_change_type(&nd, flags); | 1306 | retval = do_change_type(&nd, flags); |
| 1271 | else if (flags & MS_MOVE) | 1307 | else if (flags & MS_MOVE) |
| 1272 | retval = do_move_mount(&nd, dev_name); | 1308 | retval = do_move_mount(&nd, dev_name); |
| @@ -1311,7 +1347,7 @@ int copy_namespace(int flags, struct task_struct *tsk) | |||
| 1311 | down_write(&namespace_sem); | 1347 | down_write(&namespace_sem); |
| 1312 | /* First pass: copy the tree topology */ | 1348 | /* First pass: copy the tree topology */ |
| 1313 | new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root, | 1349 | new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root, |
| 1314 | CL_EXPIRE); | 1350 | CL_COPY_ALL | CL_EXPIRE); |
| 1315 | if (!new_ns->root) { | 1351 | if (!new_ns->root) { |
| 1316 | up_write(&namespace_sem); | 1352 | up_write(&namespace_sem); |
| 1317 | kfree(new_ns); | 1353 | kfree(new_ns); |
diff --git a/fs/pnode.c b/fs/pnode.c index 3e266c5a3071..aeeec8ba8dd2 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
| @@ -82,6 +82,8 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) | |||
| 82 | if (type != MS_SLAVE) { | 82 | if (type != MS_SLAVE) { |
| 83 | list_del_init(&mnt->mnt_slave); | 83 | list_del_init(&mnt->mnt_slave); |
| 84 | mnt->mnt_master = NULL; | 84 | mnt->mnt_master = NULL; |
| 85 | if (type == MS_UNBINDABLE) | ||
| 86 | mnt->mnt_flags |= MNT_UNBINDABLE; | ||
| 85 | } | 87 | } |
| 86 | } | 88 | } |
| 87 | 89 | ||
diff --git a/fs/pnode.h b/fs/pnode.h index b59f0e9fe6b1..020e1bb60fdb 100644 --- a/fs/pnode.h +++ b/fs/pnode.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #define IS_MNT_SLAVE(mnt) (mnt->mnt_master) | 15 | #define IS_MNT_SLAVE(mnt) (mnt->mnt_master) |
| 16 | #define IS_MNT_NEW(mnt) (!mnt->mnt_namespace) | 16 | #define IS_MNT_NEW(mnt) (!mnt->mnt_namespace) |
| 17 | #define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) | 17 | #define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) |
| 18 | #define IS_MNT_UNBINDABLE(mnt) (mnt->mnt_flags & MNT_UNBINDABLE) | ||
| 18 | 19 | ||
| 19 | #define CL_EXPIRE 0x01 | 20 | #define CL_EXPIRE 0x01 |
| 20 | #define CL_SLAVE 0x02 | 21 | #define CL_SLAVE 0x02 |
diff --git a/include/linux/fs.h b/include/linux/fs.h index eef66f54c017..1b5f502a4b8f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -104,6 +104,7 @@ extern int dir_notify_enable; | |||
| 104 | #define MS_MOVE 8192 | 104 | #define MS_MOVE 8192 |
| 105 | #define MS_REC 16384 | 105 | #define MS_REC 16384 |
| 106 | #define MS_VERBOSE 32768 | 106 | #define MS_VERBOSE 32768 |
| 107 | #define MS_UNBINDABLE (1<<17) /* change to unbindable */ | ||
| 107 | #define MS_PRIVATE (1<<18) /* change to private */ | 108 | #define MS_PRIVATE (1<<18) /* change to private */ |
| 108 | #define MS_SLAVE (1<<19) /* change to slave */ | 109 | #define MS_SLAVE (1<<19) /* change to slave */ |
| 109 | #define MS_SHARED (1<<20) /* change to shared */ | 110 | #define MS_SHARED (1<<20) /* change to shared */ |
diff --git a/include/linux/mount.h b/include/linux/mount.h index 7e133ae2a94f..dd4e83eba933 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #define MNT_NODEV 0x02 | 21 | #define MNT_NODEV 0x02 |
| 22 | #define MNT_NOEXEC 0x04 | 22 | #define MNT_NOEXEC 0x04 |
| 23 | #define MNT_SHARED 0x10 /* if the vfsmount is a shared mount */ | 23 | #define MNT_SHARED 0x10 /* if the vfsmount is a shared mount */ |
| 24 | #define MNT_UNBINDABLE 0x20 /* if the vfsmount is a unbindable mount */ | ||
| 24 | #define MNT_PNODE_MASK 0x30 /* propogation flag mask */ | 25 | #define MNT_PNODE_MASK 0x30 /* propogation flag mask */ |
| 25 | 26 | ||
| 26 | struct vfsmount { | 27 | struct vfsmount { |
