aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/direct.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-04-13 09:31:51 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-04-17 14:23:20 -0400
commit85128b2be6738fe36c224995c5ee80fe80fbb1b5 (patch)
treec25285b57766761f1508985be799535075bbf3f5 /fs/nfs/direct.c
parent71d6ad08379304128e4bdfaf0b4185d54375423e (diff)
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: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r--fs/nfs/direct.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index aab32fc3d6a8..c1b5fed7c863 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -537,7 +537,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
537 537
538 if (put_dreq(dreq)) 538 if (put_dreq(dreq))
539 nfs_direct_complete(dreq); 539 nfs_direct_complete(dreq);
540 return 0; 540 return requested_bytes;
541} 541}
542 542
543/** 543/**
@@ -566,7 +566,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
566 struct inode *inode = mapping->host; 566 struct inode *inode = mapping->host;
567 struct nfs_direct_req *dreq; 567 struct nfs_direct_req *dreq;
568 struct nfs_lock_context *l_ctx; 568 struct nfs_lock_context *l_ctx;
569 ssize_t result = -EINVAL; 569 ssize_t result = -EINVAL, requested;
570 size_t count = iov_iter_count(iter); 570 size_t count = iov_iter_count(iter);
571 nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); 571 nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
572 572
@@ -600,14 +600,19 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
600 nfs_start_io_direct(inode); 600 nfs_start_io_direct(inode);
601 601
602 NFS_I(inode)->read_io += count; 602 NFS_I(inode)->read_io += count;
603 result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); 603 requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
604 604
605 nfs_end_io_direct(inode); 605 nfs_end_io_direct(inode);
606 606
607 if (!result) { 607 if (requested > 0) {
608 result = nfs_direct_wait(dreq); 608 result = nfs_direct_wait(dreq);
609 if (result > 0) 609 if (result > 0) {
610 requested -= result;
610 iocb->ki_pos += result; 611 iocb->ki_pos += result;
612 }
613 iov_iter_revert(iter, requested);
614 } else {
615 result = requested;
611 } 616 }
612 617
613out_release: 618out_release:
@@ -954,7 +959,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
954 959
955 if (put_dreq(dreq)) 960 if (put_dreq(dreq))
956 nfs_direct_write_complete(dreq); 961 nfs_direct_write_complete(dreq);
957 return 0; 962 return requested_bytes;
958} 963}
959 964
960/** 965/**
@@ -979,7 +984,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
979 */ 984 */
980ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) 985ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
981{ 986{
982 ssize_t result = -EINVAL; 987 ssize_t result = -EINVAL, requested;
983 size_t count; 988 size_t count;
984 struct file *file = iocb->ki_filp; 989 struct file *file = iocb->ki_filp;
985 struct address_space *mapping = file->f_mapping; 990 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 1027
1023 nfs_start_io_direct(inode); 1028 nfs_start_io_direct(inode);
1024 1029
1025 result = nfs_direct_write_schedule_iovec(dreq, iter, pos); 1030 requested = nfs_direct_write_schedule_iovec(dreq, iter, pos);
1026 1031
1027 if (mapping->nrpages) { 1032 if (mapping->nrpages) {
1028 invalidate_inode_pages2_range(mapping, 1033 invalidate_inode_pages2_range(mapping,
@@ -1031,13 +1036,17 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
1031 1036
1032 nfs_end_io_direct(inode); 1037 nfs_end_io_direct(inode);
1033 1038
1034 if (!result) { 1039 if (requested > 0) {
1035 result = nfs_direct_wait(dreq); 1040 result = nfs_direct_wait(dreq);
1036 if (result > 0) { 1041 if (result > 0) {
1042 requested -= result;
1037 iocb->ki_pos = pos + result; 1043 iocb->ki_pos = pos + result;
1038 /* XXX: should check the generic_write_sync retval */ 1044 /* XXX: should check the generic_write_sync retval */
1039 generic_write_sync(iocb, result); 1045 generic_write_sync(iocb, result);
1040 } 1046 }
1047 iov_iter_revert(iter, requested);
1048 } else {
1049 result = requested;
1041 } 1050 }
1042out_release: 1051out_release:
1043 nfs_direct_req_release(dreq); 1052 nfs_direct_req_release(dreq);