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))