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

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
...@@ -272,8 +272,6 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo ...@@ -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 ...@@ -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, ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
......
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