diff options
Diffstat (limited to 'fs/pnode.c')
-rw-r--r-- | fs/pnode.c | 81 |
1 files changed, 72 insertions, 9 deletions
diff --git a/fs/pnode.c b/fs/pnode.c index f73eba24f1d1..3e266c5a3071 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -17,6 +17,16 @@ 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 inline struct vfsmount *first_slave(struct vfsmount *p) | ||
21 | { | ||
22 | return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave); | ||
23 | } | ||
24 | |||
25 | static inline struct vfsmount *next_slave(struct vfsmount *p) | ||
26 | { | ||
27 | return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); | ||
28 | } | ||
29 | |||
20 | static int do_make_slave(struct vfsmount *mnt) | 30 | static int do_make_slave(struct vfsmount *mnt) |
21 | { | 31 | { |
22 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; | 32 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; |
@@ -83,10 +93,64 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) | |||
83 | static struct vfsmount *propagation_next(struct vfsmount *m, | 93 | static struct vfsmount *propagation_next(struct vfsmount *m, |
84 | struct vfsmount *origin) | 94 | struct vfsmount *origin) |
85 | { | 95 | { |
86 | m = next_peer(m); | 96 | /* are there any slaves of this mount? */ |
87 | if (m == origin) | 97 | if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) |
88 | return NULL; | 98 | return first_slave(m); |
89 | return m; | 99 | |
100 | while (1) { | ||
101 | struct vfsmount *next; | ||
102 | struct vfsmount *master = m->mnt_master; | ||
103 | |||
104 | if ( master == origin->mnt_master ) { | ||
105 | next = next_peer(m); | ||
106 | return ((next == origin) ? NULL : next); | ||
107 | } else if (m->mnt_slave.next != &master->mnt_slave_list) | ||
108 | return next_slave(m); | ||
109 | |||
110 | /* back at master */ | ||
111 | m = master; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * return the source mount to be used for cloning | ||
117 | * | ||
118 | * @dest the current destination mount | ||
119 | * @last_dest the last seen destination mount | ||
120 | * @last_src the last seen source mount | ||
121 | * @type return CL_SLAVE if the new mount has to be | ||
122 | * cloned as a slave. | ||
123 | */ | ||
124 | static struct vfsmount *get_source(struct vfsmount *dest, | ||
125 | struct vfsmount *last_dest, | ||
126 | struct vfsmount *last_src, | ||
127 | int *type) | ||
128 | { | ||
129 | struct vfsmount *p_last_src = NULL; | ||
130 | struct vfsmount *p_last_dest = NULL; | ||
131 | *type = CL_PROPAGATION;; | ||
132 | |||
133 | if (IS_MNT_SHARED(dest)) | ||
134 | *type |= CL_MAKE_SHARED; | ||
135 | |||
136 | while (last_dest != dest->mnt_master) { | ||
137 | p_last_dest = last_dest; | ||
138 | p_last_src = last_src; | ||
139 | last_dest = last_dest->mnt_master; | ||
140 | last_src = last_src->mnt_master; | ||
141 | } | ||
142 | |||
143 | if (p_last_dest) { | ||
144 | do { | ||
145 | p_last_dest = next_peer(p_last_dest); | ||
146 | } while (IS_MNT_NEW(p_last_dest)); | ||
147 | } | ||
148 | |||
149 | if (dest != p_last_dest) { | ||
150 | *type |= CL_SLAVE; | ||
151 | return last_src; | ||
152 | } else | ||
153 | return p_last_src; | ||
90 | } | 154 | } |
91 | 155 | ||
92 | /* | 156 | /* |
@@ -114,16 +178,15 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, | |||
114 | 178 | ||
115 | for (m = propagation_next(dest_mnt, dest_mnt); m; | 179 | for (m = propagation_next(dest_mnt, dest_mnt); m; |
116 | m = propagation_next(m, dest_mnt)) { | 180 | m = propagation_next(m, dest_mnt)) { |
117 | int type = CL_PROPAGATION; | 181 | int type; |
182 | struct vfsmount *source; | ||
118 | 183 | ||
119 | if (IS_MNT_NEW(m)) | 184 | if (IS_MNT_NEW(m)) |
120 | continue; | 185 | continue; |
121 | 186 | ||
122 | if (IS_MNT_SHARED(m)) | 187 | source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); |
123 | type |= CL_MAKE_SHARED; | ||
124 | 188 | ||
125 | if (!(child = copy_tree(source_mnt, source_mnt->mnt_root, | 189 | if (!(child = copy_tree(source, source->mnt_root, type))) { |
126 | type))) { | ||
127 | ret = -ENOMEM; | 190 | ret = -ENOMEM; |
128 | list_splice(tree_list, tmp_list.prev); | 191 | list_splice(tree_list, tmp_list.prev); |
129 | goto out; | 192 | goto out; |