e2fsck: delete bad inode fix for bigalloc

While deleting a bad inode in fsck pass2, we should remove clusters
only once. We do it by remembering last released cluster while
deleting clusters one by one.

Signed-off-by: Harshad Shirwadkar <harshads@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index e922876..c6aff71 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -1610,6 +1610,7 @@
 struct del_block {
 	e2fsck_t	ctx;
 	e2_blkcnt_t	num;
+	blk64_t last_cluster;
 };
 
 /*
@@ -1624,14 +1625,20 @@
 				  void *priv_data)
 {
 	struct del_block *p = priv_data;
+	blk64_t cluster = EXT2FS_B2C(fs, *block_nr);
 
 	if (*block_nr == 0)
 		return 0;
+
+	if (cluster == p->last_cluster)
+		return 0;
+
+	p->last_cluster = cluster;
 	if ((*block_nr < fs->super->s_first_data_block) ||
 	    (*block_nr >= ext2fs_blocks_count(fs->super)))
 		return 0;
-	if ((*block_nr % EXT2FS_CLUSTER_RATIO(fs)) == 0)
-		ext2fs_block_alloc_stats2(fs, *block_nr, -1);
+
+        ext2fs_block_alloc_stats2(fs, *block_nr, -1);
 	p->num++;
 	return 0;
 }
@@ -1692,6 +1699,7 @@
 
 	del_block.ctx = ctx;
 	del_block.num = 0;
+	del_block.last_cluster = 0;
 	pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
 					     deallocate_inode_block,
 					     &del_block);
diff --git a/tests/f_bigalloc_badinode/expect.1 b/tests/f_bigalloc_badinode/expect.1
new file mode 100644
index 0000000..10ba096
--- /dev/null
+++ b/tests/f_bigalloc_badinode/expect.1
@@ -0,0 +1,12 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Symlink /testfile (inode #12) is invalid.
+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: 11/64 files (0.0% non-contiguous), 96/1024 blocks
+Exit status is 1
diff --git a/tests/f_bigalloc_badinode/expect.2 b/tests/f_bigalloc_badinode/expect.2
new file mode 100644
index 0000000..30392d4
--- /dev/null
+++ b/tests/f_bigalloc_badinode/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: 11/64 files (0.0% non-contiguous), 96/1024 blocks
+Exit status is 0
diff --git a/tests/f_bigalloc_badinode/name b/tests/f_bigalloc_badinode/name
new file mode 100644
index 0000000..e1ed216
--- /dev/null
+++ b/tests/f_bigalloc_badinode/name
@@ -0,0 +1 @@
+delete bad inode handling for bigalloc filesystems
diff --git a/tests/f_bigalloc_badinode/script b/tests/f_bigalloc_badinode/script
new file mode 100644
index 0000000..9113e9c
--- /dev/null
+++ b/tests/f_bigalloc_badinode/script
@@ -0,0 +1,24 @@
+if test -x $DEBUGFS_EXE; then
+
+SKIP_GUNZIP="true"
+TEST_DATA="$test_name.tmp"
+
+dd if=$TEST_BITS of=$TEST_DATA bs=4k count=2 seek=1> /dev/null 2>&1
+
+touch $TMPFILE
+mke2fs -Fq -t ext4 -O bigalloc -C 16384 $TMPFILE 1M > /dev/null 2>&1
+debugfs -w $TMPFILE << EOF > /dev/null 2>&1
+write $TEST_DATA testfile
+set_inode_field testfile i_mode 0120000
+quit
+EOF
+
+. $cmd_dir/run_e2fsck
+
+rm -f $TEST_DATA
+
+unset E2FSCK_TIME TEST_DATA
+
+else #if test -x $DEBUGFS_EXE; then
+	echo "$test_name: $test_description: skipped"
+fi