diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/dir.c | 49 | ||||
-rw-r--r-- | fs/nfs/file.c | 42 |
2 files changed, 76 insertions, 15 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 73f96acd5d..ff6155f5e8 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) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f06eee6dcf..55c9075924 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | static int nfs_file_open(struct inode *, struct file *); | 38 | static int nfs_file_open(struct inode *, struct file *); |
39 | static int nfs_file_release(struct inode *, struct file *); | 39 | static int nfs_file_release(struct inode *, struct file *); |
40 | static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin); | ||
40 | static int nfs_file_mmap(struct file *, struct vm_area_struct *); | 41 | static int nfs_file_mmap(struct file *, struct vm_area_struct *); |
41 | static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); | 42 | static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); |
42 | static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); | 43 | static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); |
@@ -48,7 +49,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); | |||
48 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); | 49 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); |
49 | 50 | ||
50 | struct file_operations nfs_file_operations = { | 51 | struct file_operations nfs_file_operations = { |
51 | .llseek = remote_llseek, | 52 | .llseek = nfs_file_llseek, |
52 | .read = do_sync_read, | 53 | .read = do_sync_read, |
53 | .write = do_sync_write, | 54 | .write = do_sync_write, |
54 | .aio_read = nfs_file_read, | 55 | .aio_read = nfs_file_read, |
@@ -114,6 +115,45 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
114 | return NFS_PROTO(inode)->file_release(inode, filp); | 115 | return NFS_PROTO(inode)->file_release(inode, filp); |
115 | } | 116 | } |
116 | 117 | ||
118 | /** | ||
119 | * nfs_revalidate_size - Revalidate the file size | ||
120 | * @inode - pointer to inode struct | ||
121 | * @file - pointer to struct file | ||
122 | * | ||
123 | * Revalidates the file length. This is basically a wrapper around | ||
124 | * nfs_revalidate_inode() that takes into account the fact that we may | ||
125 | * have cached writes (in which case we don't care about the server's | ||
126 | * idea of what the file length is), or O_DIRECT (in which case we | ||
127 | * shouldn't trust the cache). | ||
128 | */ | ||
129 | static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | ||
130 | { | ||
131 | struct nfs_server *server = NFS_SERVER(inode); | ||
132 | struct nfs_inode *nfsi = NFS_I(inode); | ||
133 | |||
134 | if (server->flags & NFS_MOUNT_NOAC) | ||
135 | goto force_reval; | ||
136 | if (filp->f_flags & O_DIRECT) | ||
137 | goto force_reval; | ||
138 | if (nfsi->npages != 0) | ||
139 | return 0; | ||
140 | return nfs_revalidate_inode(server, inode); | ||
141 | force_reval: | ||
142 | return __nfs_revalidate_inode(server, inode); | ||
143 | } | ||
144 | |||
145 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | ||
146 | { | ||
147 | /* origin == SEEK_END => we must revalidate the cached file length */ | ||
148 | if (origin == 2) { | ||
149 | struct inode *inode = filp->f_mapping->host; | ||
150 | int retval = nfs_revalidate_file_size(inode, filp); | ||
151 | if (retval < 0) | ||
152 | return (loff_t)retval; | ||
153 | } | ||
154 | return remote_llseek(filp, offset, origin); | ||
155 | } | ||
156 | |||
117 | /* | 157 | /* |
118 | * Flush all dirty pages, and check for write errors. | 158 | * Flush all dirty pages, and check for write errors. |
119 | * | 159 | * |