aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2006-03-27 04:14:46 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-27 11:44:39 -0500
commit1aff3c8b0511b5bb54acf7859e0c6ec9ae7287a9 (patch)
treebe50f4c89a14240b568010da1b0ce3c182352afc
parent1ce12bad85863478619688c0c7363f93a9e5edb8 (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>
-rw-r--r--fs/autofs4/autofs_i.h1
-rw-r--r--fs/autofs4/expire.c34
-rw-r--r--fs/autofs4/inode.c12
-rw-r--r--fs/autofs4/root.c23
4 files changed, 59 insertions, 11 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index eea25934da62..00da71d0f32a 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -55,6 +55,7 @@ struct autofs_info {
55 55
56 struct autofs_sb_info *sbi; 56 struct autofs_sb_info *sbi;
57 unsigned long last_used; 57 unsigned long last_used;
58 atomic_t count;
58 59
59 mode_t mode; 60 mode_t mode;
60 size_t size; 61 size_t size;
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 165fe9e2d570..053d92a745b9 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -101,6 +101,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
101 unsigned long timeout, 101 unsigned long timeout,
102 int do_now) 102 int do_now)
103{ 103{
104 struct autofs_info *ino;
104 struct dentry *p; 105 struct dentry *p;
105 106
106 DPRINTK("top %p %.*s", 107 DPRINTK("top %p %.*s",
@@ -110,14 +111,6 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
110 if (!simple_positive(top)) 111 if (!simple_positive(top))
111 return 1; 112 return 1;
112 113
113 /* Timeout of a tree mount is determined by its top dentry */
114 if (!autofs4_can_expire(top, timeout, do_now))
115 return 1;
116
117 /* Is someone visiting anywhere in the tree ? */
118 if (may_umount_tree(mnt))
119 return 1;
120
121 spin_lock(&dcache_lock); 114 spin_lock(&dcache_lock);
122 for (p = top; p; p = next_dentry(p, top)) { 115 for (p = top; p; p = next_dentry(p, top)) {
123 /* Negative dentry - give up */ 116 /* Negative dentry - give up */
@@ -130,17 +123,40 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
130 p = dget(p); 123 p = dget(p);
131 spin_unlock(&dcache_lock); 124 spin_unlock(&dcache_lock);
132 125
126 /*
127 * Is someone visiting anywhere in the subtree ?
128 * If there's no mount we need to check the usage
129 * count for the autofs dentry.
130 */
131 ino = autofs4_dentry_ino(p);
133 if (d_mountpoint(p)) { 132 if (d_mountpoint(p)) {
134 /* First busy => tree busy */
135 if (autofs4_mount_busy(mnt, p)) { 133 if (autofs4_mount_busy(mnt, p)) {
136 dput(p); 134 dput(p);
137 return 1; 135 return 1;
138 } 136 }
137 } else {
138 unsigned int ino_count = atomic_read(&ino->count);
139
140 /* allow for dget above and top is already dgot */
141 if (p == top)
142 ino_count += 2;
143 else
144 ino_count++;
145
146 if (atomic_read(&p->d_count) > ino_count) {
147 dput(p);
148 return 1;
149 }
139 } 150 }
140 dput(p); 151 dput(p);
141 spin_lock(&dcache_lock); 152 spin_lock(&dcache_lock);
142 } 153 }
143 spin_unlock(&dcache_lock); 154 spin_unlock(&dcache_lock);
155
156 /* Timeout of a tree mount is ultimately determined by its top dentry */
157 if (!autofs4_can_expire(top, timeout, do_now))
158 return 1;
159
144 return 0; 160 return 0;
145} 161}
146 162
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 1ad98d48e550..2335b1d6490f 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -46,6 +46,7 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
46 ino->size = 0; 46 ino->size = 0;
47 47
48 ino->last_used = jiffies; 48 ino->last_used = jiffies;
49 atomic_set(&ino->count, 0);
49 50
50 ino->sbi = sbi; 51 ino->sbi = sbi;
51 52
@@ -64,10 +65,19 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
64 65
65void autofs4_free_ino(struct autofs_info *ino) 66void autofs4_free_ino(struct autofs_info *ino)
66{ 67{
68 struct autofs_info *p_ino;
69
67 if (ino->dentry) { 70 if (ino->dentry) {
68 ino->dentry->d_fsdata = NULL; 71 ino->dentry->d_fsdata = NULL;
69 if (ino->dentry->d_inode) 72 if (ino->dentry->d_inode) {
73 struct dentry *parent = ino->dentry->d_parent;
74 if (atomic_dec_and_test(&ino->count)) {
75 p_ino = autofs4_dentry_ino(parent);
76 if (p_ino && parent != ino->dentry)
77 atomic_dec(&p_ino->count);
78 }
70 dput(ino->dentry); 79 dput(ino->dentry);
80 }
71 ino->dentry = NULL; 81 ino->dentry = NULL;
72 } 82 }
73 if (ino->free) 83 if (ino->free)
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;