diff options
author | Ian Kent <raven@themaw.net> | 2006-03-27 04:14:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:39 -0500 |
commit | 1aff3c8b0511b5bb54acf7859e0c6ec9ae7287a9 (patch) | |
tree | be50f4c89a14240b568010da1b0ce3c182352afc /fs/autofs4/root.c | |
parent | 1ce12bad85863478619688c0c7363f93a9e5edb8 (diff) |
[PATCH] autofs4: fix false negative return from expire
Fix the case where an expire returns busy on a tree mount when it is in fact
not busy. This case was overlooked when the patch to prevent the expiring
away of "scaffolding" directories for tree mounts was applied.
The problem arises when a tree of mounts is a member of a map with other keys.
The current logic will not expire the tree if any other mount in the map is
busy. The solution is to maintain a "minimum" use count for each autofs
dentry and compare this to the actual dentry usage count during expire.
Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/autofs4/root.c')
-rw-r--r-- | fs/autofs4/root.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index c7ff35774344..d196712c4b94 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -490,6 +490,7 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
490 | { | 490 | { |
491 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 491 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
492 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 492 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
493 | struct autofs_info *p_ino; | ||
493 | struct inode *inode; | 494 | struct inode *inode; |
494 | char *cp; | 495 | char *cp; |
495 | 496 | ||
@@ -523,6 +524,10 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
523 | 524 | ||
524 | dentry->d_fsdata = ino; | 525 | dentry->d_fsdata = ino; |
525 | ino->dentry = dget(dentry); | 526 | ino->dentry = dget(dentry); |
527 | atomic_inc(&ino->count); | ||
528 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
529 | if (p_ino && dentry->d_parent != dentry) | ||
530 | atomic_inc(&p_ino->count); | ||
526 | ino->inode = inode; | 531 | ino->inode = inode; |
527 | 532 | ||
528 | dir->i_mtime = CURRENT_TIME; | 533 | dir->i_mtime = CURRENT_TIME; |
@@ -549,11 +554,17 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
549 | { | 554 | { |
550 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 555 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
551 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 556 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
557 | struct autofs_info *p_ino; | ||
552 | 558 | ||
553 | /* This allows root to remove symlinks */ | 559 | /* This allows root to remove symlinks */ |
554 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) | 560 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) |
555 | return -EACCES; | 561 | return -EACCES; |
556 | 562 | ||
563 | if (atomic_dec_and_test(&ino->count)) { | ||
564 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
565 | if (p_ino && dentry->d_parent != dentry) | ||
566 | atomic_dec(&p_ino->count); | ||
567 | } | ||
557 | dput(ino->dentry); | 568 | dput(ino->dentry); |
558 | 569 | ||
559 | dentry->d_inode->i_size = 0; | 570 | dentry->d_inode->i_size = 0; |
@@ -570,6 +581,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
570 | { | 581 | { |
571 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 582 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
572 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 583 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
584 | struct autofs_info *p_ino; | ||
573 | 585 | ||
574 | if (!autofs4_oz_mode(sbi)) | 586 | if (!autofs4_oz_mode(sbi)) |
575 | return -EACCES; | 587 | return -EACCES; |
@@ -584,8 +596,12 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
584 | spin_unlock(&dentry->d_lock); | 596 | spin_unlock(&dentry->d_lock); |
585 | spin_unlock(&dcache_lock); | 597 | spin_unlock(&dcache_lock); |
586 | 598 | ||
599 | if (atomic_dec_and_test(&ino->count)) { | ||
600 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
601 | if (p_ino && dentry->d_parent != dentry) | ||
602 | atomic_dec(&p_ino->count); | ||
603 | } | ||
587 | dput(ino->dentry); | 604 | dput(ino->dentry); |
588 | |||
589 | dentry->d_inode->i_size = 0; | 605 | dentry->d_inode->i_size = 0; |
590 | dentry->d_inode->i_nlink = 0; | 606 | dentry->d_inode->i_nlink = 0; |
591 | 607 | ||
@@ -599,6 +615,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
599 | { | 615 | { |
600 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 616 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
601 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 617 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
618 | struct autofs_info *p_ino; | ||
602 | struct inode *inode; | 619 | struct inode *inode; |
603 | 620 | ||
604 | if ( !autofs4_oz_mode(sbi) ) | 621 | if ( !autofs4_oz_mode(sbi) ) |
@@ -621,6 +638,10 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
621 | 638 | ||
622 | dentry->d_fsdata = ino; | 639 | dentry->d_fsdata = ino; |
623 | ino->dentry = dget(dentry); | 640 | ino->dentry = dget(dentry); |
641 | atomic_inc(&ino->count); | ||
642 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
643 | if (p_ino && dentry->d_parent != dentry) | ||
644 | atomic_inc(&p_ino->count); | ||
624 | ino->inode = inode; | 645 | ino->inode = inode; |
625 | dir->i_nlink++; | 646 | dir->i_nlink++; |
626 | dir->i_mtime = CURRENT_TIME; | 647 | dir->i_mtime = CURRENT_TIME; |