From: Ming Lei ming.lei@redhat.com
mainline inclusion from mainline-v5.5-rc6 commit 83c9c547168e8b914ea6398430473a4de68c52cc category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6GTUI CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
Commit 85a8ce62c2ea ("block: add bio_truncate to fix guard_bio_eod") adds bio_truncate() for handling bio EOD. However, bio_truncate() doesn't use the passed 'op' parameter from guard_bio_eod's callers.
So bio_trunacate() may retrieve wrong 'op', and zering pages may not be done for READ bio.
Fixes this issue by moving guard_bio_eod() after bio_set_op_attrs() in submit_bh_wbc() so that bio_truncate() can always retrieve correct op info.
Meantime remove the 'op' parameter from guard_bio_eod() because it isn't used any more.
Cc: Carlos Maiolino cmaiolino@redhat.com Cc: linux-fsdevel@vger.kernel.org Fixes: 85a8ce62c2ea ("block: add bio_truncate to fix guard_bio_eod") Signed-off-by: Ming Lei ming.lei@redhat.com
Fold in kerneldoc and bio_op() change.
Signed-off-by: Jens Axboe axboe@kernel.dk
Conflicts: fs/buffer.c fs/internal.h Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Hou Tao houtao1@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- block/bio.c | 12 +++++++++++- fs/buffer.c | 8 ++++---- fs/internal.h | 2 +- fs/mpage.c | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/block/bio.c b/block/bio.c index acefd2be1cd9..a1c74f10d604 100644 --- a/block/bio.c +++ b/block/bio.c @@ -547,6 +547,16 @@ void zero_fill_bio_iter(struct bio *bio, struct bvec_iter start) } EXPORT_SYMBOL(zero_fill_bio_iter);
+/** + * bio_truncate - truncate the bio to small size of @new_size + * @bio: the bio to be truncated + * @new_size: new size for truncating the bio + * + * Description: + * Truncate the bio to new size of @new_size. If bio_op(bio) is + * REQ_OP_READ, zero the truncated part. This function should only + * be used for handling corner cases, such as bio eod. + */ void bio_truncate(struct bio *bio, unsigned new_size) { struct bio_vec bv; @@ -557,7 +567,7 @@ void bio_truncate(struct bio *bio, unsigned new_size) if (new_size >= bio->bi_iter.bi_size) return;
- if (bio_data_dir(bio) != READ) + if (bio_op(bio) != REQ_OP_READ) goto exit;
bio_for_each_segment(bv, bio, iter) { diff --git a/fs/buffer.c b/fs/buffer.c index 6be882a23758..af88734d1d38 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2990,7 +2990,7 @@ static void end_bio_bh_io_sync(struct bio *bio) * errors, this only handles the "we need to be able to * do IO at the final sector" case. */ -void guard_bio_eod(int op, struct bio *bio) +void guard_bio_eod(struct bio *bio) { sector_t maxsector; struct hd_struct *part; @@ -3059,15 +3059,15 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, bio->bi_end_io = end_bio_bh_io_sync; bio->bi_private = bh;
- /* Take care of bh's that straddle the end of the device */ - guard_bio_eod(op, bio); - if (buffer_meta(bh)) op_flags |= REQ_META; if (buffer_prio(bh)) op_flags |= REQ_PRIO; bio_set_op_attrs(bio, op, op_flags);
+ /* Take care of bh's that straddle the end of the device */ + guard_bio_eod(bio); + submit_bio(bio); return 0; } diff --git a/fs/internal.h b/fs/internal.h index 73e9829245f1..e63939e64439 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -40,7 +40,7 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait) /* * buffer.c */ -extern void guard_bio_eod(int rw, struct bio *bio); +extern void guard_bio_eod(struct bio *bio); extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, get_block_t *get_block, struct iomap *iomap); void __generic_write_end(struct inode *inode, loff_t pos, unsigned copied, diff --git a/fs/mpage.c b/fs/mpage.c index c820dc9bebab..fb2ff971c66b 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -62,7 +62,7 @@ static struct bio *mpage_bio_submit(int op, int op_flags, struct bio *bio) { bio->bi_end_io = mpage_end_io; bio_set_op_attrs(bio, op, op_flags); - guard_bio_eod(op, bio); + guard_bio_eod(bio); submit_bio(bio); return NULL; }