Add initial support for htree directories.

bitmap-optimize
Theodore Ts'o 2002-06-25 23:26:34 -04:00
parent 88372d5c4b
commit 8fdc9985c1
27 changed files with 936 additions and 202 deletions

View File

@ -1,4 +1,8 @@
2002-05-24 <tytso@snap.thunk.org>
2002-06-25 Theodore Ts'o <tytso@mit.edu>
* configure.in, configure: Add --enable-htree and --enable-clear-htree
2002-05-24 Theodore Ts'o <tytso@mit.edu>
* configure.in: Add makefile for lib/evms for the EVMS FSIM
plugin. Add --enable-old-evms configure option which uses

435
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -125,6 +125,45 @@ fi
echo "Disabling compression support by default"
)
dnl
dnl handle --enable-htree
dnl
AC_ARG_ENABLE([htree],
[ --enable-htree enable EXPERIMENTAL htree directory support],
if test "$enableval" = "no"
then
HTREE_CMT=#
echo "Disabling htree directory support"
else
HTREE_CMT=
AC_DEFINE(ENABLE_HTREE)
echo "Enabling htree directory support"
echo "WARNING: htree support is experimental"
fi
,
HTREE_CMT=#
echo "Disabling htree directory support by default"
)
AC_SUBST(HTREE_CMT)
dnl
dnl handle --enable-clear-htree
dnl
AC_ARG_ENABLE([htree-clear],
[ --enable-htree-clear clear htree because we don't trust e2fsck],
if test "$enableval" = "no"
then
HTREE_CLR_CMT=#
echo "Disabling htree clearing"
else
HTREE_CLR_CMT=
AC_DEFINE(ENABLE_HTREE_CLEAR)
echo "Enabling htree clearing"
fi
,
HTREE_CLR_CMT=#
echo "Disabling htree clearing by default"
)
AC_SUBST(HTREE_CLR_CMT)
dnl
dnl handle --enable-old-evms
dnl
AC_ARG_ENABLE([old-evms],

View File

@ -1,3 +1,30 @@
2002-06-25 Theodore Ts'o <tytso@mit.edu>
* e2fsck.c (e2fsck_reset_context): Free the dx_dirinfo structure.
* message.c: Add new abbrevations @h and @p, "HTREE directory
inode" and "problem in".
* pass1.c (check_blocks): If the inode has the INDEX_FL flag,
register the block into the indexed directory data
structures. Or if the filesystem doesn't have the
DIR_INDEX flag, offer to clear the INDEX_FL.
* pass2.c (e2fsck_pass2, parse_int_node): Add support check htree
directories (we don't check all possible corruptions yet).
* problem.h, problem.h (PR_1_HTREE_SET, PR_2_HTREE_NOTREF,
PR_2_HTREE_DUPREF, PR_2_HTREE_MIN_HASH, PR_2_HTREE_MAX_HASH,
PR_2_HTREE_CLEAR, PR_2_HTREE_FCLR, PR_2_HTREE_BADBLK): Add
new problem codes.
* unix.c (main): If ENABLE_HTREE is not defined, complain if the
filesystem has the dir_index feature.
* Makefile.in, e2fsck.h, dx_dirinfo.c: New file (and group of
functions) which keeps track of blocks in HTREE directory
blocks.
2002-05-22 Andreas Dilger <adilger@clusterfs.com>
* super.c (check_superblock): Check that the number of inodes and

View File

@ -55,17 +55,18 @@ 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 \
pass5.o journal.o swapfs.o badblocks.o util.o dirinfo.o ehandler.o \
problem.o message.o recovery.o region.o revoke.o ea_refcount.o \
$(MTRACE_OBJ)
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 $(MTRACE_OBJ)
PROFILED_OBJS= 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/ehandler.o profiled/message.o \
profiled/problem.o profiled/swapfs.o profiled/recovery.o \
profiled/region.o profiled/revoke.o profiled/ea_refcount.o
profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.o \
profiled/message.o profiled/problem.o profiled/swapfs.o \
profiled/recovery.o profiled/region.o profiled/revoke.o \
profiled/ea_refcount.o
SRCS= $(srcdir)/e2fsck.c \
$(srcdir)/super.c \
@ -82,6 +83,7 @@ SRCS= $(srcdir)/e2fsck.c \
$(srcdir)/util.c \
$(srcdir)/unix.c \
$(srcdir)/dirinfo.c \
$(srcdir)/dx_dirinfo.c \
$(srcdir)/ehandler.c \
$(srcdir)/problem.c \
$(srcdir)/message.c \

150
e2fsck/dx_dirinfo.c Normal file
View File

@ -0,0 +1,150 @@
/*
* dirinfo.c --- maintains the directory information table for e2fsck.
*
* Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
* under the terms of the GNU Public License.
*/
#include "e2fsck.h"
#ifdef ENABLE_HTREE
/*
* This subroutine is called during pass1 to create a directory info
* entry. During pass1, the passed-in parent is 0; it will get filled
* in during pass2.
*/
void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
{
struct dx_dir_info *dir;
int i, j;
errcode_t retval;
unsigned long old_size;
#if 0
printf("add_dx_dir_info for inode %lu...\n", ino);
#endif
if (!ctx->dx_dir_info) {
ctx->dx_dir_info_count = 0;
ctx->dx_dir_info_size = 100; /* Guess */
ctx->dx_dir_info = (struct dx_dir_info *)
e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size
* sizeof (struct dx_dir_info),
"directory map");
}
if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) {
old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info);
ctx->dx_dir_info_size += 10;
retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size *
sizeof(struct dx_dir_info),
(void **) &ctx->dx_dir_info);
if (retval) {
ctx->dx_dir_info_size -= 10;
return;
}
}
/*
* Normally, add_dx_dir_info is called with each inode in
* sequential order; but once in a while (like when pass 3
* needs to recreate the root directory or lost+found
* directory) it is called out of order. In those cases, we
* need to move the dx_dir_info entries down to make room, since
* the dx_dir_info array needs to be sorted by inode number for
* get_dx_dir_info()'s sake.
*/
if (ctx->dx_dir_info_count &&
ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) {
for (i = ctx->dx_dir_info_count-1; i > 0; i--)
if (ctx->dx_dir_info[i-1].ino < ino)
break;
dir = &ctx->dx_dir_info[i];
if (dir->ino != ino)
for (j = ctx->dx_dir_info_count++; j > i; j--)
ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1];
} else
dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++];
dir->ino = ino;
dir->numblocks = num_blocks;
dir->hashversion = 0;
dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
* sizeof (struct dx_dirblock_info),
"dx_block info array");
}
/*
* get_dx_dir_info() --- given an inode number, try to find the directory
* information entry for it.
*/
struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino)
{
int low, high, mid;
low = 0;
high = ctx->dx_dir_info_count-1;
if (!ctx->dx_dir_info)
return 0;
if (ino == ctx->dx_dir_info[low].ino)
return &ctx->dx_dir_info[low];
if (ino == ctx->dx_dir_info[high].ino)
return &ctx->dx_dir_info[high];
while (low < high) {
mid = (low+high)/2;
if (mid == low || mid == high)
break;
if (ino == ctx->dx_dir_info[mid].ino)
return &ctx->dx_dir_info[mid];
if (ino < ctx->dx_dir_info[mid].ino)
high = mid;
else
low = mid;
}
return 0;
}
/*
* Free the dx_dir_info structure when it isn't needed any more.
*/
void e2fsck_free_dx_dir_info(e2fsck_t ctx)
{
int i;
struct dx_dir_info *dir;
if (ctx->dx_dir_info) {
dir = ctx->dx_dir_info;
for (i=0; i < ctx->dx_dir_info_count; i++) {
if (dir->dx_block) {
ext2fs_free_mem((void **) &dir->dx_block);
dir->dx_block = 0;
}
}
ext2fs_free_mem((void **) &ctx->dx_dir_info);
ctx->dx_dir_info = 0;
}
ctx->dx_dir_info_size = 0;
ctx->dx_dir_info_count = 0;
}
/*
* Return the count of number of directories in the dx_dir_info structure
*/
int e2fsck_get_num_dx_dirinfo(e2fsck_t ctx)
{
return ctx->dx_dir_info_count;
}
/*
* A simple interator function
*/
struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control)
{
if (*control >= ctx->dx_dir_info_count)
return 0;
return(ctx->dx_dir_info + (*control)++);
}
#endif /* ENABLE_HTREE */

