summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-05-25 17:36:19 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-05-25 18:16:02 -0400
commit19f18459330f4a65fb0b58e77fc58ceceecb1839 (patch)
tree052e11c4d75b1a29d1c30060a30494dcef2eb0a7
parentdd254f5a382cc7879db7a07ed266b12d38fe3ab6 (diff)
downloadlinux-19f18459330f4a65fb0b58e77fc58ceceecb1839.tar.bz2
do "fold checks into iterate_and_advance()" right
the only case when we should skip the iterate_and_advance() guts is when nothing's left in the iterator, _not_ just when requested amount is 0. Said guts will do nothing in the latter case anyway; the problem we tried to deal with in the aforementioned commit is that when there's nothing left *and* the amount requested is 0, we might end up deferencing one iovec too many; the value we fetch from there is discarded in that case, but theoretically it might oops if the iovec array ends exactly at the end of page with the next page not mapped. Bailing out on zero size requested had an unexpected side effect - zero-length segment in the beginning of iovec array ended up throwing do_loop_readv_writev() into infinite spin; we do not advance past the empty segment at all. Reproducer is trivial: echo '#include <sys/uio.h>' >a.c echo 'main() {char c; struct iovec v[] = {{&c,0},{&c,1}}; readv(0,v,2);}' >>a.c cc a.c && ./a.out </proc/uptime which should end up with the process not hanging. Probably ought to go into LTP or xfstests... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--lib/iov_iter.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 015061e49236..2787d18fb3e1 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -101,7 +101,7 @@
#define iterate_and_advance(i, n, v, I, B, K) { \
if (unlikely(i->count < n)) \
n = i->count; \
- if (n) { \
+ if (i->count) { \
size_t skip = i->iov_offset; \
if (unlikely(i->type & ITER_BVEC)) { \
const struct bio_vec *bvec; \