diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namei.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/fs/namei.c b/fs/namei.c index a765e7a741f4..d2783c8a770b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -414,6 +414,46 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
414 | } | 414 | } |
415 | 415 | ||
416 | /* | 416 | /* |
417 | * force_reval_path - force revalidation of a dentry | ||
418 | * | ||
419 | * In some situations the path walking code will trust dentries without | ||
420 | * revalidating them. This causes problems for filesystems that depend on | ||
421 | * d_revalidate to handle file opens (e.g. NFSv4). When FS_REVAL_DOT is set | ||
422 | * (which indicates that it's possible for the dentry to go stale), force | ||
423 | * a d_revalidate call before proceeding. | ||
424 | * | ||
425 | * Returns 0 if the revalidation was successful. If the revalidation fails, | ||
426 | * either return the error returned by d_revalidate or -ESTALE if the | ||
427 | * revalidation it just returned 0. If d_revalidate returns 0, we attempt to | ||
428 | * invalidate the dentry. It's up to the caller to handle putting references | ||
429 | * to the path if necessary. | ||
430 | */ | ||
431 | static int | ||
432 | force_reval_path(struct path *path, struct nameidata *nd) | ||
433 | { | ||
434 | int status; | ||
435 | struct dentry *dentry = path->dentry; | ||
436 | |||
437 | /* | ||
438 | * only check on filesystems where it's possible for the dentry to | ||
439 | * become stale. It's assumed that if this flag is set then the | ||
440 | * d_revalidate op will also be defined. | ||
441 | */ | ||
442 | if (!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) | ||
443 | return 0; | ||
444 | |||
445 | status = dentry->d_op->d_revalidate(dentry, nd); | ||
446 | if (status > 0) | ||
447 | return 0; | ||
448 | |||
449 | if (!status) { | ||
450 | d_invalidate(dentry); | ||
451 | status = -ESTALE; | ||
452 | } | ||
453 | return status; | ||
454 | } | ||
455 | |||
456 | /* | ||
417 | * Short-cut version of permission(), for calling on directories | 457 | * Short-cut version of permission(), for calling on directories |
418 | * during pathname resolution. Combines parts of permission() | 458 | * during pathname resolution. Combines parts of permission() |
419 | * and generic_permission(), and tests ONLY for MAY_EXEC permission. | 459 | * and generic_permission(), and tests ONLY for MAY_EXEC permission. |
@@ -529,6 +569,11 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
529 | error = 0; | 569 | error = 0; |
530 | if (s) | 570 | if (s) |
531 | error = __vfs_follow_link(nd, s); | 571 | error = __vfs_follow_link(nd, s); |
572 | else if (nd->last_type == LAST_BIND) { | ||
573 | error = force_reval_path(&nd->path, nd); | ||
574 | if (error) | ||
575 | path_put(&nd->path); | ||
576 | } | ||
532 | if (dentry->d_inode->i_op->put_link) | 577 | if (dentry->d_inode->i_op->put_link) |
533 | dentry->d_inode->i_op->put_link(dentry, nd, cookie); | 578 | dentry->d_inode->i_op->put_link(dentry, nd, cookie); |
534 | } | 579 | } |