View File

@ -72,6 +72,9 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
ctx->fs->dblist = 0;
}
e2fsck_free_dir_info(ctx);
#ifdef ENABLE_HTREE
e2fsck_free_dx_dir_info(ctx);
#endif
if (ctx->refcount) {
ea_refcount_free(ctx->refcount);
ctx->refcount = 0;

View File

@ -77,6 +77,40 @@ struct dir_info {
ext2_ino_t parent; /* Parent according to treewalk */
};
/*
* The indexed directory information structure; stores information for
* directories which contain a hash tree index.
*/
struct dx_dir_info {
ext2_ino_t ino; /* Inode number */
int numblocks; /* number of blocks */
int hashversion;
struct dx_dirblock_info *dx_block; /* Array of size numblocks */
};
#define DX_DIRBLOCK_ROOT 1
#define DX_DIRBLOCK_LEAF 2
#define DX_DIRBLOCK_NODE 3
#define DX_DIRBLOCK_CORRUPT 4
#define DX_DIRBLOCK_CLEARED 8
struct dx_dirblock_info {
int type;
blk_t phys;
int flags;
blk_t parent;
ext2_dirhash_t min_hash;
ext2_dirhash_t max_hash;
ext2_dirhash_t node_min_hash;
ext2_dirhash_t node_max_hash;
};
#define DX_FLAG_REFERENCED 1
#define DX_FLAG_DUP_REF 2
#define DX_FLAG_FIRST 4
#define DX_FLAG_LAST 8
#ifdef RESOURCE_TRACK
/*
* This structure is used for keeping track of how much resources have
@ -207,6 +241,13 @@ struct e2fsck_struct {
int dir_info_size;
struct dir_info *dir_info;
/*
* Indexed directory information
*/
int dx_dir_info_count;
int dx_dir_info_size;
struct dx_dir_info *dx_dir_info;
/*
* Tuning parameters
*/
@ -292,10 +333,16 @@ extern void test_disk(e2fsck_t ctx);
extern void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
extern struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino);
extern void e2fsck_free_dir_info(e2fsck_t ctx);
extern int e2fsck_get_num_dirs(e2fsck_t ctx);
extern int e2fsck_get_num_dirinfo(e2fsck_t ctx);
extern struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control);
/* dx_dirinfo.c */
extern void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks);
extern struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino);
extern void e2fsck_free_dx_dir_info(e2fsck_t ctx);
extern int e2fsck_get_num_dx_dirinfo(e2fsck_t ctx);
extern struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control);
/* ea_refcount.c */
extern errcode_t ea_refcount_create(int size, ext2_refcount_t *ret);
extern void ea_refcount_free(ext2_refcount_t refcount);

