e2fsck: rebuild sparse extent trees & convert non-extent ext3 files

Teach e2fsck to (re)construct extent trees.  This enables us to do
either of the following: compress a highly sparse extent tree into
fewer ETB blocks; or convert a ext3-style block mapped file to an
extent file.  The reconstruction is performed during pass 1E or 3A,
as detailed below.

For files that are already extent based, this algorithm will
automatically run (pending user approval) if pass1 determines either
(1) that a whole level of extent tree will fit into a higher level of
the tree; (2) that the size of any level can be reduced by at least
one ETB block; or (3) the extent tree is unnecessarily deep.  It will
not run at all if errors are found and the user declines to fix the
errors.

The option "-E bmap2extent" can be used to force e2fsck to convert all
block map files to extent trees, and to rebuild all extent files'
extent trees.  After conversion, files larger than 12 blocks should be
defragmented to eliminate empty holes where a block lives.

The extent tree constructor is pretty dumb -- it creates a list of
leaf extents (adjacent extents are collapsed), marks all indirect
blocks / ETB blocks free, installs a new extent tree root in the
inode, then loads the leaf extents into the tree.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
debian
Darrick J. Wong 2015-04-01 19:34:40 -07:00 committed by Theodore Ts'o
parent a5abfe0382
commit e228d700d5
18 changed files with 823 additions and 35 deletions

View File

@ -62,7 +62,8 @@ OBJS= dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \
pass3.o pass4.o pass5.o journal.o badblocks.o util.o dirinfo.o \
dx_dirinfo.o ehandler.o problem.o message.o quota.o recovery.o \
region.o revoke.o ea_refcount.o rehash.o profile.o prof_err.o \
logfile.o sigcatcher.o $(MTRACE_OBJ) plausible.o readahead.o
logfile.o sigcatcher.o $(MTRACE_OBJ) plausible.o readahead.o \
extents.o
PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
profiled/super.o profiled/pass1.o profiled/pass1b.o \
@ -73,7 +74,7 @@ PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
profiled/recovery.o profiled/region.o profiled/revoke.o \
profiled/ea_refcount.o profiled/rehash.o profiled/profile.o \
profiled/prof_err.o profiled/logfile.o profiled/sigcatcher.o \
profiled/plausible.o profiled/readahead.o
profiled/plausible.o profiled/readahead.o profiled/extents.o
SRCS= $(srcdir)/e2fsck.c \
$(srcdir)/dict.c \
@ -105,6 +106,7 @@ SRCS= $(srcdir)/e2fsck.c \
prof_err.c \
$(srcdir)/quota.c \
$(srcdir)/../misc/plausible.c \
$(srcdir)/extents.c \
$(MTRACE_SRC)
all:: profiled $(PROGS) e2fsck $(MANPAGES) $(FMANPAGES)
@ -490,6 +492,16 @@ rehash.o: $(srcdir)/rehash.c $(top_builddir)/lib/config.h \
$(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/quotaio.h \
$(top_srcdir)/lib/quota/dqblk_v2.h $(top_srcdir)/lib/quota/quotaio_tree.h \
$(top_srcdir)/lib/../e2fsck/dict.h $(srcdir)/problem.h
readahead.o: $(srcdir)/readahead.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
$(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
$(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/quotaio.h \
$(top_srcdir)/lib/quota/dqblk_v2.h $(top_srcdir)/lib/quota/quotaio_tree.h \
$(top_srcdir)/lib/../e2fsck/dict.h
region.o: $(srcdir)/region.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
@ -535,13 +547,20 @@ quota.o: $(srcdir)/quota.c $(top_builddir)/lib/config.h \
$(top_srcdir)/lib/quota/dqblk_v2.h $(top_srcdir)/lib/quota/quotaio_tree.h \
$(top_srcdir)/lib/../e2fsck/dict.h $(srcdir)/problem.h
plausible.o: $(srcdir)/../misc/plausible.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
$(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/../misc/plausible.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
$(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
$(srcdir)/../misc/nls-enable.h $(srcdir)/../misc/plausible.h
readahead.o: $(srcdir)/readahead.c $(top_builddir)/lib/config.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/e2fsck.h prof_err.h
$(srcdir)/../misc/nls-enable.h
extents.o: $(srcdir)/extents.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
$(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
$(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/quotaio.h \
$(top_srcdir)/lib/quota/dqblk_v2.h $(top_srcdir)/lib/quota/quotaio_tree.h \
$(top_srcdir)/lib/../e2fsck/dict.h $(srcdir)/problem.h

View File

@ -227,6 +227,14 @@ e2fsck runtime. By default, this is set to the size of two block groups' inode
tables (typically 4MiB on a regular ext4 filesystem); if this amount is more
than 1/50th of total physical memory, readahead is disabled. Set this to zero
to disable readahead entirely.
.TP
.BI bmap2extent
Convert block-mapped files to extent-mapped files.
.TP
.BI fixes_only
Only fix damaged metadata; do not optimize htree directories or compress
extent trees. This option is incompatible with the -D and -E bmap2extent
options.
.RE
.TP
.B \-f

View File

@ -208,8 +208,8 @@ void e2fsck_free_context(e2fsck_t ctx)
typedef void (*pass_t)(e2fsck_t ctx);
static pass_t e2fsck_passes[] = {
e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4,
e2fsck_pass5, 0 };
e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3,
e2fsck_pass4, e2fsck_pass5, 0 };
#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)

View File

@ -167,6 +167,8 @@ struct resource_track {
#define E2F_OPT_FRAGCHECK 0x0800
#define E2F_OPT_JOURNAL_ONLY 0x1000 /* only replay the journal */
#define E2F_OPT_DISCARD 0x2000
#define E2F_OPT_CONVERT_BMAP 0x4000 /* convert blockmap to extent */
#define E2F_OPT_FIXES_ONLY 0x8000 /* skip all optimizations */
/*
* E2fsck flags
@ -190,6 +192,7 @@ struct resource_track {
#define E2F_FLAG_EXITING 0x1000 /* E2fsck exiting due to errors */
#define E2F_FLAG_TIME_INSANE 0x2000 /* Time is insane */
#define E2F_FLAG_PROBLEMS_FIXED 0x4000 /* At least one problem was fixed */
#define E2F_FLAG_ALLOC_OK 0x8000 /* Can we allocate blocks? */
#define E2F_RESET_FLAGS (E2F_FLAG_TIME_INSANE | E2F_FLAG_PROBLEMS_FIXED)
@ -382,6 +385,23 @@ struct e2fsck_struct {
/* How much are we allowed to readahead? */
unsigned long long readahead_kb;
/*
* Inodes to rebuild extent trees
*/
ext2fs_inode_bitmap inodes_to_rebuild;
};
/* Data structures to evaluate whether an extent tree needs rebuilding. */
struct extent_tree_level {
unsigned int num_extents;
unsigned int max_extents;
};
struct extent_tree_info {
ext2_ino_t ino;
int force_rebuild;
struct extent_tree_level ext_info[MAX_EXTENT_DEPTH_COUNT];
};
/* Used by the region allocation code */
@ -457,6 +477,19 @@ extern blk64_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret);
extern const char *ehandler_operation(const char *op);
extern void ehandler_init(io_channel channel);
/* extents.c */
struct problem_context;
errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino);
int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino);
void e2fsck_pass1e(e2fsck_t ctx);
errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode,
struct problem_context *pctx);
errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx,
struct problem_context *pctx,
struct extent_tree_info *eti,
struct ext2_extent_info *info);
/* journal.c */
extern errcode_t e2fsck_check_ext3_journal(e2fsck_t ctx);
extern errcode_t e2fsck_run_ext3_journal(e2fsck_t ctx);
@ -524,7 +557,8 @@ extern int region_allocate(region_t region, region_addr_t start, int n);
/* rehash.c */
void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino);
int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino);
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
struct problem_context *pctx);
void e2fsck_rehash_directories(e2fsck_t ctx);
/* sigcatcher.c */

