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: Chuck Lever <cel@netapp.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
committed by
Trond Myklebust
parent
19f737879c
commit
c216fd708e
@@ -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;
|
|
||||||
|
|
||||||
dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
|
count = iov_length(iov, nr_segs);
|
||||||
|
nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
|
||||||
|
|
||||||
|
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;
|
||||||
|
Reference in New Issue
Block a user