Skip to contentSkip to conversation

e2fsprogs-ibadness-counter.patch

PATCH In review Kalpak Shah 1 participant 1 message Oct 6, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 9/15 e2fsprogs-ibadness-counter.patch

The present e2fsck code checks the inode, per field basis. It doesn't take into consideration to total sanity of the inode. This may cause e2fsck turning a garbage inode into an apparently sane inode ("It is a vessel of fertilizer, and none may abide its strength.").

The following patch adds a heuristics to detect the degree of badness of an inode. icount mechanism is used to keep track of the badness of every inode. The badness is increased as various fields in inode are found to be corrupt. Badness above a certain threshold value results in deletion of the inode. The default threshold value is 7, it can be specified to e2fsck using "-E inode_badness_threshold=<value>"

This can avoid lengthy pass1b shared block processing, where a corrupt chunk of the inode table has resulted in a bunch of garbage inodes suddenly having shared blocks with a lot of good inodes (or each other).

The present e2fsck code checks the inode, per field basis. It doesn't take into consideration to total sanity of the inode. This may cause e2fsck turning a garbage inode into an apparently sane inode ("It is a vessel of fertilizer, and none may abide its strength.").

The following patch adds a heuristics to detect the degree of badness of an inode. icount mechanism is used to keep track of the badness of every inode. The badness is increased as various fields in inode are found to be corrupt. Badness above a certain threshold value results in deletion of the inode. The default threshold value is 7, it can be specified to e2fsck using "-E inode_badness_threshold=<value>"

This can avoid lengthy pass1b shared block processing, where a corrupt chunk of the inode table has resulted in a bunch of garbage inodes suddenly having shared blocks with a lot of good inodes (or each other).

e2fsck/e2fsck.h +18 -1
Index: e2fsprogs-1.41.1/e2fsck/e2fsck.h
===================================================================
@@ -11,6 +11,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stddef.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -198,6 +199,18 @@ typedef enum {
 	E2F_CLONE_ZERO
 } clone_opt_t;
 
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field)	\
+	((offsetof(typeof(*ext4_inode), field) +	\
+	  sizeof(ext4_inode->field))			\
+	<= (EXT2_GOOD_OLD_INODE_SIZE +			\
+	    (einode)->i_extra_isize))			\
+
+#define BADNESS_NORMAL 		1
+#define BADNESS_HIGH		2
+#define BADNESS_THRESHOLD	8
+#define BADNESS_BAD_MODE	100
+#define BADNESS_LARGE_FILE 	2199023255552ULL
+
 /*
  * Define the extended attribute refcount structure
  */
@@ -234,7 +247,6 @@ struct e2fsck_struct {
 			unsigned long max);
 
 	ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
-	ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
 	ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
 	ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
 	ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
@@ -249,6 +261,8 @@ struct e2fsck_struct {
 	 */
 	ext2_icount_t	inode_count;
 	ext2_icount_t inode_link_info;
+	ext2_icount_t inode_badness;
+	int inode_badness_threshold;
 
 	ext2_refcount_t	refcount;
 	ext2_refcount_t refcount_extra;
@@ -349,6 +363,7 @@ struct e2fsck_struct {
 	/* misc fields */
 	time_t now;
 	time_t time_fudge;	/* For working around buggy init scripts */
+	time_t now_tolerance_val;
 	int ext_attr_ver;
 	shared_opt_t shared;
 	clone_opt_t clone;
@@ -465,6 +480,8 @@ extern int e2fsck_pass1_check_symlink(ex
 extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
 			       struct ext2_inode *inode, int restart_flag,
 			       const char *source);
+extern void e2fsck_mark_inode_bad(e2fsck_t ctx, ino_t ino, int count);
+extern int is_inode_bad(e2fsck_t ctx, ino_t ino);
 
 /* pass2.c */
 extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
e2fsck/pass1.c +99 -33

302 lines not on this page · raw message

e2fsck/pass4.c +1 -0
Index: e2fsprogs-1.41.1/e2fsck/pass4.c
===================================================================
@@ -181,6 +181,7 @@ void e2fsck_pass4(e2fsck_t ctx)
 	}
 	ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
 	ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
+	ext2fs_free_icount(ctx->inode_badness); ctx->inode_badness = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_bb_map);
 	ctx->inode_bb_map = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
