| From 9f298ddb12253414d6b8c5234cbcd067747efdb5 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 28 Apr 2020 01:15:41 +0200 |
| Subject: gfs2: More gfs2_find_jhead fixes |
| |
| From: Andreas Gruenbacher <agruenba@redhat.com> |
| |
| [ Upstream commit aa83da7f47b26c9587bade6c4bc4736ffa308f0a ] |
| |
| It turns out that when extending an existing bio, gfs2_find_jhead fails to |
| check if the block number is consecutive, which leads to incorrect reads for |
| fragmented journals. |
| |
| In addition, limit the maximum bio size to an arbitrary value of 2 megabytes: |
| since commit 07173c3ec276 ("block: enable multipage bvecs"), if we just keep |
| adding pages until bio_add_page fails, bios will grow much larger than useful, |
| which pins more memory than necessary with barely any additional performance |
| gains. |
| |
| Fixes: f4686c26ecc3 ("gfs2: read journal in large chunks") |
| Cc: stable@vger.kernel.org # v5.2+ |
| Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> |
| Signed-off-by: Bob Peterson <rpeterso@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/gfs2/lops.c | 19 ++++++++++++------- |
| 1 file changed, 12 insertions(+), 7 deletions(-) |
| |
| diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c |
| index c090d5ad3f221..3a020bdc358cd 100644 |
| --- a/fs/gfs2/lops.c |
| +++ b/fs/gfs2/lops.c |
| @@ -259,7 +259,7 @@ static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno, |
| struct super_block *sb = sdp->sd_vfs; |
| struct bio *bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES); |
| |
| - bio->bi_iter.bi_sector = blkno << (sb->s_blocksize_bits - 9); |
| + bio->bi_iter.bi_sector = blkno << sdp->sd_fsb2bb_shift; |
| bio_set_dev(bio, sb->s_bdev); |
| bio->bi_end_io = end_io; |
| bio->bi_private = sdp; |
| @@ -505,7 +505,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, |
| unsigned int bsize = sdp->sd_sb.sb_bsize, off; |
| unsigned int bsize_shift = sdp->sd_sb.sb_bsize_shift; |
| unsigned int shift = PAGE_SHIFT - bsize_shift; |
| - unsigned int readahead_blocks = BIO_MAX_PAGES << shift; |
| + unsigned int max_bio_size = 2 * 1024 * 1024; |
| struct gfs2_journal_extent *je; |
| int sz, ret = 0; |
| struct bio *bio = NULL; |
| @@ -533,12 +533,17 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, |
| off = 0; |
| } |
| |
| - if (!bio || (bio_chained && !off)) { |
| + if (!bio || (bio_chained && !off) || |
| + bio->bi_iter.bi_size >= max_bio_size) { |
| /* start new bio */ |
| } else { |
| - sz = bio_add_page(bio, page, bsize, off); |
| - if (sz == bsize) |
| - goto block_added; |
| + sector_t sector = dblock << sdp->sd_fsb2bb_shift; |
| + |
| + if (bio_end_sector(bio) == sector) { |
| + sz = bio_add_page(bio, page, bsize, off); |
| + if (sz == bsize) |
| + goto block_added; |
| + } |
| if (off) { |
| unsigned int blocks = |
| (PAGE_SIZE - off) >> bsize_shift; |
| @@ -564,7 +569,7 @@ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, |
| off += bsize; |
| if (off == PAGE_SIZE) |
| page = NULL; |
| - if (blocks_submitted < blocks_read + readahead_blocks) { |
| + if (blocks_submitted < 2 * max_bio_size >> bsize_shift) { |
| /* Keep at least one bio in flight */ |
| continue; |
| } |
| -- |
| 2.20.1 |
| |