Commit bcdc5e019d9f525a9f181a7de642d3a9c27c7610
Committed by
Linus Torvalds
1 parent
1183dc943c
Exists in
master
and in
7 other branches
[PATCH] autofs4 needs to force fail return revalidate
For a long time now I have had a problem with not being able to return a lookup failure on an existsing directory. In autofs this corresponds to a mount failure on a autofs managed mount entry that is browsable (and so the mount point directory exists). While this problem has been present for a long time I've avoided resolving it because it was not very visible. But now that autofs v5 has "mount and expire on demand" of nested multiple mounts, such as is found when mounting an export list from a server, solving the problem cannot be avoided any longer. I've tried very hard to find a way to do this entirely within the autofs4 module but have not been able to find a satisfactory way to achieve it. So, I need to propose a change to the VFS. Signed-off-by: Ian Kent <raven@themaw.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 2 changed files with 65 additions and 23 deletions Side-by-side Diff
fs/autofs4/root.c
... | ... | @@ -137,7 +137,9 @@ |
137 | 137 | nd.flags = LOOKUP_DIRECTORY; |
138 | 138 | ret = (dentry->d_op->d_revalidate)(dentry, &nd); |
139 | 139 | |
140 | - if (!ret) { | |
140 | + if (ret <= 0) { | |
141 | + if (ret < 0) | |
142 | + status = ret; | |
141 | 143 | dcache_dir_close(inode, file); |
142 | 144 | goto out; |
143 | 145 | } |
144 | 146 | |
... | ... | @@ -400,13 +402,23 @@ |
400 | 402 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
401 | 403 | int oz_mode = autofs4_oz_mode(sbi); |
402 | 404 | int flags = nd ? nd->flags : 0; |
403 | - int status = 0; | |
405 | + int status = 1; | |
404 | 406 | |
405 | 407 | /* Pending dentry */ |
406 | 408 | if (autofs4_ispending(dentry)) { |
407 | - if (!oz_mode) | |
408 | - status = try_to_fill_dentry(dentry, flags); | |
409 | - return !status; | |
409 | + /* The daemon never causes a mount to trigger */ | |
410 | + if (oz_mode) | |
411 | + return 1; | |
412 | + | |
413 | + /* | |
414 | + * A zero status is success otherwise we have a | |
415 | + * negative error code. | |
416 | + */ | |
417 | + status = try_to_fill_dentry(dentry, flags); | |
418 | + if (status == 0) | |
419 | + return 1; | |
420 | + | |
421 | + return status; | |
410 | 422 | } |
411 | 423 | |
412 | 424 | /* Negative dentry.. invalidate if "old" */ |
... | ... | @@ -421,9 +433,19 @@ |
421 | 433 | DPRINTK("dentry=%p %.*s, emptydir", |
422 | 434 | dentry, dentry->d_name.len, dentry->d_name.name); |
423 | 435 | spin_unlock(&dcache_lock); |
424 | - if (!oz_mode) | |
425 | - status = try_to_fill_dentry(dentry, flags); | |
426 | - return !status; | |
436 | + /* The daemon never causes a mount to trigger */ | |
437 | + if (oz_mode) | |
438 | + return 1; | |
439 | + | |
440 | + /* | |
441 | + * A zero status is success otherwise we have a | |
442 | + * negative error code. | |
443 | + */ | |
444 | + status = try_to_fill_dentry(dentry, flags); | |
445 | + if (status == 0) | |
446 | + return 1; | |
447 | + | |
448 | + return status; | |
427 | 449 | } |
428 | 450 | spin_unlock(&dcache_lock); |
429 | 451 |
fs/namei.c
... | ... | @@ -372,6 +372,30 @@ |
372 | 372 | fput(nd->intent.open.file); |
373 | 373 | } |
374 | 374 | |
375 | +static inline struct dentry * | |
376 | +do_revalidate(struct dentry *dentry, struct nameidata *nd) | |
377 | +{ | |
378 | + int status = dentry->d_op->d_revalidate(dentry, nd); | |
379 | + if (unlikely(status <= 0)) { | |
380 | + /* | |
381 | + * The dentry failed validation. | |
382 | + * If d_revalidate returned 0 attempt to invalidate | |
383 | + * the dentry otherwise d_revalidate is asking us | |
384 | + * to return a fail status. | |
385 | + */ | |
386 | + if (!status) { | |
387 | + if (!d_invalidate(dentry)) { | |
388 | + dput(dentry); | |
389 | + dentry = NULL; | |
390 | + } | |
391 | + } else { | |
392 | + dput(dentry); | |
393 | + dentry = ERR_PTR(status); | |
394 | + } | |
395 | + } | |
396 | + return dentry; | |
397 | +} | |
398 | + | |
375 | 399 | /* |
376 | 400 | * Internal lookup() using the new generic dcache. |
377 | 401 | * SMP-safe |
... | ... | @@ -386,12 +410,9 @@ |
386 | 410 | if (!dentry) |
387 | 411 | dentry = d_lookup(parent, name); |
388 | 412 | |
389 | - if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { | |
390 | - if (!dentry->d_op->d_revalidate(dentry, nd) && !d_invalidate(dentry)) { | |
391 | - dput(dentry); | |
392 | - dentry = NULL; | |
393 | - } | |
394 | - } | |
413 | + if (dentry && dentry->d_op && dentry->d_op->d_revalidate) | |
414 | + dentry = do_revalidate(dentry, nd); | |
415 | + | |
395 | 416 | return dentry; |
396 | 417 | } |
397 | 418 | |
398 | 419 | |
... | ... | @@ -484,10 +505,9 @@ |
484 | 505 | */ |
485 | 506 | mutex_unlock(&dir->i_mutex); |
486 | 507 | if (result->d_op && result->d_op->d_revalidate) { |
487 | - if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { | |
488 | - dput(result); | |
508 | + result = do_revalidate(result, nd); | |
509 | + if (!result) | |
489 | 510 | result = ERR_PTR(-ENOENT); |
490 | - } | |
491 | 511 | } |
492 | 512 | return result; |
493 | 513 | } |
... | ... | @@ -767,12 +787,12 @@ |
767 | 787 | goto done; |
768 | 788 | |
769 | 789 | need_revalidate: |
770 | - if (dentry->d_op->d_revalidate(dentry, nd)) | |
771 | - goto done; | |
772 | - if (d_invalidate(dentry)) | |
773 | - goto done; | |
774 | - dput(dentry); | |
775 | - goto need_lookup; | |
790 | + dentry = do_revalidate(dentry, nd); | |
791 | + if (!dentry) | |
792 | + goto need_lookup; | |
793 | + if (IS_ERR(dentry)) | |
794 | + goto fail; | |
795 | + goto done; | |
776 | 796 | |
777 | 797 | fail: |
778 | 798 | return PTR_ERR(dentry); |