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

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

NFS: Support multiple segment iovecs in the NFS direct I/O path



Allow applications to perform asynchronous scatter-gather direct I/O
to NFS files.

Signed-off-by: default avatarChuck Lever <cel@netapp.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 19f73787
Loading
Loading
Loading
Loading
+23 −44
Original line number Original line Diff line number Diff line
@@ -272,8 +272,6 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
	int result;
	int result;
	ssize_t started = 0;
	ssize_t started = 0;


	get_dreq(dreq);

	do {
	do {
		struct nfs_read_data *data;
		struct nfs_read_data *data;
		size_t bytes;
		size_t bytes;
@@ -347,11 +345,8 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
		count -= bytes;
		count -= bytes;
	} while (count != 0);
	} while (count != 0);


	if (put_dreq(dreq))
		nfs_direct_complete(dreq);

	if (started)
	if (started)
		return 0;
		return started;
	return result < 0 ? (ssize_t) result : -EFAULT;
	return result < 0 ? (ssize_t) result : -EFAULT;
}
}


@@ -390,7 +385,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
	return -EIO;
	return -EIO;
}
}


static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
			       unsigned long nr_segs, loff_t pos)
{
{
	ssize_t result = 0;
	ssize_t result = 0;
	sigset_t oldset;
	sigset_t oldset;
@@ -407,9 +403,8 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
	if (!is_sync_kiocb(iocb))
	if (!is_sync_kiocb(iocb))
		dreq->iocb = iocb;
		dreq->iocb = iocb;


	nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
	rpc_clnt_sigmask(clnt, &oldset);
	rpc_clnt_sigmask(clnt, &oldset);
	result = nfs_direct_read_schedule(dreq, user_addr, count, pos);
	result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos);
	if (!result)
	if (!result)
		result = nfs_direct_wait(dreq);
		result = nfs_direct_wait(dreq);
	rpc_clnt_sigunmask(clnt, &oldset);
	rpc_clnt_sigunmask(clnt, &oldset);
@@ -645,8 +640,6 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
	int result;
	int result;
	ssize_t started = 0;
	ssize_t started = 0;


	get_dreq(dreq);

	do {
	do {
		struct nfs_write_data *data;
		struct nfs_write_data *data;
		size_t bytes;
		size_t bytes;
@@ -724,11 +717,8 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
		count -= bytes;
		count -= bytes;
	} while (count != 0);
	} while (count != 0);


	if (put_dreq(dreq))
		nfs_direct_write_complete(dreq, inode);

	if (started)
	if (started)
		return 0;
		return started;
	return result < 0 ? (ssize_t) result : -EFAULT;
	return result < 0 ? (ssize_t) result : -EFAULT;
}
}


@@ -768,7 +758,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
	return -EIO;
	return -EIO;
}
}


static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
				unsigned long nr_segs, loff_t pos,
				size_t count)
{
{
	ssize_t result = 0;
	ssize_t result = 0;
	sigset_t oldset;
	sigset_t oldset;
@@ -791,10 +783,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
	if (!is_sync_kiocb(iocb))
	if (!is_sync_kiocb(iocb))
		dreq->iocb = iocb;
		dreq->iocb = iocb;


	nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count);

	rpc_clnt_sigmask(clnt, &oldset);
	rpc_clnt_sigmask(clnt, &oldset);
	result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
	result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync);
	if (!result)
	if (!result)
		result = nfs_direct_wait(dreq);
		result = nfs_direct_wait(dreq);
	rpc_clnt_sigunmask(clnt, &oldset);
	rpc_clnt_sigunmask(clnt, &oldset);
@@ -830,21 +820,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
	ssize_t retval = -EINVAL;
	ssize_t retval = -EINVAL;
	struct file *file = iocb->ki_filp;
	struct file *file = iocb->ki_filp;
	struct address_space *mapping = file->f_mapping;
	struct address_space *mapping = file->f_mapping;
	/* XXX: temporary */
	size_t count;
	const char __user *buf = iov[0].iov_base;

	size_t count = iov[0].iov_len;
	count = iov_length(iov, nr_segs);
	nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);


	dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
	dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n",
		file->f_path.dentry->d_parent->d_name.name,
		file->f_path.dentry->d_parent->d_name.name,
		file->f_path.dentry->d_name.name,
		file->f_path.dentry->d_name.name,
		(unsigned long) count, (long long) pos);
		count, (long long) pos);


	if (nr_segs != 1)
		goto out;

	retval = -EFAULT;
	if (!access_ok(VERIFY_WRITE, buf, count))
		goto out;
	retval = 0;
	retval = 0;
	if (!count)
	if (!count)
		goto out;
		goto out;
@@ -853,7 +838,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
	if (retval)
	if (retval)
		goto out;
		goto out;


	retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos);
	retval = nfs_direct_read(iocb, iov, nr_segs, pos);
	if (retval > 0)
	if (retval > 0)
		iocb->ki_pos = pos + retval;
		iocb->ki_pos = pos + retval;


@@ -892,17 +877,15 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
	ssize_t retval = -EINVAL;
	ssize_t retval = -EINVAL;
	struct file *file = iocb->ki_filp;
	struct file *file = iocb->ki_filp;
	struct address_space *mapping = file->f_mapping;
	struct address_space *mapping = file->f_mapping;
	/* XXX: temporary */
	size_t count;
	const char __user *buf = iov[0].iov_base;
	size_t count = iov[0].iov_len;


	dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n",
	count = iov_length(iov, nr_segs);
	nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);

	dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n",
		file->f_path.dentry->d_parent->d_name.name,
		file->f_path.dentry->d_parent->d_name.name,
		file->f_path.dentry->d_name.name,
		file->f_path.dentry->d_name.name,
		(unsigned long) count, (long long) pos);
		count, (long long) pos);

	if (nr_segs != 1)
		goto out;


	retval = generic_write_checks(file, &pos, &count, 0);
	retval = generic_write_checks(file, &pos, &count, 0);
	if (retval)
	if (retval)
@@ -915,15 +898,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
	if (!count)
	if (!count)
		goto out;
		goto out;


	retval = -EFAULT;
	if (!access_ok(VERIFY_READ, buf, count))
		goto out;

	retval = nfs_sync_mapping(mapping);
	retval = nfs_sync_mapping(mapping);
	if (retval)
	if (retval)
		goto out;
		goto out;


	retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
	retval = nfs_direct_write(iocb, iov, nr_segs, pos, count);


	if (retval > 0)
	if (retval > 0)
		iocb->ki_pos = pos + retval;
		iocb->ki_pos = pos + retval;