Skip to content

Commit 3d392b2

Browse files
committed
ext4: add prefetch_block_bitmaps mount option
For file systems where we can afford to keep the buddy bitmaps cached, we can speed up initial writes to large file systems by starting to load the block allocation bitmaps as soon as the file system is mounted. This won't work well for _super_ large file systems, or memory constrained systems, so we only enable this when it is requested via a mount option. Addresses-Google-Bug: 159488342 Signed-off-by: Theodore Ts'o <[email protected]> Reviewed-by: Andreas Dilger <[email protected]>
1 parent ab74c7b commit 3d392b2

File tree

4 files changed

+103
-23
lines changed

4 files changed

+103
-23
lines changed

fs/ext4/ext4.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,7 @@ struct ext4_inode_info {
11881188
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
11891189
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
11901190
#define EXT4_MOUNT_WARN_ON_ERROR 0x2000000 /* Trigger WARN_ON on error */
1191+
#define EXT4_MOUNT_PREFETCH_BLOCK_BITMAPS 0x4000000
11911192
#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
11921193
#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
11931194
#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
@@ -2334,9 +2335,15 @@ struct ext4_lazy_init {
23342335
struct mutex li_list_mtx;
23352336
};
23362337

2338+
enum ext4_li_mode {
2339+
EXT4_LI_MODE_PREFETCH_BBITMAP,
2340+
EXT4_LI_MODE_ITABLE,
2341+
};
2342+
23372343
struct ext4_li_request {
23382344
struct super_block *lr_super;
2339-
struct ext4_sb_info *lr_sbi;
2345+
enum ext4_li_mode lr_mode;
2346+
ext4_group_t lr_first_not_zeroed;
23402347
ext4_group_t lr_next_group;
23412348
struct list_head lr_request;
23422349
unsigned long lr_next_sched;
@@ -2676,6 +2683,12 @@ extern int ext4_mb_reserve_blocks(struct super_block *, int);
26762683
extern void ext4_discard_preallocations(struct inode *);
26772684
extern int __init ext4_init_mballoc(void);
26782685
extern void ext4_exit_mballoc(void);
2686+
extern ext4_group_t ext4_mb_prefetch(struct super_block *sb,
2687+
ext4_group_t group,
2688+
unsigned int nr, int *cnt);
2689+
extern void ext4_mb_prefetch_fini(struct super_block *sb, ext4_group_t group,
2690+
unsigned int nr);
2691+
26792692
extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
26802693
struct buffer_head *bh, ext4_fsblk_t block,
26812694
unsigned long count, int flags);

fs/ext4/mballoc.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,9 +2232,8 @@ static int ext4_mb_good_group_nolock(struct ext4_allocation_context *ac,
22322232
* Start prefetching @nr block bitmaps starting at @group.
22332233
* Return the next group which needs to be prefetched.
22342234
*/
2235-
static ext4_group_t
2236-
ext4_mb_prefetch(struct super_block *sb, ext4_group_t group,
2237-
unsigned int nr, int *cnt)
2235+
ext4_group_t ext4_mb_prefetch(struct super_block *sb, ext4_group_t group,
2236+
unsigned int nr, int *cnt)
22382237
{
22392238
ext4_group_t ngroups = ext4_get_groups_count(sb);
22402239
struct buffer_head *bh;
@@ -2284,9 +2283,8 @@ ext4_mb_prefetch(struct super_block *sb, ext4_group_t group,
22842283
* waiting for the block allocation bitmap read to finish when
22852284
* ext4_mb_prefetch_fini is called from ext4_mb_regular_allocator().
22862285
*/
2287-
static void
2288-
ext4_mb_prefetch_fini(struct super_block *sb, ext4_group_t group,
2289-
unsigned int nr)
2286+
void ext4_mb_prefetch_fini(struct super_block *sb, ext4_group_t group,
2287+
unsigned int nr)
22902288
{
22912289
while (nr-- > 0) {
22922290
struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group,

fs/ext4/super.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,7 @@ enum {
15211521
Opt_dioread_nolock, Opt_dioread_lock,
15221522
Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
15231523
Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
1524+
Opt_prefetch_block_bitmaps,
15241525
};
15251526

15261527
static const match_table_t tokens = {
@@ -1612,6 +1613,7 @@ static const match_table_t tokens = {
16121613
{Opt_test_dummy_encryption, "test_dummy_encryption"},
16131614
{Opt_nombcache, "nombcache"},
16141615
{Opt_nombcache, "no_mbcache"}, /* for backward compatibility */
1616+
{Opt_prefetch_block_bitmaps, "prefetch_block_bitmaps"},
16151617
{Opt_removed, "check=none"}, /* mount option from ext2/3 */
16161618
{Opt_removed, "nocheck"}, /* mount option from ext2/3 */
16171619
{Opt_removed, "reservation"}, /* mount option from ext2/3 */
@@ -1829,6 +1831,8 @@ static const struct mount_opts {
18291831
{Opt_max_dir_size_kb, 0, MOPT_GTE0},
18301832
{Opt_test_dummy_encryption, 0, MOPT_STRING},
18311833
{Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
1834+
{Opt_prefetch_block_bitmaps, EXT4_MOUNT_PREFETCH_BLOCK_BITMAPS,
1835+
MOPT_SET},
18321836
{Opt_err, 0, 0}
18331837
};
18341838

@@ -3201,15 +3205,34 @@ static void print_daily_error_info(struct timer_list *t)
32013205
static int ext4_run_li_request(struct ext4_li_request *elr)
32023206
{
32033207
struct ext4_group_desc *gdp = NULL;
3204-
ext4_group_t group, ngroups;
3205-
struct super_block *sb;
3208+
struct super_block *sb = elr->lr_super;
3209+
ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
3210+
ext4_group_t group = elr->lr_next_group;
32063211
unsigned long timeout = 0;
3212+
unsigned int prefetch_ios = 0;
32073213
int ret = 0;
32083214

3209-
sb = elr->lr_super;
3210-
ngroups = EXT4_SB(sb)->s_groups_count;
3215+
if (elr->lr_mode == EXT4_LI_MODE_PREFETCH_BBITMAP) {
3216+
elr->lr_next_group = ext4_mb_prefetch(sb, group,
3217+
EXT4_SB(sb)->s_mb_prefetch, &prefetch_ios);
3218+
if (prefetch_ios)
3219+
ext4_mb_prefetch_fini(sb, elr->lr_next_group,
3220+
prefetch_ios);
3221+
trace_ext4_prefetch_bitmaps(sb, group, elr->lr_next_group,
3222+
prefetch_ios);
3223+
if (group >= elr->lr_next_group) {
3224+
ret = 1;
3225+
if (elr->lr_first_not_zeroed != ngroups &&
3226+
!sb_rdonly(sb) && test_opt(sb, INIT_INODE_TABLE)) {
3227+
elr->lr_next_group = elr->lr_first_not_zeroed;
3228+
elr->lr_mode = EXT4_LI_MODE_ITABLE;
3229+
ret = 0;
3230+
}
3231+
}
3232+
return ret;
3233+
}
32113234

3212-
for (group = elr->lr_next_group; group < ngroups; group++) {
3235+
for (; group < ngroups; group++) {
32133236
gdp = ext4_get_group_desc(sb, group, NULL);
32143237
if (!gdp) {
32153238
ret = 1;
@@ -3227,9 +3250,10 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
32273250
timeout = jiffies;
32283251
ret = ext4_init_inode_table(sb, group,
32293252
elr->lr_timeout ? 0 : 1);
3253+
trace_ext4_lazy_itable_init(sb, group);
32303254
if (elr->lr_timeout == 0) {
32313255
timeout = (jiffies - timeout) *
3232-
elr->lr_sbi->s_li_wait_mult;
3256+
EXT4_SB(elr->lr_super)->s_li_wait_mult;
32333257
elr->lr_timeout = timeout;
32343258
}
32353259
elr->lr_next_sched = jiffies + elr->lr_timeout;
@@ -3244,15 +3268,11 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
32443268
*/
32453269
static void ext4_remove_li_request(struct ext4_li_request *elr)
32463270
{
3247-
struct ext4_sb_info *sbi;
3248-
32493271
if (!elr)
32503272
return;
32513273

3252-
sbi = elr->lr_sbi;
3253-
32543274
list_del(&elr->lr_request);
3255-
sbi->s_li_request = NULL;
3275+
EXT4_SB(elr->lr_super)->s_li_request = NULL;
32563276
kfree(elr);
32573277
}
32583278

@@ -3461,16 +3481,20 @@ static int ext4_li_info_new(void)
34613481
static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
34623482
ext4_group_t start)
34633483
{
3464-
struct ext4_sb_info *sbi = EXT4_SB(sb);
34653484
struct ext4_li_request *elr;
34663485

34673486
elr = kzalloc(sizeof(*elr), GFP_KERNEL);
34683487
if (!elr)
34693488
return NULL;
34703489

34713490
elr->lr_super = sb;
3472-
elr->lr_sbi = sbi;
3473-
elr->lr_next_group = start;
3491+
elr->lr_first_not_zeroed = start;
3492+
if (test_opt(sb, PREFETCH_BLOCK_BITMAPS))
3493+
elr->lr_mode = EXT4_LI_MODE_PREFETCH_BBITMAP;
3494+
else {
3495+
elr->lr_mode = EXT4_LI_MODE_ITABLE;
3496+
elr->lr_next_group = start;
3497+
}
34743498

34753499
/*
34763500
* Randomize first schedule time of the request to
@@ -3500,8 +3524,9 @@ int ext4_register_li_request(struct super_block *sb,
35003524
goto out;
35013525
}
35023526

3503-
if (first_not_zeroed == ngroups || sb_rdonly(sb) ||
3504-
!test_opt(sb, INIT_INODE_TABLE))
3527+
if (!test_opt(sb, PREFETCH_BLOCK_BITMAPS) &&
3528+
(first_not_zeroed == ngroups || sb_rdonly(sb) ||
3529+
!test_opt(sb, INIT_INODE_TABLE)))
35053530
goto out;
35063531

35073532
elr = ext4_li_request_new(sb, first_not_zeroed);

include/trace/events/ext4.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,6 +2742,50 @@ TRACE_EVENT(ext4_error,
27422742
__entry->function, __entry->line)
27432743
);
27442744

2745+
TRACE_EVENT(ext4_prefetch_bitmaps,
2746+
TP_PROTO(struct super_block *sb, ext4_group_t group,
2747+
ext4_group_t next, unsigned int prefetch_ios),
2748+
2749+
TP_ARGS(sb, group, next, prefetch_ios),
2750+
2751+
TP_STRUCT__entry(
2752+
__field( dev_t, dev )
2753+
__field( __u32, group )
2754+
__field( __u32, next )
2755+
__field( __u32, ios )
2756+
),
2757+
2758+
TP_fast_assign(
2759+
__entry->dev = sb->s_dev;
2760+
__entry->group = group;
2761+
__entry->next = next;
2762+
__entry->ios = prefetch_ios;
2763+
),
2764+
2765+
TP_printk("dev %d,%d group %u next %u ios %u",
2766+
MAJOR(__entry->dev), MINOR(__entry->dev),
2767+
__entry->group, __entry->next, __entry->ios)
2768+
);
2769+
2770+
TRACE_EVENT(ext4_lazy_itable_init,
2771+
TP_PROTO(struct super_block *sb, ext4_group_t group),
2772+
2773+
TP_ARGS(sb, group),
2774+
2775+
TP_STRUCT__entry(
2776+
__field( dev_t, dev )
2777+
__field( __u32, group )
2778+
),
2779+
2780+
TP_fast_assign(
2781+
__entry->dev = sb->s_dev;
2782+
__entry->group = group;
2783+
),
2784+
2785+
TP_printk("dev %d,%d group %u",
2786+
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->group)
2787+
);
2788+
27452789
#endif /* _TRACE_EXT4_H */
27462790

27472791
/* This part must be outside protection */

0 commit comments

Comments
 (0)