diff options
Diffstat (limited to 'fs/pnode.c')
-rw-r--r-- | fs/pnode.c | 120 |
1 files changed, 52 insertions, 68 deletions
diff --git a/fs/pnode.c b/fs/pnode.c index d42514e32380..ab5fa9e1a79a 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -13,45 +13,30 @@ | |||
13 | #include "pnode.h" | 13 | #include "pnode.h" |
14 | 14 | ||
15 | /* return the next shared peer mount of @p */ | 15 | /* return the next shared peer mount of @p */ |
16 | static inline struct vfsmount *next_peer(struct vfsmount *p) | 16 | static inline struct mount *next_peer(struct mount *p) |
17 | { | 17 | { |
18 | return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); | 18 | return list_entry(p->mnt_share.next, struct mount, mnt_share); |
19 | } | 19 | } |
20 | 20 | ||
21 | static inline struct vfsmount *first_slave(struct vfsmount *p) | 21 | static inline struct mount *first_slave(struct mount *p) |
22 | { | 22 | { |
23 | return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave); | 23 | return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); |
24 | } | 24 | } |
25 | 25 | ||
26 | static inline struct vfsmount *next_slave(struct vfsmount *p) | 26 | static inline struct mount *next_slave(struct mount *p) |
27 | { | 27 | { |
28 | return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); | 28 | return list_entry(p->mnt_slave.next, struct mount, mnt_slave); |
29 | } | 29 | } |
30 | 30 | ||
31 | /* | 31 | static struct mount *get_peer_under_root(struct mount *mnt, |
32 | * Return true if path is reachable from root | 32 | struct mnt_namespace *ns, |
33 | * | 33 | const struct path *root) |
34 | * namespace_sem is held, and mnt is attached | ||
35 | */ | ||
36 | static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry, | ||
37 | const struct path *root) | ||
38 | { | ||
39 | while (mnt != root->mnt && mnt->mnt_parent != mnt) { | ||
40 | dentry = mnt->mnt_mountpoint; | ||
41 | mnt = mnt->mnt_parent; | ||
42 | } | ||
43 | return mnt == root->mnt && is_subdir(dentry, root->dentry); | ||
44 | } | ||
45 | |||
46 | static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, | ||
47 | struct mnt_namespace *ns, | ||
48 | const struct path *root) | ||
49 | { | 34 | { |
50 | struct vfsmount *m = mnt; | 35 | struct mount *m = mnt; |
51 | 36 | ||
52 | do { | 37 | do { |
53 | /* Check the namespace first for optimization */ | 38 | /* Check the namespace first for optimization */ |
54 | if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root)) | 39 | if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root)) |
55 | return m; | 40 | return m; |
56 | 41 | ||
57 | m = next_peer(m); | 42 | m = next_peer(m); |
@@ -66,12 +51,12 @@ static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, | |||
66 | * | 51 | * |
67 | * Caller must hold namespace_sem | 52 | * Caller must hold namespace_sem |
68 | */ | 53 | */ |
69 | int get_dominating_id(struct vfsmount *mnt, const struct path *root) | 54 | int get_dominating_id(struct mount *mnt, const struct path *root) |
70 | { | 55 | { |
71 | struct vfsmount *m; | 56 | struct mount *m; |
72 | 57 | ||
73 | for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { | 58 | for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { |
74 | struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root); | 59 | struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root); |
75 | if (d) | 60 | if (d) |
76 | return d->mnt_group_id; | 61 | return d->mnt_group_id; |
77 | } | 62 | } |
@@ -79,10 +64,10 @@ int get_dominating_id(struct vfsmount *mnt, const struct path *root) | |||
79 | return 0; | 64 | return 0; |
80 | } | 65 | } |
81 | 66 | ||
82 | static int do_make_slave(struct vfsmount *mnt) | 67 | static int do_make_slave(struct mount *mnt) |
83 | { | 68 | { |
84 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; | 69 | struct mount *peer_mnt = mnt, *master = mnt->mnt_master; |
85 | struct vfsmount *slave_mnt; | 70 | struct mount *slave_mnt; |
86 | 71 | ||
87 | /* | 72 | /* |
88 | * slave 'mnt' to a peer mount that has the | 73 | * slave 'mnt' to a peer mount that has the |
@@ -90,7 +75,7 @@ static int do_make_slave(struct vfsmount *mnt) | |||
90 | * slave it to anything that is available. | 75 | * slave it to anything that is available. |
91 | */ | 76 | */ |
92 | while ((peer_mnt = next_peer(peer_mnt)) != mnt && | 77 | while ((peer_mnt = next_peer(peer_mnt)) != mnt && |
93 | peer_mnt->mnt_root != mnt->mnt_root) ; | 78 | peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ; |
94 | 79 | ||
95 | if (peer_mnt == mnt) { | 80 | if (peer_mnt == mnt) { |
96 | peer_mnt = next_peer(mnt); | 81 | peer_mnt = next_peer(mnt); |
@@ -116,7 +101,7 @@ static int do_make_slave(struct vfsmount *mnt) | |||
116 | struct list_head *p = &mnt->mnt_slave_list; | 101 | struct list_head *p = &mnt->mnt_slave_list; |
117 | while (!list_empty(p)) { | 102 | while (!list_empty(p)) { |
118 | slave_mnt = list_first_entry(p, | 103 | slave_mnt = list_first_entry(p, |
119 | struct vfsmount, mnt_slave); | 104 | struct mount, mnt_slave); |
120 | list_del_init(&slave_mnt->mnt_slave); | 105 | list_del_init(&slave_mnt->mnt_slave); |
121 | slave_mnt->mnt_master = NULL; | 106 | slave_mnt->mnt_master = NULL; |
122 | } | 107 | } |
@@ -129,7 +114,7 @@ static int do_make_slave(struct vfsmount *mnt) | |||
129 | /* | 114 | /* |
130 | * vfsmount lock must be held for write | 115 | * vfsmount lock must be held for write |
131 | */ | 116 | */ |
132 | void change_mnt_propagation(struct vfsmount *mnt, int type) | 117 | void change_mnt_propagation(struct mount *mnt, int type) |
133 | { | 118 | { |
134 | if (type == MS_SHARED) { | 119 | if (type == MS_SHARED) { |
135 | set_mnt_shared(mnt); | 120 | set_mnt_shared(mnt); |
@@ -140,9 +125,9 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) | |||
140 | list_del_init(&mnt->mnt_slave); | 125 | list_del_init(&mnt->mnt_slave); |
141 | mnt->mnt_master = NULL; | 126 | mnt->mnt_master = NULL; |
142 | if (type == MS_UNBINDABLE) | 127 | if (type == MS_UNBINDABLE) |
143 | mnt->mnt_flags |= MNT_UNBINDABLE; | 128 | mnt->mnt.mnt_flags |= MNT_UNBINDABLE; |
144 | else | 129 | else |
145 | mnt->mnt_flags &= ~MNT_UNBINDABLE; | 130 | mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE; |
146 | } | 131 | } |
147 | } | 132 | } |
148 | 133 | ||
@@ -156,20 +141,19 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) | |||
156 | * vfsmount found while iterating with propagation_next() is | 141 | * vfsmount found while iterating with propagation_next() is |
157 | * a peer of one we'd found earlier. | 142 | * a peer of one we'd found earlier. |
158 | */ | 143 | */ |
159 | static struct vfsmount *propagation_next(struct vfsmount *m, | 144 | static struct mount *propagation_next(struct mount *m, |
160 | struct vfsmount *origin) | 145 | struct mount *origin) |
161 | { | 146 | { |
162 | /* are there any slaves of this mount? */ | 147 | /* are there any slaves of this mount? */ |
163 | if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) | 148 | if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) |
164 | return first_slave(m); | 149 | return first_slave(m); |
165 | 150 | ||
166 | while (1) { | 151 | while (1) { |
167 | struct vfsmount *next; | 152 | struct mount *master = m->mnt_master; |
168 | struct vfsmount *master = m->mnt_master; | ||
169 | 153 | ||
170 | if (master == origin->mnt_master) { | 154 | if (master == origin->mnt_master) { |
171 | next = next_peer(m); | 155 | struct mount *next = next_peer(m); |
172 | return ((next == origin) ? NULL : next); | 156 | return (next == origin) ? NULL : next; |
173 | } else if (m->mnt_slave.next != &master->mnt_slave_list) | 157 | } else if (m->mnt_slave.next != &master->mnt_slave_list) |
174 | return next_slave(m); | 158 | return next_slave(m); |
175 | 159 | ||
@@ -187,13 +171,13 @@ static struct vfsmount *propagation_next(struct vfsmount *m, | |||
187 | * @type return CL_SLAVE if the new mount has to be | 171 | * @type return CL_SLAVE if the new mount has to be |
188 | * cloned as a slave. | 172 | * cloned as a slave. |
189 | */ | 173 | */ |
190 | static struct vfsmount *get_source(struct vfsmount *dest, | 174 | static struct mount *get_source(struct mount *dest, |
191 | struct vfsmount *last_dest, | 175 | struct mount *last_dest, |
192 | struct vfsmount *last_src, | 176 | struct mount *last_src, |
193 | int *type) | 177 | int *type) |
194 | { | 178 | { |
195 | struct vfsmount *p_last_src = NULL; | 179 | struct mount *p_last_src = NULL; |
196 | struct vfsmount *p_last_dest = NULL; | 180 | struct mount *p_last_dest = NULL; |
197 | 181 | ||
198 | while (last_dest != dest->mnt_master) { | 182 | while (last_dest != dest->mnt_master) { |
199 | p_last_dest = last_dest; | 183 | p_last_dest = last_dest; |
@@ -233,33 +217,33 @@ static struct vfsmount *get_source(struct vfsmount *dest, | |||
233 | * @source_mnt: source mount. | 217 | * @source_mnt: source mount. |
234 | * @tree_list : list of heads of trees to be attached. | 218 | * @tree_list : list of heads of trees to be attached. |
235 | */ | 219 | */ |
236 | int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, | 220 | int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry, |
237 | struct vfsmount *source_mnt, struct list_head *tree_list) | 221 | struct mount *source_mnt, struct list_head *tree_list) |
238 | { | 222 | { |
239 | struct vfsmount *m, *child; | 223 | struct mount *m, *child; |
240 | int ret = 0; | 224 | int ret = 0; |
241 | struct vfsmount *prev_dest_mnt = dest_mnt; | 225 | struct mount *prev_dest_mnt = dest_mnt; |
242 | struct vfsmount *prev_src_mnt = source_mnt; | 226 | struct mount *prev_src_mnt = source_mnt; |
243 | LIST_HEAD(tmp_list); | 227 | LIST_HEAD(tmp_list); |
244 | LIST_HEAD(umount_list); | 228 | LIST_HEAD(umount_list); |
245 | 229 | ||
246 | for (m = propagation_next(dest_mnt, dest_mnt); m; | 230 | for (m = propagation_next(dest_mnt, dest_mnt); m; |
247 | m = propagation_next(m, dest_mnt)) { | 231 | m = propagation_next(m, dest_mnt)) { |
248 | int type; | 232 | int type; |
249 | struct vfsmount *source; | 233 | struct mount *source; |
250 | 234 | ||
251 | if (IS_MNT_NEW(m)) | 235 | if (IS_MNT_NEW(m)) |
252 | continue; | 236 | continue; |
253 | 237 | ||
254 | source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); | 238 | source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); |
255 | 239 | ||
256 | if (!(child = copy_tree(source, source->mnt_root, type))) { | 240 | if (!(child = copy_tree(source, source->mnt.mnt_root, type))) { |
257 | ret = -ENOMEM; | 241 | ret = -ENOMEM; |
258 | list_splice(tree_list, tmp_list.prev); | 242 | list_splice(tree_list, tmp_list.prev); |
259 | goto out; | 243 | goto out; |
260 | } | 244 | } |
261 | 245 | ||
262 | if (is_subdir(dest_dentry, m->mnt_root)) { | 246 | if (is_subdir(dest_dentry, m->mnt.mnt_root)) { |
263 | mnt_set_mountpoint(m, dest_dentry, child); | 247 | mnt_set_mountpoint(m, dest_dentry, child); |
264 | list_add_tail(&child->mnt_hash, tree_list); | 248 | list_add_tail(&child->mnt_hash, tree_list); |
265 | } else { | 249 | } else { |
@@ -275,7 +259,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, | |||
275 | out: | 259 | out: |
276 | br_write_lock(vfsmount_lock); | 260 | br_write_lock(vfsmount_lock); |
277 | while (!list_empty(&tmp_list)) { | 261 | while (!list_empty(&tmp_list)) { |
278 | child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); | 262 | child = list_first_entry(&tmp_list, struct mount, mnt_hash); |
279 | umount_tree(child, 0, &umount_list); | 263 | umount_tree(child, 0, &umount_list); |
280 | } | 264 | } |
281 | br_write_unlock(vfsmount_lock); | 265 | br_write_unlock(vfsmount_lock); |
@@ -286,7 +270,7 @@ out: | |||
286 | /* | 270 | /* |
287 | * return true if the refcount is greater than count | 271 | * return true if the refcount is greater than count |
288 | */ | 272 | */ |
289 | static inline int do_refcount_check(struct vfsmount *mnt, int count) | 273 | static inline int do_refcount_check(struct mount *mnt, int count) |
290 | { | 274 | { |
291 | int mycount = mnt_get_count(mnt) - mnt->mnt_ghosts; | 275 | int mycount = mnt_get_count(mnt) - mnt->mnt_ghosts; |
292 | return (mycount > count); | 276 | return (mycount > count); |
@@ -302,10 +286,10 @@ static inline int do_refcount_check(struct vfsmount *mnt, int count) | |||
302 | * | 286 | * |
303 | * vfsmount lock must be held for write | 287 | * vfsmount lock must be held for write |
304 | */ | 288 | */ |
305 | int propagate_mount_busy(struct vfsmount *mnt, int refcnt) | 289 | int propagate_mount_busy(struct mount *mnt, int refcnt) |
306 | { | 290 | { |
307 | struct vfsmount *m, *child; | 291 | struct mount *m, *child; |
308 | struct vfsmount *parent = mnt->mnt_parent; | 292 | struct mount *parent = mnt->mnt_parent; |
309 | int ret = 0; | 293 | int ret = 0; |
310 | 294 | ||
311 | if (mnt == parent) | 295 | if (mnt == parent) |
@@ -321,7 +305,7 @@ int propagate_mount_busy(struct vfsmount *mnt, int refcnt) | |||
321 | 305 | ||
322 | for (m = propagation_next(parent, parent); m; | 306 | for (m = propagation_next(parent, parent); m; |
323 | m = propagation_next(m, parent)) { | 307 | m = propagation_next(m, parent)) { |
324 | child = __lookup_mnt(m, mnt->mnt_mountpoint, 0); | 308 | child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); |
325 | if (child && list_empty(&child->mnt_mounts) && | 309 | if (child && list_empty(&child->mnt_mounts) && |
326 | (ret = do_refcount_check(child, 1))) | 310 | (ret = do_refcount_check(child, 1))) |
327 | break; | 311 | break; |
@@ -333,17 +317,17 @@ int propagate_mount_busy(struct vfsmount *mnt, int refcnt) | |||
333 | * NOTE: unmounting 'mnt' naturally propagates to all other mounts its | 317 | * NOTE: unmounting 'mnt' naturally propagates to all other mounts its |
334 | * parent propagates to. | 318 | * parent propagates to. |
335 | */ | 319 | */ |
336 | static void __propagate_umount(struct vfsmount *mnt) | 320 | static void __propagate_umount(struct mount *mnt) |
337 | { | 321 | { |
338 | struct vfsmount *parent = mnt->mnt_parent; | 322 | struct mount *parent = mnt->mnt_parent; |
339 | struct vfsmount *m; | 323 | struct mount *m; |
340 | 324 | ||
341 | BUG_ON(parent == mnt); | 325 | BUG_ON(parent == mnt); |
342 | 326 | ||
343 | for (m = propagation_next(parent, parent); m; | 327 | for (m = propagation_next(parent, parent); m; |
344 | m = propagation_next(m, parent)) { | 328 | m = propagation_next(m, parent)) { |
345 | 329 | ||
346 | struct vfsmount *child = __lookup_mnt(m, | 330 | struct mount *child = __lookup_mnt(&m->mnt, |
347 | mnt->mnt_mountpoint, 0); | 331 | mnt->mnt_mountpoint, 0); |
348 | /* | 332 | /* |
349 | * umount the child only if the child has no | 333 | * umount the child only if the child has no |
@@ -363,7 +347,7 @@ static void __propagate_umount(struct vfsmount *mnt) | |||
363 | */ | 347 | */ |
364 | int propagate_umount(struct list_head *list) | 348 | int propagate_umount(struct list_head *list) |
365 | { | 349 | { |
366 | struct vfsmount *mnt; | 350 | struct mount *mnt; |
367 | 351 | ||
368 | list_for_each_entry(mnt, list, mnt_hash) | 352 | list_for_each_entry(mnt, list, mnt_hash) |
369 | __propagate_umount(mnt); | 353 | __propagate_umount(mnt); |