Commit ce1a8e67 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust

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: default avatarChuck Lever <cel@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 286d7d6a
...@@ -660,10 +660,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t ...@@ -660,10 +660,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
.iov_len = count, .iov_len = count,
}; };
dprintk("nfs: direct read(%s/%s, %lu@%lu)\n", dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name, file->f_dentry->d_name.name,
(unsigned long) count, (unsigned long) pos); (unsigned long) count, (long long) pos);
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
goto out; goto out;
...@@ -716,9 +716,7 @@ out: ...@@ -716,9 +716,7 @@ out:
ssize_t ssize_t
nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
{ {
ssize_t retval = -EINVAL; ssize_t retval;
loff_t *ppos = &iocb->ki_pos;
unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct nfs_open_context *ctx = struct nfs_open_context *ctx =
(struct nfs_open_context *) file->private_data; (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,35 +724,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct iovec iov = { struct iovec iov = {
.iov_base = (char __user *)buf, .iov_base = (char __user *)buf,
.iov_len = count,
}; };
dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name, inode->i_ino, file->f_dentry->d_name.name,
(unsigned long) count, (unsigned long) pos); (unsigned long) count, (long long) pos);
retval = -EINVAL;
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
goto out; goto out;
if (count < 0)
goto out; retval = generic_write_checks(file, &pos, &count, 0);
if (pos < 0) if (retval)
goto out; goto out;
retval = -EFAULT;
if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) retval = -EINVAL;
if ((ssize_t) count < 0)
goto out; goto out;
retval = -EFBIG;
if (limit != RLIM_INFINITY) {
if (pos >= limit) {
send_sig(SIGXFSZ, current, 0);
goto out;
}
if (count > limit - (unsigned long) pos)
count = limit - (unsigned long) pos;
}
retval = 0; retval = 0;
if (!count) if (!count)
goto out; goto out;
iov.iov_len = count,
retval = -EFAULT;
if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len))
goto out;
retval = nfs_sync_mapping(mapping); retval = nfs_sync_mapping(mapping);
if (retval) if (retval)
...@@ -764,7 +759,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, ...@@ -764,7 +759,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
if (mapping->nrpages) if (mapping->nrpages)
invalidate_inode_pages2(mapping); invalidate_inode_pages2(mapping);
if (retval > 0) if (retval > 0)
*ppos = pos + retval; iocb->ki_pos = pos + retval;
out: out:
return retval; return retval;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment