Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+19 −24
Original line number Diff line number Diff line
@@ -660,10 +660,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
		.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_name.name,
		(unsigned long) count, (unsigned long) pos);
		(unsigned long) count, (long long) pos);

	if (!is_sync_kiocb(iocb))
		goto out;
@@ -716,9 +716,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
ssize_t
nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
{
	ssize_t retval = -EINVAL;
	loff_t *ppos = &iocb->ki_pos;
	unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
	ssize_t retval;
	struct file *file = iocb->ki_filp;
	struct nfs_open_context *ctx =
			(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,
	struct inode *inode = mapping->host;
	struct iovec iov = {
		.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_name.name, inode->i_ino,
		(unsigned long) count, (unsigned long) pos);
		file->f_dentry->d_name.name,
		(unsigned long) count, (long long) pos);

	retval = -EINVAL;
	if (!is_sync_kiocb(iocb))
		goto out;
	if (count < 0)
		goto out;
        if (pos < 0)
		goto out;
	retval = -EFAULT;
	if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len))

	retval = generic_write_checks(file, &pos, &count, 0);
	if (retval)
		goto out;
	retval = -EFBIG;
	if (limit != RLIM_INFINITY) {
		if (pos >= limit) {
			send_sig(SIGXFSZ, current, 0);

	retval = -EINVAL;
	if ((ssize_t) count < 0)
		goto out;
		}
		if (count > limit - (unsigned long) pos)
			count = limit - (unsigned long) pos;
	}
	retval = 0;
	if (!count)
		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);
	if (retval)
@@ -764,7 +759,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
	if (mapping->nrpages)
		invalidate_inode_pages2(mapping);
	if (retval > 0)
		*ppos = pos + retval;
		iocb->ki_pos = pos + retval;

out:
	return retval;