Change e2fsck to use a red/black tree in pass1b, to remove O(n**2)

algorithms.  Makes e2fsck much, much faster in certain rare cases
where the filesystem is severely corrupted.
bitmap-optimize
Theodore Ts'o 2002-08-01 12:37:00 -04:00
parent fe4dd429dc
commit 838e773e7a
13 changed files with 1924 additions and 245 deletions

View File

@ -1,3 +1,13 @@
2002-08-01 Theodore Ts'o <tytso@mit.edu>
* dict.c, dict.h: New file from kazlib 1.20 which implements a
red-black tree
* pass1b.c: Massive changes to take advantage of dict.c. This
removes several O(n**2) algorithms from the rare case
where there are a large number of blocks claimed by
multiple inodes.
2002-07-24 Theodore Ts'o <tytso@mit.edu>
* e2fsck.8.in, e2fsck.h, pass3.c (e2fsck_pass3), unix.c, rehash.c:

View File

@ -54,13 +54,13 @@ PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) \
#
#MCHECK= -DMCHECK
OBJS= unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o pass3.o pass4.o \
OBJS= dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o pass3.o pass4.o \
pass5.o journal.o swapfs.o badblocks.o util.o dirinfo.o dx_dirinfo.o \
ehandler.o problem.o message.o recovery.o region.o revoke.o \
ea_refcount.o rehash.o $(MTRACE_OBJ)
PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
profiled/pass1.o profiled/pass1b.o \
PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
profiled/super.o profiled/pass1.o profiled/pass1b.o \
profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \
profiled/journal.o profiled/badblocks.o profiled/util.o \
profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.o \
@ -69,6 +69,7 @@ PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
profiled/ea_refcount.o profiled/rehash.o
SRCS= $(srcdir)/e2fsck.c \
$(srcdir)/dict.c \
$(srcdir)/super.c \
$(srcdir)/pass1.c \
$(srcdir)/pass1b.c \

1515
e2fsck/dict.c Normal file

File diff suppressed because it is too large Load Diff

144
e2fsck/dict.h Normal file
View File

