| Message ID | 20251025032221.2905818-13-libaokun@huaweicloud.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series | ext4: enable block size larger than page size | expand |
On Sat 25-10-25 11:22:08, libaokun@huaweicloud.com wrote: > From: Baokun Li <libaokun1@huawei.com> > > Currently, ext4_mb_get_buddy_page_lock() uses blocks_per_page to calculate > 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, since ext4_mb_get_buddy_page_lock() already fully supports folio, > rename it to ext4_mb_get_buddy_folio_lock(). > > Signed-off-by: Baokun Li <libaokun1@huawei.com> > Reviewed-by: Zhang Yi <yi.zhang@huawei.com> Looks good, just two typo fixes below. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> > diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c > index 3494c6fe5bfb..d42d768a705a 100644 > --- a/fs/ext4/mballoc.c > +++ b/fs/ext4/mballoc.c > @@ -1510,50 +1510,52 @@ static int ext4_mb_init_cache(struct folio *folio, char *incore, gfp_t gfp) > } > Let's fix some typos when updating the comment: > /* > - * Lock the buddy and bitmap pages. This make sure other parallel init_group > - * on the same buddy page doesn't happen whild holding the buddy page lock. > - * Return locked buddy and bitmap pages on e4b struct. If buddy and bitmap > - * are on the same page e4b->bd_buddy_folio is NULL and return value is 0. > + * Lock the buddy and bitmap folios. This make sure other parallel init_group ^^^ makes > + * on the same buddy folio doesn't happen whild holding the buddy folio lock. ^^ while > + * Return locked buddy and bitmap folios on e4b struct. If buddy and bitmap > + * are on the same folio e4b->bd_buddy_folio is NULL and return value is 0. > */ Honza
On 2025-11-05 17:13, Jan Kara wrote: > On Sat 25-10-25 11:22:08, libaokun@huaweicloud.com wrote: >> From: Baokun Li <libaokun1@huawei.com> >> >> Currently, ext4_mb_get_buddy_page_lock() uses blocks_per_page to calculate >> 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, since ext4_mb_get_buddy_page_lock() already fully supports folio, >> rename it to ext4_mb_get_buddy_folio_lock(). >> >> Signed-off-by: Baokun Li <libaokun1@huawei.com> >> Reviewed-by: Zhang Yi <yi.zhang@huawei.com> > Looks good, just two typo fixes below. Feel free to add: > > Reviewed-by: Jan Kara <jack@suse.cz> > >> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c >> index 3494c6fe5bfb..d42d768a705a 100644 >> --- a/fs/ext4/mballoc.c >> +++ b/fs/ext4/mballoc.c >> @@ -1510,50 +1510,52 @@ static int ext4_mb_init_cache(struct folio *folio, char *incore, gfp_t gfp) >> } >> > Let's fix some typos when updating the comment: I’ll fix these typos in the next update. Thank you for your review! Regards, Baokun > >> /* >> - * Lock the buddy and bitmap pages. This make sure other parallel init_group >> - * on the same buddy page doesn't happen whild holding the buddy page lock. >> - * Return locked buddy and bitmap pages on e4b struct. If buddy and bitmap >> - * are on the same page e4b->bd_buddy_folio is NULL and return value is 0. >> + * Lock the buddy and bitmap folios. This make sure other parallel init_group > ^^^ makes > >> + * on the same buddy folio doesn't happen whild holding the buddy folio lock. > ^^ while > >> + * Return locked buddy and bitmap folios on e4b struct. If buddy and bitmap >> + * are on the same folio e4b->bd_buddy_folio is NULL and return value is 0. >> */ > Honza
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 3494c6fe5bfb..d42d768a705a 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1510,50 +1510,52 @@ static int ext4_mb_init_cache(struct folio *folio, char *incore, gfp_t gfp) } /* - * Lock the buddy and bitmap pages. This make sure other parallel init_group - * on the same buddy page doesn't happen whild holding the buddy page lock. - * Return locked buddy and bitmap pages on e4b struct. If buddy and bitmap - * are on the same page e4b->bd_buddy_folio is NULL and return value is 0. + * Lock the buddy and bitmap folios. This make sure other parallel init_group + * on the same buddy folio doesn't happen whild holding the buddy folio lock. + * Return locked buddy and bitmap folios on e4b struct. If buddy and bitmap + * are on the same folio e4b->bd_buddy_folio is NULL and return value is 0. */ -static int ext4_mb_get_buddy_page_lock(struct super_block *sb, +static int ext4_mb_get_buddy_folio_lock(struct super_block *sb, ext4_group_t group, struct ext4_buddy *e4b, gfp_t gfp) { struct inode *inode = EXT4_SB(sb)->s_buddy_cache; - int block, pnum, poff; - int blocks_per_page; + int block, pnum; struct folio *folio; e4b->bd_buddy_folio = NULL; e4b->bd_bitmap_folio = NULL; - blocks_per_page = PAGE_SIZE / sb->s_blocksize; /* * the buddy cache inode stores the block bitmap * and buddy information in consecutive blocks. * 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_P(inode, block); folio = __filemap_get_folio(inode->i_mapping, pnum, FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp); if (IS_ERR(folio)) return PTR_ERR(folio); BUG_ON(folio->mapping != inode->i_mapping); + WARN_ON_ONCE(folio_size(folio) < sb->s_blocksize); 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)); - if (blocks_per_page >= 2) { - /* buddy and bitmap are on the same page */ + block++; + pnum = EXT4_LBLK_TO_P(inode, block); + if (folio_contains(folio, pnum)) { + /* buddy and bitmap are on the same folio */ return 0; } - /* blocks_per_page == 1, hence we need another page for the buddy */ - folio = __filemap_get_folio(inode->i_mapping, block + 1, + /* we need another folio for the buddy */ + folio = __filemap_get_folio(inode->i_mapping, pnum, FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp); if (IS_ERR(folio)) return PTR_ERR(folio); BUG_ON(folio->mapping != inode->i_mapping); + WARN_ON_ONCE(folio_size(folio) < sb->s_blocksize); e4b->bd_buddy_folio = folio; return 0; } @@ -1592,14 +1594,14 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp) /* * This ensures that we don't reinit the buddy cache - * page which map to the group from which we are already + * folio which map to the group from which we are already * allocating. If we are looking at the buddy cache we would * have taken a reference using ext4_mb_load_buddy and that - * would have pinned buddy page to page cache. - * The call to ext4_mb_get_buddy_page_lock will mark the - * page accessed. + * would have pinned buddy folio to page cache. + * The call to ext4_mb_get_buddy_folio_lock will mark the + * folio accessed. */ - ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b, gfp); + ret = ext4_mb_get_buddy_folio_lock(sb, group, &e4b, gfp); if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) { /* * somebody initialized the group