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

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

NFS: Introduce iovec I/O helpers to fs/nfs/direct.c



Add helpers that iterate over multi-segment iovecs.  These will
be used to support multi-segment scatter/gather direct I/O in a
later patch.

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 014313a9
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -355,6 +355,41 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
	return result < 0 ? (ssize_t) result : -EFAULT;
}

static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
					      const struct iovec *iov,
					      unsigned long nr_segs,
					      loff_t pos)
{
	ssize_t result = -EINVAL;
	size_t requested_bytes = 0;
	unsigned long seg;

	get_dreq(dreq);

	for (seg = 0; seg < nr_segs; seg++) {
		const struct iovec *vec = &iov[seg];
		result = nfs_direct_read_schedule(dreq,
					(unsigned long)vec->iov_base,
						  vec->iov_len, pos);
		if (result < 0)
			break;
		requested_bytes += result;
		if ((size_t)result < vec->iov_len)
			break;
		pos += vec->iov_len;
	}

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

	if (requested_bytes != 0)
		return 0;

	if (result < 0)
		return result;
	return -EIO;
}

static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
{
	ssize_t result = 0;
@@ -697,6 +732,42 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
	return result < 0 ? (ssize_t) result : -EFAULT;
}

static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
					       const struct iovec *iov,
					       unsigned long nr_segs,
					       loff_t pos, int sync)
{
	ssize_t result = 0;
	size_t requested_bytes = 0;
	unsigned long seg;

	get_dreq(dreq);

	for (seg = 0; seg < nr_segs; seg++) {
		const struct iovec *vec = &iov[seg];
		result = nfs_direct_write_schedule(dreq,
					(unsigned long)vec->iov_base,
						   vec->iov_len,
						   pos, sync);
		if (result < 0)
			break;
		requested_bytes += result;
		if ((size_t)result < vec->iov_len)
			break;
		pos += vec->iov_len;
	}

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

	if (requested_bytes != 0)
		return 0;

	if (result < 0)
		return result;
	return -EIO;
}

static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
{
	ssize_t result = 0;