e2fsprogs-ibadness-counter.patch
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
@@ -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(exextern 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
@@ -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
@@ -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
@@ -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
@@ -467,6 +467,23 @@ static errcode_t get_inode_count(ext2_icreturn 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
@@ -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
@@ -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_tfputs (("\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 *argprofile_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
@@ -107,10 +107,6 @@ errcode_t e2fsck_reset_context(e2fsck_text2fs_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
@@ -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
@@ -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
@@ -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
@@ -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