View File

@ -63,12 +63,14 @@
* @f filesystem
* @F for @i %i (%Q) is
* @g group
* @h HTREE directory inode
* @i inode
* @I illegal
* @j journal
* @l lost+found
* @L is a link
* @o orphaned
* @p problem in
* @r root inode
* @s should be
* @S superblock
@ -116,9 +118,11 @@ static const char *abbrevs[] = {
N_("ffilesystem"),
N_("Ffor @i %i (%Q) is"),
N_("ggroup"),
N_("hHTREE @d @i"),
N_("llost+found"),
N_("Lis a link"),
N_("oorphaned"),
N_("pproblem in"),
N_("rroot @i"),
N_("sshould be"),
N_("Ssuper@b"),

View File

@ -1208,6 +1208,22 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
ctx->flags |= E2F_FLAG_RESTART;
return;
}
if (inode->i_flags & EXT2_INDEX_FL) {
if (fs->super->s_feature_compat &
EXT2_FEATURE_COMPAT_DIR_INDEX) {
#ifdef ENABLE_HTREE
e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
#endif
} else {
if (fix_problem(ctx, PR_1_HTREE_SET, pctx)) {
inode->i_flags &= ~EXT2_INDEX_FL;
e2fsck_write_inode(ctx, ino, inode,
"check_blocks");
}
}
}
if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
pb.num_blocks++;

View File

