Commit bcdc5e019d9f525a9f181a7de642d3a9c27c7610

Authored by Ian Kent
Committed by Linus Torvalds
1 parent 1183dc943c

[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

... ... @@ -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  
... ... @@ -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);