diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2017-09-11 16:17:09 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-10-11 22:38:02 -0400 |
commit | cfe057f7db1ff026c8db75469a3f9ba9736e1975 (patch) | |
tree | 95f92a36480525b3918b6e1a6d9b26d236160565 | |
parent | 8ececffa12f5555171075ce52e1226f570836b26 (diff) |
iomap_dio_actor(): fix iov_iter bugs
1) Ignoring return value from iov_iter_zero() is wrong
for iovec-backed case as well as for pipes - it can fail.
2) Failure to fault destination pages in 25Mb into a 50Mb iovec
should not act as if nothing in the area had been read, nevermind
that the first 25Mb might have *already* been read by that point.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/iomap.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/fs/iomap.c b/fs/iomap.c index be61cf742b5e..9c41008833ac 100644 --- a/fs/iomap.c +++ b/fs/iomap.c | |||
@@ -848,6 +848,7 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, | |||
848 | struct bio *bio; | 848 | struct bio *bio; |
849 | bool need_zeroout = false; | 849 | bool need_zeroout = false; |
850 | int nr_pages, ret; | 850 | int nr_pages, ret; |
851 | size_t copied = 0; | ||
851 | 852 | ||
852 | if ((pos | length | align) & ((1 << blkbits) - 1)) | 853 | if ((pos | length | align) & ((1 << blkbits) - 1)) |
853 | return -EINVAL; | 854 | return -EINVAL; |
@@ -859,7 +860,7 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, | |||
859 | /*FALLTHRU*/ | 860 | /*FALLTHRU*/ |
860 | case IOMAP_UNWRITTEN: | 861 | case IOMAP_UNWRITTEN: |
861 | if (!(dio->flags & IOMAP_DIO_WRITE)) { | 862 | if (!(dio->flags & IOMAP_DIO_WRITE)) { |
862 | iov_iter_zero(length, dio->submit.iter); | 863 | length = iov_iter_zero(length, dio->submit.iter); |
863 | dio->size += length; | 864 | dio->size += length; |
864 | return length; | 865 | return length; |
865 | } | 866 | } |
@@ -896,8 +897,11 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, | |||
896 | } | 897 | } |
897 | 898 | ||
898 | do { | 899 | do { |
899 | if (dio->error) | 900 | size_t n; |
901 | if (dio->error) { | ||
902 | iov_iter_revert(dio->submit.iter, copied); | ||
900 | return 0; | 903 | return 0; |
904 | } | ||
901 | 905 | ||
902 | bio = bio_alloc(GFP_KERNEL, nr_pages); | 906 | bio = bio_alloc(GFP_KERNEL, nr_pages); |
903 | bio_set_dev(bio, iomap->bdev); | 907 | bio_set_dev(bio, iomap->bdev); |
@@ -910,20 +914,24 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, | |||
910 | ret = bio_iov_iter_get_pages(bio, &iter); | 914 | ret = bio_iov_iter_get_pages(bio, &iter); |
911 | if (unlikely(ret)) { | 915 | if (unlikely(ret)) { |
912 | bio_put(bio); | 916 | bio_put(bio); |
913 | return ret; | 917 | return copied ? copied : ret; |
914 | } | 918 | } |
915 | 919 | ||
920 | n = bio->bi_iter.bi_size; | ||
916 | if (dio->flags & IOMAP_DIO_WRITE) { | 921 | if (dio->flags & IOMAP_DIO_WRITE) { |
917 | bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_SYNC | REQ_IDLE); | 922 | bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_SYNC | REQ_IDLE); |
918 | task_io_account_write(bio->bi_iter.bi_size); | 923 | task_io_account_write(n); |
919 | } else { | 924 | } else { |
920 | bio_set_op_attrs(bio, REQ_OP_READ, 0); | 925 | bio_set_op_attrs(bio, REQ_OP_READ, 0); |
921 | if (dio->flags & IOMAP_DIO_DIRTY) | 926 | if (dio->flags & IOMAP_DIO_DIRTY) |
922 | bio_set_pages_dirty(bio); | 927 | bio_set_pages_dirty(bio); |
923 | } | 928 | } |
924 | 929 | ||
925 | dio->size += bio->bi_iter.bi_size; | 930 | iov_iter_advance(dio->submit.iter, n); |
926 | pos += bio->bi_iter.bi_size; | 931 | |
932 | dio->size += n; | ||
933 | pos += n; | ||
934 | copied += n; | ||
927 | 935 | ||
928 | nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES); | 936 | nr_pages = iov_iter_npages(&iter, BIO_MAX_PAGES); |
929 | 937 | ||
@@ -939,9 +947,7 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length, | |||
939 | if (pad) | 947 | if (pad) |
940 | iomap_dio_zero(dio, iomap, pos, fs_block_size - pad); | 948 | iomap_dio_zero(dio, iomap, pos, fs_block_size - pad); |
941 | } | 949 | } |
942 | 950 | return copied; | |
943 | iov_iter_advance(dio->submit.iter, length); | ||
944 | return length; | ||
945 | } | 951 | } |
946 | 952 | ||
947 | ssize_t | 953 | ssize_t |