aboutsummaryrefslogtreecommitdiffstats
path: root/fs/autofs4
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2010-01-29 18:38:22 -0500
committerThomas Gleixner <tglx@linutronix.de>2010-04-27 11:32:33 -0400
commitb9ab2f38fdee96ff49b8a7bbb65cbfc60921e40c (patch)
treee5e785ba4ae7ec89564914c50638a22d756b6d19 /fs/autofs4
parentd4fe09131b66c5a7176a5dbfc9bd1ef6939643e8 (diff)
fs-dcache-scale-d_subdirs
Protect d_subdirs and d_child with d_lock, except in filesystems that aren't using dcache_lock for these anyway (eg. using i_mutex). XXX: probably don't need parent lock in inotify (because child lock should stabilize parent). Also, possibly some filesystems don't need so much locking (eg. of child dentry when modifying d_child, so long as parent is locked)... but be on the safe side. Hmm, maybe we should just say d_child list is protected by d_parent->d_lock. d_parent could remain protected with d_lock. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/autofs4')
-rw-r--r--fs/autofs4/expire.c85
-rw-r--r--fs/autofs4/inode.c7
-rw-r--r--fs/autofs4/root.c14
3 files changed, 78 insertions, 28 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 47483ca14017..915f6a93bc48 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -93,22 +93,59 @@ done:
93/* 93/*
94 * Calculate next entry in top down tree traversal. 94 * Calculate next entry in top down tree traversal.
95 * From next_mnt in namespace.c - elegant. 95 * From next_mnt in namespace.c - elegant.
96 *
97 * How is this supposed to work if we drop dcache_lock between calls anyway?
98 * How does it cope with renames?
99 * And also callers dput the returned dentry before taking dcache_lock again
100 * so what prevents it from being freed??
96 */ 101 */
97static struct dentry *next_dentry(struct dentry *p, struct dentry *root) 102static struct dentry *get_next_positive_dentry(struct dentry *p,
103 struct dentry *root)
98{ 104{
99 struct list_head *next = p->d_subdirs.next; 105 struct list_head *next;
106 struct dentry *ret;
100 107
108 spin_lock(&dcache_lock);
109again:
110 spin_lock(&p->d_lock);
111 next = p->d_subdirs.next;
101 if (next == &p->d_subdirs) { 112 if (next == &p->d_subdirs) {
102 while (1) { 113 while (1) {
103 if (p == root) 114 struct dentry *parent;
115
116 if (p == root) {
117 spin_unlock(&p->d_lock);
118 spin_unlock(&dcache_lock);
104 return NULL; 119 return NULL;
120 }
121
122 parent = p->d_parent;
123 if (!spin_trylock(&parent->d_lock)) {
124 spin_unlock(&p->d_lock);
125 goto again;
126 }
127 spin_unlock(&p->d_lock);
105 next = p->d_u.d_child.next; 128 next = p->d_u.d_child.next;
106 if (next != &p->d_parent->d_subdirs) 129 p = parent;
130 if (next != &parent->d_subdirs)
107 break; 131 break;
108 p = p->d_parent;
109 } 132 }
110 } 133 }
111 return list_entry(next, struct dentry, d_u.d_child); 134 ret = list_entry(next, struct dentry, d_u.d_child);
135
136 spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
137 /* Negative dentry - try next */
138 if (!simple_positive(ret)) {
139 spin_unlock(&ret->d_lock);
140 p = ret;
141 goto again;
142 }
143 dget_dlock(ret);
144 spin_unlock(&ret->d_lock);
145 spin_unlock(&p->d_lock);
146 spin_unlock(&dcache_lock);
147
148 return ret;
112} 149}
113 150
114/* 151/*
@@ -158,18 +195,11 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
158 if (!simple_positive(top)) 195 if (!simple_positive(top))
159 return 1; 196 return 1;
160 197
161 spin_lock(&dcache_lock); 198 for (p = dget(top); p; p = get_next_positive_dentry(p, top)) {
162 for (p = top; p; p = next_dentry(p, top)) {
163 /* Negative dentry - give up */
164 if (!simple_positive(p))
165 continue;
166 199
167 DPRINTK("dentry %p %.*s", 200 DPRINTK("dentry %p %.*s",
168 p, (int) p->d_name.len, p->d_name.name); 201 p, (int) p->d_name.len, p->d_name.name);
169 202
170 p = dget(p);
171 spin_unlock(&dcache_lock);
172
173 /* 203 /*
174 * Is someone visiting anywhere in the subtree ? 204 * Is someone visiting anywhere in the subtree ?
175 * If there's no mount we need to check the usage 205 * If there's no mount we need to check the usage
@@ -205,9 +235,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
205 } 235 }
206 } 236 }
207 dput(p); 237 dput(p);
208 spin_lock(&dcache_lock);
209 } 238 }
210 spin_unlock(&dcache_lock);
211 239
212 /* Timeout of a tree mount is ultimately determined by its top dentry */ 240 /* Timeout of a tree mount is ultimately determined by its top dentry */
213 if (!autofs4_can_expire(top, timeout, do_now)) 241 if (!autofs4_can_expire(top, timeout, do_now))
@@ -226,18 +254,11 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
226 DPRINTK("parent %p %.*s", 254 DPRINTK("parent %p %.*s",
227 parent, (int)parent->d_name.len, parent->d_name.name); 255 parent, (int)parent->d_name.len, parent->d_name.name);
228 256
229 spin_lock(&dcache_lock); 257 for (p = dget(parent); p; p = get_next_positive_dentry(p, parent)) {
230 for (p = parent; p; p = next_dentry(p, parent)) {
231 /* Negative dentry - give up */
232 if (!simple_positive(p))
233 continue;
234 258
235 DPRINTK("dentry %p %.*s", 259 DPRINTK("dentry %p %.*s",
236 p, (int) p->d_name.len, p->d_name.name); 260 p, (int) p->d_name.len, p->d_name.name);
237 261
238 p = dget(p);
239 spin_unlock(&dcache_lock);
240
241 if (d_mountpoint(p)) { 262 if (d_mountpoint(p)) {
242 /* Can we umount this guy */ 263 /* Can we umount this guy */
243 if (autofs4_mount_busy(mnt, p)) 264 if (autofs4_mount_busy(mnt, p))
@@ -249,9 +270,7 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
249 } 270 }
250cont: 271cont:
251 dput(p); 272 dput(p);
252 spin_lock(&dcache_lock);
253 } 273 }
254 spin_unlock(&dcache_lock);
255 return NULL; 274 return NULL;
256} 275}
257 276
@@ -295,6 +314,8 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
295 * A tree is eligible if :- 314 * A tree is eligible if :-
296 * - it is unused by any user process 315 * - it is unused by any user process
297 * - it has been unused for exp_timeout time 316 * - it has been unused for exp_timeout time
317 * This seems to be racy dropping dcache_lock and asking for next->next after
318 * the lock has been dropped.
298 */ 319 */
299struct dentry *autofs4_expire_indirect(struct super_block *sb, 320struct dentry *autofs4_expire_indirect(struct super_block *sb,
300 struct vfsmount *mnt, 321 struct vfsmount *mnt,
@@ -317,6 +338,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
317 timeout = sbi->exp_timeout; 338 timeout = sbi->exp_timeout;
318 339
319 spin_lock(&dcache_lock); 340 spin_lock(&dcache_lock);
341 spin_lock(&root->d_lock);
320 next = root->d_subdirs.next; 342 next = root->d_subdirs.next;
321 343
322 /* On exit from the loop expire is set to a dgot dentry 344 /* On exit from the loop expire is set to a dgot dentry
@@ -330,7 +352,10 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
330 continue; 352 continue;
331 } 353 }
332 354
333 dentry = dget(dentry); 355 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
356 dentry = dget_dlock(dentry);
357 spin_unlock(&dentry->d_lock);
358 spin_unlock(&root->d_lock);
334 spin_unlock(&dcache_lock); 359 spin_unlock(&dcache_lock);
335 360
336 spin_lock(&sbi->fs_lock); 361 spin_lock(&sbi->fs_lock);
@@ -397,8 +422,10 @@ next:
397 spin_unlock(&sbi->fs_lock); 422 spin_unlock(&sbi->fs_lock);
398 dput(dentry); 423 dput(dentry);
399 spin_lock(&dcache_lock); 424 spin_lock(&dcache_lock);
425 spin_lock(&root->d_lock);
400 next = next->next; 426 next = next->next;
401 } 427 }
428 spin_unlock(&root->d_lock);
402 spin_unlock(&dcache_lock); 429 spin_unlock(&dcache_lock);
403 return NULL; 430 return NULL;
404 431
@@ -411,7 +438,11 @@ found:
411 init_completion(&ino->expire_complete); 438 init_completion(&ino->expire_complete);
412 spin_unlock(&sbi->fs_lock); 439 spin_unlock(&sbi->fs_lock);
413 spin_lock(&dcache_lock); 440 spin_lock(&dcache_lock);
441 spin_lock(&expired->d_parent->d_lock);
442 spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
414 list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); 443 list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
444 spin_unlock(&expired->d_lock);
445 spin_unlock(&expired->d_parent->d_lock);
415 spin_unlock(&dcache_lock); 446 spin_unlock(&dcache_lock);
416 return expired; 447 return expired;
417} 448}
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index d0a3de247458..cf6192583b73 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -113,6 +113,7 @@ static void autofs4_force_release(struct autofs_sb_info *sbi)
113 113
114 spin_lock(&dcache_lock); 114 spin_lock(&dcache_lock);
115repeat: 115repeat:
116 spin_lock(&this_parent->d_lock);
116 next = this_parent->d_subdirs.next; 117 next = this_parent->d_subdirs.next;
117resume: 118resume:
118 while (next != &this_parent->d_subdirs) { 119 while (next != &this_parent->d_subdirs) {
@@ -125,11 +126,13 @@ resume:
125 } 126 }
126 127
127 if (!list_empty(&dentry->d_subdirs)) { 128 if (!list_empty(&dentry->d_subdirs)) {
129 spin_unlock(&this_parent->d_lock);
128 this_parent = dentry; 130 this_parent = dentry;
129 goto repeat; 131 goto repeat;
130 } 132 }
131 133
132 next = next->next; 134 next = next->next;
135 spin_unlock(&this_parent->d_lock);
133 spin_unlock(&dcache_lock); 136 spin_unlock(&dcache_lock);
134 137
135 DPRINTK("dentry %p %.*s", 138 DPRINTK("dentry %p %.*s",
@@ -137,20 +140,24 @@ resume:
137 140
138 dput(dentry); 141 dput(dentry);
139 spin_lock(&dcache_lock); 142 spin_lock(&dcache_lock);
143 spin_lock(&this_parent->d_lock);
140 } 144 }
141 145
142 if (this_parent != sbi->sb->s_root) { 146 if (this_parent != sbi->sb->s_root) {
143 struct dentry *dentry = this_parent; 147 struct dentry *dentry = this_parent;
144 148
145 next = this_parent->d_u.d_child.next; 149 next = this_parent->d_u.d_child.next;
150 spin_unlock(&this_parent->d_lock);
146 this_parent = this_parent->d_parent; 151 this_parent = this_parent->d_parent;
147 spin_unlock(&dcache_lock); 152 spin_unlock(&dcache_lock);
148 DPRINTK("parent dentry %p %.*s", 153 DPRINTK("parent dentry %p %.*s",
149 dentry, (int)dentry->d_name.len, dentry->d_name.name); 154 dentry, (int)dentry->d_name.len, dentry->d_name.name);
150 dput(dentry); 155 dput(dentry);
151 spin_lock(&dcache_lock); 156 spin_lock(&dcache_lock);
157 spin_lock(&this_parent->d_lock);
152 goto resume; 158 goto resume;
153 } 159 }
160 spin_unlock(&this_parent->d_lock);
154 spin_unlock(&dcache_lock); 161 spin_unlock(&dcache_lock);
155} 162}
156 163
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 5d5c6d4600bb..9fc3409f9dd9 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -226,10 +226,13 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
226 * it. 226 * it.
227 */ 227 */
228 spin_lock(&dcache_lock); 228 spin_lock(&dcache_lock);
229 spin_lock(&dentry->d_lock);
229 if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { 230 if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
231 spin_unlock(&dentry->d_lock);
230 spin_unlock(&dcache_lock); 232 spin_unlock(&dcache_lock);
231 return -ENOENT; 233 return -ENOENT;
232 } 234 }
235 spin_unlock(&dentry->d_lock);
233 spin_unlock(&dcache_lock); 236 spin_unlock(&dcache_lock);
234 237
235out: 238out:
@@ -311,9 +314,12 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
311 * multi-mount with no root mount offset. So don't try to 314 * multi-mount with no root mount offset. So don't try to
312 * mount it again. 315 * mount it again.
313 */ 316 */
317 spin_lock(&dcache_lock);
318 spin_lock(&dentry->d_lock);
314 if (ino->flags & AUTOFS_INF_PENDING || 319 if (ino->flags & AUTOFS_INF_PENDING ||
315 (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { 320 (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
316 ino->flags |= AUTOFS_INF_PENDING; 321 ino->flags |= AUTOFS_INF_PENDING;
322 spin_unlock(&dentry->d_lock);
317 spin_unlock(&dcache_lock); 323 spin_unlock(&dcache_lock);
318 spin_unlock(&sbi->fs_lock); 324 spin_unlock(&sbi->fs_lock);
319 325
@@ -328,6 +334,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
328 334
329 goto follow; 335 goto follow;
330 } 336 }
337 spin_unlock(&dentry->d_lock);
331 spin_unlock(&dcache_lock); 338 spin_unlock(&dcache_lock);
332 spin_unlock(&sbi->fs_lock); 339 spin_unlock(&sbi->fs_lock);
333follow: 340follow:
@@ -931,11 +938,16 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
931 return -EACCES; 938 return -EACCES;
932 939
933 spin_lock(&dcache_lock); 940 spin_lock(&dcache_lock);
941 spin_lock(&dentry->d_lock);
934 if (!list_empty(&dentry->d_subdirs)) { 942 if (!list_empty(&dentry->d_subdirs)) {
943 spin_unlock(&dentry->d_lock);
935 spin_unlock(&dcache_lock); 944 spin_unlock(&dcache_lock);
936 return -ENOTEMPTY; 945 return -ENOTEMPTY;
937 } 946 }
938 spin_lock(&dentry->d_lock); 947 spin_lock(&sbi->lookup_lock);
948 if (list_empty(&ino->expiring))
949 list_add(&ino->expiring, &sbi->expiring_list);
950 spin_unlock(&sbi->lookup_lock);
939 __d_drop(dentry); 951 __d_drop(dentry);
940 spin_unlock(&dentry->d_lock); 952 spin_unlock(&dentry->d_lock);
941 spin_unlock(&dcache_lock); 953 spin_unlock(&dcache_lock);