[v2] libext2fs: preload block group on request

Submitted by Artem Blagodarenko on March 3, 2017, 1:01 p.m.

Details

Message ID 1488546110-31366-1-git-send-email-artem.blagodarenko@gmail.com
State New
Headers show

Commit Message

Artem Blagodarenko March 3, 2017, 1:01 p.m.
From: Artem Blagodarenko <artem.blagodarenko@seagate.com>

---
 lib/ext2fs/blknum.c  |   46 ++++++++++++++++++++++++++++++++++++++++++++--
 lib/ext2fs/closefs.c |    7 +++++--
 lib/ext2fs/ext2_fs.h |    1 +
 lib/ext2fs/ext2fs.h  |    3 +++
 lib/ext2fs/openfs.c  |   29 +++++++----------------------
 5 files changed, 60 insertions(+), 26 deletions(-)

Patch hide | download patch | download mbox

diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c
index ac80849..a5d5082 100644
--- a/lib/ext2fs/blknum.c
+++ b/lib/ext2fs/blknum.c
@@ -186,8 +186,50 @@  struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
 					  dgrp_t group)
 {
 	int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
-
-	return (struct ext2_group_desc *)((char *)gdp + group * desc_size);
+	struct ext2_group_desc *ret_gdp;
+	struct ext2_group_desc *tmp_gdp;
+	char *dest;
+	dgrp_t block;
+	blk64_t blk;
+	int retval;
+	unsigned int i;
+	unsigned int groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
+
+	ret_gdp = (struct ext2_group_desc *)((char *)gdp + group * desc_size);
+
+	if (fs->first_meta_desc && group >= fs->first_meta_desc 
+	    && ret_gdp->bg_block_bitmap == 0) {
+		block = group / groups_per_block;
+		blk = ext2fs_descriptor_block_loc2(fs, fs->group_block, block);
+		dest = (char *) gdp + fs->blocksize * block;
+		retval = io_channel_read_blk64(fs->io, blk, 1, dest);
+		if (retval)
+			return NULL;
+
+		tmp_gdp = (struct ext2_group_desc *)dest;
+
+		for (i=0; i < groups_per_block; i++) {
+			/*
+			 * TDB: If recovery is from backup superblock, Clear
+			 * _UNININT flags & reset bg_itable_unused to zero
+			 */
+#ifdef WORDS_BIGENDIAN
+			ext2fs_swap_group_desc2(fs, tmp_gdp);
+#endif
+			if (fs->orig_super == 0 &&
+			    EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+			    EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+				ext2fs_bg_flags_clear(fs, block * groups_per_block + i, EXT2_BG_BLOCK_UNINIT);
+				ext2fs_bg_flags_clear(fs,  block * groups_per_block + i, EXT2_BG_INODE_UNINIT);
+				ext2fs_bg_itable_unused_set(fs,  block * groups_per_block + i, 0);
+				// The checksum will be reset later, but fix it here
+				// anyway to avoid printing a lot of spurious errors. 
+				ext2fs_group_desc_csum_set(fs,  block * groups_per_block + i);
+			}
+			tmp_gdp = (struct ext2_group_desc *)((char *)tmp_gdp + EXT2_DESC_SIZE(fs->super));
+		}
+	}
+	return ret_gdp;
 }
 
 /* Do the same but as an ext4 group desc for internal use here */
diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
index b255759..994b841 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -285,10 +285,8 @@  errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
 	__u32		feature_incompat;
 	struct ext2_super_block *super_shadow = 0;
 	struct ext2_group_desc *group_shadow = 0;
-#ifdef WORDS_BIGENDIAN
 	struct ext2_group_desc *gdp;
 	dgrp_t		j;
-#endif
 	char	*group_ptr;
 	blk64_t	old_desc_blocks;
 	struct ext2fs_numeric_progress_struct progress;
@@ -337,6 +335,11 @@  errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
 	}
 #else
 	super_shadow = fs->super;
