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
,
104 err
= io_channel_cache_readahead(fs
->io
, start
, out
- start
);
108 err
= ext2fs_find_first_set_block_bitmap2(ra_map
, start
, end
,
118 /* Try not to spew bitmap range errors for readahead */
119 static errcode_t
mark_bmap_range(ext2fs_block_bitmap map
,
120 blk64_t blk
, unsigned int num
)
122 if (blk
>= ext2fs_get_generic_bmap_start(map
) &&
123 blk
+ num
<= ext2fs_get_generic_bmap_end(map
))
124 ext2fs_mark_block_bitmap_range2(map
, blk
, num
);
126 return EXT2_ET_INVALID_ARGUMENT
;
130 static errcode_t
mark_bmap(ext2fs_block_bitmap map
, blk64_t blk
)
132 if (blk
>= ext2fs_get_generic_bmap_start(map
) &&
133 blk
<= ext2fs_get_generic_bmap_end(map
))
134 ext2fs_mark_block_bitmap2(map
, blk
);
136 return EXT2_ET_INVALID_ARGUMENT
;
140 errcode_t
e2fsck_readahead(ext2_filsys fs
, int flags
, dgrp_t start
,
143 blk64_t super
, old_gdt
, new_gdt
;
146 ext2fs_block_bitmap ra_map
= NULL
;
147 dgrp_t end
= start
+ ngroups
;
150 dbg_printf("%s: flags=0x%x start=%d groups=%d\n", __func__
, flags
,
152 if (flags
& ~E2FSCK_READA_ALL_FLAGS
)
153 return EXT2_ET_INVALID_ARGUMENT
;
155 if (end
> fs
->group_desc_count
)
156 end
= fs
->group_desc_count
;
161 err
= ext2fs_allocate_block_bitmap(fs
, "readahead bitmap",
166 for (i
= start
; i
< end
; i
++) {
167 err
= ext2fs_super_and_bgd_loc2(fs
, i
, &super
, &old_gdt
,
172 if (flags
& E2FSCK_READA_SUPER
) {
173 err
= mark_bmap(ra_map
, super
);
178 if (flags
& E2FSCK_READA_GDT
) {
179 err
= mark_bmap_range(ra_map
,
180 old_gdt
? old_gdt
: new_gdt
,
186 if ((flags
& E2FSCK_READA_BBITMAP
) &&
187 !ext2fs_bg_flags_test(fs
, i
, EXT2_BG_BLOCK_UNINIT
) &&
188 ext2fs_bg_free_blocks_count(fs
, i
) <
189 fs
->super
->s_blocks_per_group
) {
190 super
= ext2fs_block_bitmap_loc(fs
, i
);
191 err
= mark_bmap(ra_map
, super
);
196 if ((flags
& E2FSCK_READA_IBITMAP
) &&
197 !ext2fs_bg_flags_test(fs
, i
, EXT2_BG_INODE_UNINIT
) &&
198 ext2fs_bg_free_inodes_count(fs
, i
) <
199 fs
->super
->s_inodes_per_group
) {
200 super
= ext2fs_inode_bitmap_loc(fs
, i
);
201 err
= mark_bmap(ra_map
, super
);
206 if ((flags
& E2FSCK_READA_ITABLE
) &&
207 ext2fs_bg_free_inodes_count(fs
, i
) <
208 fs
->super
->s_inodes_per_group
) {
209 super
= ext2fs_inode_table_loc(fs
, i
);
210 blocks
= fs
->inode_blocks_per_group
-
211 (ext2fs_bg_itable_unused(fs
, i
) *
212 EXT2_INODE_SIZE(fs
->super
) / fs
->blocksize
);
213 err
= mark_bmap_range(ra_map
, super
, blocks
);
220 err
= e2fsck_readahead_bitmap(fs
, ra_map
);
222 ext2fs_free_block_bitmap(ra_map
);
226 int e2fsck_can_readahead(ext2_filsys fs
)
230 err
= io_channel_cache_readahead(fs
->io
, 0, 1);
231 dbg_printf("%s: supp=%d\n", __func__
, err
!= EXT2_ET_OP_NOT_SUPPORTED
);
232 return err
!= EXT2_ET_OP_NOT_SUPPORTED
;
235 unsigned long long e2fsck_guess_readahead(ext2_filsys fs
)
237 unsigned long long guess
;
240 * The optimal readahead sizes were experimentally determined by
241 * djwong in August 2014. Setting the RA size to two block groups'
242 * worth of inode table blocks seems to yield the largest reductions
245 guess
= 2ULL * fs
->blocksize
* fs
->inode_blocks_per_group
;
247 /* Disable RA if it'd use more 1/50th of RAM. */
248 if (get_memory_size() > (guess
* 50))