diff options
Diffstat (limited to 'fs/autofs4/expire.c')
-rw-r--r-- | fs/autofs4/expire.c | 127 |
1 files changed, 60 insertions, 67 deletions
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 | } |