537
e2fsck/extents.c Normal file
View File

@ -0,0 +1,537 @@
/*
* extents.c --- rebuild extent tree
*
* Copyright (C) 2014 Oracle.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License, version 2.
* %End-Header%
*/
#include "config.h"
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "e2fsck.h"
#include "problem.h"
#undef DEBUG
#undef DEBUG_SUMMARY
#undef DEBUG_FREE
#define NUM_EXTENTS 341 /* about one ETB' worth of extents */
static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino);
/* Schedule an inode to have its extent tree rebuilt during pass 1E. */
errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino)
{
if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super,
EXT3_FEATURE_INCOMPAT_EXTENTS) ||
(ctx->options & E2F_OPT_NO) ||
(ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino))
return 0;
if (ctx->flags & E2F_FLAG_ALLOC_OK)
return e2fsck_rebuild_extents(ctx, ino);
if (!ctx->inodes_to_rebuild)
e2fsck_allocate_inode_bitmap(ctx->fs,
_("extent rebuild inode map"),
EXT2FS_BMAP64_RBTREE,
"inodes_to_rebuild",
&ctx->inodes_to_rebuild);
if (ctx->inodes_to_rebuild)
ext2fs_mark_inode_bitmap2(ctx->inodes_to_rebuild, ino);
return 0;
}
/* Ask if an inode will have its extents rebuilt during pass 1E. */
int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino)
{
if (!ctx->inodes_to_rebuild)
return 0;
return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino);
}
struct extent_list {
blk64_t blocks_freed;
struct ext2fs_extent *extents;
unsigned int count;
unsigned int size;
unsigned int ext_read;
errcode_t retval;
ext2_ino_t ino;
};
static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list)
{
ext2_filsys fs = ctx->fs;
ext2_extent_handle_t handle;
struct ext2fs_extent extent;
errcode_t retval;
retval = ext2fs_extent_open(fs, list->ino, &handle);
if (retval)
return retval;
retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
if (retval)
goto out;
do {
if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
goto next;
/* Internal node; free it and we'll re-allocate it later */
if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
#if defined(DEBUG) || defined(DEBUG_FREE)
printf("ino=%d free=%llu bf=%llu\n", list->ino,
extent.e_pblk, list->blocks_freed + 1);
#endif
list->blocks_freed++;
ext2fs_block_alloc_stats2(fs, extent.e_pblk, -1);
goto next;
}
list->ext_read++;
/* Can we attach it to the previous extent? */
if (list->count) {
struct ext2fs_extent *last = list->extents +
list->count - 1;
blk64_t end = last->e_len + extent.e_len;
if (last->e_pblk + last->e_len == extent.e_pblk &&
last->e_lblk + last->e_len == extent.e_lblk &&
(last->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ==
(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
end < (1ULL << 32)) {
last->e_len += extent.e_len;
#ifdef DEBUG
printf("R: ino=%d len=%u\n", list->ino,
last->e_len);
#endif
goto next;
}
}
/* Do we need to expand? */
if (list->count == list->size) {
unsigned int new_size = (list->size + NUM_EXTENTS) *
sizeof(struct ext2fs_extent);
retval = ext2fs_resize_mem(0, new_size, &list->extents);
if (retval)
goto out;
list->size += NUM_EXTENTS;
}
/* Add a new extent */
memcpy(list->extents + list->count, &extent, sizeof(extent));
#ifdef DEBUG
printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino,
extent.e_pblk, extent.e_lblk, extent.e_len);
#endif
list->count++;
next:
retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent);
} while (retval == 0);
out:
/* Ok if we run off the end */
if (retval == EXT2_ET_EXTENT_NO_NEXT)
retval = 0;
ext2fs_extent_free(handle);
return retval;
}
static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt,
blk64_t ref_blk EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
{
struct extent_list *list = priv_data;
/* Internal node? */
if (blockcnt < 0) {
#if defined(DEBUG) || defined(DEBUG_FREE)
printf("ino=%d free=%llu bf=%llu\n", list->ino, *blocknr,
list->blocks_freed + 1);
#endif
list->blocks_freed++;
ext2fs_block_alloc_stats2(fs, *blocknr, -1);
return 0;
}
/* Can we attach it to the previous extent? */
if (list->count) {
struct ext2fs_extent *last = list->extents +
list->count - 1;
blk64_t end = last->e_len + 1;
if (last->e_pblk + last->e_len == *blocknr &&
end < (1ULL << 32)) {
last->e_len++;
#ifdef DEBUG
printf("R: ino=%d len=%u\n", list->ino, last->e_len);
#endif
return 0;
}
}
/* Do we need to expand? */
if (list->count == list->size) {
unsigned int new_size = (list->size + NUM_EXTENTS) *
sizeof(struct ext2fs_extent);
list->retval = ext2fs_resize_mem(0, new_size, &list->extents);
if (list->retval)
return BLOCK_ABORT;
list->size += NUM_EXTENTS;
}
/* Add a new extent */
list->extents[list->count].e_pblk = *blocknr;
list->extents[list->count].e_lblk = blockcnt;
list->extents[list->count].e_len = 1;
list->extents[list->count].e_flags = 0;
#ifdef DEBUG
printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, *blocknr,
blockcnt, 1);
#endif
list->count++;
return 0;
}
static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list,
ext2_ino_t ino)
{
struct ext2_inode inode;
errcode_t retval;
ext2_extent_handle_t handle;
unsigned int i, ext_written;
struct ext2fs_extent *ex, extent;
list->count = 0;
list->blocks_freed = 0;
list->ino = ino;
list->ext_read = 0;
e2fsck_read_inode(ctx, ino, &inode, "rebuild_extents");
/* Skip deleted inodes and inline data files */
if (inode.i_links_count == 0 ||
inode.i_flags & EXT4_INLINE_DATA_FL)
return 0;
/* Collect lblk->pblk mappings */
if (inode.i_flags & EXT4_EXTENTS_FL) {
retval = load_extents(ctx, list);
goto extents_loaded;
}
retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0,
find_blocks, list);
if (retval)
goto err;
if (list->retval) {
retval = list->retval;
goto err;
}
extents_loaded:
/* Reset extent tree */
inode.i_flags &= ~EXT4_EXTENTS_FL;
memset(inode.i_block, 0, sizeof(inode.i_block));
/* Make a note of freed blocks */
retval = ext2fs_iblk_sub_blocks(ctx->fs, &inode, list->blocks_freed);
if (retval)
goto err;
/* Now stuff extents into the file */
retval = ext2fs_extent_open2(ctx->fs, ino, &inode, &handle);
if (retval)
goto err;
ext_written = 0;
for (i = 0, ex = list->extents; i < list->count; i++, ex++) {
memcpy(&extent, ex, sizeof(struct ext2fs_extent));
extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT;
if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
if (extent.e_len > EXT_UNINIT_MAX_LEN) {
extent.e_len = EXT_UNINIT_MAX_LEN;
ex->e_pblk += EXT_UNINIT_MAX_LEN;
ex->e_lblk += EXT_UNINIT_MAX_LEN;
ex->e_len -= EXT_UNINIT_MAX_LEN;
ex--;
i--;
}
} else {
if (extent.e_len > EXT_INIT_MAX_LEN) {
extent.e_len = EXT_INIT_MAX_LEN;
ex->e_pblk += EXT_INIT_MAX_LEN;
ex->e_lblk += EXT_INIT_MAX_LEN;
ex->e_len -= EXT_INIT_MAX_LEN;
ex--;
i--;
}
}
#ifdef DEBUG
printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", ino,
extent.e_pblk, extent.e_lblk, extent.e_len);
#endif
retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER,
&extent);
if (retval)
goto err2;
retval = ext2fs_extent_fix_parents(handle);
if (retval)
goto err2;
ext_written++;
}
#if defined(DEBUG) || defined(DEBUG_SUMMARY)
printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read,
ext_written);
#endif
e2fsck_write_inode(ctx, ino, &inode, "rebuild_extents");
err2:
ext2fs_extent_free(handle);
err:
return retval;
}
/* Rebuild the extents immediately */
static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino)
{
struct extent_list list;
errcode_t err;
if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super,
EXT3_FEATURE_INCOMPAT_EXTENTS) ||
(ctx->options & E2F_OPT_NO) ||
(ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino))
return 0;
e2fsck_read_bitmaps(ctx);
memset(&list, 0, sizeof(list));
err = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS,
&list.extents);
if (err)
return err;
list.size = NUM_EXTENTS;
err = rebuild_extent_tree(ctx, &list, ino);
ext2fs_free_mem(&list.extents);
return err;
}
static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
{
struct problem_context pctx;
#ifdef RESOURCE_TRACK
struct resource_track rtrack;
#endif
struct extent_list list;
int first = 1;
ext2_ino_t ino = 0;
errcode_t retval;
if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super,
EXT3_FEATURE_INCOMPAT_EXTENTS) ||
!ext2fs_test_valid(ctx->fs) ||
ctx->invalid_bitmaps) {
if (ctx->inodes_to_rebuild)
ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild);
ctx->inodes_to_rebuild = NULL;
}
if (ctx->inodes_to_rebuild == NULL)
return;
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&pctx);
e2fsck_read_bitmaps(ctx);
memset(&list, 0, sizeof(list));
retval = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS,
&list.extents);
list.size = NUM_EXTENTS;
while (1) {
retval = ext2fs_find_first_set_inode_bitmap2(
ctx->inodes_to_rebuild, ino + 1,
ctx->fs->super->s_inodes_count, &ino);
if (retval)
break;
pctx.ino = ino;
if (first) {
fix_problem(ctx, pr_header, &pctx);
first = 0;
}
pctx.errcode = rebuild_extent_tree(ctx, &list, ino);
if (pctx.errcode) {
end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
fix_problem(ctx, PR_1E_OPTIMIZE_EXT_ERR, &pctx);
}
if (ctx->progress && !ctx->progress_fd)
e2fsck_simple_progress(ctx, "Rebuilding extents",
100.0 * (float) ino /
(float) ctx->fs->super->s_inodes_count,
ino);
}
end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild);
ctx->inodes_to_rebuild = NULL;
ext2fs_free_mem(&list.extents);
print_resource_track(ctx, pass_name, &rtrack, ctx->fs->io);
}
/* Scan a file to see if we should rebuild its extent tree */
errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode,
struct problem_context *pctx)
{
struct extent_tree_info eti;
struct ext2_extent_info info, top_info;
struct ext2fs_extent extent;
ext2_extent_handle_t ehandle;
ext2_filsys fs = ctx->fs;
errcode_t retval;
/* block map file and we want extent conversion */
if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
!(inode->i_flags & EXT4_INLINE_DATA_FL) &&
(ctx->options & E2F_OPT_CONVERT_BMAP)) {
return e2fsck_rebuild_extents_later(ctx, ino);
}
if (!(inode->i_flags & EXT4_EXTENTS_FL))
return 0;
memset(&eti, 0, sizeof(eti));
eti.ino = ino;
/* Otherwise, go scan the extent tree... */
retval = ext2fs_extent_open2(fs, ino, inode, &ehandle);
if (retval)
return 0;
retval = ext2fs_extent_get_info(ehandle, &top_info);
if (retval)
goto out;
/* Check maximum extent depth */
pctx->ino = ino;
pctx->blk = top_info.max_depth;
pctx->blk2 = ext2fs_max_extent_depth(ehandle);
if (pctx->blk2 < pctx->blk &&
fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx))
eti.force_rebuild = 1;
/* Can we collect extent tree level stats? */
pctx->blk = MAX_EXTENT_DEPTH_COUNT;
if (pctx->blk2 > pctx->blk)
fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx);
/* We need to fix tree depth problems, but the scan isn't a fix. */
if (ctx->options & E2F_OPT_FIXES_ONLY)
goto out;
retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_ROOT, &extent);
if (retval)
goto out;
do {
retval = ext2fs_extent_get_info(ehandle, &info);
if (retval)
break;
/*
* If this is the first extent in an extent block that we
* haven't visited, collect stats on the block.
*/
if (info.curr_entry == 1 &&
!(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
!eti.force_rebuild) {
struct extent_tree_level *etl;
etl = eti.ext_info + info.curr_level;
etl->num_extents += info.num_entries;
etl->max_extents += info.max_entries;
/*
* Implementation wart: Splitting extent blocks when
* appending will leave the old block with one free
* entry. Therefore unless the node is totally full,
* pretend that a non-root extent block can hold one
* fewer entry than it actually does, so that we don't
* repeatedly rebuild the extent tree.
*/
if (info.curr_level &&
info.num_entries < info.max_entries)
etl->max_extents--;
}
/* Skip to the end of a block of leaf nodes */
if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) {
retval = ext2fs_extent_get(ehandle,
EXT2_EXTENT_LAST_SIB,
&extent);
if (retval)
break;
}
retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_NEXT, &extent);
} while (retval == 0);
out:
ext2fs_extent_free(ehandle);
return e2fsck_should_rebuild_extents(ctx, pctx, &eti, &top_info);
}
/* Having scanned a file's extent tree, decide if we should rebuild it */
errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx,
struct problem_context *pctx,
struct extent_tree_info *eti,
struct ext2_extent_info *info)
{
struct extent_tree_level *ei;
int i, j, op;
unsigned int extents_per_block;
if (eti->force_rebuild)
goto rebuild;
extents_per_block = (ctx->fs->blocksize -
sizeof(struct ext3_extent_header)) /
sizeof(struct ext3_extent);
/*
* If we can consolidate a level or shorten the tree, schedule the
* extent tree to be rebuilt.
*/
for (i = 0, ei = eti->ext_info; i < info->max_depth + 1; i++, ei++) {
if (ei->max_extents - ei->num_extents > extents_per_block) {
pctx->blk = i;
op = PR_1E_CAN_NARROW_EXTENT_TREE;
goto rebuild;
}
for (j = 0; j < i; j++) {
if (ei->num_extents < eti->ext_info[j].max_extents) {
pctx->blk = i;
op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
goto rebuild;
}
}
}
return 0;
rebuild:
if (eti->force_rebuild || fix_problem(ctx, op, pctx))
return e2fsck_rebuild_extents_later(ctx, eti->ino);
return 0;
}
void e2fsck_pass1e(e2fsck_t ctx)
{
rebuild_extents(ctx, "Pass 1E", PR_1E_PASS_HEADER);
}

