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 { |