diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namespace.c | 4 | ||||
-rw-r--r-- | fs/pnode.c | 54 | ||||
-rw-r--r-- | fs/pnode.h | 2 |
3 files changed, 56 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 | ||
20 | static 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 | |||
20 | void change_mnt_propagation(struct vfsmount *mnt, int type) | 65 | void 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 |