aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/pnode.c54
-rw-r--r--fs/pnode.h2
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/mount.h3
5 files changed, 60 insertions, 4 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 4b1af01c2fb4..46f99bc585bd 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -67,6 +67,8 @@ struct vfsmount *alloc_vfsmnt(const char *name)
67 INIT_LIST_HEAD(&mnt->mnt_list); 67 INIT_LIST_HEAD(&mnt->mnt_list);
68 INIT_LIST_HEAD(&mnt->mnt_expire); 68 INIT_LIST_HEAD(&mnt->mnt_expire);
69 INIT_LIST_HEAD(&mnt->mnt_share); 69 INIT_LIST_HEAD(&mnt->mnt_share);
70 INIT_LIST_HEAD(&mnt->mnt_slave_list);
71 INIT_LIST_HEAD(&mnt->mnt_slave);
70 if (name) { 72 if (name) {
71 int size = strlen(name) + 1; 73 int size = strlen(name) + 1;
72 char *newname = kmalloc(size, GFP_KERNEL); 74 char *newname = kmalloc(size, GFP_KERNEL);
@@ -1243,7 +1245,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
1243 data_page); 1245 data_page);
1244 else if (flags & MS_BIND) 1246 else if (flags & MS_BIND)
1245 retval = do_loopback(&nd, dev_name, flags & MS_REC); 1247 retval = do_loopback(&nd, dev_name, flags & MS_REC);
1246 else if (flags & (MS_SHARED | MS_PRIVATE)) 1248 else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
1247 retval = do_change_type(&nd, flags); 1249 retval = do_change_type(&nd, flags);
1248 else if (flags & MS_MOVE) 1250 else if (flags & MS_MOVE)
1249 retval = do_move_mount(&nd, dev_name); 1251 retval = do_move_mount(&nd, dev_name);
diff --git a/fs/pnode.c b/fs/pnode.c
index 7bc942d047cd..f73eba24f1d1 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -17,13 +17,61 @@ static inline struct vfsmount *next_peer(struct vfsmount *p)
17 return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); 17 return list_entry(p->mnt_share.next, struct vfsmount, mnt_share);
18} 18}
19 19
20static int do_make_slave(struct vfsmount *mnt)
21{
22 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master;
23 struct vfsmount *slave_mnt;
24
25 /*
26 * slave 'mnt' to a peer mount that has the
27 * same root dentry. If none is available than
28 * slave it to anything that is available.
29 */
30 while ((peer_mnt = next_peer(peer_mnt)) != mnt &&
31 peer_mnt->mnt_root != mnt->mnt_root) ;
32
33 if (peer_mnt == mnt) {
34 peer_mnt = next_peer(mnt);
35 if (peer_mnt == mnt)
36 peer_mnt = NULL;
37 }
38 list_del_init(&mnt->mnt_share);
39
40 if (peer_mnt)
41 master = peer_mnt;
42
43 if (master) {
44 list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
45 slave_mnt->mnt_master = master;
46 list_del(&mnt->mnt_slave);
47 list_add(&mnt->mnt_slave, &master->mnt_slave_list);
48 list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
49 INIT_LIST_HEAD(&mnt->mnt_slave_list);
50 } else {
51 struct list_head *p = &mnt->mnt_slave_list;
52 while (!list_empty(p)) {
53 slave_mnt = list_entry(p->next,
54 struct vfsmount, mnt_slave);
55 list_del_init(&slave_mnt->mnt_slave);
56 slave_mnt->mnt_master = NULL;
57 }
58 }
59 mnt->mnt_master = master;
60 CLEAR_MNT_SHARED(mnt);
61 INIT_LIST_HEAD(&mnt->mnt_slave_list);
62 return 0;
63}
64
20void change_mnt_propagation(struct vfsmount *mnt, int type) 65void change_mnt_propagation(struct vfsmount *mnt, int type)
21{ 66{
22 if (type == MS_SHARED) { 67 if (type == MS_SHARED) {
23 set_mnt_shared(mnt); 68 set_mnt_shared(mnt);
24 } else { 69 return;
25 list_del_init(&mnt->mnt_share); 70 }
26 mnt->mnt_flags &= ~MNT_PNODE_MASK; 71 do_make_slave(mnt);
72 if (type != MS_SLAVE) {
73 list_del_init(&mnt->mnt_slave);
74 mnt->mnt_master = NULL;
27 } 75 }
28} 76}
29 77
diff --git a/fs/pnode.h b/fs/pnode.h
index 9b88ba06794a..b59f0e9fe6b1 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -12,10 +12,12 @@
12#include <linux/mount.h> 12#include <linux/mount.h>
13 13
14#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED) 14#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED)
15#define IS_MNT_SLAVE(mnt) (mnt->mnt_master)
15#define IS_MNT_NEW(mnt) (!mnt->mnt_namespace) 16#define IS_MNT_NEW(mnt) (!mnt->mnt_namespace)
16#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) 17#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED)
17 18
18#define CL_EXPIRE 0x01 19#define CL_EXPIRE 0x01
20#define CL_SLAVE 0x02
19#define CL_COPY_ALL 0x04 21#define CL_COPY_ALL 0x04
20#define CL_MAKE_SHARED 0x08 22#define CL_MAKE_SHARED 0x08
21#define CL_PROPAGATION 0x10 23#define CL_PROPAGATION 0x10
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8bdb504be73b..eef66f54c017 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -105,6 +105,7 @@ extern int dir_notify_enable;
105#define MS_REC 16384 105#define MS_REC 16384
106#define MS_VERBOSE 32768 106#define MS_VERBOSE 32768
107#define MS_PRIVATE (1<<18) /* change to private */ 107#define MS_PRIVATE (1<<18) /* change to private */
108#define MS_SLAVE (1<<19) /* change to slave */
108#define MS_SHARED (1<<20) /* change to shared */ 109#define MS_SHARED (1<<20) /* change to shared */
109#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ 110#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */
110#define MS_ACTIVE (1<<30) 111#define MS_ACTIVE (1<<30)
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 2582559718fc..7e133ae2a94f 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -38,6 +38,9 @@ struct vfsmount {
38 struct list_head mnt_list; 38 struct list_head mnt_list;
39 struct list_head mnt_expire; /* link in fs-specific expiry list */ 39 struct list_head mnt_expire; /* link in fs-specific expiry list */
40 struct list_head mnt_share; /* circular list of shared mounts */ 40 struct list_head mnt_share; /* circular list of shared mounts */
41 struct list_head mnt_slave_list;/* list of slave mounts */
42 struct list_head mnt_slave; /* slave list entry */
43 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
41 struct namespace *mnt_namespace; /* containing namespace */ 44 struct namespace *mnt_namespace; /* containing namespace */
42 int mnt_pinned; 45 int mnt_pinned;
43}; 46};