mirror of https://github.com/vitalif/e2fsprogs
Merge branch 'maint' into next
commit
94676ef2b3
|
@ -209,8 +209,6 @@ static pass_t e2fsck_passes[] = {
|
||||||
e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3,
|
e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3,
|
||||||
e2fsck_pass4, e2fsck_pass5, 0 };
|
e2fsck_pass4, e2fsck_pass5, 0 };
|
||||||
|
|
||||||
#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART)
|
|
||||||
|
|
||||||
int e2fsck_run(e2fsck_t ctx)
|
int e2fsck_run(e2fsck_t ctx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -175,10 +175,10 @@ struct resource_track {
|
||||||
*/
|
*/
|
||||||
#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
|
#define E2F_FLAG_ABORT 0x0001 /* Abort signaled */
|
||||||
#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
|
#define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */
|
||||||
#define E2F_FLAG_SIGNAL_MASK 0x0003
|
#define E2F_FLAG_SIGNAL_MASK (E2F_FLAG_ABORT | E2F_FLAG_CANCEL)
|
||||||
#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
|
#define E2F_FLAG_RESTART 0x0004 /* Restart signaled */
|
||||||
|
#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK | E2F_FLAG_RESTART)
|
||||||
#define E2F_FLAG_RESTART_LATER 0x0008 /* Restart after all iterations done */
|
#define E2F_FLAG_RESTART_LATER 0x0008 /* Restart after all iterations done */
|
||||||
|
|
||||||
#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
|
#define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */
|
||||||
|
|
||||||
#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
|
#define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */
|
||||||
|
|
|
@ -482,6 +482,10 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check if there is no place for an EA header */
|
||||||
|
if (inode->i_extra_isize >= max - sizeof(__u32))
|
||||||
|
return;
|
||||||
|
|
||||||
eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
|
eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
|
||||||
inode->i_extra_isize);
|
inode->i_extra_isize);
|
||||||
if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
|
if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
|
||||||
|
@ -1166,7 +1170,7 @@ void e2fsck_pass1(e2fsck_t ctx)
|
||||||
pass1_readahead(ctx, &ra_group, &ino_threshold);
|
pass1_readahead(ctx, &ra_group, &ino_threshold);
|
||||||
ehandler_operation(old_op);
|
ehandler_operation(old_op);
|
||||||
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
|
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
|
||||||
return;
|
goto endit;
|
||||||
if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
|
if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
|
||||||
/*
|
/*
|
||||||
* If badblocks says badblocks is bad, offer to clear
|
* If badblocks says badblocks is bad, offer to clear
|
||||||
|
@ -1847,6 +1851,8 @@ endit:
|
||||||
|
|
||||||
if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0)
|
if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0)
|
||||||
print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
|
print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
|
||||||
|
else
|
||||||
|
ctx->invalid_bitmaps++;
|
||||||
}
|
}
|
||||||
#undef FINISH_INODE_LOOP
|
#undef FINISH_INODE_LOOP
|
||||||
|
|
||||||
|
@ -2820,7 +2826,20 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
|
||||||
ext2_ino_t ino = pctx->ino;
|
ext2_ino_t ino = pctx->ino;
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
blk64_t eof_lblk;
|
blk64_t eof_lblk;
|
||||||
|
struct ext3_extent_header *eh;
|
||||||
|
|
||||||
|
/* Check for a proper extent header... */
|
||||||
|
eh = (struct ext3_extent_header *) &inode->i_block[0];
|
||||||
|
retval = ext2fs_extent_header_verify(eh, sizeof(inode->i_block));
|
||||||
|
if (retval) {
|
||||||
|
if (fix_problem(ctx, PR_1_MISSING_EXTENT_HEADER, pctx))
|
||||||
|
e2fsck_clear_inode(ctx, ino, inode, 0,
|
||||||
|
"check_blocks_extents");
|
||||||
|
pctx->errcode = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...since this function doesn't fail if i_block is zeroed. */
|
||||||
pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle);
|
pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle);
|
||||||
if (pctx->errcode) {
|
if (pctx->errcode) {
|
||||||
if (fix_problem(ctx, PR_1_READ_EXTENT, pctx))
|
if (fix_problem(ctx, PR_1_READ_EXTENT, pctx))
|
||||||
|
|
|
@ -161,14 +161,14 @@ void e2fsck_pass2(e2fsck_t ctx)
|
||||||
check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
|
check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
|
||||||
cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
|
cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
|
||||||
&cd);
|
&cd);
|
||||||
if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ctx->flags & E2F_FLAG_RESTART_LATER) {
|
if (ctx->flags & E2F_FLAG_RESTART_LATER) {
|
||||||
ctx->flags |= E2F_FLAG_RESTART;
|
ctx->flags |= E2F_FLAG_RESTART;
|
||||||
return;
|
ctx->flags &= ~E2F_FLAG_RESTART_LATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->flags & E2F_FLAG_RUN_RETURN)
|
||||||
|
return;
|
||||||
|
|
||||||
if (cd.pctx.errcode) {
|
if (cd.pctx.errcode) {
|
||||||
fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
|
fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
|
||||||
ctx->flags |= E2F_FLAG_ABORT;
|
ctx->flags |= E2F_FLAG_ABORT;
|
||||||
|
@ -922,7 +922,7 @@ static int check_dir_block(ext2_filsys fs,
|
||||||
ibuf = buf = cd->buf;
|
ibuf = buf = cd->buf;
|
||||||
ctx = cd->ctx;
|
ctx = cd->ctx;
|
||||||
|
|
||||||
if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
|
if (ctx->flags & E2F_FLAG_RUN_RETURN)
|
||||||
return DIRENT_ABORT;
|
return DIRENT_ABORT;
|
||||||
|
|
||||||
if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
|
if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
|
||||||
|
|
|
@ -1114,6 +1114,11 @@ static struct e2fsck_problem problem_table[] = {
|
||||||
N_("@i %i on bigalloc @f cannot be @b mapped. "),
|
N_("@i %i on bigalloc @f cannot be @b mapped. "),
|
||||||
PROMPT_FIX, 0 },
|
PROMPT_FIX, 0 },
|
||||||
|
|
||||||
|
/* Inode has corrupt extent header */
|
||||||
|
{ PR_1_MISSING_EXTENT_HEADER,
|
||||||
|
N_("@i %i has corrupt @x header. "),
|
||||||
|
PROMPT_CLEAR_INODE, 0 },
|
||||||
|
|
||||||
/* Pass 1b errors */
|
/* Pass 1b errors */
|
||||||
|
|
||||||
/* Pass 1B: Rescan for duplicate/bad blocks */
|
/* Pass 1B: Rescan for duplicate/bad blocks */
|
||||||
|
|
|
@ -651,6 +651,9 @@ struct problem_context {
|
||||||
/* bigalloc fs cannot have blockmap files */
|
/* bigalloc fs cannot have blockmap files */
|
||||||
#define PR_1_NO_BIGALLOC_BLOCKMAP_FILES 0x010080
|
#define PR_1_NO_BIGALLOC_BLOCKMAP_FILES 0x010080
|
||||||
|
|
||||||
|
/* Missing extent header */
|
||||||
|
#define PR_1_MISSING_EXTENT_HEADER 0x010081
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pass 1b errors
|
* Pass 1b errors
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -71,6 +71,8 @@ int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino)
|
||||||
return ext2fs_u32_list_test(ctx->dirs_to_hash, ino);
|
return ext2fs_u32_list_test(ctx->dirs_to_hash, ino);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef REHASH_DEBUG
|
||||||
|
|
||||||
struct fill_dir_struct {
|
struct fill_dir_struct {
|
||||||
char *buf;
|
char *buf;
|
||||||
struct ext2_inode *inode;
|
struct ext2_inode *inode;
|
||||||
|
@ -684,8 +686,8 @@ static errcode_t calculate_tree(ext2_filsys fs,
|
||||||
struct write_dir_struct {
|
struct write_dir_struct {
|
||||||
struct out_dir *outdir;
|
struct out_dir *outdir;
|
||||||
errcode_t err;
|
errcode_t err;
|
||||||
|
ext2_ino_t ino;
|
||||||
e2fsck_t ctx;
|
e2fsck_t ctx;
|
||||||
blk64_t cleared;
|
|
||||||
ext2_ino_t dir;
|
ext2_ino_t dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -703,10 +705,15 @@ static int write_dir_block(ext2_filsys fs,
|
||||||
blk64_t blk;
|
blk64_t blk;
|
||||||
char *dir, *buf = 0;
|
char *dir, *buf = 0;
|
||||||
|
|
||||||
if (*block_nr == 0)
|
#ifdef REHASH_DEBUG
|
||||||
return 0;
|
printf("%u: write_dir_block %lld:%lld", wd->ino, blockcnt, *block_nr);
|
||||||
if (blockcnt < 0)
|
#endif
|
||||||
|
if ((*block_nr == 0) || (blockcnt < 0)) {
|
||||||
|
#ifdef REHASH_DEBUG
|
||||||
|
printf(" - skip\n");
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (blockcnt < wd->outdir->num)
|
if (blockcnt < wd->outdir->num)
|
||||||
dir = wd->outdir->buf + (blockcnt * fs->blocksize);
|
dir = wd->outdir->buf + (blockcnt * fs->blocksize);
|
||||||
else if (wd->ctx->lost_and_found == wd->dir) {
|
else if (wd->ctx->lost_and_found == wd->dir) {
|
||||||
|
@ -717,26 +724,20 @@ static int write_dir_block(ext2_filsys fs,
|
||||||
dir = buf;
|
dir = buf;
|
||||||
wd->outdir->num++;
|
wd->outdir->num++;
|
||||||
} else {
|
} else {
|
||||||
/* We don't need this block, so release it */
|
/* Don't free blocks at the end of the directory, they
|
||||||
e2fsck_read_bitmaps(wd->ctx);
|
* will be truncated by the caller. */
|
||||||
blk = *block_nr;
|
#ifdef REHASH_DEBUG
|
||||||
/*
|
printf(" - not freed\n");
|
||||||
* In theory, we only release blocks from the end of the
|
#endif
|
||||||
* directory file, so it's fine to clobber a whole cluster at
|
return 0;
|
||||||
* once.
|
|
||||||
*/
|
|
||||||
if (blk % EXT2FS_CLUSTER_RATIO(fs) == 0) {
|
|
||||||
ext2fs_block_alloc_stats2(fs, blk, -1);
|
|
||||||
wd->cleared++;
|
|
||||||
}
|
|
||||||
*block_nr = 0;
|
|
||||||
return BLOCK_CHANGED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir);
|
wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir);
|
||||||
if (buf)
|
if (buf)
|
||||||
ext2fs_free_mem(&buf);
|
ext2fs_free_mem(&buf);
|
||||||
|
|
||||||
|
#ifdef REHASH_DEBUG
|
||||||
|
printf(" - write (%d)\n", wd->err);
|
||||||
|
#endif
|
||||||
if (wd->err)
|
if (wd->err)
|
||||||
return BLOCK_ABORT;
|
return BLOCK_ABORT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -756,11 +757,11 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
|
||||||
|
|
||||||
wd.outdir = outdir;
|
wd.outdir = outdir;
|
||||||
wd.err = 0;
|
wd.err = 0;
|
||||||
|
wd.ino = ino;
|
||||||
wd.ctx = ctx;
|
wd.ctx = ctx;
|
||||||
wd.cleared = 0;
|
|
||||||
wd.dir = ino;
|
wd.dir = ino;
|
||||||
|
|
||||||
retval = ext2fs_block_iterate3(fs, ino, 0, 0,
|
retval = ext2fs_block_iterate3(fs, ino, 0, NULL,
|
||||||
write_dir_block, &wd);
|
write_dir_block, &wd);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -772,14 +773,17 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
|
||||||
inode->i_flags &= ~EXT2_INDEX_FL;
|
inode->i_flags &= ~EXT2_INDEX_FL;
|
||||||
else
|
else
|
||||||
inode->i_flags |= EXT2_INDEX_FL;
|
inode->i_flags |= EXT2_INDEX_FL;
|
||||||
retval = ext2fs_inode_size_set(fs, inode,
|
#ifdef REHASH_DEBUG
|
||||||
outdir->num * fs->blocksize);
|
printf("%u: set inode size to %u blocks = %u bytes\n",
|
||||||
|
ino, outdir->num, outdir->num * fs->blocksize);
|
||||||
|
#endif
|
||||||
|
retval = ext2fs_inode_size_set(fs, inode, (ext2_off64_t)outdir->num *
|
||||||
|
fs->blocksize);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
ext2fs_iblk_sub_blocks(fs, inode, wd.cleared);
|
|
||||||
e2fsck_write_inode(ctx, ino, inode, "rehash_dir");
|
|
||||||
|
|
||||||
return 0;
|
/* ext2fs_punch() calls ext2fs_write_inode() which writes the size */
|
||||||
|
return ext2fs_punch(fs, ino, inode, NULL, outdir->num, ~0ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
|
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
|
||||||
|
@ -789,12 +793,9 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
struct ext2_inode inode;
|
struct ext2_inode inode;
|
||||||
char *dir_buf = 0;
|
char *dir_buf = 0;
|
||||||
struct fill_dir_struct fd;
|
struct fill_dir_struct fd = { NULL };
|
||||||
struct out_dir outdir;
|
struct out_dir outdir = { 0 };
|
||||||
|
|
||||||
outdir.max = outdir.num = 0;
|
|
||||||
outdir.buf = 0;
|
|
||||||
outdir.hashes = 0;
|
|
||||||
e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
|
e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
|
||||||
|
|
||||||
if (ext2fs_has_feature_inline_data(fs->super) &&
|
if (ext2fs_has_feature_inline_data(fs->super) &&
|
||||||
|
@ -802,24 +803,19 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
retval = ENOMEM;
|
retval = ENOMEM;
|
||||||
fd.harray = 0;
|
|
||||||
dir_buf = malloc(inode.i_size);
|
dir_buf = malloc(inode.i_size);
|
||||||
if (!dir_buf)
|
if (!dir_buf)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
fd.max_array = inode.i_size / 32;
|
fd.max_array = inode.i_size / 32;
|
||||||
fd.num_array = 0;
|
|
||||||
fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
|
fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
|
||||||
if (!fd.harray)
|
if (!fd.harray)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
|
fd.ino = ino;
|
||||||
fd.ctx = ctx;
|
fd.ctx = ctx;
|
||||||
fd.buf = dir_buf;
|
fd.buf = dir_buf;
|
||||||
fd.inode = &inode;
|
fd.inode = &inode;
|
||||||
fd.ino = ino;
|
|
||||||
fd.err = 0;
|
|
||||||
fd.dir_size = 0;
|
|
||||||
fd.compress = 0;
|
|
||||||
fd.dir = ino;
|
fd.dir = ino;
|
||||||
if (!ext2fs_has_feature_dir_index(fs->super) ||
|
if (!ext2fs_has_feature_dir_index(fs->super) ||
|
||||||
(inode.i_size / fs->blocksize) < 2)
|
(inode.i_size / fs->blocksize) < 2)
|
||||||
|
|
|
@ -1819,8 +1819,15 @@ print_unsupp_features:
|
||||||
}
|
}
|
||||||
no_journal:
|
no_journal:
|
||||||
|
|
||||||
if (ctx->qctx) {
|
if (run_result & E2F_FLAG_ABORT) {
|
||||||
|
fatal_error(ctx, _("aborted"));
|
||||||
|
} else if (run_result & E2F_FLAG_CANCEL) {
|
||||||
|
log_out(ctx, _("%s: e2fsck canceled.\n"), ctx->device_name ?
|
||||||
|
ctx->device_name : ctx->filesystem_name);
|
||||||
|
exit_value |= FSCK_CANCELED;
|
||||||
|
} else if (ctx->qctx && !ctx->invalid_bitmaps) {
|
||||||
int i, needs_writeout;
|
int i, needs_writeout;
|
||||||
|
|
||||||
for (i = 0; i < MAXQUOTAS; i++) {
|
for (i = 0; i < MAXQUOTAS; i++) {
|
||||||
if (qtype != -1 && qtype != i)
|
if (qtype != -1 && qtype != i)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1847,18 +1854,13 @@ no_journal:
|
||||||
ext2fs_close_free(&ctx->fs);
|
ext2fs_close_free(&ctx->fs);
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
if (run_result & E2F_FLAG_ABORT)
|
|
||||||
fatal_error(ctx, _("aborted"));
|
|
||||||
|
|
||||||
#ifdef MTRACE
|
#ifdef MTRACE
|
||||||
mtrace_print("Cleanup");
|
mtrace_print("Cleanup");
|
||||||
#endif
|
#endif
|
||||||
was_changed = ext2fs_test_changed(fs);
|
was_changed = ext2fs_test_changed(fs);
|
||||||
if (run_result & E2F_FLAG_CANCEL) {
|
if (!(ctx->flags & E2F_FLAG_RUN_RETURN) &&
|
||||||
log_out(ctx, _("%s: e2fsck canceled.\n"), ctx->device_name ?
|
!(ctx->options & E2F_OPT_READONLY)) {
|
||||||
ctx->device_name : ctx->filesystem_name);
|
|
||||||
exit_value |= FSCK_CANCELED;
|
|
||||||
} else if (!(ctx->options & E2F_OPT_READONLY)) {
|
|
||||||
if (ext2fs_test_valid(fs)) {
|
if (ext2fs_test_valid(fs)) {
|
||||||
if (!(sb->s_state & EXT2_VALID_FS))
|
if (!(sb->s_state & EXT2_VALID_FS))
|
||||||
exit_value |= FSCK_NONDESTRUCT;
|
exit_value |= FSCK_NONDESTRUCT;
|
||||||
|
|
|
@ -48,7 +48,7 @@ static int check_zero_block(char *buf, int blocksize)
|
||||||
*/
|
*/
|
||||||
static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
|
static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
|
||||||
char *block_buf, blk_t *p, int level,
|
char *block_buf, blk_t *p, int level,
|
||||||
blk_t start, blk_t count, int max)
|
blk64_t start, blk64_t count, int max)
|
||||||
{
|
{
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
blk_t b;
|
blk_t b;
|
||||||
|
@ -57,11 +57,11 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
|
||||||
int freed = 0;
|
int freed = 0;
|
||||||
|
|
||||||
#ifdef PUNCH_DEBUG
|
#ifdef PUNCH_DEBUG
|
||||||
printf("Entering ind_punch, level %d, start %u, count %u, "
|
printf("Entering ind_punch, level %d, start %llu, count %llu, "
|
||||||
"max %d\n", level, start, count, max);
|
"max %d\n", level, start, count, max);
|
||||||
#endif
|
#endif
|
||||||
incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super)-2)*level);
|
incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super) - 2) * level);
|
||||||
for (i=0, offset=0; i < max; i++, p++, offset += incr) {
|
for (i = 0, offset = 0; i < max; i++, p++, offset += incr) {
|
||||||
if (offset >= start + count)
|
if (offset >= start + count)
|
||||||
break;
|
break;
|
||||||
if (*p == 0 || (offset+incr) <= start)
|
if (*p == 0 || (offset+incr) <= start)
|
||||||
|
@ -101,8 +101,9 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
|
||||||
return ext2fs_iblk_sub_blocks(fs, inode, freed);
|
return ext2fs_iblk_sub_blocks(fs, inode, freed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BLK_T_MAX ((blk_t)~0ULL)
|
||||||
static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
|
static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
|
||||||
char *block_buf, blk_t start, blk_t count)
|
char *block_buf, blk64_t start, blk64_t end)
|
||||||
{
|
{
|
||||||
errcode_t retval;
|
errcode_t retval;
|
||||||
char *buf = 0;
|
char *buf = 0;
|
||||||
|
@ -111,6 +112,15 @@ static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
|
||||||
blk_t *bp = inode->i_block;
|
blk_t *bp = inode->i_block;
|
||||||
blk_t addr_per_block;
|
blk_t addr_per_block;
|
||||||
blk64_t max = EXT2_NDIR_BLOCKS;
|
blk64_t max = EXT2_NDIR_BLOCKS;
|
||||||
|
blk_t count;
|
||||||
|
|
||||||
|
/* Check start/end don't overflow the 2^32-1 indirect block limit */
|
||||||
|
if (start > BLK_T_MAX)
|
||||||
|
return 0;
|
||||||
|
if (end >= BLK_T_MAX || end - start + 1 >= BLK_T_MAX)
|
||||||
|
count = BLK_T_MAX - start;
|
||||||
|
else
|
||||||
|
count = end - start + 1;
|
||||||
|
|
||||||
if (!block_buf) {
|
if (!block_buf) {
|
||||||
retval = ext2fs_get_array(3, fs->blocksize, &buf);
|
retval = ext2fs_get_array(3, fs->blocksize, &buf);
|
||||||
|
@ -119,11 +129,11 @@ static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
|
||||||
block_buf = buf;
|
block_buf = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_per_block = (blk_t) fs->blocksize >> 2;
|
addr_per_block = (blk_t)fs->blocksize >> 2;
|
||||||
|
|
||||||
for (level = 0; level < 4; level++, max *= (blk64_t)addr_per_block) {
|
for (level = 0; level < 4; level++, max *= (blk64_t)addr_per_block) {
|
||||||
#ifdef PUNCH_DEBUG
|
#ifdef PUNCH_DEBUG
|
||||||
printf("Main loop level %d, start %u count %u "
|
printf("Main loop level %d, start %llu count %u "
|
||||||
"max %llu num %d\n", level, start, count, max, num);
|
"max %llu num %d\n", level, start, count, max, num);
|
||||||
#endif
|
#endif
|
||||||
if (start < max) {
|
if (start < max) {
|
||||||
|
@ -150,6 +160,7 @@ errout:
|
||||||
ext2fs_free_mem(&buf);
|
ext2fs_free_mem(&buf);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
#undef BLK_T_MAX
|
||||||
|
|
||||||
#ifdef PUNCH_DEBUG
|
#ifdef PUNCH_DEBUG
|
||||||
|
|
||||||
|
@ -460,8 +471,8 @@ static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocate all logical blocks starting at start to end, inclusive.
|
* Deallocate all logical _blocks_ starting at start to end, inclusive.
|
||||||
* If end is ~0, then this is effectively truncate.
|
* If end is ~0ULL, then this is effectively truncate.
|
||||||
*/
|
*/
|
||||||
errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
|
errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
|
||||||
struct ext2_inode *inode,
|
struct ext2_inode *inode,
|
||||||
|
@ -485,19 +496,14 @@ errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
|
||||||
return ext2fs_punch_inline_data(fs, ino, inode, start, end);
|
return ext2fs_punch_inline_data(fs, ino, inode, start, end);
|
||||||
else if (inode->i_flags & EXT4_EXTENTS_FL)
|
else if (inode->i_flags & EXT4_EXTENTS_FL)
|
||||||
retval = ext2fs_punch_extent(fs, ino, inode, start, end);
|
retval = ext2fs_punch_extent(fs, ino, inode, start, end);
|
||||||
else {
|
else
|
||||||
blk_t count;
|
retval = ext2fs_punch_ind(fs, inode, block_buf, start, end);
|
||||||
|
|
||||||
if (start > ~0U)
|
|
||||||
return 0;
|
|
||||||
if (end > ~0U)
|
|
||||||
end = ~0U;
|
|
||||||
count = ((end - start + 1) < ~0U) ? (end - start + 1) : ~0U;
|
|
||||||
retval = ext2fs_punch_ind(fs, inode, block_buf,
|
|
||||||
(blk_t) start, count);
|
|
||||||
}
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
#ifdef PUNCH_DEBUG
|
||||||
|
printf("%u: write inode size now %u blocks %u\n",
|
||||||
|
ino, inode->i_size, inode->i_blocks);
|
||||||
|
#endif
|
||||||
return ext2fs_write_inode(fs, ino, inode);
|
return ext2fs_write_inode(fs, ino, inode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,11 @@
|
||||||
#define DEL_BLK 0x0002
|
#define DEL_BLK 0x0002
|
||||||
|
|
||||||
blk_t test1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
|
blk_t test1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
|
||||||
blk_t test2[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1 };
|
blk_t test2[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1, 0 };
|
||||||
blk_t test3[] = { 3, 1, 4, 5, 9, 2, 7, 10, 5, 6, 10, 8, 0 };
|
blk_t test3[] = { 3, 1, 4, 5, 9, 2, 7, 10, 5, 6, 10, 8, 0 };
|
||||||
blk_t test4[] = { 20, 50, 12, 17, 13, 2, 66, 23, 56, 0 };
|
blk_t test4[] = { 20, 50, 12, 17, 13, 2, 66, 23, 56, 0 };
|
||||||
blk_t test4a[] = {
|
blk_t test4a[] = {
|
||||||
20, 1,
|
20, 1,
|
||||||
50, 1,
|
50, 1,
|
||||||
3, 0,
|
3, 0,
|
||||||
17, 1,
|
17, 1,
|
||||||
|
|
|
@ -93,7 +93,7 @@ set on new or empty files. If it is set on a file which already has
|
||||||
data blocks, it is undefined when the blocks assigned to the file will
|
data blocks, it is undefined when the blocks assigned to the file will
|
||||||
be fully stable. If the 'C' flag is set on a directory, it will have no
|
be fully stable. If the 'C' flag is set on a directory, it will have no
|
||||||
effect on the directory, but new files created in that directory will
|
effect on the directory, but new files created in that directory will
|
||||||
the No_COW attribute.)
|
have the No_COW attribute set.)
|
||||||
.PP
|
.PP
|
||||||
A file with the 'd' attribute set is not candidate for backup when the
|
A file with the 'd' attribute set is not candidate for backup when the
|
||||||
.BR dump (8)
|
.BR dump (8)
|
||||||
|
|
|
@ -3070,6 +3070,18 @@ retry_open:
|
||||||
ext_mount_opts);
|
ext_mount_opts);
|
||||||
free(ext_mount_opts);
|
free(ext_mount_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Warn if file system needs recovery and it is opened for writing. */
|
||||||
|
if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & EXT2_MF_MOUNTED) &&
|
||||||
|
(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
|
||||||
|
(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
_("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
|
||||||
|
"\te2fsck -E journal_only %s\n\n"
|
||||||
|
"then rerun this command. Otherwise, any changes made may be overwritten\n"
|
||||||
|
"by journal recovery.\n"), device_name);
|
||||||
|
}
|
||||||
|
|
||||||
free(device_name);
|
free(device_name);
|
||||||
remove_error_table(&et_ext2_error_table);
|
remove_error_table(&et_ext2_error_table);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
Pass 1: Checking inodes, blocks, and sizes
|
||||||
|
Pass 2: Checking directory structure
|
||||||
|
Pass 3: Checking directory connectivity
|
||||||
|
Pass 3A: Optimizing directories
|
||||||
|
Pass 4: Checking reference counts
|
||||||
|
Pass 5: Checking group summary information
|
||||||
|
|
||||||
|
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
|
||||||
|
|
||||||
|
352 inodes used (41.12%, out of 856)
|
||||||
|
0 non-contiguous files (0.0%)
|
||||||
|
1 non-contiguous directory (0.3%)
|
||||||
|
# of inodes with ind/dind/tind blocks: 0/0/0
|
||||||
|
Extent depth histogram: 342/1
|
||||||
|
586 blocks used (68.94%, out of 850)
|
||||||
|
0 bad blocks
|
||||||
|
0 large files
|
||||||
|
|
||||||
|
340 regular files
|
||||||
|
3 directories
|
||||||
|
0 character device files
|
||||||
|
0 block device files
|
||||||
|
0 fifos
|
||||||
|
0 links
|
||||||
|
0 symbolic links (0 fast symbolic links)
|
||||||
|
0 sockets
|
||||||
|
------------
|
||||||
|
343 files
|
||||||
|
Exit status is 1
|
|
@ -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: 352/856 files (0.3% non-contiguous), 586/850 blocks
|
||||||
|
Exit status is 0
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
htree extent compression
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
FSCK_OPT="-fyvD"
|
||||||
|
. $cmd_dir/run_e2fsck
|
||||||
|
|
||||||
|
exit $?
|
||||||
|
# This script depends on "mke2fs -d", which is only in master and not maint,
|
||||||
|
# to populate the file directory tree poorly (namely that there are no
|
||||||
|
# contiguous blocks in the directory leaf and the extent tree is large).
|
||||||
|
|
||||||
|
# Once the "mke2fs -d" option is available on the "maint" branch, the
|
||||||
|
# above few lines should be deleted, along with the "image.gz" file.
|
||||||
|
|
||||||
|
TMPDIR=${TMPDIR:-"/tmp"}
|
||||||
|
OUT=$test_name.log
|
||||||
|
|
||||||
|
FSCK_OPT="-fyvD"
|
||||||
|
SKIP_GUNZIP="true"
|
||||||
|
|
||||||
|
NAMELEN=250
|
||||||
|
SRC=$TMPDIR/$test_name.tmp
|
||||||
|
SUB=subdir
|
||||||
|
BASE=$SRC/$SUB/$(yes | tr -d '\n' | dd bs=$NAMELEN count=1 2> /dev/null)
|
||||||
|
TMPFILE=${TMPFILE:-"$TMPDIR/image"}
|
||||||
|
BSIZE=1024
|
||||||
|
|
||||||
|
> $OUT
|
||||||
|
mkdir -p $SRC/$SUB
|
||||||
|
# calculate the number of files needed to create the directory extent tree
|
||||||
|
# deep enough to exceed the in-inode index and spill into an index block.
|
||||||
|
#
|
||||||
|
# dirents per block * extents per block * (index blocks > i_blocks)
|
||||||
|
NUM=$(((BSIZE / (NAMELEN + 8)) * (BSIZE / 12) * 2))
|
||||||
|
# Create source files. Unfortunately hard links will be copied as links,
|
||||||
|
# and blocks with only NULs will be turned into holes.
|
||||||
|
if [ ! -f $BASE.1 ]; then
|
||||||
|
for N in $(seq $NUM); do
|
||||||
|
echo "foo" > $BASE.$N
|
||||||
|
done >> $OUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
# make filesystem with enough inodes and blocks to hold all the test files
|
||||||
|
> $TMPFILE
|
||||||
|
NUM=$((NUM * 5 / 3))
|
||||||
|
echo "mke2fs -b $BSIZE -O dir_index,extent -d$SRC -N$NUM $TMPFILE $NUM" >> $OUT
|
||||||
|
$MKE2FS -b $BSIZE -O dir_index,extent -d$SRC -N$NUM $TMPFILE $NUM >> $OUT 2>&1
|
||||||
|
rm -r $SRC
|
||||||
|
|
||||||
|
# Run e2fsck to convert dir to htree before deleting the files, as mke2fs
|
||||||
|
# doesn't do this. Run second e2fsck to verify there is no corruption yet.
|
||||||
|
(
|
||||||
|
EXP1=$test_dir/expect.pre.1
|
||||||
|
EXP2=$test_dir/expect.pre.2
|
||||||
|
OUT1=$test_name.pre.1.log
|
||||||
|
OUT2=$test_name.pre.2.log
|
||||||
|
DESCRIPTION="$(cat $test_dir/name) setup"
|
||||||
|
. $cmd_dir/run_e2fsck
|
||||||
|
)
|
||||||
|
|
||||||
|
# generate a list of filenames for debugfs to delete, one from each leaf block
|
||||||
|
DELETE_LIST=$TMPDIR/delete.$$
|
||||||
|
$DEBUGFS -c -R "htree subdir" $TMPFILE 2>> $OUT |
|
||||||
|
grep -A2 "Reading directory block" |
|
||||||
|
awk '/yyyyy/ { print "rm '$SUB'/"$4 }' > $DELETE_LIST
|
||||||
|
$DEBUGFS -w -f $DELETE_LIST $TMPFILE >> $OUT 2>&1
|
||||||
|
rm $DELETE_LIST
|
||||||
|
cp $TMPFILE $TMPFILE.sav
|
||||||
|
|
||||||
|
. $cmd_dir/run_e2fsck
|
|
@ -27,8 +27,7 @@ Inode 17 extent tree (at level 1) could be shorter. Fix? yes
|
||||||
|
|
||||||
Inode 17, i_blocks is 32, should be 0. 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
|
Inode 18 has corrupt extent header. Clear inode? yes
|
||||||
Clear inode? yes
|
|
||||||
|
|
||||||
Inode 18, i_blocks is 2, should be 0. Fix? yes
|
Inode 18, i_blocks is 2, should be 0. Fix? yes
|
||||||
|
|
||||||
|
|
|
@ -14,5 +14,5 @@ Pass 4: Checking reference counts
|
||||||
Pass 5: Checking group summary information
|
Pass 5: Checking group summary information
|
||||||
|
|
||||||
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
|
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
|
||||||
test_filesys: 47730/100192 files (0.0% non-contiguous), 13551/31745 blocks
|
test_filesys: 47730/100192 files (0.0% non-contiguous), 13550/31745 blocks
|
||||||
Exit status is 1
|
Exit status is 1
|
||||||
|
|
|
@ -3,5 +3,5 @@ Pass 2: Checking directory structure
|
||||||
Pass 3: Checking directory connectivity
|
Pass 3: Checking directory connectivity
|
||||||
Pass 4: Checking reference counts
|
Pass 4: Checking reference counts
|
||||||
Pass 5: Checking group summary information
|
Pass 5: Checking group summary information
|
||||||
test_filesys: 47730/100192 files (0.0% non-contiguous), 13551/31745 blocks
|
test_filesys: 47730/100192 files (0.0% non-contiguous), 13550/31745 blocks
|
||||||
Exit status is 0
|
Exit status is 0
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
Pass 1: Checking inodes, blocks, and sizes
|
||||||
|
Inode 12 has corrupt extent header. Clear inode? yes
|
||||||
|
|
||||||
|
Pass 2: Checking directory structure
|
||||||
|
Entry 'testa' in / (2) has deleted/unused inode 12. Clear? yes
|
||||||
|
|
||||||
|
Pass 3: Checking directory connectivity
|
||||||
|
Pass 4: Checking reference counts
|
||||||
|
Pass 5: Checking group summary information
|
||||||
|
Inode bitmap differences: -12
|
||||||
|
Fix? yes
|
||||||
|
|
||||||
|
Free inodes count wrong for group #0 (115, counted=116).
|
||||||
|
Fix? yes
|
||||||
|
|
||||||
|
Free inodes count wrong (115, counted=116).
|
||||||
|
Fix? yes
|
||||||
|
|
||||||
|
|
||||||
|
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
|
||||||
|
test_filesys: 12/128 files (0.0% non-contiguous), 15/256 blocks
|
||||||
|
Exit status is 1
|
|
@ -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: 12/128 files (0.0% non-contiguous), 15/256 blocks
|
||||||
|
Exit status is 0
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
zap inode with zeroed extent header
|
Loading…
Reference in New Issue