Commit aa83da7f authored by Andreas Gruenbacher's avatar Andreas Gruenbacher
Browse files

gfs2: More gfs2_find_jhead fixes



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 07173c3e ("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: f4686c26 ("gfs2: read journal in large chunks")
Cc: stable@vger.kernel.org # v5.2+
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
parent 566a2ab3
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -263,7 +263,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;
@@ -509,7 +509,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;
@@ -537,12 +537,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 {
				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;
@@ -568,7 +573,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;
			}