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 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) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f06eee6dcff5..55c907592490 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 | * |
