diff options
-rw-r--r-- | fs/autofs4/autofs_i.h | 1 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 29 | ||||
-rw-r--r-- | fs/autofs4/root.c | 75 |
3 files changed, 40 insertions, 65 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 4b40cbc71e9b..69a2f5c92319 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -163,6 +163,7 @@ void autofs4_free_ino(struct autofs_info *); | |||
163 | 163 | ||
164 | /* Expiration */ | 164 | /* Expiration */ |
165 | int is_autofs4_dentry(struct dentry *); | 165 | int is_autofs4_dentry(struct dentry *); |
166 | int autofs4_expire_wait(struct dentry *dentry); | ||
166 | int autofs4_expire_run(struct super_block *, struct vfsmount *, | 167 | int autofs4_expire_run(struct super_block *, struct vfsmount *, |
167 | struct autofs_sb_info *, | 168 | struct autofs_sb_info *, |
168 | struct autofs_packet_expire __user *); | 169 | struct autofs_packet_expire __user *); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 705b9f057fb3..cdabb796ff01 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -402,6 +402,35 @@ found: | |||
402 | return expired; | 402 | return expired; |
403 | } | 403 | } |
404 | 404 | ||
405 | int autofs4_expire_wait(struct dentry *dentry) | ||
406 | { | ||
407 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
408 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
409 | int status; | ||
410 | |||
411 | /* Block on any pending expire */ | ||
412 | spin_lock(&sbi->fs_lock); | ||
413 | if (ino->flags & AUTOFS_INF_EXPIRING) { | ||
414 | spin_unlock(&sbi->fs_lock); | ||
415 | |||
416 | DPRINTK("waiting for expire %p name=%.*s", | ||
417 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
418 | |||
419 | status = autofs4_wait(sbi, dentry, NFY_NONE); | ||
420 | wait_for_completion(&ino->expire_complete); | ||
421 | |||
422 | DPRINTK("expire done status=%d", status); | ||
423 | |||
424 | if (d_unhashed(dentry)) | ||
425 | return -EAGAIN; | ||
426 | |||
427 | return status; | ||
428 | } | ||
429 | spin_unlock(&sbi->fs_lock); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
405 | /* Perform an expiry operation */ | 434 | /* Perform an expiry operation */ |
406 | int autofs4_expire_run(struct super_block *sb, | 435 | int autofs4_expire_run(struct super_block *sb, |
407 | struct vfsmount *mnt, | 436 | struct vfsmount *mnt, |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index e062ee5a3ed5..ae22bde0bbd7 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -130,34 +130,6 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
130 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 130 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
131 | int status; | 131 | int status; |
132 | 132 | ||
133 | /* Block on any pending expiry here; invalidate the dentry | ||
134 | when expiration is done to trigger mount request with a new | ||
135 | dentry */ | ||
136 | spin_lock(&sbi->fs_lock); | ||
137 | if (ino->flags & AUTOFS_INF_EXPIRING) { | ||
138 | spin_unlock(&sbi->fs_lock); | ||
139 | |||
140 | DPRINTK("waiting for expire %p name=%.*s", | ||
141 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
142 | |||
143 | status = autofs4_wait(sbi, dentry, NFY_NONE); | ||
144 | wait_for_completion(&ino->expire_complete); | ||
145 | |||
146 | DPRINTK("expire done status=%d", status); | ||
147 | |||
148 | /* | ||
149 | * If the directory still exists the mount request must | ||
150 | * continue otherwise it can't be followed at the right | ||
151 | * time during the walk. | ||
152 | */ | ||
153 | status = d_invalidate(dentry); | ||
154 | if (status != -EBUSY) | ||
155 | return -EAGAIN; | ||
156 | |||
157 | goto cont; | ||
158 | } | ||
159 | spin_unlock(&sbi->fs_lock); | ||
160 | cont: | ||
161 | DPRINTK("dentry=%p %.*s ino=%p", | 133 | DPRINTK("dentry=%p %.*s ino=%p", |
162 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | 134 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); |
163 | 135 | ||
@@ -248,22 +220,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
248 | } | 220 | } |
249 | 221 | ||
250 | /* If an expire request is pending everyone must wait. */ | 222 | /* If an expire request is pending everyone must wait. */ |
251 | spin_lock(&sbi->fs_lock); | 223 | autofs4_expire_wait(dentry); |
252 | if (ino->flags & AUTOFS_INF_EXPIRING) { | ||
253 | spin_unlock(&sbi->fs_lock); | ||
254 | |||
255 | DPRINTK("waiting for active request %p name=%.*s", | ||
256 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
257 | |||
258 | status = autofs4_wait(sbi, dentry, NFY_NONE); | ||
259 | wait_for_completion(&ino->expire_complete); | ||
260 | 224 | ||
261 | DPRINTK("request done status=%d", status); | ||
262 | |||
263 | goto cont; | ||
264 | } | ||
265 | spin_unlock(&sbi->fs_lock); | ||
266 | cont: | ||
267 | /* We trigger a mount for almost all flags */ | 225 | /* We trigger a mount for almost all flags */ |
268 | lookup_type = nd->flags & (TRIGGER_FLAGS | TRIGGER_INTENTS); | 226 | lookup_type = nd->flags & (TRIGGER_FLAGS | TRIGGER_INTENTS); |
269 | if (!(lookup_type || dentry->d_flags & DCACHE_AUTOFS_PENDING)) | 227 | if (!(lookup_type || dentry->d_flags & DCACHE_AUTOFS_PENDING)) |
@@ -332,6 +290,14 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
332 | return 1; | 290 | return 1; |
333 | 291 | ||
334 | /* | 292 | /* |
293 | * If the directory has gone away due to an expire | ||
294 | * we have been called as ->d_revalidate() and so | ||
295 | * we need to return false and proceed to ->lookup(). | ||
296 | */ | ||
297 | if (autofs4_expire_wait(dentry) == -EAGAIN) | ||
298 | return 0; | ||
299 | |||
300 | /* | ||
335 | * A zero status is success otherwise we have a | 301 | * A zero status is success otherwise we have a |
336 | * negative error code. | 302 | * negative error code. |
337 | */ | 303 | */ |
@@ -339,15 +305,6 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
339 | if (status == 0) | 305 | if (status == 0) |
340 | return 1; | 306 | return 1; |
341 | 307 | ||
342 | /* | ||
343 | * A status of EAGAIN here means that the dentry has gone | ||
344 | * away while waiting for an expire to complete. If we are | ||
345 | * racing with expire lookup will wait for it so this must | ||
346 | * be a revalidate and we need to send it to lookup. | ||
347 | */ | ||
348 | if (status == -EAGAIN) | ||
349 | return 0; | ||
350 | |||
351 | return status; | 308 | return status; |
352 | } | 309 | } |
353 | spin_unlock(&sbi->fs_lock); | 310 | spin_unlock(&sbi->fs_lock); |
@@ -557,19 +514,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
557 | * so it must have been successful, so just wait for it. | 514 | * so it must have been successful, so just wait for it. |
558 | */ | 515 | */ |
559 | ino = autofs4_dentry_ino(expiring); | 516 | ino = autofs4_dentry_ino(expiring); |
560 | spin_lock(&sbi->fs_lock); | 517 | autofs4_expire_wait(expiring); |
561 | if (ino->flags & AUTOFS_INF_EXPIRING) { | ||
562 | spin_unlock(&sbi->fs_lock); | ||
563 | DPRINTK("wait for incomplete expire %p name=%.*s", | ||
564 | expiring, expiring->d_name.len, | ||
565 | expiring->d_name.name); | ||
566 | autofs4_wait(sbi, expiring, NFY_NONE); | ||
567 | wait_for_completion(&ino->expire_complete); | ||
568 | DPRINTK("request completed"); | ||
569 | goto cont; | ||
570 | } | ||
571 | spin_unlock(&sbi->fs_lock); | ||
572 | cont: | ||
573 | spin_lock(&sbi->lookup_lock); | 518 | spin_lock(&sbi->lookup_lock); |
574 | if (!list_empty(&ino->expiring)) | 519 | if (!list_empty(&ino->expiring)) |
575 | list_del_init(&ino->expiring); | 520 | list_del_init(&ino->expiring); |