2 * readahead.c -- Prefetch filesystem metadata to speed up fsck.
4 * Copyright (C) 2014 Oracle.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
20 # define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
22 # define dbg_printf(f, a...)
32 static int readahead_dir_block(ext2_filsys fs
, struct ext2_db_entry2
*db
,
35 struct read_dblist
*pr
= priv_data
;
36 e2_blkcnt_t count
= (pr
->flags
& E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT
?
39 if (!pr
->run_len
|| db
->blk
!= pr
->run_start
+ pr
->run_len
) {
41 pr
->err
= io_channel_cache_readahead(fs
->io
,
44 dbg_printf("readahead start=%llu len=%llu err=%d\n",
45 pr
->run_start
, pr
->run_len
,
48 pr
->run_start
= db
->blk
;
53 return pr
->err
? DBLIST_ABORT
: 0;
56 errcode_t
e2fsck_readahead_dblist(ext2_filsys fs
, int flags
,
58 unsigned long long start
,
59 unsigned long long count
)
62 struct read_dblist pr
;
64 dbg_printf("%s: flags=0x%x\n", __func__
, flags
);
65 if (flags
& ~E2FSCK_RA_DBLIST_ALL_FLAGS
)
66 return EXT2_ET_INVALID_ARGUMENT
;
68 memset(&pr
, 0, sizeof(pr
));
70 err
= ext2fs_dblist_iterate3(dblist
, readahead_dir_block
, start
,
78 err
= io_channel_cache_readahead(fs
->io
, pr
.run_start
,
84 static errcode_t
e2fsck_readahead_bitmap(ext2_filsys fs
,
85 ext2fs_block_bitmap ra_map
)
87 blk64_t start
, end
, out
;
91 end
= ext2fs_blocks_count(fs
->super
) - 1;
93 err
= ext2fs_find_first_set_block_bitmap2(ra_map
, start
, end
, &out
);
96 err
= ext2fs_find_first_zero_block_bitmap2(ra_map
, start
, end
,
106 err
= io_channel_cache_readahead(fs
->io
, start
, out
- start
);
110 err
= ext2fs_find_first_set_block_bitmap2(ra_map
, start
, end
,
120 /* Try not to spew bitmap range errors for readahead */
121 static errcode_t
mark_bmap_range(ext2fs_block_bitmap map
,
122 blk64_t blk
, unsigned int num
)
124 if (blk
>= ext2fs_get_generic_bmap_start(map
) &&
125 blk
+ num
<= ext2fs_get_generic_bmap_end(map
))
126 ext2fs_mark_block_bitmap_range2(map
, blk
, num
);
128 return EXT2_ET_INVALID_ARGUMENT
;
132 static errcode_t
mark_bmap(ext2fs_block_bitmap map
, blk64_t blk
)
134 if (blk
>= ext2fs_get_generic_bmap_start(map
) &&
135 blk
<= ext2fs_get_generic_bmap_end(map
))
136 ext2fs_mark_block_bitmap2(map
, blk
);
138 return EXT2_ET_INVALID_ARGUMENT
;
142 errcode_t
e2fsck_readahead(ext2_filsys fs
, int flags
, dgrp_t start
,
145 blk64_t super
, old_gdt
, new_gdt
;
148 ext2fs_block_bitmap ra_map
= NULL
;
149 dgrp_t end
= start
+ ngroups
;
152 dbg_printf("%s: flags=0x%x start=%d groups=%d\n", __func__
, flags
,
154 if (flags
& ~E2FSCK_READA_ALL_FLAGS
)
155 return EXT2_ET_INVALID_ARGUMENT
;
157 if (end
> fs
->group_desc_count
)
158 end
= fs
->group_desc_count
;
163 err
= ext2fs_allocate_block_bitmap(fs
, "readahead bitmap",
168 for (i
= start
; i
< end
; i
++) {
169 err
= ext2fs_super_and_bgd_loc2(fs
, i
, &super
, &old_gdt
,
174 if (flags
& E2FSCK_READA_SUPER
) {
175 err
= mark_bmap(ra_map
, super
);
180 if (flags
& E2FSCK_READA_GDT
) {
181 err
= mark_bmap_range(ra_map
,
182 old_gdt
? old_gdt
: new_gdt
,
188 if ((flags
& E2FSCK_READA_BBITMAP
) &&
189 !ext2fs_bg_flags_test(fs
, i
, EXT2_BG_BLOCK_UNINIT
) &&
190 ext2fs_bg_free_blocks_count(fs
, i
) <
191 fs
->super
->s_blocks_per_group
) {
192 super
= ext2fs_block_bitmap_loc(fs
, i
);
193 err
= mark_bmap(ra_map
, super
);
198 if ((flags
& E2FSCK_READA_IBITMAP
) &&
199 !ext2fs_bg_flags_test(fs
, i
, EXT2_BG_INODE_UNINIT
) &&
200 ext2fs_bg_free_inodes_count(fs
, i
) <
201 fs
->super
->s_inodes_per_group
) {
202 super
= ext2fs_inode_bitmap_loc(fs
, i
);
203 err
= mark_bmap(ra_map
, super
);
208 if ((flags
& E2FSCK_READA_ITABLE
) &&
209 ext2fs_bg_free_inodes_count(fs
, i
) <
210 fs
->super
->s_inodes_per_group
) {
211 super
= ext2fs_inode_table_loc(fs
, i
);
212 blocks
= fs
->inode_blocks_per_group
-
213 (ext2fs_bg_itable_unused(fs
, i
) *
214 EXT2_INODE_SIZE(fs
->super
) / fs
->blocksize
);
215 err
= mark_bmap_range(ra_map
, super
, blocks
);
222 err
= e2fsck_readahead_bitmap(fs
, ra_map
);
224 ext2fs_free_block_bitmap(ra_map
);
228 int e2fsck_can_readahead(ext2_filsys fs
)
232 err
= io_channel_cache_readahead(fs
->io
, 0, 1);
233 dbg_printf("%s: supp=%d\n", __func__
, err
!= EXT2_ET_OP_NOT_SUPPORTED
);
234 return err
!= EXT2_ET_OP_NOT_SUPPORTED
;
237 unsigned long long e2fsck_guess_readahead(ext2_filsys fs
)
239 unsigned long long guess
;
242 * The optimal readahead sizes were experimentally determined by
243 * djwong in August 2014. Setting the RA size to two block groups'
244 * worth of inode table blocks seems to yield the largest reductions
247 guess
= 2ULL * fs
->blocksize
* fs
->inode_blocks_per_group
;
249 /* Disable RA if it'd use more 1/50th of RAM. */
250 if (get_memory_size() > (guess
* 50))