diff options
Diffstat (limited to 'fs/autofs4/expire.c')
-rw-r--r-- | fs/autofs4/expire.c | 212 |
1 files changed, 137 insertions, 75 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index a796c9417fb1..450f529a4eae 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry, | |||
26 | if (ino == NULL) | 26 | if (ino == NULL) |
27 | return 0; | 27 | return 0; |
28 | 28 | ||
29 | /* No point expiring a pending mount */ | ||
30 | if (ino->flags & AUTOFS_INF_PENDING) | ||
31 | return 0; | ||
32 | |||
33 | if (!do_now) { | 29 | if (!do_now) { |
34 | /* Too young to die */ | 30 | /* Too young to die */ |
35 | if (!timeout || time_after(ino->last_used + timeout, now)) | 31 | if (!timeout || time_after(ino->last_used + timeout, now)) |
@@ -56,7 +52,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
56 | 52 | ||
57 | path_get(&path); | 53 | path_get(&path); |
58 | 54 | ||
59 | if (!follow_down(&path)) | 55 | if (!follow_down_one(&path)) |
60 | goto done; | 56 | goto done; |
61 | 57 | ||
62 | if (is_autofs4_dentry(path.dentry)) { | 58 | if (is_autofs4_dentry(path.dentry)) { |
@@ -91,24 +87,116 @@ done: | |||
91 | } | 87 | } |
92 | 88 | ||
93 | /* | 89 | /* |
94 | * Calculate next entry in top down tree traversal. | 90 | * Calculate and dget next entry in the subdirs list under root. |
95 | * From next_mnt in namespace.c - elegant. | ||
96 | */ | 91 | */ |
97 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | 92 | static struct dentry *get_next_positive_subdir(struct dentry *prev, |
93 | struct dentry *root) | ||
98 | { | 94 | { |
99 | struct list_head *next = p->d_subdirs.next; | 95 | struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); |
96 | struct list_head *next; | ||
97 | struct dentry *p, *q; | ||
98 | |||
99 | spin_lock(&sbi->lookup_lock); | ||
100 | 100 | ||
101 | if (prev == NULL) { | ||
102 | spin_lock(&root->d_lock); | ||
103 | prev = dget_dlock(root); | ||
104 | next = prev->d_subdirs.next; | ||
105 | p = prev; | ||
106 | goto start; | ||
107 | } | ||
108 | |||
109 | p = prev; | ||
110 | spin_lock(&p->d_lock); | ||
111 | again: | ||
112 | next = p->d_u.d_child.next; | ||
113 | start: | ||
114 | if (next == &root->d_subdirs) { | ||
115 | spin_unlock(&p->d_lock); | ||
116 | spin_unlock(&sbi->lookup_lock); | ||
117 | dput(prev); | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | q = list_entry(next, struct dentry, d_u.d_child); | ||
122 | |||
123 | spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); | ||
124 | /* Negative dentry - try next */ | ||
125 | if (!simple_positive(q)) { | ||
126 | spin_unlock(&p->d_lock); | ||
127 | p = q; | ||
128 | goto again; | ||
129 | } | ||
130 | dget_dlock(q); | ||
131 | spin_unlock(&q->d_lock); | ||
132 | spin_unlock(&p->d_lock); | ||
133 | spin_unlock(&sbi->lookup_lock); | ||
134 | |||
135 | dput(prev); | ||
136 | |||
137 | return q; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Calculate and dget next entry in top down tree traversal. | ||
142 | */ | ||
143 | static struct dentry *get_next_positive_dentry(struct dentry *prev, | ||
144 | struct dentry *root) | ||
145 | { | ||
146 | struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); | ||
147 | struct list_head *next; | ||
148 | struct dentry *p, *ret; | ||
149 | |||
150 | if (prev == NULL) | ||
151 | return dget(root); | ||
152 | |||
153 | spin_lock(&sbi->lookup_lock); | ||
154 | relock: | ||
155 | p = prev; | ||
156 | spin_lock(&p->d_lock); | ||
157 | again: | ||
158 | next = p->d_subdirs.next; | ||
101 | if (next == &p->d_subdirs) { | 159 | if (next == &p->d_subdirs) { |
102 | while (1) { | 160 | while (1) { |
103 | if (p == root) | 161 | struct dentry *parent; |
162 | |||
163 | if (p == root) { | ||
164 | spin_unlock(&p->d_lock); | ||
165 | spin_unlock(&sbi->lookup_lock); | ||
166 | dput(prev); | ||
104 | return NULL; | 167 | return NULL; |
168 | } | ||
169 | |||
170 | parent = p->d_parent; | ||
171 | if (!spin_trylock(&parent->d_lock)) { | ||
172 | spin_unlock(&p->d_lock); | ||
173 | cpu_relax(); | ||
174 | goto relock; | ||
175 | } | ||
176 | spin_unlock(&p->d_lock); | ||
105 | next = p->d_u.d_child.next; | 177 | next = p->d_u.d_child.next; |
106 | if (next != &p->d_parent->d_subdirs) | 178 | p = parent; |
179 | if (next != &parent->d_subdirs) | ||
107 | break; | 180 | break; |
108 | p = p->d_parent; | ||
109 | } | 181 | } |
110 | } | 182 | } |
111 | return list_entry(next, struct dentry, d_u.d_child); | 183 | ret = list_entry(next, struct dentry, d_u.d_child); |
184 | |||
185 | spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); | ||
186 | /* Negative dentry - try next */ | ||
187 | if (!simple_positive(ret)) { | ||
188 | spin_unlock(&p->d_lock); | ||
189 | p = ret; | ||
190 | goto again; | ||
191 | } | ||
192 | dget_dlock(ret); | ||
193 | spin_unlock(&ret->d_lock); | ||
194 | spin_unlock(&p->d_lock); | ||
195 | spin_unlock(&sbi->lookup_lock); | ||
196 | |||
197 | dput(prev); | ||
198 | |||
199 | return ret; | ||
112 | } | 200 | } |
113 | 201 | ||
114 | /* | 202 | /* |
@@ -158,18 +246,11 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
158 | if (!simple_positive(top)) | 246 | if (!simple_positive(top)) |
159 | return 1; | 247 | return 1; |
160 | 248 | ||
161 | spin_lock(&dcache_lock); | 249 | p = NULL; |
162 | for (p = top; p; p = next_dentry(p, top)) { | 250 | while ((p = get_next_positive_dentry(p, top))) { |
163 | /* Negative dentry - give up */ | ||
164 | if (!simple_positive(p)) | ||
165 | continue; | ||
166 | |||
167 | DPRINTK("dentry %p %.*s", | 251 | DPRINTK("dentry %p %.*s", |
168 | p, (int) p->d_name.len, p->d_name.name); | 252 | p, (int) p->d_name.len, p->d_name.name); |
169 | 253 | ||
170 | p = dget(p); | ||
171 | spin_unlock(&dcache_lock); | ||
172 | |||
173 | /* | 254 | /* |
174 | * Is someone visiting anywhere in the subtree ? | 255 | * Is someone visiting anywhere in the subtree ? |
175 | * If there's no mount we need to check the usage | 256 | * If there's no mount we need to check the usage |
@@ -198,16 +279,13 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
198 | else | 279 | else |
199 | ino_count++; | 280 | ino_count++; |
200 | 281 | ||
201 | if (atomic_read(&p->d_count) > ino_count) { | 282 | if (p->d_count > ino_count) { |
202 | top_ino->last_used = jiffies; | 283 | top_ino->last_used = jiffies; |
203 | dput(p); | 284 | dput(p); |
204 | return 1; | 285 | return 1; |
205 | } | 286 | } |
206 | } | 287 | } |
207 | dput(p); | ||
208 | spin_lock(&dcache_lock); | ||
209 | } | 288 | } |
210 | spin_unlock(&dcache_lock); | ||
211 | 289 | ||
212 | /* Timeout of a tree mount is ultimately determined by its top dentry */ | 290 | /* Timeout of a tree mount is ultimately determined by its top dentry */ |
213 | if (!autofs4_can_expire(top, timeout, do_now)) | 291 | if (!autofs4_can_expire(top, timeout, do_now)) |
@@ -226,32 +304,21 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
226 | DPRINTK("parent %p %.*s", | 304 | DPRINTK("parent %p %.*s", |
227 | parent, (int)parent->d_name.len, parent->d_name.name); | 305 | parent, (int)parent->d_name.len, parent->d_name.name); |
228 | 306 | ||
229 | spin_lock(&dcache_lock); | 307 | p = NULL; |
230 | for (p = parent; p; p = next_dentry(p, parent)) { | 308 | while ((p = get_next_positive_dentry(p, parent))) { |
231 | /* Negative dentry - give up */ | ||
232 | if (!simple_positive(p)) | ||
233 | continue; | ||
234 | |||
235 | DPRINTK("dentry %p %.*s", | 309 | DPRINTK("dentry %p %.*s", |
236 | p, (int) p->d_name.len, p->d_name.name); | 310 | p, (int) p->d_name.len, p->d_name.name); |
237 | 311 | ||
238 | p = dget(p); | ||
239 | spin_unlock(&dcache_lock); | ||
240 | |||
241 | if (d_mountpoint(p)) { | 312 | if (d_mountpoint(p)) { |
242 | /* Can we umount this guy */ | 313 | /* Can we umount this guy */ |
243 | if (autofs4_mount_busy(mnt, p)) | 314 | if (autofs4_mount_busy(mnt, p)) |
244 | goto cont; | 315 | continue; |
245 | 316 | ||
246 | /* Can we expire this guy */ | 317 | /* Can we expire this guy */ |
247 | if (autofs4_can_expire(p, timeout, do_now)) | 318 | if (autofs4_can_expire(p, timeout, do_now)) |
248 | return p; | 319 | return p; |
249 | } | 320 | } |
250 | cont: | ||
251 | dput(p); | ||
252 | spin_lock(&dcache_lock); | ||
253 | } | 321 | } |
254 | spin_unlock(&dcache_lock); | ||
255 | return NULL; | 322 | return NULL; |
256 | } | 323 | } |
257 | 324 | ||
@@ -264,6 +331,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
264 | unsigned long timeout; | 331 | unsigned long timeout; |
265 | struct dentry *root = dget(sb->s_root); | 332 | struct dentry *root = dget(sb->s_root); |
266 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 333 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
334 | struct autofs_info *ino; | ||
267 | 335 | ||
268 | if (!root) | 336 | if (!root) |
269 | return NULL; | 337 | return NULL; |
@@ -272,17 +340,18 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
272 | timeout = sbi->exp_timeout; | 340 | timeout = sbi->exp_timeout; |
273 | 341 | ||
274 | spin_lock(&sbi->fs_lock); | 342 | spin_lock(&sbi->fs_lock); |
343 | ino = autofs4_dentry_ino(root); | ||
344 | /* No point expiring a pending mount */ | ||
345 | if (ino->flags & AUTOFS_INF_PENDING) | ||
346 | goto out; | ||
275 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 347 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
276 | struct autofs_info *ino = autofs4_dentry_ino(root); | 348 | struct autofs_info *ino = autofs4_dentry_ino(root); |
277 | if (d_mountpoint(root)) { | ||
278 | ino->flags |= AUTOFS_INF_MOUNTPOINT; | ||
279 | root->d_mounted--; | ||
280 | } | ||
281 | ino->flags |= AUTOFS_INF_EXPIRING; | 349 | ino->flags |= AUTOFS_INF_EXPIRING; |
282 | init_completion(&ino->expire_complete); | 350 | init_completion(&ino->expire_complete); |
283 | spin_unlock(&sbi->fs_lock); | 351 | spin_unlock(&sbi->fs_lock); |
284 | return root; | 352 | return root; |
285 | } | 353 | } |
354 | out: | ||
286 | spin_unlock(&sbi->fs_lock); | 355 | spin_unlock(&sbi->fs_lock); |
287 | dput(root); | 356 | dput(root); |
288 | 357 | ||
@@ -302,8 +371,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
302 | { | 371 | { |
303 | unsigned long timeout; | 372 | unsigned long timeout; |
304 | struct dentry *root = sb->s_root; | 373 | struct dentry *root = sb->s_root; |
374 | struct dentry *dentry; | ||
305 | struct dentry *expired = NULL; | 375 | struct dentry *expired = NULL; |
306 | struct list_head *next; | ||
307 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 376 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
308 | int exp_leaves = how & AUTOFS_EXP_LEAVES; | 377 | int exp_leaves = how & AUTOFS_EXP_LEAVES; |
309 | struct autofs_info *ino; | 378 | struct autofs_info *ino; |
@@ -315,25 +384,13 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
315 | now = jiffies; | 384 | now = jiffies; |
316 | timeout = sbi->exp_timeout; | 385 | timeout = sbi->exp_timeout; |
317 | 386 | ||
318 | spin_lock(&dcache_lock); | 387 | dentry = NULL; |
319 | next = root->d_subdirs.next; | 388 | while ((dentry = get_next_positive_subdir(dentry, root))) { |
320 | |||
321 | /* On exit from the loop expire is set to a dgot dentry | ||
322 | * to expire or it's NULL */ | ||
323 | while ( next != &root->d_subdirs ) { | ||
324 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
325 | |||
326 | /* Negative dentry - give up */ | ||
327 | if (!simple_positive(dentry)) { | ||
328 | next = next->next; | ||
329 | continue; | ||
330 | } | ||
331 | |||
332 | dentry = dget(dentry); | ||
333 | spin_unlock(&dcache_lock); | ||
334 | |||
335 | spin_lock(&sbi->fs_lock); | 389 | spin_lock(&sbi->fs_lock); |
336 | ino = autofs4_dentry_ino(dentry); | 390 | ino = autofs4_dentry_ino(dentry); |
391 | /* No point expiring a pending mount */ | ||
392 | if (ino->flags & AUTOFS_INF_PENDING) | ||
393 | goto next; | ||
337 | 394 | ||
338 | /* | 395 | /* |
339 | * Case 1: (i) indirect mount or top level pseudo direct mount | 396 | * Case 1: (i) indirect mount or top level pseudo direct mount |
@@ -347,7 +404,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
347 | 404 | ||
348 | /* Path walk currently on this dentry? */ | 405 | /* Path walk currently on this dentry? */ |
349 | ino_count = atomic_read(&ino->count) + 2; | 406 | ino_count = atomic_read(&ino->count) + 2; |
350 | if (atomic_read(&dentry->d_count) > ino_count) | 407 | if (dentry->d_count > ino_count) |
351 | goto next; | 408 | goto next; |
352 | 409 | ||
353 | /* Can we umount this guy */ | 410 | /* Can we umount this guy */ |
@@ -369,7 +426,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
369 | if (!exp_leaves) { | 426 | if (!exp_leaves) { |
370 | /* Path walk currently on this dentry? */ | 427 | /* Path walk currently on this dentry? */ |
371 | ino_count = atomic_read(&ino->count) + 1; | 428 | ino_count = atomic_read(&ino->count) + 1; |
372 | if (atomic_read(&dentry->d_count) > ino_count) | 429 | if (dentry->d_count > ino_count) |
373 | goto next; | 430 | goto next; |
374 | 431 | ||
375 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { | 432 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { |
@@ -383,7 +440,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
383 | } else { | 440 | } else { |
384 | /* Path walk currently on this dentry? */ | 441 | /* Path walk currently on this dentry? */ |
385 | ino_count = atomic_read(&ino->count) + 1; | 442 | ino_count = atomic_read(&ino->count) + 1; |
386 | if (atomic_read(&dentry->d_count) > ino_count) | 443 | if (dentry->d_count > ino_count) |
387 | goto next; | 444 | goto next; |
388 | 445 | ||
389 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 446 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
@@ -394,11 +451,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
394 | } | 451 | } |
395 | next: | 452 | next: |
396 | spin_unlock(&sbi->fs_lock); | 453 | spin_unlock(&sbi->fs_lock); |
397 | dput(dentry); | ||
398 | spin_lock(&dcache_lock); | ||
399 | next = next->next; | ||
400 | } | 454 | } |
401 | spin_unlock(&dcache_lock); | ||
402 | return NULL; | 455 | return NULL; |
403 | 456 | ||
404 | found: | 457 | found: |
@@ -408,9 +461,13 @@ found: | |||
408 | ino->flags |= AUTOFS_INF_EXPIRING; | 461 | ino->flags |= AUTOFS_INF_EXPIRING; |
409 | init_completion(&ino->expire_complete); | 462 | init_completion(&ino->expire_complete); |
410 | spin_unlock(&sbi->fs_lock); | 463 | spin_unlock(&sbi->fs_lock); |
411 | spin_lock(&dcache_lock); | 464 | spin_lock(&sbi->lookup_lock); |
465 | spin_lock(&expired->d_parent->d_lock); | ||
466 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | ||
412 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 467 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
413 | spin_unlock(&dcache_lock); | 468 | spin_unlock(&expired->d_lock); |
469 | spin_unlock(&expired->d_parent->d_lock); | ||
470 | spin_unlock(&sbi->lookup_lock); | ||
414 | return expired; | 471 | return expired; |
415 | } | 472 | } |
416 | 473 | ||
@@ -498,11 +555,16 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
498 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); | 555 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); |
499 | 556 | ||
500 | spin_lock(&sbi->fs_lock); | 557 | spin_lock(&sbi->fs_lock); |
501 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | ||
502 | sb->s_root->d_mounted++; | ||
503 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | ||
504 | } | ||
505 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 558 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
559 | spin_lock(&dentry->d_lock); | ||
560 | if (!ret) { | ||
561 | if ((IS_ROOT(dentry) || | ||
562 | (autofs_type_indirect(sbi->type) && | ||
563 | IS_ROOT(dentry->d_parent))) && | ||
564 | !(dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | ||
565 | __managed_dentry_set_automount(dentry); | ||
566 | } | ||
567 | spin_unlock(&dentry->d_lock); | ||
506 | complete_all(&ino->expire_complete); | 568 | complete_all(&ino->expire_complete); |
507 | spin_unlock(&sbi->fs_lock); | 569 | spin_unlock(&sbi->fs_lock); |
508 | dput(dentry); | 570 | dput(dentry); |