Commit 6117f180 authored by Baokun Li's avatar Baokun Li Committed by Theodore Ts'o
Browse files

ext4: support large block size in ext4_mb_load_buddy_gfp()



Currently, ext4_mb_load_buddy_gfp() uses blocks_per_page to calculate the
folio index and offset. However, when blocksize is larger than PAGE_SIZE,
blocks_per_page becomes zero, leading to a potential division-by-zero bug.

To support BS > PS, use bytes to compute folio index and offset within
folio to get rid of blocks_per_page.

Also, if buddy and bitmap land in the same folio, we get that folio’s ref
instead of looking it up again before updating the buddy.

Signed-off-by: default avatarBaokun Li <libaokun1@huawei.com>
Reviewed-by: default avatarZhang Yi <yi.zhang@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarOjaswin Mujoo <ojaswin@linux.ibm.com>
Message-ID: <20251121090654.631996-12-libaokun@huaweicloud.com>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 2a8de76b
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -1659,17 +1659,15 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp)

/*
 * Locking note:  This routine calls ext4_mb_init_cache(), which takes the
 * block group lock of all groups for this page; do not hold the BG lock when
 * block group lock of all groups for this folio; do not hold the BG lock when
 * calling this routine!
 */
static noinline_for_stack int
ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
		       struct ext4_buddy *e4b, gfp_t gfp)
{
	int blocks_per_page;
	int block;
	int pnum;
	int poff;
	struct folio *folio;
	int ret;
	struct ext4_group_info *grp;
@@ -1679,7 +1677,6 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
	might_sleep();
	mb_debug(sb, "load group %u\n", group);

	blocks_per_page = PAGE_SIZE / sb->s_blocksize;
	grp = ext4_get_group_info(sb, group);
	if (!grp)
		return -EFSCORRUPTED;
@@ -1707,8 +1704,7 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
	 * So for each group we need two blocks.
	 */
	block = group * 2;
	pnum = block / blocks_per_page;
	poff = block % blocks_per_page;
	pnum = EXT4_LBLK_TO_PG(inode, block);

	/* Avoid locking the folio in the fast path ... */
	folio = __filemap_get_folio(inode->i_mapping, pnum, FGP_ACCESSED, 0);
@@ -1740,7 +1736,8 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
					goto err;
				}
				mb_cmp_bitmaps(e4b, folio_address(folio) +
					       (poff * sb->s_blocksize));
					offset_in_folio(folio,
						EXT4_LBLK_TO_B(inode, block)));
			}
			folio_unlock(folio);
		}
@@ -1756,12 +1753,18 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,

	/* Folios marked accessed already */
	e4b->bd_bitmap_folio = folio;
	e4b->bd_bitmap = folio_address(folio) + (poff * sb->s_blocksize);
	e4b->bd_bitmap = folio_address(folio) +
			 offset_in_folio(folio, EXT4_LBLK_TO_B(inode, block));

	block++;
	pnum = block / blocks_per_page;
	poff = block % blocks_per_page;
	pnum = EXT4_LBLK_TO_PG(inode, block);
	/* buddy and bitmap are on the same folio? */
	if (folio_contains(folio, pnum)) {
		folio_get(folio);
		goto update_buddy;
	}

	/* we need another folio for the buddy */
	folio = __filemap_get_folio(inode->i_mapping, pnum, FGP_ACCESSED, 0);
	if (IS_ERR(folio) || !folio_test_uptodate(folio)) {
		if (!IS_ERR(folio))
@@ -1796,9 +1799,11 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
		goto err;
	}

update_buddy:
	/* Folios marked accessed already */
	e4b->bd_buddy_folio = folio;
	e4b->bd_buddy = folio_address(folio) + (poff * sb->s_blocksize);
	e4b->bd_buddy = folio_address(folio) +
			offset_in_folio(folio, EXT4_LBLK_TO_B(inode, block));

	return 0;