diff options
Diffstat (limited to 'fs/autofs4/expire.c')
-rw-r--r-- | fs/autofs4/expire.c | 91 |
1 files changed, 77 insertions, 14 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 894fee54d4d8..cdabb796ff01 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -259,13 +259,15 @@ static struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
259 | now = jiffies; | 259 | now = jiffies; |
260 | timeout = sbi->exp_timeout; | 260 | timeout = sbi->exp_timeout; |
261 | 261 | ||
262 | /* Lock the tree as we must expire as a whole */ | ||
263 | spin_lock(&sbi->fs_lock); | 262 | spin_lock(&sbi->fs_lock); |
264 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 263 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
265 | struct autofs_info *ino = autofs4_dentry_ino(root); | 264 | struct autofs_info *ino = autofs4_dentry_ino(root); |
266 | 265 | if (d_mountpoint(root)) { | |
267 | /* Set this flag early to catch sys_chdir and the like */ | 266 | ino->flags |= AUTOFS_INF_MOUNTPOINT; |
267 | root->d_mounted--; | ||
268 | } | ||
268 | ino->flags |= AUTOFS_INF_EXPIRING; | 269 | ino->flags |= AUTOFS_INF_EXPIRING; |
270 | init_completion(&ino->expire_complete); | ||
269 | spin_unlock(&sbi->fs_lock); | 271 | spin_unlock(&sbi->fs_lock); |
270 | return root; | 272 | return root; |
271 | } | 273 | } |
@@ -292,6 +294,8 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
292 | struct list_head *next; | 294 | struct list_head *next; |
293 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 295 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
294 | int exp_leaves = how & AUTOFS_EXP_LEAVES; | 296 | int exp_leaves = how & AUTOFS_EXP_LEAVES; |
297 | struct autofs_info *ino; | ||
298 | unsigned int ino_count; | ||
295 | 299 | ||
296 | if (!root) | 300 | if (!root) |
297 | return NULL; | 301 | return NULL; |
@@ -316,6 +320,9 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
316 | dentry = dget(dentry); | 320 | dentry = dget(dentry); |
317 | spin_unlock(&dcache_lock); | 321 | spin_unlock(&dcache_lock); |
318 | 322 | ||
323 | spin_lock(&sbi->fs_lock); | ||
324 | ino = autofs4_dentry_ino(dentry); | ||
325 | |||
319 | /* | 326 | /* |
320 | * Case 1: (i) indirect mount or top level pseudo direct mount | 327 | * Case 1: (i) indirect mount or top level pseudo direct mount |
321 | * (autofs-4.1). | 328 | * (autofs-4.1). |
@@ -326,6 +333,11 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
326 | DPRINTK("checking mountpoint %p %.*s", | 333 | DPRINTK("checking mountpoint %p %.*s", |
327 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 334 | dentry, (int)dentry->d_name.len, dentry->d_name.name); |
328 | 335 | ||
336 | /* Path walk currently on this dentry? */ | ||
337 | ino_count = atomic_read(&ino->count) + 2; | ||
338 | if (atomic_read(&dentry->d_count) > ino_count) | ||
339 | goto next; | ||
340 | |||
329 | /* Can we umount this guy */ | 341 | /* Can we umount this guy */ |
330 | if (autofs4_mount_busy(mnt, dentry)) | 342 | if (autofs4_mount_busy(mnt, dentry)) |
331 | goto next; | 343 | goto next; |
@@ -343,23 +355,25 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
343 | 355 | ||
344 | /* Case 2: tree mount, expire iff entire tree is not busy */ | 356 | /* Case 2: tree mount, expire iff entire tree is not busy */ |
345 | if (!exp_leaves) { | 357 | if (!exp_leaves) { |
346 | /* Lock the tree as we must expire as a whole */ | 358 | /* Path walk currently on this dentry? */ |
347 | spin_lock(&sbi->fs_lock); | 359 | ino_count = atomic_read(&ino->count) + 1; |
348 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { | 360 | if (atomic_read(&dentry->d_count) > ino_count) |
349 | struct autofs_info *inf = autofs4_dentry_ino(dentry); | 361 | goto next; |
350 | 362 | ||
351 | /* Set this flag early to catch sys_chdir and the like */ | 363 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { |
352 | inf->flags |= AUTOFS_INF_EXPIRING; | ||
353 | spin_unlock(&sbi->fs_lock); | ||
354 | expired = dentry; | 364 | expired = dentry; |
355 | goto found; | 365 | goto found; |
356 | } | 366 | } |
357 | spin_unlock(&sbi->fs_lock); | ||
358 | /* | 367 | /* |
359 | * Case 3: pseudo direct mount, expire individual leaves | 368 | * Case 3: pseudo direct mount, expire individual leaves |
360 | * (autofs-4.1). | 369 | * (autofs-4.1). |
361 | */ | 370 | */ |
362 | } else { | 371 | } else { |
372 | /* Path walk currently on this dentry? */ | ||
373 | ino_count = atomic_read(&ino->count) + 1; | ||
374 | if (atomic_read(&dentry->d_count) > ino_count) | ||
375 | goto next; | ||
376 | |||
363 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 377 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
364 | if (expired) { | 378 | if (expired) { |
365 | dput(dentry); | 379 | dput(dentry); |
@@ -367,6 +381,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
367 | } | 381 | } |
368 | } | 382 | } |
369 | next: | 383 | next: |
384 | spin_unlock(&sbi->fs_lock); | ||
370 | dput(dentry); | 385 | dput(dentry); |
371 | spin_lock(&dcache_lock); | 386 | spin_lock(&dcache_lock); |
372 | next = next->next; | 387 | next = next->next; |
@@ -377,12 +392,45 @@ next: | |||
377 | found: | 392 | found: |
378 | DPRINTK("returning %p %.*s", | 393 | DPRINTK("returning %p %.*s", |
379 | expired, (int)expired->d_name.len, expired->d_name.name); | 394 | expired, (int)expired->d_name.len, expired->d_name.name); |
395 | ino = autofs4_dentry_ino(expired); | ||
396 | ino->flags |= AUTOFS_INF_EXPIRING; | ||
397 | init_completion(&ino->expire_complete); | ||
398 | spin_unlock(&sbi->fs_lock); | ||
380 | spin_lock(&dcache_lock); | 399 | spin_lock(&dcache_lock); |
381 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 400 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
382 | spin_unlock(&dcache_lock); | 401 | spin_unlock(&dcache_lock); |
383 | return expired; | 402 | return expired; |
384 | } | 403 | } |
385 | 404 | ||
405 | int autofs4_expire_wait(struct dentry *dentry) | ||
406 | { | ||
407 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
408 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
409 | int status; | ||
410 | |||
411 | /* Block on any pending expire */ | ||
412 | spin_lock(&sbi->fs_lock); | ||
413 | if (ino->flags & AUTOFS_INF_EXPIRING) { | ||
414 | spin_unlock(&sbi->fs_lock); | ||
415 | |||
416 | DPRINTK("waiting for expire %p name=%.*s", | ||
417 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
418 | |||
419 | status = autofs4_wait(sbi, dentry, NFY_NONE); | ||
420 | wait_for_completion(&ino->expire_complete); | ||
421 | |||
422 | DPRINTK("expire done status=%d", status); | ||
423 | |||
424 | if (d_unhashed(dentry)) | ||
425 | return -EAGAIN; | ||
426 | |||
427 | return status; | ||
428 | } | ||
429 | spin_unlock(&sbi->fs_lock); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
386 | /* Perform an expiry operation */ | 434 | /* Perform an expiry operation */ |
387 | int autofs4_expire_run(struct super_block *sb, | 435 | int autofs4_expire_run(struct super_block *sb, |
388 | struct vfsmount *mnt, | 436 | struct vfsmount *mnt, |
@@ -390,7 +438,9 @@ int autofs4_expire_run(struct super_block *sb, | |||
390 | struct autofs_packet_expire __user *pkt_p) | 438 | struct autofs_packet_expire __user *pkt_p) |
391 | { | 439 | { |
392 | struct autofs_packet_expire pkt; | 440 | struct autofs_packet_expire pkt; |
441 | struct autofs_info *ino; | ||
393 | struct dentry *dentry; | 442 | struct dentry *dentry; |
443 | int ret = 0; | ||
394 | 444 | ||
395 | memset(&pkt,0,sizeof pkt); | 445 | memset(&pkt,0,sizeof pkt); |
396 | 446 | ||
@@ -406,9 +456,15 @@ int autofs4_expire_run(struct super_block *sb, | |||
406 | dput(dentry); | 456 | dput(dentry); |
407 | 457 | ||
408 | if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) | 458 | if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) |
409 | return -EFAULT; | 459 | ret = -EFAULT; |
410 | 460 | ||
411 | return 0; | 461 | spin_lock(&sbi->fs_lock); |
462 | ino = autofs4_dentry_ino(dentry); | ||
463 | ino->flags &= ~AUTOFS_INF_EXPIRING; | ||
464 | complete_all(&ino->expire_complete); | ||
465 | spin_unlock(&sbi->fs_lock); | ||
466 | |||
467 | return ret; | ||
412 | } | 468 | } |
413 | 469 | ||
414 | /* Call repeatedly until it returns -EAGAIN, meaning there's nothing | 470 | /* Call repeatedly until it returns -EAGAIN, meaning there's nothing |
@@ -433,9 +489,16 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
433 | 489 | ||
434 | /* This is synchronous because it makes the daemon a | 490 | /* This is synchronous because it makes the daemon a |
435 | little easier */ | 491 | little easier */ |
436 | ino->flags |= AUTOFS_INF_EXPIRING; | ||
437 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); | 492 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); |
493 | |||
494 | spin_lock(&sbi->fs_lock); | ||
495 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | ||
496 | sb->s_root->d_mounted++; | ||
497 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | ||
498 | } | ||
438 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 499 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
500 | complete_all(&ino->expire_complete); | ||
501 | spin_unlock(&sbi->fs_lock); | ||
439 | dput(dentry); | 502 | dput(dentry); |
440 | } | 503 | } |
441 | 504 | ||