+	/* make sure all in memory */
+	for (j = 0; j < fs->group_desc_count; j++) {
+		gdp = ext2fs_group_desc(fs, group_shadow, j);
+	}
+
 	group_shadow = ext2fs_group_desc(fs, fs->group_desc, 0);
 #endif
 
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 27a7d3a..4858684 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -202,6 +202,7 @@  struct ext4_group_desc
 #define EXT2_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not initialized */
 #define EXT2_BG_BLOCK_UNINIT	0x0002 /* Block bitmap not initialized */
 #define EXT2_BG_INODE_ZEROED	0x0004 /* On-disk itable initialized to zero */
+#define EXT2_BG_READ		0x0008 /* Block group was read from disk */
 
 /*
  * Data structures used by the directory indexing feature
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 8ff49ca..d23bd99 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -221,6 +221,9 @@  struct struct_ext2_filsys {
 	int				fragsize;
 	dgrp_t				group_desc_count;
 	unsigned long			desc_blocks;
+	blk64_t				group_block;
+	/* first meta descriptor block */
+	dgrp_t				first_meta_desc;
 	struct opaque_ext2_group_desc *	group_desc;
 	unsigned int			inode_blocks_per_group;
 	ext2fs_inode_bitmap		inode_map;
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
index ba39e01..12a3935 100644
--- a/lib/ext2fs/openfs.c
+++ b/lib/ext2fs/openfs.c
@@ -121,11 +121,9 @@  errcode_t ext2fs_open2(const char *name, const char *io_options,
 	blk64_t		group_block, blk;
 	char		*dest, *cp;
 	int		group_zero_adjust = 0;
-#ifdef WORDS_BIGENDIAN
 	unsigned int	groups_per_block;
 	struct ext2_group_desc *gdp;
 	int		j;
-#endif
 
 	EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
 
@@ -377,7 +375,7 @@  errcode_t ext2fs_open2(const char *name, const char *io_options,
 	}
 	fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
 					  EXT2_DESC_PER_BLOCK(fs->super));
-	retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
+	retval = ext2fs_get_arrayzero(fs->desc_blocks, fs->blocksize,
 				&fs->group_desc);
 	if (retval)
 		goto cleanup;
@@ -412,40 +410,27 @@  errcode_t ext2fs_open2(const char *name, const char *io_options,
 					     first_meta_bg, dest);
 		if (retval)
 			goto cleanup;
-#ifdef WORDS_BIGENDIAN
-		gdp = (struct ext2_group_desc *) dest;
 		for (j=0; j < groups_per_block*first_meta_bg; j++) {
 			gdp = ext2fs_group_desc(fs, fs->group_desc, j);
-			ext2fs_swap_group_desc2(fs, gdp);
-		}
-#endif
-		dest += fs->blocksize*first_meta_bg;
-	}
-	for (i=first_meta_bg ; i < fs->desc_blocks; i++) {
-		blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
-		retval = io_channel_read_blk64(fs->io, blk, 1, dest);
-		if (retval)
-			goto cleanup;
 #ifdef WORDS_BIGENDIAN
-		for (j=0; j < groups_per_block; j++) {
-			gdp = ext2fs_group_desc(fs, fs->group_desc,
-						i * groups_per_block + j);
 			ext2fs_swap_group_desc2(fs, gdp);
-		}
 #endif
-		dest += fs->blocksize;
+		}
+		dest += fs->blocksize*first_meta_bg;
 	}
 
+	fs->first_meta_desc = groups_per_block * first_meta_bg;
+	fs->group_block = group_block;
 	fs->stride = fs->super->s_raid_stride;
 
 	/*
 	 * If recovery is from backup superblock, Clear _UNININT flags &
 	 * reset bg_itable_unused to zero
 	 */
-	if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
+	if (first_meta_bg && superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
 		dgrp_t group;
 
-		for (group = 0; group < fs->group_desc_count; group++) {
+		for (group = 0; group < groups_per_block*first_meta_bg; group++) {
 			ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
 			ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
 			ext2fs_bg_itable_unused_set(fs, group, 0);