diff options
author | Chuck Lever <cel@netapp.com> | 2005-11-30 18:08:17 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-06 14:58:47 -0500 |
commit | ce1a8e6796150233f5098100f70217521dc7c08f (patch) | |
tree | 439d2abd246e051c43d1cdb7ee3b77b8864fd2b3 /fs | |
parent | 286d7d6a0cb38d3d4316a1dfea9b0c0fc5a6455b (diff) |
NFS: use generic_write_checks() to sanity check direct writes
Replace ad hoc write parameter sanity checking in nfs_file_direct_write()
with a call to generic_write_checks(). This should make the proper checks
modulo the O_LARGEFILE flag, and should catch NFSv2-specific limitations by
virtue of i_sb->s_maxbytes.
Test plan:
Posix compliance testing with both NFSv2 and NFSv3.
Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/direct.c | 43 |
1 files changed, 19 insertions, 24 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index ae2be0744191..f69d95aa78b2 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -660,10 +660,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t | |||
660 | .iov_len = count, | 660 | .iov_len = count, |
661 | }; | 661 | }; |
662 | 662 | ||
663 | dprintk("nfs: direct read(%s/%s, %lu@%lu)\n", | 663 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", |
664 | file->f_dentry->d_parent->d_name.name, | 664 | file->f_dentry->d_parent->d_name.name, |
665 | file->f_dentry->d_name.name, | 665 | file->f_dentry->d_name.name, |
666 | (unsigned long) count, (unsigned long) pos); | 666 | (unsigned long) count, (long long) pos); |
667 | 667 | ||
668 | if (!is_sync_kiocb(iocb)) | 668 | if (!is_sync_kiocb(iocb)) |
669 | goto out; | 669 | goto out; |
@@ -716,9 +716,7 @@ out: | |||
716 | ssize_t | 716 | ssize_t |
717 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) | 717 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) |
718 | { | 718 | { |
719 | ssize_t retval = -EINVAL; | 719 | ssize_t retval; |
720 | loff_t *ppos = &iocb->ki_pos; | ||
721 | unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
722 | struct file *file = iocb->ki_filp; | 720 | struct file *file = iocb->ki_filp; |
723 | struct nfs_open_context *ctx = | 721 | struct nfs_open_context *ctx = |
724 | (struct nfs_open_context *) file->private_data; | 722 | (struct nfs_open_context *) file->private_data; |
@@ -726,35 +724,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
726 | struct inode *inode = mapping->host; | 724 | struct inode *inode = mapping->host; |
727 | struct iovec iov = { | 725 | struct iovec iov = { |
728 | .iov_base = (char __user *)buf, | 726 | .iov_base = (char __user *)buf, |
729 | .iov_len = count, | ||
730 | }; | 727 | }; |
731 | 728 | ||
732 | dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", | 729 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", |
733 | file->f_dentry->d_parent->d_name.name, | 730 | file->f_dentry->d_parent->d_name.name, |
734 | file->f_dentry->d_name.name, inode->i_ino, | 731 | file->f_dentry->d_name.name, |
735 | (unsigned long) count, (unsigned long) pos); | 732 | (unsigned long) count, (long long) pos); |
736 | 733 | ||
734 | retval = -EINVAL; | ||
737 | if (!is_sync_kiocb(iocb)) | 735 | if (!is_sync_kiocb(iocb)) |
738 | goto out; | 736 | goto out; |
739 | if (count < 0) | 737 | |
740 | goto out; | 738 | retval = generic_write_checks(file, &pos, &count, 0); |
741 | if (pos < 0) | 739 | if (retval) |
742 | goto out; | 740 | goto out; |
743 | retval = -EFAULT; | 741 | |
744 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 742 | retval = -EINVAL; |
743 | if ((ssize_t) count < 0) | ||
745 | goto out; | 744 | goto out; |
746 | retval = -EFBIG; | ||
747 | if (limit != RLIM_INFINITY) { | ||
748 | if (pos >= limit) { | ||
749 | send_sig(SIGXFSZ, current, 0); | ||
750 | goto out; | ||
751 | } | ||
752 | if (count > limit - (unsigned long) pos) | ||
753 | count = limit - (unsigned long) pos; | ||
754 | } | ||
755 | retval = 0; | 745 | retval = 0; |
756 | if (!count) | 746 | if (!count) |
757 | goto out; | 747 | goto out; |
748 | iov.iov_len = count, | ||
749 | |||
750 | retval = -EFAULT; | ||
751 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | ||
752 | goto out; | ||
758 | 753 | ||
759 | retval = nfs_sync_mapping(mapping); | 754 | retval = nfs_sync_mapping(mapping); |
760 | if (retval) | 755 | if (retval) |
@@ -764,7 +759,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
764 | if (mapping->nrpages) | 759 | if (mapping->nrpages) |
765 | invalidate_inode_pages2(mapping); | 760 | invalidate_inode_pages2(mapping); |
766 | if (retval > 0) | 761 | if (retval > 0) |
767 | *ppos = pos + retval; | 762 | iocb->ki_pos = pos + retval; |
768 | 763 | ||
769 | out: | 764 | out: |
770 | return retval; | 765 | return retval; |