@ -0,0 +1,144 @@
/*
* Dictionary Abstract Data Type
* Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
*
* Free Software License:
*
* All rights are reserved by the author, with the following exceptions:
* Permission is granted to freely reproduce and distribute this software,
* possibly in exchange for a fee, provided that this copyright notice appears
* intact. Permission is also granted to adapt this software to produce
* derivative works, as long as the modified versions carry this copyright
* notice and additional notices stating that the work has been modified.
* This source code may be translated into executable form and incorporated
* into proprietary software; there is no requirement for such software to
* contain a copyright notice related to this source.
*
* $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $
* $Name: kazlib_1_20 $
*/
#ifndef DICT_H
#define DICT_H
#include <limits.h>
#ifdef KAZLIB_SIDEEFFECT_DEBUG
#include "sfx.h"
#endif
/*
* Blurb for inclusion into C++ translation units
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned long dictcount_t;
#define DICTCOUNT_T_MAX ULONG_MAX
/*
* The dictionary is implemented as a red-black tree
*/
typedef enum { dnode_red, dnode_black } dnode_color_t;
typedef struct dnode_t {
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
struct dnode_t *dict_left;
struct dnode_t *dict_right;
struct dnode_t *dict_parent;
dnode_color_t dict_color;
const void *dict_key;
void *dict_data;
#else
int dict_dummy;
#endif
} dnode_t;
typedef int (*dict_comp_t)(const void *, const void *);
typedef dnode_t *(*dnode_alloc_t)(void *);
typedef void (*dnode_free_t)(dnode_t *, void *);
typedef struct dict_t {
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
dnode_t dict_nilnode;
dictcount_t dict_nodecount;
dictcount_t dict_maxcount;
dict_comp_t dict_compare;
dnode_alloc_t dict_allocnode;
dnode_free_t dict_freenode;
void *dict_context;
int dict_dupes;
#else
int dict_dummmy;
#endif
} dict_t;
typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
typedef struct dict_load_t {
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
dict_t *dict_dictptr;
dnode_t dict_nilnode;
#else
int dict_dummmy;
#endif
} dict_load_t;
extern dict_t *dict_create(dictcount_t, dict_comp_t);
extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *);
extern void dict_destroy(dict_t *);
extern void dict_free_nodes(dict_t *);
extern void dict_free(dict_t *);
extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t);
extern void dict_init_like(dict_t *, const dict_t *);
extern int dict_verify(dict_t *);
extern int dict_similar(const dict_t *, const dict_t *);
extern dnode_t *dict_lookup(dict_t *, const void *);
extern dnode_t *dict_lower_bound(dict_t *, const void *);
extern dnode_t *dict_upper_bound(dict_t *, const void *);
extern void dict_insert(dict_t *, dnode_t *, const void *);
extern dnode_t *dict_delete(dict_t *, dnode_t *);
extern int dict_alloc_insert(dict_t *, const void *, void *);
extern void dict_delete_free(dict_t *, dnode_t *);
extern dnode_t *dict_first(dict_t *);
extern dnode_t *dict_last(dict_t *);
extern dnode_t *dict_next(dict_t *, dnode_t *);
extern dnode_t *dict_prev(dict_t *, dnode_t *);
extern dictcount_t dict_count(dict_t *);
extern int dict_isempty(dict_t *);
extern int dict_isfull(dict_t *);
extern int dict_contains(dict_t *, dnode_t *);
extern void dict_allow_dupes(dict_t *);
extern int dnode_is_in_a_dict(dnode_t *);
extern dnode_t *dnode_create(void *);
extern dnode_t *dnode_init(dnode_t *, void *);
extern void dnode_destroy(dnode_t *);
extern void *dnode_get(dnode_t *);
extern const void *dnode_getkey(dnode_t *);
extern void dnode_put(dnode_t *, void *);
extern void dict_process(dict_t *, void *, dnode_process_t);
extern void dict_load_begin(dict_load_t *, dict_t *);
extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
extern void dict_load_end(dict_load_t *);
extern void dict_merge(dict_t *, dict_t *);
#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
#ifdef KAZLIB_SIDEEFFECT_DEBUG
#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
#else
#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount)
#endif
#define dict_count(D) ((D)->dict_nodecount)
#define dict_isempty(D) ((D)->dict_nodecount == 0)
#define dnode_get(N) ((N)->dict_data)
#define dnode_getkey(N) ((N)->dict_key)
#define dnode_put(N, X) ((N)->dict_data = (X))
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -36,48 +36,25 @@
#include "e2fsck.h"
#include "problem.h"
#include "dict.h"
/* Define an extension to the ext2 library's block count information */
#define BLOCK_COUNT_EXTATTR (-5)
/*
* This is structure is allocated for each time that a block is
* claimed by more than one file. So if a particular block is claimed
* by 3 files, then three copies of this structure will be allocated,
* one for each conflict.
*
* The linked list structure is as follows:
*
* dup_blk --> block #34 --> block #35 --> block #47
* inode #12 inode #14 inode #17
* num_bad = 3 num_bad = 2 num_bad = 2
* | | |
* V V V
* block #34 block #35 block #47
* inode #14 inode #15 inode #23
* |
* V
* block #34
* inode #15
*
* The num_bad field indicates how many inodes are sharing a
* particular block, and is only stored in the first element of the
* linked list for a particular block. As the block conflicts are
* resolved, num_bad is decremented; when it reaches 1, then we no
* longer need to worry about that block.
*/
struct dup_block {
blk_t block; /* Block number */
ext2_ino_t ino; /* Inode number */
int num_bad;
int flags;
/* Pointer to next dup record with different block */
struct dup_block *next_block;
/* Pointer to next dup record with different inode */
struct dup_block *next_inode;
struct block_el {
blk_t block;
struct block_el *next;
};
#define FLAG_EXTATTR (1)
struct inode_el {
ext2_ino_t inode;
struct inode_el *next;
};
struct dup_block {
int num_bad;
struct inode_el *inode_list;
};
/*
* This structure stores information about a particular inode which
@ -87,38 +64,129 @@ struct dup_block {
* of multiply-claimed blocks.
*/
struct dup_inode {
ext2_ino_t ino, dir;
ext2_ino_t dir;
int num_dupblocks;
struct ext2_inode inode;
struct dup_inode *next;
struct block_el *block_list;
};
static int process_pass1b_block(ext2_filsys fs, blk_t *blocknr,
e2_blkcnt_t blockcnt, blk_t ref_blk,
int ref_offset, void *priv_data);
static void delete_file(e2fsck_t ctx, struct dup_inode *dp,
char *block_buf);
static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf);
static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
struct dup_inode *dp, char *block_buf);
static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
struct dup_inode *dp, char* block_buf);
static int check_if_fs_block(e2fsck_t ctx, blk_t test_blk);
static void pass1b(e2fsck_t ctx, char *block_buf);
static void pass1c(e2fsck_t ctx, char *block_buf);
static void pass1d(e2fsck_t ctx, char *block_buf);
static struct dup_block *dup_blk = 0;
static struct dup_inode *dup_ino = 0;
static int dup_inode_count = 0;
static dict_t blk_dict, ino_dict;
static ext2fs_inode_bitmap inode_dup_map;
static int dict_int_cmp(const void *a, const void *b)
{
int ia, ib;
ia = (int) a;
ib = (int) b;
return (ia-ib);
}
/*
* Add a duplicate block record
*/
static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk_t blk,
struct ext2_inode *inode)
{
dnode_t *n;
struct dup_block *db;
struct dup_inode *di;
struct block_el *blk_el;
struct inode_el *ino_el;
n = dict_lookup(&blk_dict, (void *) blk);
if (n)
db = (struct dup_block *) dnode_get(n);
else {
db = (struct dup_block *) e2fsck_allocate_memory(ctx,
sizeof(struct dup_block), "duplicate block header");
db->num_bad = 0;
db->inode_list = 0;
dict_alloc_insert(&blk_dict, (void *) blk, db);
}
ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx,
sizeof(struct inode_el), "inode element");
ino_el->inode = ino;
ino_el->next = db->inode_list;
db->inode_list = ino_el;
db->num_bad++;
n = dict_lookup(&ino_dict, (void *) ino);
if (n)
di = (struct dup_inode *) dnode_get(n);
else {
di = (struct dup_inode *) e2fsck_allocate_memory(ctx,
sizeof(struct dup_inode), "duplicate inode header");
di->dir = (ino == EXT2_ROOT_INO) ? EXT2_ROOT_INO : 0 ;
di->num_dupblocks = 0;
di->block_list = 0;
di->inode = *inode;
dict_alloc_insert(&ino_dict, (void *) ino, di);
}
blk_el = (struct block_el *) e2fsck_allocate_memory(ctx,
sizeof(struct block_el), "block element");
blk_el->block = blk;
blk_el->next = di->block_list;
di->block_list = blk_el;
di->num_dupblocks++;
}
/*
* Free a duplicate inode record
*/
static void inode_dnode_free(dnode_t *node, void *context)
{
struct dup_inode *di;
struct block_el *p, *next;
di = (struct dup_inode *) dnode_get(node);
for (p = di->block_list; p; p = next) {
next = p->next;
free(p);
}
free(node);
}
/*
* Free a duplicate block record
*/
static void block_dnode_free(dnode_t *node, void *context)
{
struct dup_block *db;
struct inode_el *p, *next;
db = (struct dup_block *) dnode_get(node);
for (p = db->inode_list; p; p = next) {
next = p->next;
free(p);
}
free(node);
}
/*
* Main procedure for handling duplicate blocks
*/
void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
{
ext2_filsys fs = ctx->fs;
struct dup_block *p, *q, *next_p, *next_q;
struct dup_inode *r, *next_r;
struct problem_context pctx;
clear_problem_context(&pctx);
@ -130,6 +198,11 @@ void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
ctx->flags |= E2F_FLAG_ABORT;
return;
}
dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp);
dict_init(&blk_dict, DICTCOUNT_T_MAX, dict_int_cmp);
dict_set_allocator(&ino_dict, NULL, inode_dnode_free, NULL);
dict_set_allocator(&blk_dict, NULL, block_dnode_free, NULL);
pass1b(ctx, block_buf);
pass1c(ctx, block_buf);
@ -139,28 +212,18 @@ void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
* Time to free all of the accumulated data structures that we
* don't need anymore.
*/
ext2fs_free_inode_bitmap(inode_dup_map); inode_dup_map = 0;
ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0;
for (p = dup_blk; p; p = next_p) {
next_p = p->next_block;
for (q = p; q; q = next_q) {
next_q = q->next_inode;
ext2fs_free_mem((void **) &q);
}
}
for (r = dup_ino; r; r = next_r) {
next_r = r->next;
ext2fs_free_mem((void **) &r);
}
dict_free_nodes(&ino_dict);
dict_free_nodes(&blk_dict);
}
/*
* Scan the inodes looking for inodes that contain duplicate blocks.
*/
struct process_block_struct {
e2fsck_t ctx;
ext2_ino_t ino;
int dup_blocks;
e2fsck_t ctx;
struct ext2_inode *inode;
struct problem_context *pctx;
};
@ -171,10 +234,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
struct ext2_inode inode;
ext2_inode_scan scan;
struct process_block_struct pb;
struct dup_inode *dp;
struct dup_block *q, *r;
struct problem_context pctx;
int i, ea_flag;
clear_problem_context(&pctx);
@ -205,6 +265,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
pb.ino = ino;
pb.dup_blocks = 0;
pb.inode = &inode;
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
process_pass1b_block, &pb);
if (inode.i_file_acl)
@ -212,16 +273,8 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
BLOCK_COUNT_EXTATTR, 0, 0, &pb);
if (pb.dup_blocks) {
end_problem_latch(ctx, PR_LATCH_DBLOCK);
dp = (struct dup_inode *) e2fsck_allocate_memory(ctx,
sizeof(struct dup_inode),
"duplicate inode record");
dp->ino = ino;
dp->dir = 0;
dp->inode = inode;
dp->num_dupblocks = pb.dup_blocks;
dp->next = dup_ino;
dup_ino = dp;
if (ino != EXT2_BAD_INO)
if (ino >= EXT2_FIRST_INODE(fs->super) ||
ino == EXT2_ROOT_INO)
dup_inode_count++;
}
if (pctx.errcode)
@ -238,21 +291,6 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
}
ext2fs_close_inode_scan(scan);
e2fsck_use_inode_shortcuts(ctx, 0);
/*
* Set the num_bad field
*/
for (q = dup_blk; q; q = q->next_block) {
i = 0;
ea_flag = 0;
for (r = q; r; r = r->next_inode) {
if (r->flags & FLAG_EXTATTR) {
if (ea_flag++)
continue;
}
i++;
}
q->num_bad = i;
}
}
static int process_pass1b_block(ext2_filsys fs,
@ -263,7 +301,6 @@ static int process_pass1b_block(ext2_filsys fs,
void *priv_data)
{
struct process_block_struct *p;
struct dup_block *dp, *q;
e2fsck_t ctx;
if (HOLE_BLKADDR(*block_nr))
@ -271,37 +308,19 @@ static int process_pass1b_block(ext2_filsys fs,
p = (struct process_block_struct *) priv_data;
ctx = p->ctx;
if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
/* OK, this is a duplicate block */
if (p->ino != EXT2_BAD_INO) {
p->pctx->blk = *block_nr;
fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
}
p->dup_blocks++;
ext2fs_mark_block_bitmap(ctx->block_dup_map, *block_nr);
ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
dp = (struct dup_block *) e2fsck_allocate_memory(ctx,
sizeof(struct dup_block),
"duplicate block record");
dp->block = *block_nr;
dp->ino = p->ino;
dp->num_bad = 0;
dp->flags = (blockcnt == BLOCK_COUNT_EXTATTR) ?
FLAG_EXTATTR : 0;
q = dup_blk;
while (q) {
if (q->block == *block_nr)
break;
q = q->next_block;
}
if (q) {
dp->next_inode = q->next_inode;
q->next_inode = dp;
} else {
dp->next_block = dup_blk;
dup_blk = dp;
}
if (!ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr))
return 0;
/* OK, this is a duplicate block */
if (p->ino != EXT2_BAD_INO) {
p->pctx->blk = *block_nr;
fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
}
p->dup_blocks++;
ext2fs_mark_inode_bitmap(inode_dup_map, p->ino);
add_dupe(ctx, p->ino, *block_nr, p->inode);
return 0;
}
@ -323,6 +342,7 @@ static int search_dirent_proc(ext2_ino_t dir, int entry,
{
struct search_dir_struct *sd;
struct dup_inode *p;
dnode_t *n;
sd = (struct search_dir_struct *) priv_data;
@ -330,19 +350,14 @@ static int search_dirent_proc(ext2_ino_t dir, int entry,
/* Should abort this inode, but not everything */
return 0;
if (!dirent->inode || (entry < DIRENT_OTHER_FILE) ||
if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) ||
!ext2fs_test_inode_bitmap(inode_dup_map, dirent->inode))
return 0;
for (p = dup_ino; p; p = p->next) {
if ((p->ino >= sd->first_inode) &&
(p->ino == dirent->inode))
break;
}
if (!p || p->dir)
n = dict_lookup(&ino_dict, (void *) dirent->inode);
if (!n)
return 0;
p = (struct dup_inode *) dnode_get(n);
p->dir = dir;
sd->count--;
@ -353,8 +368,6 @@ static int search_dirent_proc(ext2_ino_t dir, int entry,
static void pass1c(e2fsck_t ctx, char *block_buf)
{
ext2_filsys fs = ctx->fs;
struct dup_inode *p;
int inodes_left = dup_inode_count;
struct search_dir_struct sd;
struct problem_context pctx;
@ -362,22 +375,11 @@ static void pass1c(e2fsck_t ctx, char *block_buf)
fix_problem(ctx, PR_1C_PASS_HEADER, &pctx);
/*
* First check to see if any of the inodes with dup blocks is
* a special inode. (Note that the bad block inode isn't
* counted.)
*/
for (p = dup_ino; p; p = p->next) {
if ((p->ino < EXT2_FIRST_INODE(fs->super)) &&
(p->ino != EXT2_BAD_INO))
inodes_left--;
}
/*
* Search through all directories to translate inodes to names
* (by searching for the containing directory for that inode.)
*/
sd.count = inodes_left;
sd.count = dup_inode_count;
sd.first_inode = EXT2_FIRST_INODE(fs->super);
sd.max_inode = fs->super->s_inodes_count;
ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf,
@ -387,48 +389,50 @@ static void pass1c(e2fsck_t ctx, char *block_buf)
static void pass1d(e2fsck_t ctx, char *block_buf)
{
ext2_filsys fs = ctx->fs;
struct dup_inode *p, *s;
struct dup_block *q, *r;
ext2_ino_t *shared;
struct dup_inode *p, *t;
struct dup_block *q;
ext2_ino_t *shared, ino;
int shared_len;
int i;
int file_ok;
int meta_data = 0;
struct problem_context pctx;
dnode_t *n, *m;
struct block_el *s;
struct inode_el *r;
clear_problem_context(&pctx);
fix_problem(ctx, PR_1D_PASS_HEADER, &pctx);
e2fsck_read_bitmaps(ctx);
pctx.num = dup_inode_count;
pctx.num = dup_inode_count; /* dict_count(&ino_dict); */
fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx);
shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
sizeof(ext2_ino_t) * dup_inode_count,
sizeof(ext2_ino_t) * dict_count(&ino_dict),
"Shared inode list");
for (p = dup_ino; p; p = p->next) {
for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) {
p = (struct dup_inode *) dnode_get(n);
shared_len = 0;
file_ok = 1;
if (p->ino == EXT2_BAD_INO)
ino = (ext2_ino_t) dnode_getkey(n);
if (ino == EXT2_BAD_INO)
continue;
/*
* Search through the duplicate records to see which
* inodes share blocks with this one
* Find all of the inodes which share blocks with this
* one. First we find all of the duplicate blocks
* belonging to this inode, and then search each block
* get the list of inodes, and merge them together.
*/
for (q = dup_blk; q; q = q->next_block) {
/*
* See if this block is used by this inode.
* If it isn't, continue.
*/
for (r = q; r; r = r->next_inode)
if (r->ino == p->ino)
break;
if (!r)
continue;
for (s = p->block_list; s; s = s->next) {
m = dict_lookup(&blk_dict, (void *) s->block);
if (!m)
continue; /* Should never happen... */
q = (struct dup_block *) dnode_get(m);
if (q->num_bad > 1)
file_ok = 0;
if (check_if_fs_block(ctx, q->block)) {
if (check_if_fs_block(ctx, s->block)) {
file_ok = 0;
meta_data = 1;
}
@ -439,14 +443,14 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
* if an inode is already in shared[], don't
* add it again.
*/
for (r = q; r; r = r->next_inode) {
if (r->ino == p->ino)
for (r = q->inode_list; r; r = r->next) {
if (r->inode == ino)
continue;
for (i = 0; i < shared_len; i++)
if (shared[i] == r->ino)
if (shared[i] == r->inode)
break;
if (i == shared_len) {
shared[shared_len++] = r->ino;
shared[shared_len++] = r->inode;
}
}
}
@ -455,7 +459,7 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
* Report the inode that we are working on
*/
pctx.inode = &p->inode;
pctx.ino = p->ino;
pctx.ino = ino;
pctx.dir = p->dir;
pctx.blkcount = p->num_dupblocks;
pctx.num = meta_data ? shared_len+1 : shared_len;
@ -467,17 +471,16 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx);
for (i = 0; i < shared_len; i++) {
for (s = dup_ino; s; s = s->next)
if (s->ino == shared[i])
break;
if (!s)
continue;
m = dict_lookup(&ino_dict, (void *) shared[i]);
if (!m)
continue; /* should never happen */
t = (struct dup_inode *) dnode_get(m);
/*
* Report the inode that we are sharing with
*/
pctx.inode = &s->inode;
pctx.ino = s->ino;
pctx.dir = s->dir;
pctx.inode = &t->inode;
pctx.ino = shared[i];
pctx.dir = t->dir;
fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
}
if (file_ok) {
@ -485,14 +488,14 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
continue;
}
if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
pctx.errcode = clone_file(ctx, p, block_buf);
pctx.errcode = clone_file(ctx, ino, p, block_buf);
if (pctx.errcode)
fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
else
continue;
}
if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
delete_file(ctx, p, block_buf);
delete_file(ctx, ino, p, block_buf);
else
ext2fs_unmark_valid(fs);
}
@ -503,12 +506,12 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
* Drop the refcount on the dup_block structure, and clear the entry
* in the block_dup_map if appropriate.
*/
static void decrement_badcount(e2fsck_t ctx, struct dup_block *p)
static void decrement_badcount(e2fsck_t ctx, blk_t block, struct dup_block *p)
{
p->num_bad--;
if (p->num_bad <= 0 ||
(p->num_bad == 1 && !check_if_fs_block(ctx, p->block)))
ext2fs_unmark_block_bitmap(ctx->block_dup_map, p->block);
(p->num_bad == 1 && !check_if_fs_block(ctx, block)))
ext2fs_unmark_block_bitmap(ctx->block_dup_map, block);
}
static int delete_file_block(ext2_filsys fs,
@ -520,6 +523,7 @@ static int delete_file_block(ext2_filsys fs,
{
struct process_block_struct *pb;
struct dup_block *p;
dnode_t *n;
e2fsck_t ctx;
pb = (struct process_block_struct *) priv_data;
@ -529,11 +533,10 @@ static int delete_file_block(ext2_filsys fs,
return 0;
if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
for (p = dup_blk; p; p = p->next_block)
if (p->block == *block_nr)
break;
if (p) {
decrement_badcount(ctx, p);
n = dict_lookup(&blk_dict, (void *) *block_nr);
if (n) {
p = (struct dup_block *) dnode_get(n);
decrement_badcount(ctx, *block_nr, p);
} else
com_err("delete_file_block", 0,
_("internal error; can't find dup_blk for %d\n"),
@ -546,7 +549,8 @@ static int delete_file_block(ext2_filsys fs,
return 0;
}
static void delete_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
struct dup_inode *dp, char* block_buf)
{
ext2_filsys fs = ctx->fs;
struct process_block_struct pb;
@ -554,29 +558,29 @@ static void delete_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
struct problem_context pctx;
clear_problem_context(&pctx);
pctx.ino = pb.ino = dp->ino;
pctx.ino = pb.ino = ino;
pb.dup_blocks = dp->num_dupblocks;
pb.ctx = ctx;
pctx.str = "delete_file";
pctx.errcode = ext2fs_block_iterate2(fs, dp->ino, 0, block_buf,
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
delete_file_block, &pb);
if (pctx.errcode)
fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, dp->ino);
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, dp->ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
if (ctx->inode_bad_map)
ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, dp->ino);
ext2fs_unmark_inode_bitmap(fs->inode_map, dp->ino);
ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
ext2fs_mark_ib_dirty(fs);
ext2fs_mark_bb_dirty(fs);
e2fsck_read_inode(ctx, dp->ino, &inode, "delete_file");
e2fsck_read_inode(ctx, ino, &inode, "delete_file");
inode.i_links_count = 0;
inode.i_dtime = time(0);
if (inode.i_file_acl)
delete_file_block(fs, &inode.i_file_acl,
BLOCK_COUNT_EXTATTR, 0, 0, &pb);
e2fsck_write_inode(ctx, dp->ino, &inode, "delete_file");
e2fsck_write_inode(ctx, ino, &inode, "delete_file");
}
struct clone_struct {
@ -597,6 +601,7 @@ static int clone_file_block(ext2_filsys fs,
blk_t new_block;
errcode_t retval;
struct clone_struct *cs = (struct clone_struct *) priv_data;
dnode_t *n;
e2fsck_t ctx;
ctx = cs->ctx;
@ -605,10 +610,9 @@ static int clone_file_block(ext2_filsys fs,
return 0;
if (ext2fs_test_block_bitmap(ctx->block_dup_map, *block_nr)) {
for (p = dup_blk; p; p = p->next_block)
if (p->block == *block_nr)
break;
if (p) {
n = dict_lookup(&blk_dict, (void *) *block_nr);
if (n) {
p = (struct dup_block *) dnode_get(n);
retval = ext2fs_new_block(fs, 0, ctx->block_found_map,
&new_block);
if (retval) {
@ -639,7 +643,7 @@ static int clone_file_block(ext2_filsys fs,
cs->errcode = retval;
return BLOCK_ABORT;
}
decrement_badcount(ctx, p);
decrement_badcount(ctx, *block_nr, p);
*block_nr = new_block;
ext2fs_mark_block_bitmap(ctx->block_found_map,
new_block);
@ -653,13 +657,18 @@ static int clone_file_block(ext2_filsys fs,
return 0;
}
static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
struct dup_inode *dp, char* block_buf)
{
ext2_filsys fs = ctx->fs;
errcode_t retval;
struct clone_struct cs;
struct problem_context pctx;
blk_t blk;
dnode_t *n;
struct inode_el *ino_el;
struct dup_block *db;
struct dup_inode *di;
clear_problem_context(&pctx);
cs.errcode = 0;
@ -669,12 +678,12 @@ static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
if (retval)
return retval;
if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dp->ino))
cs.dir = dp->ino;
if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, ino))
cs.dir = ino;
pctx.ino = dp->ino;
pctx.ino = ino;
pctx.str = "clone_file";
pctx.errcode = ext2fs_block_iterate2(fs, dp->ino, 0, block_buf,
pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf,
clone_file_block, &cs);
ext2fs_mark_bb_dirty(fs);
if (pctx.errcode) {
@ -692,31 +701,25 @@ static int clone_file(e2fsck_t ctx, struct dup_inode *dp, char* block_buf)
if (blk && (clone_file_block(fs, &dp->inode.i_file_acl,
BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
BLOCK_CHANGED)) {
struct dup_block *p, *q;
struct dup_inode *r;
e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
/*
* If we cloned the EA block, find all other inodes
* which refered to that EA block, and modify
* them to point to the new EA block.
*/
for (p = dup_blk; p; p = p->next_block) {
if (p->block == blk)
break;
}
for (q = p; q ; q = q->next_inode) {
if (!(q->flags & FLAG_EXTATTR))
n = dict_lookup(&blk_dict, (void *) blk);
db = (struct dup_block *) dnode_get(n);
for (ino_el = db->inode_list; ino_el; ino_el = ino_el->next) {
if (ino_el->inode == ino)
continue;
for (r = dup_ino; r; r = r->next)
if (r->ino == q->ino)
break;
if (r) {
r->inode.i_file_acl = dp->inode.i_file_acl;
e2fsck_write_inode(ctx, q->ino, &r->inode,
"clone file EA");
n = dict_lookup(&ino_dict, (void *) ino_el->inode);
di = (struct dup_inode *) dnode_get(n);
if (di->inode.i_file_acl == blk) {
di->inode.i_file_acl = dp->inode.i_file_acl;
e2fsck_write_inode(ctx, ino_el->inode,
&dp->inode, "clone file EA");
decrement_badcount(ctx, blk, db);
}
q->ino = 0; /* Should free the structure... */
decrement_badcount(ctx, p);
}
}
retval = 0;

View File

@ -1,3 +1,9 @@
2002-08-01 Theodore Ts'o <tytso@mit.edu>
* f_dup, f_dup2, f_dup3, f_bbfile, f_dupfsblks: Update expect
scripts to deal with ordering changes caused by use of a
red-block tree in pass1b.
2002-07-19 Theodore Ts'o <tytso@mit.edu>
* f_expand, f_h_badnode, f_h_badroot: Modify the expect scripts to

View File

@ -13,8 +13,8 @@ Pass 1C: Scan directories for inodes with dup blocks.
Pass 1D: Reconciling duplicate blocks
(There are 3 inodes containing duplicate/bad blocks.)
File /termcap (inode #12, mod time Sun Jan 2 08:29:13 1994)
has 2 duplicate block(s), shared with 1 file(s):
File / (inode #2, mod time Sun Jan 2 08:29:13 1994)
has 1 duplicate block(s), shared with 1 file(s):
<The bad blocks inode> (inode #1, mod time Sun Jul 17 00:47:58 1994)
Clone duplicate/bad blocks? yes
@ -23,8 +23,8 @@ File /lost+found (inode #11, mod time Sun Jan 2 08:28:40 1994)
<The bad blocks inode> (inode #1, mod time Sun Jul 17 00:47:58 1994)
Clone duplicate/bad blocks? yes
File / (inode #2, mod time Sun Jan 2 08:29:13 1994)
has 1 duplicate block(s), shared with 1 file(s):
File /termcap (inode #12, mod time Sun Jan 2 08:29:13 1994)
has 2 duplicate block(s), shared with 1 file(s):
<The bad blocks inode> (inode #1, mod time Sun Jul 17 00:47:58 1994)
Clone duplicate/bad blocks? yes

View File

@ -9,14 +9,14 @@ Pass 1C: Scan directories for inodes with dup blocks.
Pass 1D: Reconciling duplicate blocks
(There are 2 inodes containing duplicate/bad blocks.)
File /motd (inode #13, mod time Tue Sep 21 03:19:20 1993)
has 2 duplicate block(s), shared with 1 file(s):
/termcap (inode #12, mod time Tue Sep 21 03:19:14 1993)
Clone duplicate/bad blocks? yes
File /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993)
has 2 duplicate block(s), shared with 1 file(s):
/motd (inode #13, mod time Tue Sep 21 03:19:20 1993)
Clone duplicate/bad blocks? yes
File /motd (inode #13, mod time Tue Sep 21 03:19:20 1993)
has 2 duplicate block(s), shared with 1 file(s):
/termcap (inode #12, mod time Tue Sep 21 03:19:14 1993)
Duplicated blocks already reassigned or cloned.
Pass 2: Checking directory structure

View File

@ -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: 13/16 files (7.7% non-contiguous), 40/100 blocks
test_filesys: 13/16 files (15.4% non-contiguous), 40/100 blocks
Exit status is 0

View File

@ -10,7 +10,7 @@ Pass 1C: Scan directories for inodes with dup blocks.
Pass 1D: Reconciling duplicate blocks
(There are 3 inodes containing duplicate/bad blocks.)
File /pass1.c (inode #14, mod time Tue Sep 21 04:28:37 1993)
File /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993)
has 2 duplicate block(s), shared with 1 file(s):
/motd (inode #13, mod time Tue Sep 21 03:19:20 1993)
Clone duplicate/bad blocks? yes
@ -21,7 +21,7 @@ File /motd (inode #13, mod time Tue Sep 21 03:19:20 1993)
/termcap (inode #12, mod time Tue Sep 21 03:19:14 1993)
Clone duplicate/bad blocks? yes
File /termcap (inode #12, mod time Tue Sep 21 03:19:14 1993)
File /pass1.c (inode #14, mod time Tue Sep 21 04:28:37 1993)
has 2 duplicate block(s), shared with 1 file(s):
/motd (inode #13, mod time Tue Sep 21 03:19:20 1993)
Duplicated blocks already reassigned or cloned.

View File

@ -10,7 +10,7 @@ Pass 1C: Scan directories for inodes with dup blocks.
Pass 1D: Reconciling duplicate blocks
(There are 3 inodes containing duplicate/bad blocks.)
File /e2fsck (inode #16, mod time Tue Sep 21 04:32:22 1993)
File /lost+found (inode #11, mod time Mon Sep 20 03:26:36 1993)
has 2 duplicate block(s), shared with 0 file(s):
Clone duplicate/bad blocks? yes
@ -18,7 +18,7 @@ File /pass1.c (inode #14, mod time Tue Sep 21 04:28:37 1993)
has 2 duplicate block(s), shared with 0 file(s):
Clone duplicate/bad blocks? yes
File /lost+found (inode #11, mod time Mon Sep 20 03:26:36 1993)
File /e2fsck (inode #16, mod time Tue Sep 21 04:32:22 1993)
has 2 duplicate block(s), shared with 0 file(s):
Clone duplicate/bad blocks? yes

View File

@ -14,8 +14,8 @@ Pass 1C: Scan directories for inodes with dup blocks.
Pass 1D: Reconciling duplicate blocks
(There are 3 inodes containing duplicate/bad blocks.)
File /quux (inode #14, mod time Thu Aug 5 07:18:09 1999)
has 1 duplicate block(s), shared with 2 file(s):
File /foo (inode #12, mod time Thu Apr 28 17:57:53 1994)
has 4 duplicate block(s), shared with 2 file(s):
<filesystem metadata>
/bar (inode #13, mod time Thu Aug 5 07:17:17 1999)
Clone duplicate/bad blocks? yes
@ -23,12 +23,12 @@ Clone duplicate/bad blocks? yes
File /bar (inode #13, mod time Thu Aug 5 07:17:17 1999)
has 2 duplicate block(s), shared with 3 file(s):
<filesystem metadata>
/quux (inode #14, mod time Thu Aug 5 07:18:09 1999)
/foo (inode #12, mod time Thu Apr 28 17:57:53 1994)
/quux (inode #14, mod time Thu Aug 5 07:18:09 1999)
Clone duplicate/bad blocks? yes
File /foo (inode #12, mod time Thu Apr 28 17:57:53 1994)
has 4 duplicate block(s), shared with 2 file(s):
File /quux (inode #14, mod time Thu Aug 5 07:18:09 1999)
has 1 duplicate block(s), shared with 2 file(s):
<filesystem metadata>
/bar (inode #13, mod time Thu Aug 5 07:17:17 1999)
Clone duplicate/bad blocks? yes

View File

@ -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: 14/32 files (7.1% non-contiguous), 30/100 blocks
test_filesys: 14/32 files (0.0% non-contiguous), 30/100 blocks
Exit status is 0