[PATCH 6/6] nfs: Support vector I/O throughout the NFS direct I/O path

From: Chuck Lever
Date: Fri May 19 2006 - 14:00:28 EST


Now that the preliminaries are complete, it is safe to loop over all the
segments in an iovec, dispatching all of the requests against a single
nfs_direct_req.

Test plan:
Specialized test applications using vectored synchronous and asynchronous
I/O.

Signed-off-by: Chuck Lever <cel@xxxxxxxxxx>
---

fs/nfs/direct.c | 78 +++++++++++++++++++++++++++++++++++--------------------
1 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 3d4ded0..e62b905 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -281,8 +281,6 @@ static int nfs_direct_read_schedule(stru
unsigned int pgbase;
unsigned int started = 0;

- dreq->outstanding++;
-
pgbase = user_addr & ~PAGE_MASK;
do {
struct nfs_read_data *data;
@@ -351,13 +349,30 @@ static int nfs_direct_read_schedule(stru
count -= bytes;
} while (count != 0);

+ return started;
+}
+
+static int nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
+{
+ ssize_t started = 0;
+ unsigned long seg;
+
+ dreq->outstanding++;
+
+ for (seg = 0; seg < nr_segs; seg++) {
+ unsigned long user_addr = (unsigned long) iov[seg].iov_base;
+ size_t count = iov[seg].iov_len;
+ started += nfs_direct_read_schedule(dreq, user_addr, count, pos);
+ pos += count;
+ }
+
if (nfs_direct_dec_outstanding(dreq))
nfs_direct_complete(dreq);

return started;
}

-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;
sigset_t oldset;
@@ -375,7 +390,7 @@ static ssize_t nfs_direct_read(struct ki
dreq->iocb = iocb;

rpc_clnt_sigmask(clnt, &oldset);
- if (nfs_direct_read_schedule(dreq, user_addr, count, pos))
+ if (nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos))
result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);

@@ -606,8 +621,6 @@ static int nfs_direct_write_schedule(str
unsigned int pgbase;
unsigned int started = 0;

- dreq->outstanding++;
-
pgbase = user_addr & ~PAGE_MASK;
do {
struct nfs_write_data *data;
@@ -679,13 +692,31 @@ static int nfs_direct_write_schedule(str
count -= bytes;
} while (count != 0);

+ return started;
+}
+
+
+static int 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 started = 0;
+ unsigned long seg;
+
+ dreq->outstanding++;
+
+ for (seg = 0; seg < nr_segs; seg++) {
+ unsigned long user_addr = (unsigned long) iov[seg].iov_base;
+ size_t count = iov[seg].iov_len;
+ started += nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
+ pos += count;
+ }
+
if (nfs_direct_dec_outstanding(dreq))
- nfs_direct_write_complete(dreq, inode);
+ nfs_direct_write_complete(dreq, dreq->inode);

return started;
}

-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;
sigset_t oldset;
@@ -711,7 +742,7 @@ static ssize_t nfs_direct_write(struct k
nfs_begin_data_update(inode);

rpc_clnt_sigmask(clnt, &oldset);
- if (nfs_direct_write_schedule(dreq, user_addr, count, pos, sync))
+ if (nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync))
result = nfs_direct_wait(dreq);
rpc_clnt_sigunmask(clnt, &oldset);

@@ -775,28 +806,22 @@ ssize_t nfs_file_direct_read(struct kioc
ssize_t retval;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
- /* XXX: temporary */
- const char __user *buf = iov[0].iov_base;
- size_t count = iov[0].iov_len;

retval = check_access_ok(VERIFY_WRITE, iov, nr_segs);
if (retval <= 0)
goto out;
nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, retval);

- dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
+ dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n",
file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name,
- (unsigned long) count, (long long) pos);
-
- if (nr_segs != 1)
- return -EINVAL;
+ retval, (long long) pos);

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

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

@@ -832,35 +857,32 @@ out:
ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- ssize_t retval;
+ ssize_t retval, count;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
- /* XXX: temporary */
- const char __user *buf = iov[0].iov_base;
- size_t count = iov[0].iov_len;

retval = check_access_ok(VERIFY_READ, iov, nr_segs);
if (retval <= 0)
goto out;
nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, retval);

- dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
+ dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n",
file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name,
- (unsigned long) count, (long long) pos);
-
- if (nr_segs != 1)
- return -EINVAL;
+ retval, (long long) pos);

+ count = retval;
retval = generic_write_checks(file, &pos, &count, 0);
if (retval)
goto out;
+ if (!count)
+ goto out; /* return 0 */

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

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

/*
* XXX: nfs_end_data_update() already ensures this file's
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/