diff options
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/autofs_i.h | 11 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 127 | ||||
-rw-r--r-- | fs/autofs4/root.c | 18 |
3 files changed, 87 insertions, 69 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 3912dcf047e5..9d2ae9b30d9f 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -254,6 +254,17 @@ static inline int simple_positive(struct dentry *dentry) | |||
254 | return dentry->d_inode && !d_unhashed(dentry); | 254 | return dentry->d_inode && !d_unhashed(dentry); |
255 | } | 255 | } |
256 | 256 | ||
257 | static inline void __autofs4_add_expiring(struct dentry *dentry) | ||
258 | { | ||
259 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
260 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
261 | if (ino) { | ||
262 | if (list_empty(&ino->expiring)) | ||
263 | list_add(&ino->expiring, &sbi->expiring_list); | ||
264 | } | ||
265 | return; | ||
266 | } | ||
267 | |||
257 | static inline void autofs4_add_expiring(struct dentry *dentry) | 268 | static inline void autofs4_add_expiring(struct dentry *dentry) |
258 | { | 269 | { |
259 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 270 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index ee6402050f13..968c1434af62 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -91,24 +91,64 @@ done: | |||
91 | } | 91 | } |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Calculate next entry in top down tree traversal. | 94 | * Calculate and dget next entry in top down tree traversal. |
95 | * From next_mnt in namespace.c - elegant. | ||
96 | */ | 95 | */ |
97 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | 96 | static struct dentry *get_next_positive_dentry(struct dentry *prev, |
97 | struct dentry *root) | ||
98 | { | 98 | { |
99 | struct list_head *next = p->d_subdirs.next; | 99 | struct list_head *next; |
100 | struct dentry *p, *ret; | ||
101 | |||
102 | if (prev == NULL) | ||
103 | return dget(prev); | ||
100 | 104 | ||
105 | spin_lock(&dcache_lock); | ||
106 | relock: | ||
107 | p = prev; | ||
108 | spin_lock(&p->d_lock); | ||
109 | again: | ||
110 | next = p->d_subdirs.next; | ||
101 | if (next == &p->d_subdirs) { | 111 | if (next == &p->d_subdirs) { |
102 | while (1) { | 112 | while (1) { |
103 | if (p == root) | 113 | struct dentry *parent; |
114 | |||
115 | if (p == root) { | ||
116 | spin_unlock(&p->d_lock); | ||
117 | spin_unlock(&dcache_lock); | ||
118 | dput(prev); | ||
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 | cpu_relax(); | ||
126 | goto relock; | ||
127 | } | ||
128 | spin_unlock(&p->d_lock); | ||
105 | next = p->d_u.d_child.next; | 129 | next = p->d_u.d_child.next; |
106 | if (next != &p->d_parent->d_subdirs) | 130 | p = parent; |
131 | if (next != &parent->d_subdirs) | ||
107 | break; | 132 | break; |
108 | p = p->d_parent; | ||
109 | } | 133 | } |
110 | } | 134 | } |
111 | return list_entry(next, struct dentry, d_u.d_child); | 135 | ret = list_entry(next, struct dentry, d_u.d_child); |
136 | |||
137 | spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); | ||
138 | /* Negative dentry - try next */ | ||
139 | if (!simple_positive(ret)) { | ||
140 | spin_unlock(&ret->d_lock); | ||
141 | p = ret; | ||
142 | goto again; | ||
143 | } | ||
144 | dget_dlock(ret); | ||
145 | spin_unlock(&ret->d_lock); | ||
146 | spin_unlock(&p->d_lock); | ||
147 | spin_unlock(&dcache_lock); | ||
148 | |||
149 | dput(prev); | ||
150 | |||
151 | return ret; | ||
112 | } | 152 | } |
113 | 153 | ||
114 | /* | 154 | /* |
@@ -158,22 +198,11 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
158 | if (!simple_positive(top)) | 198 | if (!simple_positive(top)) |
159 | return 1; | 199 | return 1; |
160 | 200 | ||
161 | spin_lock(&dcache_lock); | 201 | p = NULL; |
162 | for (p = top; p; p = next_dentry(p, top)) { | 202 | while ((p = get_next_positive_dentry(p, top))) { |
163 | spin_lock(&p->d_lock); | ||
164 | /* Negative dentry - give up */ | ||
165 | if (!simple_positive(p)) { | ||
166 | spin_unlock(&p->d_lock); | ||
167 | continue; | ||
168 | } | ||
169 | |||
170 | DPRINTK("dentry %p %.*s", | 203 | DPRINTK("dentry %p %.*s", |
171 | p, (int) p->d_name.len, p->d_name.name); | 204 | p, (int) p->d_name.len, p->d_name.name); |
172 | 205 | ||
173 | p = dget_dlock(p); | ||
174 | spin_unlock(&p->d_lock); | ||
175 | spin_unlock(&dcache_lock); | ||
176 | |||
177 | /* | 206 | /* |
178 | * Is someone visiting anywhere in the subtree ? | 207 | * Is someone visiting anywhere in the subtree ? |
179 | * If there's no mount we need to check the usage | 208 | * If there's no mount we need to check the usage |
@@ -208,10 +237,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
208 | return 1; | 237 | return 1; |
209 | } | 238 | } |
210 | } | 239 | } |
211 | dput(p); | ||
212 | spin_lock(&dcache_lock); | ||
213 | } | 240 | } |
214 | spin_unlock(&dcache_lock); | ||
215 | 241 | ||
216 | /* Timeout of a tree mount is ultimately determined by its top dentry */ | 242 | /* Timeout of a tree mount is ultimately determined by its top dentry */ |
217 | if (!autofs4_can_expire(top, timeout, do_now)) | 243 | if (!autofs4_can_expire(top, timeout, do_now)) |
@@ -230,36 +256,21 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
230 | DPRINTK("parent %p %.*s", | 256 | DPRINTK("parent %p %.*s", |
231 | parent, (int)parent->d_name.len, parent->d_name.name); | 257 | parent, (int)parent->d_name.len, parent->d_name.name); |
232 | 258 | ||
233 | spin_lock(&dcache_lock); | 259 | p = NULL; |
234 | for (p = parent; p; p = next_dentry(p, parent)) { | 260 | while ((p = get_next_positive_dentry(p, parent))) { |
235 | spin_lock(&p->d_lock); | ||
236 | /* Negative dentry - give up */ | ||
237 | if (!simple_positive(p)) { | ||
238 | spin_unlock(&p->d_lock); | ||
239 | continue; | ||
240 | } | ||
241 | |||
242 | DPRINTK("dentry %p %.*s", | 261 | DPRINTK("dentry %p %.*s", |
243 | p, (int) p->d_name.len, p->d_name.name); | 262 | p, (int) p->d_name.len, p->d_name.name); |
244 | 263 | ||
245 | p = dget_dlock(p); | ||
246 | spin_unlock(&p->d_lock); | ||
247 | spin_unlock(&dcache_lock); | ||
248 | |||
249 | if (d_mountpoint(p)) { | 264 | if (d_mountpoint(p)) { |
250 | /* Can we umount this guy */ | 265 | /* Can we umount this guy */ |
251 | if (autofs4_mount_busy(mnt, p)) | 266 | if (autofs4_mount_busy(mnt, p)) |
252 | goto cont; | 267 | continue; |
253 | 268 | ||
254 | /* Can we expire this guy */ | 269 | /* Can we expire this guy */ |
255 | if (autofs4_can_expire(p, timeout, do_now)) | 270 | if (autofs4_can_expire(p, timeout, do_now)) |
256 | return p; | 271 | return p; |
257 | } | 272 | } |
258 | cont: | ||
259 | dput(p); | ||
260 | spin_lock(&dcache_lock); | ||
261 | } | 273 | } |
262 | spin_unlock(&dcache_lock); | ||
263 | return NULL; | 274 | return NULL; |
264 | } | 275 | } |
265 | 276 | ||
@@ -310,8 +321,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
310 | { | 321 | { |
311 | unsigned long timeout; | 322 | unsigned long timeout; |
312 | struct dentry *root = sb->s_root; | 323 | struct dentry *root = sb->s_root; |
324 | struct dentry *dentry; | ||
313 | struct dentry *expired = NULL; | 325 | struct dentry *expired = NULL; |
314 | struct list_head *next; | ||
315 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 326 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
316 | int exp_leaves = how & AUTOFS_EXP_LEAVES; | 327 | int exp_leaves = how & AUTOFS_EXP_LEAVES; |
317 | struct autofs_info *ino; | 328 | struct autofs_info *ino; |
@@ -323,26 +334,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
323 | now = jiffies; | 334 | now = jiffies; |
324 | timeout = sbi->exp_timeout; | 335 | timeout = sbi->exp_timeout; |
325 | 336 | ||
326 | spin_lock(&dcache_lock); | 337 | dentry = NULL; |
327 | next = root->d_subdirs.next; | 338 | while ((dentry = get_next_positive_dentry(dentry, root))) { |
328 | |||
329 | /* On exit from the loop expire is set to a dgot dentry | ||
330 | * to expire or it's NULL */ | ||
331 | while ( next != &root->d_subdirs ) { | ||
332 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
333 | |||
334 | /* Negative dentry - give up */ | ||
335 | spin_lock(&dentry->d_lock); | ||
336 | if (!simple_positive(dentry)) { | ||
337 | next = next->next; | ||
338 | spin_unlock(&dentry->d_lock); | ||
339 | continue; | ||
340 | } | ||
341 | |||
342 | dentry = dget_dlock(dentry); | ||
343 | spin_unlock(&dentry->d_lock); | ||
344 | spin_unlock(&dcache_lock); | ||
345 | |||
346 | spin_lock(&sbi->fs_lock); | 339 | spin_lock(&sbi->fs_lock); |
347 | ino = autofs4_dentry_ino(dentry); | 340 | ino = autofs4_dentry_ino(dentry); |
348 | 341 | ||
@@ -405,11 +398,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
405 | } | 398 | } |
406 | next: | 399 | next: |
407 | spin_unlock(&sbi->fs_lock); | 400 | spin_unlock(&sbi->fs_lock); |
408 | dput(dentry); | ||
409 | spin_lock(&dcache_lock); | ||
410 | next = next->next; | ||
411 | } | 401 | } |
412 | spin_unlock(&dcache_lock); | ||
413 | return NULL; | 402 | return NULL; |
414 | 403 | ||
415 | found: | 404 | found: |
@@ -420,7 +409,11 @@ found: | |||
420 | init_completion(&ino->expire_complete); | 409 | init_completion(&ino->expire_complete); |
421 | spin_unlock(&sbi->fs_lock); | 410 | spin_unlock(&sbi->fs_lock); |
422 | spin_lock(&dcache_lock); | 411 | spin_lock(&dcache_lock); |
412 | spin_lock(&expired->d_parent->d_lock); | ||
413 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | ||
423 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 414 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
415 | spin_unlock(&expired->d_lock); | ||
416 | spin_unlock(&expired->d_parent->d_lock); | ||
424 | spin_unlock(&dcache_lock); | 417 | spin_unlock(&dcache_lock); |
425 | return expired; | 418 | return expired; |
426 | } | 419 | } |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 7922509b5b2b..7a9ed6b88291 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -143,10 +143,13 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
143 | * it. | 143 | * it. |
144 | */ | 144 | */ |
145 | spin_lock(&dcache_lock); | 145 | spin_lock(&dcache_lock); |
146 | spin_lock(&dentry->d_lock); | ||
146 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 147 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
148 | spin_unlock(&dentry->d_lock); | ||
147 | spin_unlock(&dcache_lock); | 149 | spin_unlock(&dcache_lock); |
148 | return -ENOENT; | 150 | return -ENOENT; |
149 | } | 151 | } |
152 | spin_unlock(&dentry->d_lock); | ||
150 | spin_unlock(&dcache_lock); | 153 | spin_unlock(&dcache_lock); |
151 | 154 | ||
152 | out: | 155 | out: |
@@ -253,7 +256,9 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
253 | lookup_type = autofs4_need_mount(nd->flags); | 256 | lookup_type = autofs4_need_mount(nd->flags); |
254 | spin_lock(&sbi->fs_lock); | 257 | spin_lock(&sbi->fs_lock); |
255 | spin_lock(&dcache_lock); | 258 | spin_lock(&dcache_lock); |
259 | spin_lock(&dentry->d_lock); | ||
256 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | 260 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { |
261 | spin_unlock(&dentry->d_lock); | ||
257 | spin_unlock(&dcache_lock); | 262 | spin_unlock(&dcache_lock); |
258 | spin_unlock(&sbi->fs_lock); | 263 | spin_unlock(&sbi->fs_lock); |
259 | goto follow; | 264 | goto follow; |
@@ -266,6 +271,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
266 | */ | 271 | */ |
267 | if (ino->flags & AUTOFS_INF_PENDING || | 272 | if (ino->flags & AUTOFS_INF_PENDING || |
268 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { | 273 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { |
274 | spin_unlock(&dentry->d_lock); | ||
269 | spin_unlock(&dcache_lock); | 275 | spin_unlock(&dcache_lock); |
270 | spin_unlock(&sbi->fs_lock); | 276 | spin_unlock(&sbi->fs_lock); |
271 | 277 | ||
@@ -275,6 +281,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
275 | 281 | ||
276 | goto follow; | 282 | goto follow; |
277 | } | 283 | } |
284 | spin_unlock(&dentry->d_lock); | ||
278 | spin_unlock(&dcache_lock); | 285 | spin_unlock(&dcache_lock); |
279 | spin_unlock(&sbi->fs_lock); | 286 | spin_unlock(&sbi->fs_lock); |
280 | follow: | 287 | follow: |
@@ -347,10 +354,12 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
347 | 354 | ||
348 | /* Check for a non-mountpoint directory with no contents */ | 355 | /* Check for a non-mountpoint directory with no contents */ |
349 | spin_lock(&dcache_lock); | 356 | spin_lock(&dcache_lock); |
357 | spin_lock(&dentry->d_lock); | ||
350 | if (S_ISDIR(dentry->d_inode->i_mode) && | 358 | if (S_ISDIR(dentry->d_inode->i_mode) && |
351 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 359 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
352 | DPRINTK("dentry=%p %.*s, emptydir", | 360 | DPRINTK("dentry=%p %.*s, emptydir", |
353 | dentry, dentry->d_name.len, dentry->d_name.name); | 361 | dentry, dentry->d_name.len, dentry->d_name.name); |
362 | spin_unlock(&dentry->d_lock); | ||
354 | spin_unlock(&dcache_lock); | 363 | spin_unlock(&dcache_lock); |
355 | 364 | ||
356 | /* The daemon never causes a mount to trigger */ | 365 | /* The daemon never causes a mount to trigger */ |
@@ -367,6 +376,7 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
367 | 376 | ||
368 | return status; | 377 | return status; |
369 | } | 378 | } |
379 | spin_unlock(&dentry->d_lock); | ||
370 | spin_unlock(&dcache_lock); | 380 | spin_unlock(&dcache_lock); |
371 | 381 | ||
372 | return 1; | 382 | return 1; |
@@ -776,12 +786,16 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
776 | return -EACCES; | 786 | return -EACCES; |
777 | 787 | ||
778 | spin_lock(&dcache_lock); | 788 | spin_lock(&dcache_lock); |
789 | spin_lock(&sbi->lookup_lock); | ||
790 | spin_lock(&dentry->d_lock); | ||
779 | if (!list_empty(&dentry->d_subdirs)) { | 791 | if (!list_empty(&dentry->d_subdirs)) { |
792 | spin_unlock(&dentry->d_lock); | ||
793 | spin_unlock(&sbi->lookup_lock); | ||
780 | spin_unlock(&dcache_lock); | 794 | spin_unlock(&dcache_lock); |
781 | return -ENOTEMPTY; | 795 | return -ENOTEMPTY; |
782 | } | 796 | } |
783 | autofs4_add_expiring(dentry); | 797 | __autofs4_add_expiring(dentry); |
784 | spin_lock(&dentry->d_lock); | 798 | spin_unlock(&sbi->lookup_lock); |
785 | __d_drop(dentry); | 799 | __d_drop(dentry); |
786 | spin_unlock(&dentry->d_lock); | 800 | spin_unlock(&dentry->d_lock); |
787 | spin_unlock(&dcache_lock); | 801 | spin_unlock(&dcache_lock); |