@ -50,6 +50,8 @@
#define _INLINE_ inline
#endif
#undef DX_DEBUG
/*
* Keeps track of how many times an inode is referenced.
*/
@ -66,6 +68,7 @@ static int update_dir_block(ext2_filsys fs,
blk_t ref_block,
int ref_offset,
void *priv_data);
static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
struct check_dir_struct {
char *buf;
@ -85,7 +88,13 @@ void e2fsck_pass2(e2fsck_t ctx)
#endif
struct dir_info *dir;
struct check_dir_struct cd;
struct dx_dir_info *dx_dir;
struct dx_dirblock_info *dx_db, *dx_parent;
blk_t b;
int i;
problem_t code;
int bad_dir;
#ifdef RESOURCE_TRACK
init_resource_track(&rtrack);
#endif
@ -136,7 +145,93 @@ void e2fsck_pass2(e2fsck_t ctx)
ctx->flags |= E2F_FLAG_ABORT;
return;
}
#ifdef ENABLE_HTREE
for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
if (dx_dir->ino == 0)
continue;
clear_problem_context(&pctx);
bad_dir = 0;
pctx.dir = dx_dir->ino;
dx_db = dx_dir->dx_block;
if (dx_db->flags & DX_FLAG_REFERENCED)
dx_db->flags |= DX_FLAG_DUP_REF;
else
dx_db->flags |= DX_FLAG_REFERENCED;
/*
* Find all of the first and last leaf blocks, and
* update their parent's min and max hash values
*/
for (b=0, dx_db = dx_dir->dx_block;
b < dx_dir->numblocks;
b++, dx_db++) {
if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
!(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
continue;
dx_parent = &dx_dir->dx_block[dx_db->parent];
/*
* XXX Make sure dx_parent->min_hash > dx_db->min_hash
*/
if (dx_db->flags & DX_FLAG_FIRST)
dx_parent->min_hash = dx_db->min_hash;
/*
* XXX Make sure dx_parent->max_hash < dx_db->max_hash
*/
if (dx_db->flags & DX_FLAG_LAST)
dx_parent->max_hash = dx_db->max_hash;
}
for (b=0, dx_db = dx_dir->dx_block;
b < dx_dir->numblocks;
b++, dx_db++) {
pctx.blkcount = b;
pctx.group = dx_db->parent;
code = 0;
if (!(dx_db->flags & DX_FLAG_FIRST) &&
(dx_db->min_hash < dx_db->node_min_hash)) {
pctx.blk = dx_db->min_hash;
pctx.blk2 = dx_db->node_min_hash;
code = PR_2_HTREE_MIN_HASH;
fix_problem(ctx, code, &pctx);
bad_dir++;
}
/*
* This test doesn't apply for the root block
* at block #0
*/
if (b &&
(dx_db->max_hash > dx_db->node_max_hash)) {
pctx.blk = dx_db->max_hash;
pctx.blk2 = dx_db->node_max_hash;
code = PR_2_HTREE_MAX_HASH;
fix_problem(ctx, code, &pctx);
}
if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
code = PR_2_HTREE_NOTREF;
fix_problem(ctx, code, &pctx);
bad_dir++;
} else if (dx_db->flags & DX_FLAG_DUP_REF) {
code = PR_2_HTREE_DUPREF;
fix_problem(ctx, code, &pctx);
bad_dir++;
}
if (code == 0)
continue;
}
if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
clear_htree(ctx, dx_dir->ino);
dx_dir->ino = 0;
break;
}
#ifdef ENABLE_HTREE_CLEAR
if (dx_dir->ino) {
fix_problem(ctx, PR_2_HTREE_FCLR, &pctx);
clear_htree(ctx, dx_dir->ino);
dx_dir->ino = 0;
}
#endif
}
#endif
ext2fs_free_mem((void **) &buf);
ext2fs_free_dblist(fs->dblist);
@ -353,13 +448,107 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
return 1;
}
#ifdef ENABLE_HTREE
static void parse_int_node(ext2_filsys fs,
struct ext2_db_entry *db,
struct check_dir_struct *cd,
struct dx_dir_info *dx_dir,
char *block_buf)
{
struct ext2_dx_root_info *root;
struct ext2_dx_entry *ent;
struct ext2_dx_countlimit *limit;
struct dx_dirblock_info *dx_db;
int i;
blk_t blk;
ext2_dirhash_t min_hash = 0xffffffff;
ext2_dirhash_t max_hash = 0;
ext2_dirhash_t hash = 0;
if (db->blockcnt == 0) {
root = (struct ext2_dx_root_info *) (block_buf + 24);
#ifdef DX_DEBUG
printf("Root node dump:\n");
printf("\t Reserved zero: %d\n", root->reserved_zero);
printf("\t Hash Version: %d\n", root->hash_version);
printf("\t Info length: %d\n", root->info_length);
printf("\t Indirect levels: %d\n", root->indirect_levels);
printf("\t Flags: %d\n", root->unused_flags);
#endif
ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
} else {
ent = (struct ext2_dx_entry *) (block_buf+8);
}
limit = (struct ext2_dx_countlimit *) ent;
#ifdef DX_DEBUG
printf("Number of entries (count): %d\n", limit->count);
printf("Number of entries (limit): %d\n", limit->limit);
#endif
for (i=0; i < limit->count; i++) {
hash = i ? (ent[i].hash & ~1) : 0;
/*
* XXX Check to make make sure the hash[i] < hash[i+1]
*/
#ifdef DX_DEBUG
printf("Entry #%d: Hash 0x%08x, block %d\n", i,
hash, ent[i].block);
#endif
blk = ent[i].block & 0x0ffffff;
/* Check to make sure the block is valid */
if (blk > dx_dir->numblocks) {
if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
cd->pctx)) {
clear_htree(cd->ctx, cd->pctx.ino);
dx_dir->ino = 0;
return;
}
}
dx_db = &dx_dir->dx_block[blk];
if (dx_db->flags & DX_FLAG_REFERENCED) {
dx_db->flags |= DX_FLAG_DUP_REF;
} else {
dx_db->flags |= DX_FLAG_REFERENCED;
dx_db->parent = db->blockcnt;
}
if (hash < min_hash)
min_hash = hash;
if (hash > max_hash)
max_hash = hash;
dx_db->node_min_hash = hash;
if ((i+1) < limit->count)
dx_db->node_max_hash = (ent[i+1].hash & ~1);
else {
dx_db->node_max_hash = 0xfffffffe;
dx_db->flags |= DX_FLAG_LAST;
}
if (i == 0)
dx_db->flags |= DX_FLAG_FIRST;
}
#ifdef DX_DEBUG
printf("Blockcnt = %d, min hash 0x%08x, max hash 0x%08x\n",
db->blockcnt, min_hash, max_hash);
#endif
dx_db = &dx_dir->dx_block[db->blockcnt];
dx_db->min_hash = min_hash;
dx_db->max_hash = max_hash;
}
#endif /* ENABLE_HTREE */
static int check_dir_block(ext2_filsys fs,
struct ext2_db_entry *db,
void *priv_data)
{
struct dir_info *subdir, *dir;
struct dx_dir_info *dx_dir;
#ifdef ENABLE_HTREE
struct dx_dirblock_info *dx_db = 0;
#endif /* ENABLE_HTREE */
struct ext2_dir_entry *dirent;
ext2_dirhash_t hash;
int offset = 0;
int dir_modified = 0;
int dot_state;
@ -419,6 +608,32 @@ static int check_dir_block(ext2_filsys fs,
}
memset(buf, 0, fs->blocksize);
}
#ifdef ENABLE_HTREE
dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
if (dx_dir && dx_dir->ino) {
if (db->blockcnt >= dx_dir->numblocks) {
printf("XXX should never happen!!!\n");
abort();
}
dx_db = &dx_dir->dx_block[db->blockcnt];
dx_db->type = DX_DIRBLOCK_LEAF;
dx_db->phys = block_nr;
dx_db->min_hash = ~0;
dx_db->max_hash = 0;
dirent = (struct ext2_dir_entry *) buf;
/*
* XXX we need to check to make sure the root
* directory block is actually valid!
*/
if (db->blockcnt == 0) {
dx_db->type = DX_DIRBLOCK_ROOT;
dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
} else if ((dirent->inode == 0) &&
(dirent->rec_len == fs->blocksize))
dx_db->type = DX_DIRBLOCK_NODE;
}
#endif /* ENABLE_HTREE */
do {
dot_state++;
@ -563,6 +778,17 @@ static int check_dir_block(ext2_filsys fs,
if (check_filetype(ctx, dirent, ino, &cd->pctx))
dir_modified++;
#ifdef ENABLE_HTREE
if (dx_db) {
ext2fs_dirhash(dx_dir->hashversion, dirent->name,
(dirent->name_len & 0xFF), &hash);
if (hash < dx_db->min_hash)
dx_db->min_hash = hash;
if (hash > dx_db->max_hash)
dx_db->max_hash = hash;
}
#endif
/*
* If this is a directory, then mark its parent in its
* dir_info structure. If the parent field is already
@ -604,6 +830,18 @@ static int check_dir_block(ext2_filsys fs,
#if 0
printf("\n");
#endif
#ifdef ENABLE_HTREE
if (dx_db) {
#ifdef DX_DEBUG
printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
db->blockcnt, dx_db->type,
dx_db->min_hash, dx_db->max_hash);
#endif
if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
(dx_db->type == DX_DIRBLOCK_NODE))
parse_int_node(fs, db, cd, dx_dir, buf);
}
#endif /* ENABLE_HTREE */
if (offset != fs->blocksize) {
cd->pctx.num = dirent->rec_len - fs->blocksize + offset;
if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
@ -696,6 +934,20 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
}
}
/*
* This fuction clears the htree flag on an inode
*/
static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
{
struct ext2_inode inode;
struct problem_context pctx;
e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
}
extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
ext2_ino_t ino, char *buf)
{

View File

@ -665,6 +665,11 @@ static const struct e2fsck_problem problem_table[] = {
N_("@b #%B (%b) causes symlink to be too big. "),
PROMPT_CLEAR, PR_LATCH_TOOBIG },
/* INDEX_FL flag set on a non-HTREE filesystem */
{ PR_1_HTREE_SET,
N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
PROMPT_CLEAR, 0 },
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
@ -984,6 +989,40 @@ static const struct e2fsck_problem problem_table[] = {
N_("@f contains large files, but lacks LARGE_FILE flag in @S.\n"),
PROMPT_FIX, 0 },
/* Node in HTREE directory not referenced */
{ PR_2_HTREE_NOTREF,
N_("@p @h %d: node (%B) not referenced\n"),
PROMPT_NONE, 0 },
/* Node in HTREE directory referenced twice */
{ PR_2_HTREE_DUPREF,
N_("@p @h %d: node (%B) referenced twice\n"),
PROMPT_NONE, 0 },
/* Node in HTREE directory has bad min hash */
{ PR_2_HTREE_MIN_HASH,
N_("@p @h %d: node (%B) has bad min hash\n"),
PROMPT_NONE, 0 },
/* Node in HTREE directory has bad max hash */
{ PR_2_HTREE_MAX_HASH,
N_("@p @h %d: node (%B) has bad max hash\n"),
PROMPT_NONE, 0 },
/* Clear invalid HTREE directory */
{ PR_2_HTREE_CLEAR,
N_("Invalid @h %d (%q). "), PROMPT_CLEAR, 0 },
/* Clear the htree flag forcibly */
{ PR_2_HTREE_FCLR,
N_("Forcibly clearing HTREE flag on @i %d (%q). (Beta test code)\n"),
PROMPT_NONE, 0 },
/* Bad block in htree interior node */
{ PR_2_HTREE_BADBLK,
N_("@p @h %d (%q): bad @b number %B.\n"),
PROMPT_CLEAR, 0 },
/* Pass 3 errors */
/* Pass 3: Checking directory connectivity */

View File

@ -385,6 +385,9 @@ struct problem_context {
/* Symlink too big */
#define PR_1_TOOBIG_SYMLINK 0x010046
/* INDEX_FL flag set on a non-HTREE filesystem */
#define PR_1_HTREE_SET 0x010047
/*
* Pass 1b errors
*/
@ -584,6 +587,27 @@ struct problem_context {
/* Filesystem contains large files, but has no such flag in sb */
#define PR_2_FEATURE_LARGE_FILES 0x020033
/* Node in HTREE directory not referenced */
#define PR_2_HTREE_NOTREF 0x020034
/* Node in HTREE directory referenced twice */
#define PR_2_HTREE_DUPREF 0x020035
/* Node in HTREE directory has bad min hash */
#define PR_2_HTREE_MIN_HASH 0x020036
/* Node in HTREE directory has bad max hash */
#define PR_2_HTREE_MAX_HASH 0x020037
/* Clear invalid HTREE directory */
#define PR_2_HTREE_CLEAR 0x020038
/* Clear the htree flag forcibly */
#define PR_2_HTREE_FCLR 0x020039
/* Bad block in htree interior node */
#define PR_2_HTREE_BADBLK 0x02003A
/*
* Pass 3 errors
*/

View File

@ -876,7 +876,16 @@ restart:
com_err(ctx->program_name, 0,
_("Warning: compression support is experimental.\n"));
#endif
#ifndef ENABLE_HTREE
if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
com_err(ctx->program_name, 0,
_("E2fsck not compiled with HTREE support,\n\t"
"but filesystem %s has HTREE directories.\n"),
ctx->device_name);
goto get_newer;
}
#endif
/*
* If the user specified a specific superblock, presumably the
* master superblock has been trashed. So we mark the

View File

@ -1,3 +1,12 @@
2002-06-25 Theodore Ts'o <tytso@mit.edu>
* Makefile.in (test_script): Add pass in the state of
--enable-htree and --enable-clear-htree to the test
script.
* f_h_normal, f_h_badnode: New test cases to test the htree
directory code.
2002-06-09 Andreas Dilger <adilger@clusterfs.com>
* f_8192_block, f_16384_block: Basic tests of 8192-byte block

View File

@ -16,6 +16,8 @@ all:: @DO_TEST_SUITE@
test_script: test_script.in Makefile
@echo "Creating test_script..."
@echo "#!/bin/sh" > test_script
@HTREE_CMT@ @echo "HTREE=y" >> test_script
@HTREE_CLR_CMT@ @echo "HTREE_CLR=y" >> test_script
@echo "SRCDIR=@srcdir@" >> test_script
@cat $(srcdir)/test_script.in >> test_script
@chmod +x test_script

View File

@ -0,0 +1,16 @@
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Problem in HTREE directory inode 12929: node (531) has bad max hash
Problem in HTREE directory inode 12929: node (993) referenced twice
Problem in HTREE directory inode 12929: node (1061) has bad min hash
Problem in HTREE directory inode 12929: node (1062) has bad max hash
Problem in HTREE directory inode 12929: node (1062) not referenced
Invalid HTREE directory inode 12929 (/test2). Clear? yes
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 47730/100192 files (0.0% non-contiguous), 13689/31745 blocks
Exit status is 1

View File

@ -0,0 +1,7 @@
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: 47730/100192 files (0.0% non-contiguous), 13689/31745 blocks
Exit status is 0

BIN
tests/f_h_badnode/image.gz Normal file

Binary file not shown.

1
tests/f_h_badnode/name Normal file
View File

@ -0,0 +1 @@
hash directory with bad HTREE nodes

6
tests/f_h_badnode/script Normal file
View File

@ -0,0 +1,6 @@
if test "$HTREE"x = yx -a "$HTREE_CLR"x = x; then
. $cmd_dir/run_e2fsck
else
rm -f $test_name.ok $test_name.failed
echo "skipped"
fi

View File

@ -0,0 +1,7 @@
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: 47729/100192 files (0.0% non-contiguous), 13687/31745 blocks
Exit status is 0

View File

@ -0,0 +1,7 @@
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: 47729/100192 files (0.0% non-contiguous), 13687/31745 blocks
Exit status is 0

BIN
tests/f_h_normal/image.gz Normal file

Binary file not shown.

1
tests/f_h_normal/name Normal file
View File

@ -0,0 +1 @@
Normal HTREE directory

6
tests/f_h_normal/script Normal file
View File

@ -0,0 +1,6 @@
if test "$HTREE"x = yx -a "$HTREE_CLR"x = x; then
. $cmd_dir/run_e2fsck
else
rm -f $test_name.ok $test_name.failed
echo "skipped"
fi

3
tests/f_h_normal/script~ Normal file
View File

@ -0,0 +1,3 @@
if test "$HTREE"x = yx ; then
. $cmd_dir/run_e2fsck
fi