Merge branch 'maint' into next
Conflicts:
e2fsck/pass1.c
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 53f10b1..d6d0ba9 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -473,6 +473,7 @@
extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode, int restart_flag,
const char *source);
+extern void e2fsck_intercept_block_allocations(e2fsck_t ctx);
/* pass2.c */
extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 3f287b0..648c578 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -764,6 +764,7 @@
"block interate buffer");
if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
e2fsck_use_inode_shortcuts(ctx, 1);
+ e2fsck_intercept_block_allocations(ctx);
old_op = ehandler_operation(_("opening inode scan"));
pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
&scan);
@@ -1306,10 +1307,6 @@
}
if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
- ext2fs_block_bitmap save_bmap;
-
- save_bmap = fs->block_map;
- fs->block_map = ctx->block_found_map;
clear_problem_context(&pctx);
pctx.errcode = ext2fs_create_resize_inode(fs);
if (pctx.errcode) {
@@ -1327,7 +1324,6 @@
e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
"recreate inode");
}
- fs->block_map = save_bmap;
ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
}
@@ -2132,6 +2128,45 @@
}
pb->fragmented = 1;
}
+ /*
+ * If we notice a gap in the logical block mappings of an
+ * extent-mapped directory, offer to close the hole by
+ * moving the logical block down, otherwise we'll go mad in
+ * pass 3 allocating empty directory blocks to fill the hole.
+ */
+ if (try_repairs && is_dir &&
+ pb->last_block + 1 < (e2_blkcnt_t)extent.e_lblk) {
+ blk64_t new_lblk;
+
+ new_lblk = pb->last_block + 1;
+ if (EXT2FS_CLUSTER_RATIO(ctx->fs) > 1)
+ new_lblk = ((new_lblk +
+ EXT2FS_CLUSTER_RATIO(ctx->fs)) &
+ EXT2FS_CLUSTER_MASK(ctx->fs)) |
+ (extent.e_lblk &
+ EXT2FS_CLUSTER_MASK(ctx->fs));
+ pctx->blk = extent.e_lblk;
+ pctx->blk2 = new_lblk;
+ if (fix_problem(ctx, PR_1_COLLAPSE_DBLOCK, pctx)) {
+ extent.e_lblk = new_lblk;
+ pb->inode_modified = 1;
+ pctx->errcode = ext2fs_extent_replace(ehandle,
+ 0, &extent);
+ if (pctx->errcode) {
+ pctx->errcode = 0;
+ goto alloc_later;
+ }
+ pctx->errcode = ext2fs_extent_fix_parents(ehandle);
+ if (pctx->errcode)
+ goto failed_add_dir_block;
+ pctx->errcode = ext2fs_extent_goto(ehandle,
+ extent.e_lblk);
+ if (pctx->errcode)
+ goto failed_add_dir_block;
+ last_lblk = extent.e_lblk + extent.e_len - 1;
+ }
+ }
+alloc_later:
while (is_dir && (++pb->last_db_block <
(e2_blkcnt_t) extent.e_lblk)) {
pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist,
@@ -2926,8 +2961,8 @@
first_block = ext2fs_group_first_block2(fs,
flexbg_size * flexbg);
last_grp = group | (flexbg_size - 1);
- if (last_grp > fs->group_desc_count)
- last_grp = fs->group_desc_count;
+ if (last_grp >= fs->group_desc_count)
+ last_grp = fs->group_desc_count - 1;
last_block = ext2fs_group_last_block2(fs, last_grp);
} else
last_block = ext2fs_group_last_block2(fs, group);
@@ -3212,11 +3247,6 @@
fs->read_inode = pass1_read_inode;
fs->write_inode = pass1_write_inode;
ctx->stashed_ino = 0;
- ext2fs_set_alloc_block_callback(fs, e2fsck_get_alloc_block,
- 0);
- ext2fs_set_block_alloc_stats_callback(fs,
- e2fsck_block_alloc_stats,
- 0);
} else {
fs->get_blocks = 0;
fs->check_directory = 0;
@@ -3224,3 +3254,10 @@
fs->write_inode = 0;
}
}
+
+void e2fsck_intercept_block_allocations(e2fsck_t ctx)
+{
+ ext2fs_set_alloc_block_callback(ctx->fs, e2fsck_get_alloc_block, 0);
+ ext2fs_set_block_alloc_stats_callback(ctx->fs,
+ e2fsck_block_alloc_stats, 0);
+}
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index c2a3cf3..8d42d10 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -630,7 +630,6 @@
_("internal error: can't find dup_blk for %llu\n"),
*block_nr);
} else {
- ext2fs_unmark_block_bitmap2(ctx->block_found_map, *block_nr);
ext2fs_block_alloc_stats2(fs, *block_nr, -1);
pb->dup_blocks++;
}
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 5488c73..0ef9637 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -1336,7 +1336,6 @@
if ((*block_nr < fs->super->s_first_data_block) ||
(*block_nr >= ext2fs_blocks_count(fs->super)))
return 0;
- ext2fs_unmark_block_bitmap2(p->ctx->block_found_map, *block_nr);
ext2fs_block_alloc_stats2(fs, *block_nr, -1);
p->num++;
return 0;
@@ -1379,8 +1378,6 @@
return;
}
if (count == 0) {
- ext2fs_unmark_block_bitmap2(ctx->block_found_map,
- ext2fs_file_acl_block(fs, &inode));
ext2fs_block_alloc_stats2(fs,
ext2fs_file_acl_block(fs, &inode), -1);
}
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index 6f7f855..4fc390a 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -779,27 +779,6 @@
return BLOCK_CHANGED;
}
-/*
- * Ensure that all blocks are marked in the block_found_map, since it's
- * possible that the library allocated an extent node block or a block map
- * block during the directory rebuilding; these new allocations are not
- * captured in block_found_map. This is bad since we could later use
- * block_found_map to allocate more blocks.
- */
-static int find_new_blocks_proc(ext2_filsys fs,
- blk64_t *blocknr,
- e2_blkcnt_t blockcnt,
- blk64_t ref_block EXT2FS_ATTR((unused)),
- int ref_offset EXT2FS_ATTR((unused)),
- void *priv_data)
-{
- struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
- e2fsck_t ctx = es->ctx;
-
- ext2fs_mark_block_bitmap2(ctx->block_found_map, *blocknr);
- return 0;
-}
-
errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
int num, int guaranteed_size)
{
@@ -830,27 +809,11 @@
es.ctx = ctx;
es.dir = dir;
- before = ext2fs_free_blocks_count(fs->super);
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
0, expand_dir_proc, &es);
if (es.err)
return es.err;
- after = ext2fs_free_blocks_count(fs->super);
-
- /*
- * If the free block count has dropped by more than the blocks we
- * allocated ourselves, then we must've allocated some extent/map
- * blocks. Therefore, we must iterate this dir's blocks again to
- * ensure that all newly allocated blocks are captured in
- * block_found_map.
- */
- if ((before - after) > es.newblocks) {
- retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY,
- 0, find_new_blocks_proc, &es);
- if (es.err)
- return es.err;
- }
/*
* Update the size and block count fields in the inode.
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 18d8025..a1986c6 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1038,6 +1038,11 @@
N_("@i %i block %b conflicts with critical metadata, skipping block checks.\n"),
PROMPT_NONE, 0 },
+ /* Directory inode block <block> should be at block <otherblock> */
+ { PR_1_COLLAPSE_DBLOCK,
+ N_("@d @i %i @b %b should be at @b %c. "),
+ PROMPT_FIX, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 9001ef4..ab6ced7 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -665,6 +665,9 @@
/* Couldn't clone file (error) */
#define PR_1D_CLONE_ERROR 0x013008
+/* Directory inode has a missing block (hole) */
+#define PR_1_COLLAPSE_DBLOCK 0x010072
+
/*
* Pass 2 errors
*/
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 3b05715..5913ae7 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -725,8 +725,6 @@
* once.
*/
if (blk % EXT2FS_CLUSTER_RATIO(fs) == 0) {
- ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map,
- blk);
ext2fs_block_alloc_stats2(fs, blk, -1);
wd->cleared++;
}
@@ -850,7 +848,7 @@
/* Sort the list */
resort:
- if (fd.compress)
+ if (fd.compress && fd.num_array > 1)
qsort(fd.harray+2, fd.num_array-2, sizeof(struct hash_entry),
hash_cmp);
else
@@ -869,7 +867,7 @@
}
/* Sort non-hashed directories by inode number */
- if (fd.compress)
+ if (fd.compress && fd.num_array > 1)
qsort(fd.harray+2, fd.num_array-2,
sizeof(struct hash_entry), ino_cmp);
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index bb5141f..d883c9e 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -1780,7 +1780,7 @@
io_channel_flush(ctx->fs->io);
print_resource_track(ctx, NULL, &ctx->global_rtrack, ctx->fs->io);
- ext2fs_close_free(&fs);
+ ext2fs_close_free(&ctx->fs);
free(ctx->journal_name);
e2fsck_free_context(ctx);
diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
index b36d288..578fd7f 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -255,8 +255,11 @@
b &= ~(c_ratio - 1);
finish &= ~(c_ratio -1);
do {
- if (b+num-1 > ext2fs_blocks_count(fs->super))
+ if (b + num - 1 >= ext2fs_blocks_count(fs->super)) {
+ if (finish > start)
+ return EXT2_ET_BLOCK_ALLOC_FAIL;
b = fs->super->s_first_data_block;
+ }
if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) {
*ret = b;
return 0;
diff --git a/misc/mk_hugefiles.c b/misc/mk_hugefiles.c
index 41280f0..6bc25e6 100644
--- a/misc/mk_hugefiles.c
+++ b/misc/mk_hugefiles.c
@@ -188,7 +188,9 @@
cp = search_sysfs_block(st.st_rdev, path);
if (!cp)
return 0;
- strncat(path, "/start", SYSFS_PATH_LEN-1);
+ if (strlen(path) > SYSFS_PATH_LEN - sizeof("/start"))
+ return 0;
+ strcat(path, "/start");
f = fopen(path, "r");
if (!f)
return 0;
diff --git a/tests/f_boundscheck/expect.1 b/tests/f_boundscheck/expect.1
new file mode 100644
index 0000000..c2170b8
--- /dev/null
+++ b/tests/f_boundscheck/expect.1
@@ -0,0 +1,25 @@
+ext2fs_check_desc: Corrupt group descriptor: bad block for inode table
+../e2fsck/e2fsck: Group descriptors look bad... trying backup blocks...
+../e2fsck/e2fsck: Bad magic number in super-block while using the backup blocks../e2fsck/e2fsck: going back to original superblock
+Note: if several inode or block bitmap blocks or part
+of the inode table require relocation, you may wish to try
+running e2fsck with the '-b 8193' option first. The problem
+may lie only with the primary block group descriptors, and
+the backup block group descriptors may be OK.
+
+Inode table for group 1 is not in group. (block 4294967295)
+WARNING: SEVERE DATA LOSS POSSIBLE.
+Relocate? yes
+
+One or more block group descriptor checksums are invalid. Fix? yes
+
+Group descriptor 1 checksum is 0x6ea2, should be 0x7edd. FIXED.
+Pass 1: Checking inodes, blocks, and sizes
+Error allocating 256 contiguous block(s) in block group 1 for inode table: Could not allocate block in ext2 filesystem
+e2fsck: aborted
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+
+test_filesys: ********** WARNING: Filesystem still has errors **********
+
+Exit status is 0
diff --git a/tests/f_boundscheck/expect.2 b/tests/f_boundscheck/expect.2
new file mode 100644
index 0000000..c2170b8
--- /dev/null
+++ b/tests/f_boundscheck/expect.2
@@ -0,0 +1,25 @@
+ext2fs_check_desc: Corrupt group descriptor: bad block for inode table
+../e2fsck/e2fsck: Group descriptors look bad... trying backup blocks...
+../e2fsck/e2fsck: Bad magic number in super-block while using the backup blocks../e2fsck/e2fsck: going back to original superblock
+Note: if several inode or block bitmap blocks or part
+of the inode table require relocation, you may wish to try
+running e2fsck with the '-b 8193' option first. The problem
+may lie only with the primary block group descriptors, and
+the backup block group descriptors may be OK.
+
+Inode table for group 1 is not in group. (block 4294967295)
+WARNING: SEVERE DATA LOSS POSSIBLE.
+Relocate? yes
+
+One or more block group descriptor checksums are invalid. Fix? yes
+
+Group descriptor 1 checksum is 0x6ea2, should be 0x7edd. FIXED.
+Pass 1: Checking inodes, blocks, and sizes
+Error allocating 256 contiguous block(s) in block group 1 for inode table: Could not allocate block in ext2 filesystem
+e2fsck: aborted
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+
+test_filesys: ********** WARNING: Filesystem still has errors **********
+
+Exit status is 0
diff --git a/tests/f_boundscheck/image.bz2 b/tests/f_boundscheck/image.bz2
new file mode 100644
index 0000000..098d02e
--- /dev/null
+++ b/tests/f_boundscheck/image.bz2
Binary files differ
diff --git a/tests/f_boundscheck/name b/tests/f_boundscheck/name
new file mode 100644
index 0000000..192d279
--- /dev/null
+++ b/tests/f_boundscheck/name
@@ -0,0 +1 @@
+infinite loop due to off by one error when finding free space for inode table relocation
diff --git a/tests/f_boundscheck/script b/tests/f_boundscheck/script
new file mode 100755
index 0000000..fbbce62
--- /dev/null
+++ b/tests/f_boundscheck/script
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+FSCK_OPT=-fy
+IMAGE=$test_dir/image.bz2
+
+bzip2 -d < $IMAGE > $TMPFILE
+#e2label $TMPFILE test_filesys
+
+# Run fsck to fix things?
+EXP1=$test_dir/expect.1
+OUT1=$test_name.1.log
+rm -rf $test_name.failed $test_name.ok
+
+$FSCK $FSCK_OPT $TMPFILE 2>&1 | head -n 1000 | tail -n +2 > $OUT1
+echo "Exit status is $?" >> $OUT1
+
+# Run a second time
+EXP2=$test_dir/expect.2
+OUT2=$test_name.2.log
+
+$FSCK $FSCK_OPT $TMPFILE 2>&1 | head -n 1000 | tail -n +2 > $OUT2
+echo "Exit status is $?" >> $OUT2
+
+# Figure out what happened
+if cmp -s $EXP1 $OUT1 && cmp -s $EXP2 $OUT2; then
+ echo "$test_name: $test_description: ok"
+ touch $test_name.ok
+else
+ echo "$test_name: $test_description: failed"
+ diff -u $EXP1 $OUT1 >> $test_name.failed
+ diff -u $EXP2 $OUT2 >> $test_name.failed
+fi
diff --git a/tests/f_holedir2/expect.1 b/tests/f_holedir2/expect.1
index 5124f61..455f4b0 100644
--- a/tests/f_holedir2/expect.1
+++ b/tests/f_holedir2/expect.1
@@ -1,21 +1,19 @@
Pass 1: Checking inodes, blocks, and sizes
Inode 12, i_size is 0, should be 5120. Fix? yes
-Inode 13, i_size is 4096, should be 5120. Fix? yes
+Directory inode 13 block 2 should be at block 1. Fix? yes
Pass 2: Checking directory structure
Directory inode 12 has an unallocated block #3. Allocate? yes
-Directory inode 13 has an unallocated block #1. Allocate? yes
-
Pass 3: Checking directory connectivity
Pass 3A: Optimizing directories
Pass 4: Checking reference counts
Pass 5: Checking group summary information
-Free blocks count wrong for group #0 (79, counted=77).
+Free blocks count wrong for group #0 (78, counted=77).
Fix? yes
-Free blocks count wrong (79, counted=77).
+Free blocks count wrong (78, counted=77).
Fix? yes
diff --git a/tests/f_holedir3/expect.1 b/tests/f_holedir3/expect.1
new file mode 100644
index 0000000..074ca6c
--- /dev/null
+++ b/tests/f_holedir3/expect.1
@@ -0,0 +1,13 @@
+Pass 1: Checking inodes, blocks, and sizes
+Directory inode 12 block 5 should be at block 2. Fix? yes
+
+Inode 12, i_size is 6144, should be 3072. Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 17/128 files (5.9% non-contiguous), 1093/2048 blocks
+Exit status is 1
diff --git a/tests/f_holedir3/expect.2 b/tests/f_holedir3/expect.2
new file mode 100644
index 0000000..b675e6d
--- /dev/null
+++ b/tests/f_holedir3/expect.2
@@ -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: 17/128 files (5.9% non-contiguous), 1093/2048 blocks
+Exit status is 0
diff --git a/tests/f_holedir3/image.gz b/tests/f_holedir3/image.gz
new file mode 100644
index 0000000..c5eeb37
--- /dev/null
+++ b/tests/f_holedir3/image.gz
Binary files differ
diff --git a/tests/f_holedir3/name b/tests/f_holedir3/name
new file mode 100644
index 0000000..a526787
--- /dev/null
+++ b/tests/f_holedir3/name
@@ -0,0 +1,2 @@
+real directories with holes and zero i_size
+