Commit 85128b2b authored by Al Viro's avatar Al Viro

fix nfs O_DIRECT advancing iov_iter too much

It leaves the iterator advanced by the amount of IO it has requested
instead of the amount actually transferred.  Among other things,
that confuses the hell out of generic_file_splice_read().
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 71d6ad08
...@@ -537,7 +537,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -537,7 +537,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
if (put_dreq(dreq)) if (put_dreq(dreq))
nfs_direct_complete(dreq); nfs_direct_complete(dreq);
return 0; return requested_bytes;
} }
/** /**
...@@ -566,7 +566,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ...@@ -566,7 +566,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct nfs_direct_req *dreq; struct nfs_direct_req *dreq;
struct nfs_lock_context *l_ctx; struct nfs_lock_context *l_ctx;
ssize_t result = -EINVAL; ssize_t result = -EINVAL, requested;
size_t count = iov_iter_count(iter); size_t count = iov_iter_count(iter);
nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
...@@ -600,15 +600,20 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) ...@@ -600,15 +600,20 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
nfs_start_io_direct(inode); nfs_start_io_direct(inode);
NFS_I(inode)->read_io += count; NFS_I(inode)->read_io += count;
result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
nfs_end_io_direct(inode); nfs_end_io_direct(inode);
if (!result) { if (requested > 0) {
result = nfs_direct_wait(dreq); result = nfs_direct_wait(dreq);
if (result > 0) if (result > 0) {
requested -= result;
iocb->ki_pos += result; iocb->ki_pos += result;
} }
iov_iter_revert(iter, requested);
} else {
result = requested;
}
out_release: out_release:
nfs_direct_req_release(dreq); nfs_direct_req_release(dreq);
...@@ -954,7 +959,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -954,7 +959,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
if (put_dreq(dreq)) if (put_dreq(dreq))
nfs_direct_write_complete(dreq); nfs_direct_write_complete(dreq);
return 0; return requested_bytes;
} }
/** /**
...@@ -979,7 +984,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -979,7 +984,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
*/ */
ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
{ {
ssize_t result = -EINVAL; ssize_t result = -EINVAL, requested;
size_t count; size_t count;
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;
...@@ -1022,7 +1027,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -1022,7 +1027,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
nfs_start_io_direct(inode); nfs_start_io_direct(inode);
result = nfs_direct_write_schedule_iovec(dreq, iter, pos); requested = nfs_direct_write_schedule_iovec(dreq, iter, pos);
if (mapping->nrpages) { if (mapping->nrpages) {
invalidate_inode_pages2_range(mapping, invalidate_inode_pages2_range(mapping,
...@@ -1031,13 +1036,17 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) ...@@ -1031,13 +1036,17 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
nfs_end_io_direct(inode); nfs_end_io_direct(inode);
if (!result) { if (requested > 0) {
result = nfs_direct_wait(dreq); result = nfs_direct_wait(dreq);
if (result > 0) { if (result > 0) {
requested -= result;
iocb->ki_pos = pos + result; iocb->ki_pos = pos + result;
/* XXX: should check the generic_write_sync retval */ /* XXX: should check the generic_write_sync retval */
generic_write_sync(iocb, result); generic_write_sync(iocb, result);
} }
iov_iter_revert(iter, requested);
} else {
result = requested;
} }
out_release: out_release:
nfs_direct_req_release(dreq); nfs_direct_req_release(dreq);
......
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