diff options
author | Abhi Das <adas@redhat.com> | 2016-11-16 22:44:23 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-11-17 00:00:48 -0500 |
commit | 680bb946a1ae04fe0ff369a4965f76b48c07dc54 (patch) | |
tree | be2ca455a6186b86a08e3ab1c22d49748cc6ed75 | |
parent | 4a59015372840a6fc35d7fd40638a9d5dc3ec958 (diff) |
fix iov_iter_advance() for ITER_PIPE
iov_iter_advance() needs to decrement iter->count by the number of
bytes we'd moved beyond. Normal flavours do that, but ITER_PIPE
doesn't and ITER_PIPE generic_file_read_iter() for O_DIRECT files
ends up with a bogus fallback to page cache read, resulting in incorrect
values for file offset and bytes read.
Signed-off-by: Abhi Das <adas@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | lib/iov_iter.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index f0c7f1481bae..f2bd21b93dfc 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -683,10 +683,11 @@ static void pipe_advance(struct iov_iter *i, size_t size) | |||
683 | struct pipe_inode_info *pipe = i->pipe; | 683 | struct pipe_inode_info *pipe = i->pipe; |
684 | struct pipe_buffer *buf; | 684 | struct pipe_buffer *buf; |
685 | int idx = i->idx; | 685 | int idx = i->idx; |
686 | size_t off = i->iov_offset; | 686 | size_t off = i->iov_offset, orig_sz; |
687 | 687 | ||
688 | if (unlikely(i->count < size)) | 688 | if (unlikely(i->count < size)) |
689 | size = i->count; | 689 | size = i->count; |
690 | orig_sz = size; | ||
690 | 691 | ||
691 | if (size) { | 692 | if (size) { |
692 | if (off) /* make it relative to the beginning of buffer */ | 693 | if (off) /* make it relative to the beginning of buffer */ |
@@ -713,6 +714,7 @@ static void pipe_advance(struct iov_iter *i, size_t size) | |||
713 | pipe->nrbufs--; | 714 | pipe->nrbufs--; |
714 | } | 715 | } |
715 | } | 716 | } |
717 | i->count -= orig_sz; | ||
716 | } | 718 | } |
717 | 719 | ||
718 | void iov_iter_advance(struct iov_iter *i, size_t size) | 720 | void iov_iter_advance(struct iov_iter *i, size_t size) |