On Mar 11, 2014, at 12:57 AM, Darrick J. Wong <darrick.wong@xxxxxxxxxx> wrote: > This patch adds to libext2fs the ability to pre-fetch metadata > into the page cache in the hopes of speeding up libext2fs' clients. > There are two new library functions -- the first allows a client to > readahead a list of blocks, and the second is a helper function that > uses that first mechanism to load group data (bitmaps, inode tables). > > e2fsck will employ both of these methods to speed itself up. You can also add a Reviewed-by: Andreas Dilger <adilger@xxxxxxxxx> on this. > diff --git a/lib/ext2fs/readahead.c b/lib/ext2fs/readahead.c > new file mode 100644 > index 0000000..ed6e555 > --- /dev/null > +++ b/lib/ext2fs/readahead.c > @@ -0,0 +1,188 @@ > +struct read_dblist { > + errcode_t err; > + blk64_t run_start; > + blk64_t run_len; > +}; > + > +static EXT2_QSORT_TYPE readahead_dir_block_cmp(const void *a, const void *b) > +{ > + const struct ext2_db_entry2 *db_a = > + (const struct ext2_db_entry2 *) a; > + const struct ext2_db_entry2 *db_b = > + (const struct ext2_db_entry2 *) b; > + > + return (int) (db_a->blk - db_b->blk); > +} > + > +static int readahead_dir_block(ext2_filsys fs, struct ext2_db_entry2 *db, > + void *priv_data) > +{ > + errcode_t err = 0; > + struct read_dblist *pr = priv_data; > + > + if (!pr->run_len || db->blk != pr->run_start + pr->run_len) { It probably isn't necessary to check "!pr->run_len", since the only case where this isn't entered on a new look is db->blk == 0, which is always loaded when the filesystem is mounted anyway. Cheers, Andreas > + if (pr->run_len) { > + pr->err = io_channel_cache_readahead(fs->io, > + pr->run_start, > + pr->run_len); > + dbg_printf("readahead start=%llu len=%llu err=%d\n", > + pr->run_start, pr->run_len, > + (int)pr->err); > + } > + pr->run_start = db->blk; > + pr->run_len = 0; > + } > + pr->run_len += db->blockcnt; > + > + return pr->err ? DBLIST_ABORT : 0; > +} > + > +errcode_t ext2fs_readahead_dblist(ext2_filsys fs, int flags, > + ext2_dblist dblist) > +{ > + errcode_t err; > + struct read_dblist pr; > + > + dbg_printf("%s: flags=0x%x\n", __func__, flags); > + if (flags) > + return EXT2_ET_INVALID_ARGUMENT; > + > + ext2fs_dblist_sort2(dblist, readahead_dir_block_cmp); > + > + memset(&pr, 0, sizeof(pr)); > + err = ext2fs_dblist_iterate2(dblist, readahead_dir_block, &pr); > + if (pr.err) > + return pr.err; > + if (err) > + return err; > + > + if (pr.run_len) > + err = io_channel_cache_readahead(fs->io, pr.run_start, > + pr.run_len); > + > + return err; > +} > + > +errcode_t ext2fs_readahead(ext2_filsys fs, int flags, dgrp_t start, > + dgrp_t ngroups) > +{ > + blk64_t super, old_gdt, new_gdt; > + blk_t blocks; > + dgrp_t i; > + ext2_dblist dblist; > + dgrp_t end = start + ngroups; > + errcode_t err = 0; > + > + dbg_printf("%s: flags=0x%x start=%d groups=%d\n", __func__, flags, > + start, ngroups); > + if (flags & ~EXT2_READA_ALL_FLAGS) > + return EXT2_ET_INVALID_ARGUMENT; > + > + if (end > fs->group_desc_count) > + end = fs->group_desc_count; > + > + if (flags == 0) > + return 0; > + > + err = ext2fs_init_dblist(fs, &dblist); > + if (err) > + return err; > + > + for (i = start; i < end; i++) { > + err = ext2fs_super_and_bgd_loc2(fs, i, &super, &old_gdt, > + &new_gdt, &blocks); > + if (err) > + break; > + > + if (flags & EXT2_READA_SUPER) { > + err = ext2fs_add_dir_block2(dblist, 0, super, 0); > + if (err) > + break; > + } > + > + if (flags & EXT2_READA_GDT) { > + if (old_gdt) > + err = ext2fs_add_dir_block2(dblist, 0, old_gdt, > + blocks); > + else if (new_gdt) > + err = ext2fs_add_dir_block2(dblist, 0, new_gdt, > + blocks); > + else > + err = 0; > + if (err) > + break; > + } > + > + if ((flags & EXT2_READA_BBITMAP) && > + !ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && > + ext2fs_bg_free_blocks_count(fs, i) < > + fs->super->s_blocks_per_group) { > + super = ext2fs_block_bitmap_loc(fs, i); > + err = ext2fs_add_dir_block2(dblist, 0, super, 1); > + if (err) > + break; > + } > + > + if ((flags & EXT2_READA_IBITMAP) && > + !ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && > + ext2fs_bg_free_inodes_count(fs, i) < > + fs->super->s_inodes_per_group) { > + super = ext2fs_inode_bitmap_loc(fs, i); > + err = ext2fs_add_dir_block2(dblist, 0, super, 1); > + if (err) > + break; > + } > + > + if ((flags & EXT2_READA_ITABLE) && > + ext2fs_bg_free_inodes_count(fs, i) < > + fs->super->s_inodes_per_group) { > + super = ext2fs_inode_table_loc(fs, i); > + blocks = fs->inode_blocks_per_group - > + (ext2fs_bg_itable_unused(fs, i) * > + EXT2_INODE_SIZE(fs->super) / fs->blocksize); > + err = ext2fs_add_dir_block2(dblist, 0, super, blocks); > + if (err) > + break; > + } > + } > + > + if (!err) > + err = ext2fs_readahead_dblist(fs, 0, dblist); > + > + ext2fs_free_dblist(dblist); > + return err; > +} > + > +int ext2fs_can_readahead(ext2_filsys fs) > +{ > + errcode_t err; > + > + err = io_channel_cache_readahead(fs->io, 0, 1); > + dbg_printf("%s: supp=%d\n", __func__, err != EXT2_ET_OP_NOT_SUPPORTED); > + return err != EXT2_ET_OP_NOT_SUPPORTED; > +} > > -- > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html Cheers, Andreas
Attachment:
signature.asc
Description: Message signed with OpenPGP using GPGMail