Skip to content

Commit 6117f18

Browse files
LiBaokun96tytso
authored andcommitted
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: Baokun Li <libaokun1@huawei.com> Reviewed-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com> Message-ID: <20251121090654.631996-12-libaokun@huaweicloud.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 2a8de76 commit 6117f18

1 file changed

Lines changed: 16 additions & 11 deletions

File tree

fs/ext4/mballoc.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,17 +1659,15 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp)
16591659

16601660
/*
16611661
* Locking note: This routine calls ext4_mb_init_cache(), which takes the
1662-
* block group lock of all groups for this page; do not hold the BG lock when
1662+
* block group lock of all groups for this folio; do not hold the BG lock when
16631663
* calling this routine!
16641664
*/
16651665
static noinline_for_stack int
16661666
ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
16671667
struct ext4_buddy *e4b, gfp_t gfp)
16681668
{
1669-
int blocks_per_page;
16701669
int block;
16711670
int pnum;
1672-
int poff;
16731671
struct folio *folio;
16741672
int ret;
16751673
struct ext4_group_info *grp;
@@ -1679,7 +1677,6 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
16791677
might_sleep();
16801678
mb_debug(sb, "load group %u\n", group);
16811679

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

17131709
/* Avoid locking the folio in the fast path ... */
17141710
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,
17401736
goto err;
17411737
}
17421738
mb_cmp_bitmaps(e4b, folio_address(folio) +
1743-
(poff * sb->s_blocksize));
1739+
offset_in_folio(folio,
1740+
EXT4_LBLK_TO_B(inode, block)));
17441741
}
17451742
folio_unlock(folio);
17461743
}
@@ -1756,12 +1753,18 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
17561753

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

17611759
block++;
1762-
pnum = block / blocks_per_page;
1763-
poff = block % blocks_per_page;
1760+
pnum = EXT4_LBLK_TO_PG(inode, block);
1761+
/* buddy and bitmap are on the same folio? */
1762+
if (folio_contains(folio, pnum)) {
1763+
folio_get(folio);
1764+
goto update_buddy;
1765+
}
17641766

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

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

18031808
return 0;
18041809

0 commit comments

Comments
 (0)