Skip to content

Commit 85128b2

Browse files
author
Al Viro
committed
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 <[email protected]>
1 parent 71d6ad0 commit 85128b2

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

fs/nfs/direct.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
537537

538538
if (put_dreq(dreq))
539539
nfs_direct_complete(dreq);
540-
return 0;
540+
return requested_bytes;
541541
}
542542

543543
/**
@@ -566,7 +566,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
566566
struct inode *inode = mapping->host;
567567
struct nfs_direct_req *dreq;
568568
struct nfs_lock_context *l_ctx;
569-
ssize_t result = -EINVAL;
569+
ssize_t result = -EINVAL, requested;
570570
size_t count = iov_iter_count(iter);
571571
nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
572572

@@ -600,14 +600,19 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
600600
nfs_start_io_direct(inode);
601601

602602
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);
604604

605605
nfs_end_io_direct(inode);
606606

607-
if (!result) {
607+
if (requested > 0) {
608608
result = nfs_direct_wait(dreq);
609-
if (result > 0)
609+
if (result > 0) {
610+
requested -= result;
610611
iocb->ki_pos += result;
612+
}
613+
iov_iter_revert(iter, requested);
614+
} else {
615+
result = requested;
611616
}
612617

613618
out_release:
@@ -954,7 +959,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
954959

955960
if (put_dreq(dreq))
956961
nfs_direct_write_complete(dreq);
957-
return 0;
962+
return requested_bytes;
958963
}
959964

960965
/**
@@ -979,7 +984,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
979984
*/
980985
ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
981986
{
982-
ssize_t result = -EINVAL;
987+
ssize_t result = -EINVAL, requested;
983988
size_t count;
984989
struct file *file = iocb->ki_filp;
985990
struct address_space *mapping = file->f_mapping;
@@ -1022,7 +1027,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
10221027

10231028
nfs_start_io_direct(inode);
10241029

1025-
result = nfs_direct_write_schedule_iovec(dreq, iter, pos);
1030+
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos);
10261031

10271032
if (mapping->nrpages) {
10281033
invalidate_inode_pages2_range(mapping,
@@ -1031,13 +1036,17 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
10311036

10321037
nfs_end_io_direct(inode);
10331038

1034-
if (!result) {
1039+
if (requested > 0) {
10351040
result = nfs_direct_wait(dreq);
10361041
if (result > 0) {
1042+
requested -= result;
10371043
iocb->ki_pos = pos + result;
10381044
/* XXX: should check the generic_write_sync retval */
10391045
generic_write_sync(iocb, result);
10401046
}
1047+
iov_iter_revert(iter, requested);
1048+
} else {
1049+
result = requested;
10411050
}
10421051
out_release:
10431052
nfs_direct_req_release(dreq);

0 commit comments

Comments
 (0)