e2fsck/pass2.c +73 -19

208 lines not on this page · raw message

e2fsck/problem.c +5 -0
Index: e2fsprogs-1.41.1/e2fsck/problem.c
===================================================================
@@ -1354,6 +1354,11 @@ static struct e2fsck_problem problem_tab
 	  N_("@i %N found in @g %g unused inodes area.  "),
 	  PROMPT_FIX, PR_PREEN_OK },
 
+	/* Inode too bad */
+	{ PR_2_INODE_TOOBAD,
+	  N_("@i %i is badly corrupt (badness value = %N).  "),
+	  PROMPT_CLEAR, PR_PREEN_OK },
+
 	/* Pass 3 errors */
 
 	/* Pass 3: Checking directory connectivity */
e2fsck/problem.h +3 -0
Index: e2fsprogs-1.41.1/e2fsck/problem.h
===================================================================
@@ -814,6 +814,9 @@ struct problem_context {
 /* Inode found in group unused inodes area */
 #define PR_2_INOREF_IN_UNUSED		0x020047
 
+/* Inode completely corrupt */
+#define PR_2_INODE_TOOBAD		0x020048
+
 /*
  * Pass 3 errors
  */
lib/ext2fs/icount.c +17 -0
Index: e2fsprogs-1.41.1/lib/ext2fs/icount.c
===================================================================
@@ -467,6 +467,23 @@ static errcode_t get_inode_count(ext2_ic
 	return 0;
 }
 
+int ext2fs_icount_is_set(ext2_icount_t icount, ext2_ino_t ino)
+{
+	__u16 result;
+
+	if (ext2fs_test_inode_bitmap(icount->single, ino))
+		return 1;
+	else if (icount->multiple) {
+		if (ext2fs_test_inode_bitmap(icount->multiple, ino))
+			return 1;
+		return 0;
+	}
+	ext2fs_icount_fetch(icount, ino, &result);
+	if (result)
+		return 1;
+	return 0;
+}
+
 errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
 {
 	errcode_t	ret = 0;
e2fsck/pass1b.c +2 -2
Index: e2fsprogs-1.41.1/e2fsck/pass1b.c
===================================================================
@@ -612,8 +612,8 @@ static void delete_file(e2fsck_t ctx, ex
 						     block_buf, delete_file_block, &pb);
 	if (pctx.errcode)
 		fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
-	if (ctx->inode_bad_map)
-		ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+	if (ctx->inode_badness)
+		e2fsck_mark_inode_bad(ctx, ino, 0);
 	ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
 
 	/* Inode may have changed by block_iterate, so reread it */
e2fsck/unix.c +16 -0
Index: e2fsprogs-1.41.1/e2fsck/unix.c
===================================================================
@@ -650,6 +650,18 @@ static void parse_extended_opts(e2fsck_t
 				extended_usage++;
 				continue;
 			}
+		/* -E inode_badness_threshold=<value> */
+ 		} else if (strcmp(token, "inode_badness_threshold") == 0) {
+ 			if (!arg) {
+ 				extended_usage++;
+ 				continue;
+ 			}
+ 			ctx->inode_badness_threshold = strtoul(arg, &p, 0);
+			if (*p != '\0' || (ctx->inode_badness_threshold > 200)){
+				fprintf(stderr, _("Invalid badness value.\n"));
+				extended_usage++;
+				continue;
+			}
 		} else {
 			fprintf(stderr, _("Unknown extended option: %s\n"),
 				token);
@@ -668,6 +680,7 @@ static void parse_extended_opts(e2fsck_t
 		fputs(("\tshared=<preserve|lost+found|delete>\n"), stderr);
 		fputs(("\tclone=<dup|zero>\n"), stderr);
 		fputs(("\texpand_extra_isize\n"), stderr);
+		fputs(("\tinode_badness_threhold=(value)\n"), stderr);
 		fputc('\n', stderr);
 		exit(1);
 	}
@@ -732,6 +745,9 @@ static errcode_t PRS(int argc, char *arg
 	profile_init(config_fn, &ctx->profile);
 	initialize_profile_options(ctx);
 
+	ctx->inode_badness_threshold = BADNESS_THRESHOLD;
+	ctx->now_tolerance_val = 172800; /* Two days */
+
 	while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF)
 		switch (c) {
 		case 'C':
e2fsck/e2fsck.c +0 -4
Index: e2fsprogs-1.41.1/e2fsck/e2fsck.c
===================================================================
@@ -107,10 +107,6 @@ errcode_t e2fsck_reset_context(e2fsck_t 
 		ext2fs_free_inode_bitmap(ctx->inode_bb_map);
 		ctx->inode_bb_map = 0;
 	}
-	if (ctx->inode_bad_map) {
-		ext2fs_free_inode_bitmap(ctx->inode_bad_map);
-		ctx->inode_bad_map = 0;
-	}
 	if (ctx->inode_imagic_map) {
 		ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
 		ctx->inode_imagic_map = 0;
e2fsck/e2fsck.8.in +7 -0
Index: e2fsprogs-1.41.1/e2fsck/e2fsck.8.in
===================================================================
@@ -203,6 +203,13 @@ Set the version of the extended attribut
 will require while checking the filesystem.  The version number may 
 be 1 or 2.  The default extended attribute version format is 2.
 .TP
+.BI inode_badness_threshold= threshold_value
+A badness counter is associated with every inode, which determines the degree
+of inode corruption. Each error found in the inode will increase the badness by
+1 or 2, and inodes with a badness at or above
+.I threshold_value will be prompted for deletion. The default
+.I threshold_value is 7.
+.TP
 .BI fragcheck
 During pass 1, print a detailed report of any discontiguous blocks for
 files in the filesystem.
lib/ext2fs/ext2fs.h +1 -0
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2fs.h
===================================================================
@@ -974,6 +974,7 @@ extern errcode_t ext2fs_initialize(const
 
 /* icount.c */
 extern void ext2fs_free_icount(ext2_icount_t icount);
+extern int ext2fs_icount_is_set(ext2_icount_t icount, ext2_ino_t ino);
 extern errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
 					  int flags, ext2_icount_t *ret);
 extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags,
tests/f_messy_inode/expect.1 +5 -3
Index: e2fsprogs-1.41.1/tests/f_messy_inode/expect.1
===================================================================
@@ -20,19 +20,21 @@ Pass 2: Checking directory structure
 i_file_acl for inode 14 (/MAKEDEV) is 4294901760, should be zero.
 Clear? yes
 
+Inode 14 is badly corrupt (badness value = 13).  Clear? yes
+
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
 Block bitmap differences:  -(43--49)
 Fix? yes
 
-Free blocks count wrong for group #0 (68, counted=75).
+Free blocks count wrong for group #0 (70, counted=77).
 Fix? yes
 
-Free blocks count wrong (68, counted=75).
+Free blocks count wrong (70, counted=77).
 Fix? yes
 
 
 test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 29/32 files (3.4% non-contiguous), 25/100 blocks
+test_filesys: 28/32 files (3.6% non-contiguous), 23/100 blocks
 Exit status is 1
tests/f_messy_inode/expect.2 +1 -1
Index: e2fsprogs-1.41.1/tests/f_messy_inode/expect.2
===================================================================
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test_filesys: 29/32 files (0.0% non-contiguous), 25/100 blocks
+test_filesys: 28/32 files (0.0% non-contiguous), 23/100 blocks
 Exit status is 0