View File

@ -56,6 +56,8 @@
#define _INLINE_ inline
#endif
#undef DEBUG
static int process_block(ext2_filsys fs, blk64_t *blocknr,
e2_blkcnt_t blockcnt, blk64_t ref_blk,
int ref_offset, void *priv_data);
@ -95,6 +97,7 @@ struct process_block_struct {
ext2fs_block_bitmap fs_meta_blocks;
e2fsck_t ctx;
region_t region;
struct extent_tree_info eti;
};
struct process_inode_block {
@ -1835,6 +1838,7 @@ void e2fsck_pass1(e2fsck_t ctx)
}
e2fsck_pass1_dupblocks(ctx, block_buf);
}
ctx->flags |= E2F_FLAG_ALLOC_OK;
ext2fs_free_mem(&inodes_to_process);
endit:
e2fsck_use_inode_shortcuts(ctx, 0);
@ -2486,6 +2490,23 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
if (pctx->errcode)
return;
if (!(ctx->options & E2F_OPT_FIXES_ONLY) &&
!pb->eti.force_rebuild) {
struct extent_tree_level *etl;
etl = pb->eti.ext_info + info.curr_level;
etl->num_extents += info.num_entries;
etl->max_extents += info.max_entries;
/*
* Implementation wart: Splitting extent blocks when appending
* will leave the old block with one free entry. Therefore
* unless the node is totally full, pretend that a non-root
* extent block can hold one fewer entry than it actually does,
* so that we don't repeatedly rebuild the extent tree.
*/
if (info.curr_level && info.num_entries < info.max_entries)
etl->max_extents--;
}
pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
&extent);
@ -2822,11 +2843,27 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
retval = ext2fs_extent_get_info(ehandle, &info);
if (retval == 0) {
if (info.max_depth >= MAX_EXTENT_DEPTH_COUNT)
info.max_depth = MAX_EXTENT_DEPTH_COUNT-1;
ctx->extent_depth_count[info.max_depth]++;
int max_depth = info.max_depth;
if (max_depth >= MAX_EXTENT_DEPTH_COUNT)
max_depth = MAX_EXTENT_DEPTH_COUNT-1;
ctx->extent_depth_count[max_depth]++;
}
/* Check maximum extent depth */
pctx->blk = info.max_depth;
pctx->blk2 = ext2fs_max_extent_depth(ehandle);
if (pctx->blk2 < pctx->blk &&
fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx))
pb->eti.force_rebuild = 1;
/* Can we collect extent tree level stats? */
pctx->blk = MAX_EXTENT_DEPTH_COUNT;
if (pctx->blk2 > pctx->blk)
fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx);
memset(pb->eti.ext_info, 0, sizeof(pb->eti.ext_info));
pb->eti.ino = pb->ino;
pb->region = region_create(0, info.max_lblk);
if (!pb->region) {
ext2fs_extent_free(ehandle);
@ -2849,6 +2886,16 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
region_free(pb->region);
pb->region = NULL;
ext2fs_extent_free(ehandle);
/* Rebuild unless it's a dir and we're rehashing it */
if (LINUX_S_ISDIR(inode->i_mode) &&
e2fsck_dir_will_be_rehashed(ctx, ino))
return;
if (ctx->options & E2F_OPT_CONVERT_BMAP)
e2fsck_rebuild_extents_later(ctx, ino);
else
e2fsck_should_rebuild_extents(ctx, pctx, &pb->eti, &info);
}
/*
@ -2933,6 +2980,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
pb.pctx = pctx;
pb.ctx = ctx;
pb.inode_modified = 0;
pb.eti.force_rebuild = 0;
pctx->ino = ino;
pctx->errcode = 0;
@ -2984,6 +3032,15 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
"check_blocks");
fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
(fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
if (ctx->options & E2F_OPT_CONVERT_BMAP) {
#ifdef DEBUG
printf("bmap rebuild ino=%d\n", ino);
#endif
if (!LINUX_S_ISDIR(inode->i_mode) ||
!e2fsck_dir_will_be_rehashed(ctx, ino))
e2fsck_rebuild_extents_later(ctx, ino);
}
}
}
end_problem_latch(ctx, PR_LATCH_BLOCK);

View File

@ -1101,6 +1101,11 @@ static struct e2fsck_problem problem_table[] = {
N_("@A memory for encrypted @d list\n"),
PROMPT_NONE, PR_FATAL },
/* Inode extent tree could be more shallow */
{ PR_1_EXTENT_BAD_MAX_DEPTH,
N_("@i %i @x tree could be more shallow (%b; could be <= %c)\n"),
PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK },
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
@ -1198,6 +1203,48 @@ static struct e2fsck_problem problem_table[] = {
{ PR_1D_CLONE_ERROR,
N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
/* Pass 1E Extent tree optimization */
/* Pass 1E: Optimizing extent trees */
{ PR_1E_PASS_HEADER,
N_("Pass 1E: Optimizing @x trees\n"),
PROMPT_NONE, PR_PREEN_NOMSG },
/* Failed to optimize extent tree */
{ PR_1E_OPTIMIZE_EXT_ERR,
N_("Failed to optimize @x tree %p (%i): %m\n"),
PROMPT_NONE, 0 },
/* Optimizing extent trees */
{ PR_1E_OPTIMIZE_EXT_HEADER,
N_("Optimizing @x trees: "),
PROMPT_NONE, PR_MSG_ONLY },
/* Rebuilding extent tree %d */
{ PR_1E_OPTIMIZE_EXT,
" %i",
PROMPT_NONE, PR_LATCH_OPTIMIZE_EXT | PR_PREEN_NOHDR},
/* Rebuilding extent tree end */
{ PR_1E_OPTIMIZE_EXT_END,
"\n",
PROMPT_NONE, PR_PREEN_NOHDR },
/* Internal error: extent tree depth too large */
{ PR_1E_MAX_EXTENT_TREE_DEPTH,
N_("Internal error: max extent tree depth too large (%b; expected=%c).\n"),
PROMPT_NONE, PR_FATAL },
/* Inode extent tree could be shorter */
{ PR_1E_CAN_COLLAPSE_EXTENT_TREE,
N_("@i %i @x tree (at level %b) could be shorter. "),
PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK },
/* Inode extent tree could be narrower */
{ PR_1E_CAN_NARROW_EXTENT_TREE,
N_("@i %i @x tree (at (level %b) could be narrower. "),
PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK },
/* Pass 2 errors */
/* Pass 2: Checking directory structure */
@ -1946,6 +1993,7 @@ static struct latch_descr pr_latch_info[] = {
{ PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
{ PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END },
{ PR_LATCH_BG_CHECKSUM, PR_0_GDT_CSUM_LATCH, 0 },
{ PR_LATCH_OPTIMIZE_EXT, PR_1E_OPTIMIZE_EXT_HEADER, PR_1E_OPTIMIZE_EXT_END },
{ -1, 0, 0 },
};

View File

@ -40,6 +40,7 @@ struct problem_context {
#define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */
#define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */
#define PR_LATCH_BG_CHECKSUM 0x00A0 /* Latch for block group checksums */
#define PR_LATCH_OPTIMIZE_EXT 0x00B0 /* Latch for rebuild extents */
#define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1)
@ -644,6 +645,9 @@ struct problem_context {
/* Error allocating memory for encrypted directory list */
#define PR_1_ALLOCATE_ENCRYPTED_DIRLIST 0x01007E
/* extent tree max depth too big */
#define PR_1_EXTENT_BAD_MAX_DEPTH 0x01007F
/*
* Pass 1b errors
*/
@ -706,6 +710,33 @@ struct problem_context {
/* Couldn't clone file (error) */
#define PR_1D_CLONE_ERROR 0x013008
/*
* Pass 1e --- rebuilding extent trees
*/
/* Pass 1e: Rebuilding extent trees */
#define PR_1E_PASS_HEADER 0x014000
/* Error rehash directory */
#define PR_1E_OPTIMIZE_EXT_ERR 0x014001
/* Rebuilding extent trees */
#define PR_1E_OPTIMIZE_EXT_HEADER 0x014002
/* Rebuilding extent %d */
#define PR_1E_OPTIMIZE_EXT 0x014003
/* Rebuilding extent tree end */
#define PR_1E_OPTIMIZE_EXT_END 0x014004
/* Internal error: extent tree depth too large */
#define PR_1E_MAX_EXTENT_TREE_DEPTH 0x014005
/* Inode extent tree could be shorter */
#define PR_1E_CAN_COLLAPSE_EXTENT_TREE 0x014006
/* Inode extent tree could be narrower */
#define PR_1E_CAN_NARROW_EXTENT_TREE 0x014007
/*
* Pass 2 errors
*/
@ -1035,6 +1066,8 @@ struct problem_context {
/* Rehashing dir end */
#define PR_3A_OPTIMIZE_DIR_END 0x031005
/* Pass 3B is really just 1E */
/*
* Pass 4 errors
*/

View File

@ -762,11 +762,11 @@ static int write_dir_block(ext2_filsys fs,
static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
struct out_dir *outdir,
ext2_ino_t ino, int compress)
ext2_ino_t ino, struct ext2_inode *inode,
int compress)
{
struct write_dir_struct wd;
errcode_t retval;
struct ext2_inode inode;
retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
if (retval)
@ -785,22 +785,23 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
if (wd.err)
return wd.err;
e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
e2fsck_read_inode(ctx, ino, inode, "rehash_dir");
if (compress)
inode.i_flags &= ~EXT2_INDEX_FL;
inode->i_flags &= ~EXT2_INDEX_FL;
else
inode.i_flags |= EXT2_INDEX_FL;
retval = ext2fs_inode_size_set(fs, &inode,
inode->i_flags |= EXT2_INDEX_FL;
retval = ext2fs_inode_size_set(fs, inode,
outdir->num * fs->blocksize);
if (retval)
return retval;
ext2fs_iblk_sub_blocks(fs, &inode, wd.cleared);
e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
ext2fs_iblk_sub_blocks(fs, inode, wd.cleared);
e2fsck_write_inode(ctx, ino, inode, "rehash_dir");
return 0;
}
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
struct problem_context *pctx)
{
ext2_filsys fs = ctx->fs;
errcode_t retval;
@ -911,10 +912,14 @@ resort:
goto errout;
}
retval = write_directory(ctx, fs, &outdir, ino, fd.compress);
retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress);
if (retval)
goto errout;
if (ctx->options & E2F_OPT_CONVERT_BMAP)
retval = e2fsck_rebuild_extents_later(ctx, ino);
else
retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx);
errout:
free(dir_buf);
free(fd.harray);
@ -979,7 +984,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
#if 0
fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx);
#endif
pctx.errcode = e2fsck_rehash_dir(ctx, ino);
pctx.errcode = e2fsck_rehash_dir(ctx, ino, &pctx);
if (pctx.errcode) {
end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR);
fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx);

View File

@ -606,6 +606,13 @@ void check_super_block(e2fsck_t ctx)
ext2fs_mark_super_dirty(fs);
}
/* Did user ask us to convert files to extents? */
if (ctx->options & E2F_OPT_CONVERT_BMAP) {
fs->super->s_feature_incompat |=
EXT3_FEATURE_INCOMPAT_EXTENTS;
ext2fs_mark_super_dirty(fs);
}
if ((fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
(fs->super->s_first_meta_bg > fs->desc_blocks)) {
pctx.group = fs->desc_blocks;

View File

@ -709,6 +709,12 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
else
ctx->log_fn = string_copy(ctx, arg, 0);
continue;
} else if (strcmp(token, "bmap2extent") == 0) {
ctx->options |= E2F_OPT_CONVERT_BMAP;
continue;
} else if (strcmp(token, "fixes_only") == 0) {
ctx->options |= E2F_OPT_FIXES_ONLY;
continue;
} else {
fprintf(stderr, _("Unknown extended option: %s\n"),
token);
@ -728,6 +734,7 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
fputs(("\tdiscard\n"), stderr);
fputs(("\tnodiscard\n"), stderr);
fputs(("\treadahead_kb=<buffer size>\n"), stderr);
fputs(("\tbmap2extent\n"), stderr);
fputc('\n', stderr);
exit(1);
}
@ -961,6 +968,22 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
if (extended_opts)
parse_extended_opts(ctx, extended_opts);
/* Complain about mutually exclusive rebuilding activities */
if (getenv("E2FSCK_FIXES_ONLY"))
ctx->options |= E2F_OPT_FIXES_ONLY;
if ((ctx->options & E2F_OPT_COMPRESS_DIRS) &&
(ctx->options & E2F_OPT_FIXES_ONLY)) {
com_err(ctx->program_name, 0, "%s",
_("The -D and -E fixes_only options are incompatible."));
fatal_error(ctx, 0);
}
if ((ctx->options & E2F_OPT_CONVERT_BMAP) &&
(ctx->options & E2F_OPT_FIXES_ONLY)) {
com_err(ctx->program_name, 0, "%s",
_("The -E bmap2extent and fixes_only options are incompatible."));
fatal_error(ctx, 0);
}
if ((cp = getenv("E2FSCK_CONFIG")) != NULL)
config_fn[0] = cp;
profile_set_syntax_err_cb(syntax_err_report);

View File

@ -2,8 +2,11 @@ Pass 1: Checking inodes, blocks, and sizes
Inode 12 has an invalid extent node (blk 22, lblk 0)
Clear? yes
Inode 12 extent tree (at level 1) could be shorter. Fix? yes
Inode 12, i_blocks is 16, should be 8. Fix? yes
Pass 1E: Optimizing extent trees
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
@ -11,13 +14,13 @@ Pass 5: Checking group summary information
Block bitmap differences: -(21--23) -25
Fix? yes
Free blocks count wrong for group #0 (71, counted=75).
Free blocks count wrong for group #0 (73, counted=77).
Fix? yes
Free blocks count wrong (71, counted=75).
Free blocks count wrong (73, counted=77).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 12/16 files (0.0% non-contiguous), 25/100 blocks
test_filesys: 12/16 files (0.0% non-contiguous), 23/100 blocks
Exit status is 1

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: 12/16 files (0.0% non-contiguous), 25/100 blocks
test_filesys: 12/16 files (0.0% non-contiguous), 23/100 blocks
Exit status is 0

View File

@ -2,8 +2,11 @@ Pass 1: Checking inodes, blocks, and sizes
Inode 12 has an invalid extent node (blk 1295, lblk 0)
Clear? yes
Inode 12 extent tree (at level 1) could be shorter. Fix? yes
Inode 12, i_blocks is 712, should be 0. Fix? yes
Pass 1E: Optimizing extent trees
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts

View File

@ -2,8 +2,11 @@ Pass 1: Checking inodes, blocks, and sizes
Inode 12 has an invalid extent node (blk 1604, lblk 0)
Clear? yes
Inode 12 extent tree (at level 1) could be shorter. Fix? yes
Inode 12, i_blocks is 18, should be 0. Fix? yes
Pass 1E: Optimizing extent trees
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts

View File

@ -3,8 +3,11 @@ Inode 12, end of extent exceeds allowed value
(logical block 15, physical block 200, len 30)
Clear? yes
Inode 12 extent tree (at (level 1) could be narrower. Fix? yes
Inode 12, i_blocks is 154, should be 94. Fix? yes
Pass 1E: Optimizing extent trees
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
@ -12,13 +15,13 @@ Pass 5: Checking group summary information
Block bitmap differences: -(200--229)
Fix? yes
Free blocks count wrong for group #0 (156, counted=186).
Free blocks count wrong for group #0 (158, counted=188).
Fix? yes
Free blocks count wrong (156, counted=186).
Free blocks count wrong (158, counted=188).
Fix? yes
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 12/32 files (8.3% non-contiguous), 70/256 blocks
test_filesys: 12/32 files (8.3% non-contiguous), 68/256 blocks
Exit status is 1

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: 12/32 files (8.3% non-contiguous), 70/256 blocks
test_filesys: 12/32 files (8.3% non-contiguous), 68/256 blocks
Exit status is 0

View File

@ -6,6 +6,8 @@ Inode 12 has an invalid extent
(logical block 0, invalid physical block 21994527527949, len 17)
Clear? yes
Inode 12 extent tree (at level 1) could be shorter. Fix? yes
Inode 12, i_blocks is 34, should be 0. Fix? yes
Inode 13 missing EXTENT_FL, but is in extents format
@ -21,6 +23,8 @@ Inode 17 has an invalid extent
(logical block 0, invalid physical block 22011707397135, len 15)
Clear? yes
Inode 17 extent tree (at level 1) could be shorter. Fix? yes
Inode 17, i_blocks is 32, should be 0. Fix? yes
Error while reading over extent tree in inode 18: Corrupt extent header
@ -31,6 +35,7 @@ Inode 18, i_blocks is 2, should be 0. Fix? yes
Special (device/socket/fifo) file (inode 19) has extents
or inline-data flag set. Clear? yes
Pass 1E: Optimizing extent trees
Pass 2: Checking directory structure
Entry 'fbad-flag' in / (2) has deleted/unused inode 18. Clear? yes