diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-07 18:37:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-07 18:53:47 -0400 |
commit | 1d6757fbff5bc86e94e59ab0d7bdd7e71351d839 (patch) | |
tree | 65e75b32e0810961615101cb1f137a060c707c6b | |
parent | eba4f669d6ec9be4173bb2619e9b8500b3c36542 (diff) |
[PATCH] NFS: Fix lookup intent handling
We should never apply a lookup intent to anything other than the last
path component in an open(), create() or access() call.
Introduce the helper nfs_lookup_check_intent() which always returns
zero if LOOKUP_CONTINUE or LOOKUP_PARENT are set, and returns the
intent flags if we're on the last component of the lookup.
By doing so, we fix a bug in open(O_EXCL), where we may end up
optimizing away a real lookup of the parent directory.
Problem noticed by Linda Dunaphant <linda.dunaphant@ccur.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/nfs/dir.c | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 73f96acd5d37..ff6155f5e8d9 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -528,19 +528,39 @@ static inline void nfs_renew_times(struct dentry * dentry) | |||
528 | dentry->d_time = jiffies; | 528 | dentry->d_time = jiffies; |
529 | } | 529 | } |
530 | 530 | ||
531 | /* | ||
532 | * Return the intent data that applies to this particular path component | ||
533 | * | ||
534 | * Note that the current set of intents only apply to the very last | ||
535 | * component of the path. | ||
536 | * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. | ||
537 | */ | ||
538 | static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) | ||
539 | { | ||
540 | if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) | ||
541 | return 0; | ||
542 | return nd->flags & mask; | ||
543 | } | ||
544 | |||
545 | /* | ||
546 | * Inode and filehandle revalidation for lookups. | ||
547 | * | ||
548 | * We force revalidation in the cases where the VFS sets LOOKUP_REVAL, | ||
549 | * or if the intent information indicates that we're about to open this | ||
550 | * particular file and the "nocto" mount flag is not set. | ||
551 | * | ||
552 | */ | ||
531 | static inline | 553 | static inline |
532 | int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) | 554 | int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) |
533 | { | 555 | { |
534 | struct nfs_server *server = NFS_SERVER(inode); | 556 | struct nfs_server *server = NFS_SERVER(inode); |
535 | 557 | ||
536 | if (nd != NULL) { | 558 | if (nd != NULL) { |
537 | int ndflags = nd->flags; | ||
538 | /* VFS wants an on-the-wire revalidation */ | 559 | /* VFS wants an on-the-wire revalidation */ |
539 | if (ndflags & LOOKUP_REVAL) | 560 | if (nd->flags & LOOKUP_REVAL) |
540 | goto out_force; | 561 | goto out_force; |
541 | /* This is an open(2) */ | 562 | /* This is an open(2) */ |
542 | if ((ndflags & LOOKUP_OPEN) && | 563 | if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 && |
543 | !(ndflags & LOOKUP_CONTINUE) && | ||
544 | !(server->flags & NFS_MOUNT_NOCTO)) | 564 | !(server->flags & NFS_MOUNT_NOCTO)) |
545 | goto out_force; | 565 | goto out_force; |
546 | } | 566 | } |
@@ -560,12 +580,8 @@ static inline | |||
560 | int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, | 580 | int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, |
561 | struct nameidata *nd) | 581 | struct nameidata *nd) |
562 | { | 582 | { |
563 | int ndflags = 0; | ||
564 | |||
565 | if (nd) | ||
566 | ndflags = nd->flags; | ||
567 | /* Don't revalidate a negative dentry if we're creating a new file */ | 583 | /* Don't revalidate a negative dentry if we're creating a new file */ |
568 | if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE)) | 584 | if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0) |
569 | return 0; | 585 | return 0; |
570 | return !nfs_check_verifier(dir, dentry); | 586 | return !nfs_check_verifier(dir, dentry); |
571 | } | 587 | } |
@@ -700,12 +716,16 @@ struct dentry_operations nfs_dentry_operations = { | |||
700 | .d_iput = nfs_dentry_iput, | 716 | .d_iput = nfs_dentry_iput, |
701 | }; | 717 | }; |
702 | 718 | ||
719 | /* | ||
720 | * Use intent information to check whether or not we're going to do | ||
721 | * an O_EXCL create using this path component. | ||
722 | */ | ||
703 | static inline | 723 | static inline |
704 | int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) | 724 | int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) |
705 | { | 725 | { |
706 | if (NFS_PROTO(dir)->version == 2) | 726 | if (NFS_PROTO(dir)->version == 2) |
707 | return 0; | 727 | return 0; |
708 | if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE)) | 728 | if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0) |
709 | return 0; | 729 | return 0; |
710 | return (nd->intent.open.flags & O_EXCL) != 0; | 730 | return (nd->intent.open.flags & O_EXCL) != 0; |
711 | } | 731 | } |
@@ -772,12 +792,13 @@ struct dentry_operations nfs4_dentry_operations = { | |||
772 | .d_iput = nfs_dentry_iput, | 792 | .d_iput = nfs_dentry_iput, |
773 | }; | 793 | }; |
774 | 794 | ||
795 | /* | ||
796 | * Use intent information to determine whether we need to substitute | ||
797 | * the NFSv4-style stateful OPEN for the LOOKUP call | ||
798 | */ | ||
775 | static int is_atomic_open(struct inode *dir, struct nameidata *nd) | 799 | static int is_atomic_open(struct inode *dir, struct nameidata *nd) |
776 | { | 800 | { |
777 | if (!nd) | 801 | if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0) |
778 | return 0; | ||
779 | /* Check that we are indeed trying to open this file */ | ||
780 | if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN)) | ||
781 | return 0; | 802 | return 0; |
782 | /* NFS does not (yet) have a stateful open for directories */ | 803 | /* NFS does not (yet) have a stateful open for directories */ |
783 | if (nd->flags & LOOKUP_DIRECTORY) | 804 | if (nd->flags & LOOKUP_DIRECTORY) |