[Ocfs2-tools-devel] [patch] Add test programs in ocfs2-test to verify removing slots. take 1

tao.ma tao.ma at oracle.com
Wed Jul 11 02:20:47 PDT 2007


Add test script in ocfs2-test to test whether removing can work OK.

1. test_remove.c
 This file is used to create some boudary situation to test whether
 tunefs.ocfs2 can work OK with removing slots.
When we have orphan files or have some blocks allocated in truncate log
or local alloc, we can't remove the slots, so the option CREATE_ORPHAN_FILE,
CREATE_TRUNCATE_LOG and CREATE_LOCAL_ALLOC are used to check it.

2. corrupt.patch
With this patch, tunefs.ocfs2 will abort at the specified place and we 
can check
whether fsck.ocfs2 can fix the aborted problem.

3. remove_slot.patch
The main test script to test removing slots.


-------------- next part --------------
Index: programs/tunefs-test/remove-slot/remove_slot.sh
===================================================================
--- programs/tunefs-test/remove-slot/remove_slot.sh	(revision 0)
+++ programs/tunefs-test/remove-slot/remove_slot.sh	(revision 0)
@@ -0,0 +1,523 @@
+#!/bin/bash
+#
+# Copyright (C) 2007 Oracle.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public
+# License, version 2,  as published by the Free Software Foundation.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 021110-1307, USA.
+#
+
+################################################################
+
+#
+# This script will check the remove slot function for tunefs.ocfs2.
+#
+# precondition_test:
+# check whether tunefs.ocfs2 abort its operation when the precondition
+# isn't satisfied. The extra program "test_remove" is needed to create
+# some files under some specified location.
+#
+# normal_test:
+# This program will do the normal test for removing slots. It includes
+# creating files using the specified slots and shrinking the slots. 
+#
+# corrupt_test:
+# This program will do some corruption test which need to patch tunefs.ocfs2
+# with the specified "corrupt.patch" in this directory. So that tunefs.ocfs2
+# will abort at the specified place and we can check whether fsck.ocfs2 can
+# fix the problem.
+#
+
+MKFS_BIN=`which mkfs.ocfs2`
+FSCK_BIN=`which fsck.ocfs2`
+DEBUGFS_BIN=`which debugfs.ocfs2`
+TUNEFS_BIN=`which tunefs.ocfs2`
+TEST_AUX_BIN=
+LOG_DIR=$PWD
+
+BLOCKDEV=`which blockdev`
+DEVICE=""
+
+FSCK_OUTPUT="/tmp/fsck.ocfs2.output"
+FSCK_OUTPUT_STANDARD="/tmp/fsck.ocfs2.output.std"
+
+#
+# usage			Display help information and exit.
+#
+function usage()
+{
+	local script="${0##*/}"
+	cat <<-EOF
+	Usage: $script [options] device
+
+	Options:
+	      --help                       display this help and exit
+	      --log-dir=DIRECTORY          use the DIRECTORY to store the log
+	      --with-tunefs=PROGRAM        use the PROGRAM as tunefs.ocfs2
+	      --with-fsck=PROGRAM          use the PROGRAM as fsck.ocfs2
+	      --with-mkfs=PROGRAM          use the PROGRAM as fswreck
+	      --with-debugfs=PROGRAM       use the PROGRAM as mkfs.ocfs2
+	      --with-aux=PROGRAM           use the PROGRAM as auxiliary tool.
+
+	Examples:
+
+	  $script --with-aux=./test_remove --log-dir=/tmp /dev/sdd1
+	EOF
+}
+
+#
+# warn_if_bad
+#
+#	$1	the result to check
+#	$2	the result we want
+#	$3	the error messge
+#	$4	the line num of the caller
+#
+#
+function warn_if_bad()
+{
+	local -i rc="$1"
+	local -i wanted="$2"
+	local script="${0##*/}"
+
+	# Ignore if no problems
+	[ "$rc" -eq "$wanted" ] && return 0
+
+	# Broken
+	shift
+	echo "$script: $@">&2
+	echo "$script: $@">&3
+	return 1
+}
+
+#
+# exit_if_bad		Put out error message(s) if $1 has bad RC.
+#
+#	$1	the result to check
+#	$2	the result we want
+#	$3	the error messge
+#	$4	the line num of the caller
+#
+#       Exits with 1 unless $1 is 0
+#
+function exit_if_bad()
+{
+	warn_if_bad "$@" || exit 1
+	return 0
+}
+
+function set_log_file()
+{
+	mkdir -p $LOG_DIR
+	if [ ! -d $LOG_DIR ]; then
+		echo "log_dir[$LOG_DIR] not exist, use [$PWD] instead."
+		LOG_DIR=$PWD
+	fi
+	
+	output_log="$LOG_DIR/`date +%F-%H-%M-%S`-output.log"
+	exec 3>&1
+	exec 1>$output_log 2>&1
+}
+
+function precondition_test()
+{
+	echo "Orphan dir test: Create a file under the directory and tunefs.ocfs2 should fail."
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	slot_num=4
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	slot_num=`expr $slot_num - 1`
+	$TEST_AUX_BIN -n $slot_num -o $DEVICE
+	exit_if_bad $? "0" "fail to create orphan file for slot $slot_num" $LINENO
+
+	echo "y"|$TUNEFS_BIN -N $slot_num $DEVICE
+	exit_if_bad $? "1" "tunefs.ocfs2 should fail while there is some orphan file for slot $slot_num" $LINENO
+
+	echo "local alloc test: Alloc some bits to local alloc and tunefs.ocfs2 should fail."
+	slot_num=4
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	slot_num=`expr $slot_num - 1`
+	$TEST_AUX_BIN -n $slot_num -l $DEVICE
+	exit_if_bad $? "0" "fail to allocate local alloc file for slot $slot_num" $LINENO
+
+	echo "y"|$TUNEFS_BIN -N $slot_num $DEVICE
+	exit_if_bad $? "1" "tunefs.ocfs2 should fail while local alloc file for slot $slot_num isn't empty." $LINENO
+
+	echo "truncate log test: Alloc some bits to truncate log and tunefs.ocfs2 should fail."
+	slot_num=4
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	slot_num=`expr $slot_num - 1`
+	$TEST_AUX_BIN -n $slot_num -l $DEVICE
+	exit_if_bad $? "0" "fail to allocate truncate log file for slot $slot_num" $LINENO
+
+	echo "y"|$TUNEFS_BIN -N $slot_num $DEVICE
+	exit_if_bad $? "1" "tunefs.ocfs2 should fail while truncate log for slot $slot_num isn't empty." $LINENO
+}
+
+# create some test files in all the slots
+function create_test_files()
+{
+	local max_slots=$1
+	local dir="/tmp/test$RANDOM"
+	local -i i=0
+	local -i j=0
+	local prefix=$RANDOM
+	local -i mount_slot=0
+	local -i mounted_slot=0
+
+	mkdir $dir
+
+	for((mount_slot=0;mount_slot<$max_slots;mount_slot++))
+	do
+		mount -t ocfs2 -o preferred_slot=$mount_slot $DEVICE $dir
+		exit_if_bad $? "0" "fail to mount $DEVICE at $dir in slot $mount_slot" $LINENO
+
+		# check whether the device is mounted in the preferred slot.
+		# now I use dmesg log to find the mounted slot, I am not sure
+		# whether there is another place in the system for me to read
+		# the mounted slot.
+		mounted_slot=`dmesg|tail -n 1|sed -e 's/^.*slot \(.*\))/\1/'`
+		[ $mounted_slot = $mount_slot ]
+		exit_if_bad $? "0" "we should mount $DEVICE in slot $mount_slot, not $mounted_slot" $LINENO
+
+		prefix=$RANDOM
+		mkdir "$dir/$prefix"
+		echo "Create some test files using slot $mount_slot in dir $dir/$prefix."
+
+		# we close xtrace since there are too many commands.
+		set +x
+
+		#create some inodes at the specified inodes.
+		for((i=1;i<10000;i++))
+		do
+			touch "$dir/$prefix/ino$i"
+		done
+
+		#reopen xtrace
+		set -x
+		umount $dir
+		exit_if_bad $? "0" "fail to umount $DEVICE at $dir" $LINENO
+	done
+	rm -r $dir
+
+}
+
+function normal_test()
+{
+	local -i slot_num=8
+	local -i result=0
+
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	#save the perfect fsck output first for our future use.
+	$FSCK_BIN -fy $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT_STANDARD
+
+	# First remove the slot once at a time, from 8->7->..->3->2.
+	while((slot_num>=2))
+	do
+		create_test_files $slot_num
+
+		slot_num=`expr $slot_num - 1`
+		# Decrease the size.
+		echo "y"|$TUNEFS_BIN -N $slot_num $DEVICE
+
+		result=`$DEBUGFS_BIN -R "stats" $DEVICE|grep "Slots"|awk '{print $4}'`
+		exit_if_bad $result $slot_num "fsck find errors after decrease slot to $slot_num." $LINENO
+
+		$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT
+		diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+		exit_if_bad $? "0" "fsck find errors after decrease slot to $slot_num." $LINENO
+
+	done
+
+	#shrink the slot from 8 to 2 directly.
+	slot_num=8
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	#save the perfect fsck output first for our future use.
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT_STANDARD
+
+	create_test_files $slot_num
+
+	slot_num=2
+	# Decrease the size.
+	echo "y"|$TUNEFS_BIN -N $slot_num $DEVICE
+
+	result=`$DEBUGFS_BIN -R "stats" $DEVICE|grep "Slots"|awk '{print $4}'`
+	exit_if_bad $result $slot_num "fsck find errors after decrease slot to $slot_num." $LINENO
+
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT
+	diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+	exit_if_bad $? "0" "fsck find errors after decrease slot to $slot_num." $LINENO
+}
+
+function check_volume()
+{
+	local mount_slot=$1
+	local mounted_slot="0"
+	local dir=$2
+	local lineno=$3
+
+	# we shouldn't find any error during a second fsck.
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT
+	diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+	exit_if_bad $? "0" "fsck find errors in the second fsck." $lineno
+
+	# we should be able to mount the volume in the preferred slot
+	# without any problem.
+	mount -t ocfs2 -o preferred_slot=$mount_slot $DEVICE $dir
+	exit_if_bad $? "0" "fail to mount $DEVICE at $dir in slot $mount_slot" $lineno
+	mounted_slot=`dmesg|tail -n 1|sed -e 's/^.*slot \(.*\))/\1/'`
+	[ $mounted_slot = $mount_slot ]
+	exit_if_bad $? "0" "we should succeed to mount $DEVICE at $dir in slot $mount_slot" $LINENO
+	umount $dir
+
+}
+
+# The following definition is defined according to the corrupt place
+# we define in corrupt.patch.
+RS_AFTER_RELINK_EXTENT_ALLOC=1
+RS_AFTER_RELINK_INODE_ALLOC=2
+RS_AFTER_TRUNCATE_ORPHAN=3
+RS_AFTER_TRUNCATE_JOURNAL=4
+RS_AFTER_WRITE_SUPER=5
+RS_AFTER_REMOVE_ONE_SLOT=6
+RS_AFTER_MOVE_SOME_REC=7
+RS_AFTER_CHANGE_SUB_ALLOC=8
+RS_AFTER_LINK_GROUP=9
+RS_AFTER_MOVE_ONE_GROUP=10
+RS_AFTER_EMPTY_JOURNAL=11
+
+function corrupt_test()
+{
+	local -i corrupt_place=1
+	local -i slot_num=8
+	local -i mount_slot=`expr $slot_num - 1`
+	local -i mounted_slot=0
+	local -i new_slot=4
+	local -i removed_slot=`expr $slot_num - 1`
+	local removed_slot_string=`printf "%04d" $removed_slot`
+	local result=""
+	local dir="/tmp/test$RANDOM"
+
+	mkdir $dir
+
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	#save the perfect fsck output first for our future use.
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT_STANDARD
+
+	create_test_files $slot_num
+
+	#RS_AFTER_RELINK_EXTENT_ALLOC = 1
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_RELINK_EXTENT_ALLOC -N $new_slot $DEVICE
+
+	$FSCK_BIN -fy $DEVICE>/dev/null
+
+	check_volume $mount_slot $dir $LINENO
+
+	# RS_AFTER_RELINK_INODE_ALLOC = 2
+	# the initial inode shouldn't be empty for our test.
+	result=`echo "stat //inode_alloc:$removed_slot_string"|$DEBUGFS_BIN $DEVICE|grep "Size:"|awk '{print $8}'`
+	[ $result != "0" ]
+	exit_if_bad $? 0 "The inode alloc for removed slot shouldn't be empty." $LINENO
+
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_RELINK_INODE_ALLOC -N $new_slot $DEVICE
+
+	$FSCK_BIN -fy $DEVICE>/dev/null
+
+	check_volume $mount_slot $dir $LINENO
+
+	# after relink inode alloc, the inode stored in inode_alloc:removed_slot
+	# should be moved to other groups.
+	result=`echo "stat //inode_alloc:$removed_slot_string"|$DEBUGFS_BIN $DEVICE|grep "Size:"|awk '{print $8}'`
+	exit_if_bad $result "0" "The inode alloc for removed slot should be empty." $LINENO
+
+	#RS_AFTER_TRUNCATE_ORPHAN = 3
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_TRUNCATE_ORPHAN -N $new_slot $DEVICE
+
+	# the orphan dir is empty, so fsck.ocfs2 should create another one.
+	$FSCK_BIN -fy $DEVICE|grep "ORPHAN_DIR_MISSING"
+	exit_if_bad $? "0" "The orphan dir should be created." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	#RS_AFTER_TRUNCATE_JOURNAL = 4
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_TRUNCATE_JOURNAL -N $new_slot $DEVICE
+
+	# the journal is truncated, so fsck.ocfs2 should create another one.
+	$FSCK_BIN -fy $DEVICE|grep "JOURNAL_FILE_INVALID"
+	exit_if_bad $? "0" "The journal file should be created." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	#RS_AFTER_WRITE_SUPER = 5
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_WRITE_SUPER -N $new_slot $DEVICE
+
+	# the function is almost finished, system dir's count problem should be fixed.
+	$FSCK_BIN -fy $DEVICE|grep "INODE_COUNT"
+	exit_if_bad $? "0" "The inode count should be fixed ." $LINENO
+
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT
+	diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+	exit_if_bad $? "0" "fsck find errors in the second fsck." $LINENO
+
+	# the slot have been removed, we shouldn't mount on the removed slot,
+	# so ocfs2 will select another slot to mount the volume.
+	mount -t ocfs2 -o preferred_slot=$mount_slot $DEVICE $dir
+	mounted_slot=`dmesg|tail -n 1|sed -e 's/^.*slot \(.*\))/\1/'`
+	[ $mounted_slot != $mount_slot ]
+	exit_if_bad $? "0" "we shouldn't succeed to mount $DEVICE at $dir in slot $mount_slot" $LINENO
+	umount $dir
+
+	#RS_AFTER_REMOVE_ONE_SLOT = 6
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_REMOVE_ONE_SLOT -N $new_slot $DEVICE
+	
+	# all the work for removing 1 slot is done, no error should be found.
+	$FSCK_BIN -fy $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT
+	diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+	exit_if_bad $? "0" "fsck find errors after the fsck." $LINENO
+
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT
+	diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+	exit_if_bad $? "0" "fsck find errors in the second fsck." $LINENO
+
+	# Now the slot shrink is finished, so we have to recreate the test environment.
+	slot_num=8
+	dd if=/dev/zero of=$DEVICE bs=4096 count=3
+	$MKFS_BIN -b 512 -C 4K -N $slot_num $DEVICE
+
+	#save the perfect fsck output first for our future use.
+	$FSCK_BIN -f $DEVICE|sed -e '/slots/ d'>$FSCK_OUTPUT_STANDARD
+
+	create_test_files $slot_num
+
+	#RS_AFTER_MOVE_SOME_REC = 7
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_MOVE_SOME_REC -N $new_slot $DEVICE
+	
+	$FSCK_BIN -fy $DEVICE|grep "CHAIN_EMPTY"
+	exit_if_bad $? "0" "The error 'CHAIN_EMPTY' should be found." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	#RS_AFTER_CHANGE_SUB_ALLOC = 8
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_CHANGE_SUB_ALLOC -N $new_slot $DEVICE
+	
+	$FSCK_BIN -fy $DEVICE|grep "INODE_SUBALLOC"
+	exit_if_bad $? "0" "The error 'INODE_SUBALLOC' should be found." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	#RS_AFTER_LINK_GROUP = 9
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_LINK_GROUP -N $new_slot $DEVICE
+
+	$FSCK_BIN -fy $DEVICE|grep "GROUP_PARENT"
+	exit_if_bad $? "0" "The error 'GROUP_PARENT' should be found." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	#RS_AFTER_MOVE_ONE_GROUP = 10
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_MOVE_ONE_GROUP -N $new_slot $DEVICE
+
+	$FSCK_BIN -fy $DEVICE|grep "GROUP_DUPLICATE"
+	exit_if_bad $? "0" "The error 'GROUP_DUPLICATE' should be found." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	#RS_AFTER_EMPTY_JOURNAL
+	echo "y"|$TUNEFS_BIN --corrupt $RS_AFTER_EMPTY_JOURNAL -N $new_slot $DEVICE
+
+	# the journal is truncated, so fsck.ocfs2 should create another one.
+	$FSCK_BIN -fy $DEVICE|grep "JOURNAL_FILE_INVALID"
+	exit_if_bad $? "0" "The journal file should be created." $LINENO
+
+	check_volume $mount_slot $dir $LINENO
+
+	rmdir $dir
+}
+
+################################################################
+
+#
+# main
+#
+if [ "$#" -eq "0" ]
+then
+	usage
+	exit 255
+fi
+
+while [ "$#" -gt "0" ]
+do
+	case "$1" in
+	"--help")
+		usage
+		exit 255
+		;;
+	"--log-dir="*)
+		LOG_DIR="${1#--log-dir=}"
+		;;
+	"--with-tunefs="*)
+		TUNEFS_BIN="${1#--with-tunefs=}"
+		;;
+	"--with-fsck="*)
+		FSCK_BIN="${1#--with-fsck=}"
+		;;
+	"--with-mkfs="*)
+		MKFS_BIN="${1#--with-mkfs=}"
+		;;
+	"--with-debugfs="*)
+		DEBUGFS_BIN="${1#--with-debugfs=}"
+		;;
+	"--with-aux="*)
+		TEST_AUX_BIN="${1#--with-aux=}"
+		;;
+	*)
+		DEVICE="$1"
+		;;
+	esac
+	shift
+done
+
+if [ ! -b "$DEVICE" ]; then
+	echo "invalid block device - $DEVICE"
+	usage
+	exit 1
+fi
+
+which $TEST_AUX_BIN
+if [ "$?" != "0" ]; then
+	echo "$TEST_AUX_BIN not exist, can't go on the test."
+	usage
+	exit 1
+fi
+
+set_log_file
+
+#from now on all the command and log will be recorded to the logfile.
+set -x
+
+precondition_test
+
+normal_test
+
+corrupt_test
+
+exit 0

Property changes on: programs/tunefs-test/remove-slot/remove_slot.sh
___________________________________________________________________
Name: svn:executable
   + *

Index: programs/tunefs-test/remove-slot/corrupt.patch
===================================================================
--- programs/tunefs-test/remove-slot/corrupt.patch	(revision 0)
+++ programs/tunefs-test/remove-slot/corrupt.patch	(revision 0)
@@ -0,0 +1,177 @@
+diff -urNp ocfs2-tools/tunefs.ocfs2/remove_slot.c corrupt.ocfs2-tools/tunefs.ocfs2/remove_slot.c
+--- ocfs2-tools/tunefs.ocfs2/remove_slot.c	2007-07-10 15:28:56.000000000 -0400
++++ corrupt.ocfs2-tools/tunefs.ocfs2/remove_slot.c	2007-07-10 15:29:10.000000000 -0400
+@@ -32,6 +32,12 @@
+ 
+ extern ocfs2_tune_opts opts;
+ 
++static inline void test_corrupt(enum corrupt_place place)
++{
++	if (opts.corrupt_place == place)
++		abort();
++}
++
+ struct moved_group {
+ 	uint64_t blkno;
+ 	char *gd_buf;
+@@ -138,6 +144,8 @@ static errcode_t move_group(ocfs2_filesy
+ 	if (ret)
+ 		goto bail;
+ 
++	test_corrupt(RS_AFTER_LINK_GROUP);
++
+ 	/* modify the chain record and the new files simultaneously. */
+ 	cr->c_blkno = gd->bg_blkno;
+ 	cr->c_total += gd->bg_bits;
+@@ -235,11 +243,15 @@ static errcode_t move_chain_rec(ocfs2_fi
+ 			}
+ 		}
+ 
++		test_corrupt(RS_AFTER_CHANGE_SUB_ALLOC);
++
+ 		/* move the group to the new slots. */
+ 		ret = move_group(fs, ctxt, group);
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_MOVE_ONE_GROUP);
++
+ 		group = group->next;
+ 	}
+ 
+@@ -340,6 +352,8 @@ static errcode_t relink_system_alloc(ocf
+ 				"while iterating system alloc file");
+ 			goto bail;
+ 		}
++
++		test_corrupt(RS_AFTER_MOVE_SOME_REC);
+ 	}
+ 
+ 
+@@ -427,6 +441,8 @@ static errcode_t empty_and_truncate_jour
+ 	if (ret)
+ 		goto bail;
+ 
++	test_corrupt(RS_AFTER_EMPTY_JOURNAL);
++
+ 	ret = ocfs2_truncate(fs, blkno, 0);
+ 	if (ret)
+ 		goto bail;
+@@ -542,12 +558,16 @@ errcode_t remove_slots(ocfs2_filesys *fs
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_RELINK_EXTENT_ALLOC);
++
+ 		/* Link the specified inode alloc file to others. */
+ 		ret = relink_system_alloc(fs, removed_slot, opts.num_slots,
+ 					  INODE_ALLOC_SYSTEM_INODE);
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_RELINK_INODE_ALLOC);
++
+ 		/* Truncate the orphan dir to release its clusters
+ 		 * to the global bitmap.
+ 		 */
+@@ -555,11 +575,15 @@ errcode_t remove_slots(ocfs2_filesys *fs
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_TRUNCATE_ORPHAN);
++
+ 		/* empty the content of journal and truncate its clusters. */
+ 		ret = empty_and_truncate_journal(fs, removed_slot);
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_TRUNCATE_JOURNAL);
++
+ 		/* Now, we decrease the max_slots first and then remove the
+ 		 * slots for the reason that:
+ 		 *
+@@ -581,6 +605,8 @@ errcode_t remove_slots(ocfs2_filesys *fs
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_WRITE_SUPER);
++
+ 		/* The extra system dir entries should be removed. */
+ 		ret = remove_slot_entry(fs, removed_slot);
+ 		if (ret)
+@@ -593,6 +619,8 @@ errcode_t remove_slots(ocfs2_filesys *fs
+ 		if (ret)
+ 			goto bail;
+ 
++		test_corrupt(RS_AFTER_REMOVE_ONE_SLOT);
++
+ 		removed_slot--;
+ 	}
+ 
+diff -urNp ocfs2-tools/tunefs.ocfs2/tunefs.c corrupt.ocfs2-tools/tunefs.ocfs2/tunefs.c
+--- ocfs2-tools/tunefs.ocfs2/tunefs.c	2007-06-19 09:48:58.000000000 -0400
++++ corrupt.ocfs2-tools/tunefs.ocfs2/tunefs.c	2007-07-09 10:13:27.000000000 -0400
+@@ -34,6 +34,7 @@ static void usage(const char *progname)
+ {
+ 	fprintf(stderr, "usage: %s [-J journal-options] [-L volume-label]\n"
+ 			"\t\t[-M mount-type] [-N number-of-node-slots] [-Q query-fmt]\n"
++			"\t\t[--corrupt place]\n"
+ 			"\t\t[-qSUvV] [--backup-super] device [blocks-count]\n",
+ 			progname);
+ 	exit(0);
+@@ -195,6 +196,7 @@ static void get_options(int argc, char *
+ 		{ "uuid-reset", 0, 0, 'U'},
+ 		{ "mount", 1, 0, 'M' },
+ 		{ "backup-super", 0, 0, BACKUP_SUPER_OPTION },
++		{ "corrupt", 1, 0, CORRUPT_OPTION },
+ 		{ 0, 0, 0, 0}
+ 	};
+ 
+@@ -293,6 +295,10 @@ static void get_options(int argc, char *
+ 			opts.backup_super = 1;
+ 			break;
+ 
++		case CORRUPT_OPTION:
++			opts.corrupt_place = strtol(optarg, &dummy, 0);
++			break;
++
+ 		default:
+ 			usage(opts.progname);
+ 			break;
+diff -urNp ocfs2-tools/tunefs.ocfs2/tunefs.h corrupt.ocfs2-tools/tunefs.ocfs2/tunefs.h
+--- ocfs2-tools/tunefs.ocfs2/tunefs.h	2007-06-14 15:00:12.000000000 -0400
++++ corrupt.ocfs2-tools/tunefs.ocfs2/tunefs.h	2007-07-09 10:26:37.000000000 -0400
+@@ -70,6 +70,7 @@
+ 
+ enum {
+ 	BACKUP_SUPER_OPTION = CHAR_MAX + 1,
++	CORRUPT_OPTION
+ };
+ 
+ typedef struct _ocfs2_tune_opts {
+@@ -86,6 +87,7 @@ typedef struct _ocfs2_tune_opts {
+ 	int quiet;
+ 	int prompt;
+ 	int backup_super;
++	int corrupt_place;
+ 	time_t tune_time;
+ 	int fd;
+ } ocfs2_tune_opts;
+@@ -94,3 +96,17 @@ void print_query(char *queryfmt);
+ 
+ errcode_t remove_slots(ocfs2_filesys *fs);
+ errcode_t remove_slot_check(ocfs2_filesys *fs);
++
++enum corrupt_place {
++	RS_AFTER_RELINK_EXTENT_ALLOC = 1,
++	RS_AFTER_RELINK_INODE_ALLOC,
++	RS_AFTER_TRUNCATE_ORPHAN,
++	RS_AFTER_TRUNCATE_JOURNAL,
++	RS_AFTER_WRITE_SUPER,
++	RS_AFTER_REMOVE_ONE_SLOT,
++	RS_AFTER_MOVE_SOME_REC,
++	RS_AFTER_CHANGE_SUB_ALLOC,
++	RS_AFTER_LINK_GROUP,
++	RS_AFTER_MOVE_ONE_GROUP,
++	RS_AFTER_EMPTY_JOURNAL
++};
Index: programs/tunefs-test/remove-slot/test_remove.c
===================================================================
--- programs/tunefs-test/remove-slot/test_remove.c	(revision 0)
+++ programs/tunefs-test/remove-slot/test_remove.c	(revision 0)
@@ -0,0 +1,354 @@
+/*
+ * test_remove.c
+ *
+ * test file for removing slots.
+ *
+ * Copyright (C) 2007 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+/*
+ * This file is used to create some boudary situation to test whether
+ * tunefs.ocfs2 can work OK with removing slots.
+ *
+ * When we have orphan files or have some blocks allocated in truncate log
+ * or local alloc, we can't remove the slots, so the option CREATE_ORPHAN_FILE,
+ * CREATE_TRUNCATE_LOG and CREATE_LOCAL_ALLOC are used to check it.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stddef.h>
+
+#include <ocfs2/ocfs2.h>
+
+
+char *progname = NULL;
+
+static void handle_signal (int sig)
+{
+	switch (sig) {
+	case SIGTERM:
+	case SIGINT:
+		exit(1);
+	}
+
+	return ;
+}
+
+enum operations {
+	CREATE_TRUNCATE_LOG = 1,
+	CREATE_LOCAL_ALLOC,
+	CREATE_ORPHAN_FILE
+};
+
+struct{
+	uint16_t slot;
+	enum operations ops;
+} options;
+
+static char *device = NULL;
+
+static errcode_t create_local_alloc(ocfs2_filesys *fs, uint16_t slot);
+static errcode_t create_orphan_file(ocfs2_filesys *fs, uint16_t slot);
+static errcode_t create_truncate_log(ocfs2_filesys *fs, uint16_t slot);
+
+static void usage (const char *progname)
+{
+	fprintf(stderr, "usage: %s -n node-num [-lot] device\n",
+		progname);
+
+	exit(0);
+}
+
+static int read_options(int argc, char **argv)
+{
+	int c;
+
+	progname = basename(argv[0]);
+
+	if (argc < 2)
+		return 1;
+
+	while(1) {
+		c = getopt(argc, argv, "n:i:lot");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'n':	/* the slot num. */
+			options.slot = strtoul(optarg, NULL, 0);
+			break;
+
+		case 'l':
+			if (options.ops != 0)
+				usage(progname);
+			options.ops = CREATE_LOCAL_ALLOC;
+			break;
+
+		case 'o':
+			if (options.ops != 0)
+				usage(progname);
+			options.ops = CREATE_ORPHAN_FILE;
+			break;
+
+		case 't':
+			if (options.ops != 0)
+				usage(progname);
+			options.ops = CREATE_TRUNCATE_LOG;
+			break;
+
+		default:
+			usage(progname);
+			break;
+		}
+	}
+
+	if (optind < argc && argv[optind])
+		device = argv[optind];
+
+	return 0;
+}
+
+int main (int argc, char **argv)
+{
+	ocfs2_filesys *fs = NULL;
+	errcode_t ret = 1;
+
+	initialize_ocfs_error_table();
+
+#define INSTALL_SIGNAL(sig)					\
+	do {							\
+		if (signal(sig, handle_signal) == SIG_ERR) {	\
+		    printf("Could not set " #sig "\n");		\
+		    goto bail;					\
+		}						\
+	} while (0)
+
+	INSTALL_SIGNAL(SIGTERM);
+	INSTALL_SIGNAL(SIGINT);
+
+	memset(&options, 0, sizeof(options));
+	if (read_options(argc, argv)) {
+		usage(progname);
+		goto bail;
+	}
+
+	if (!device || !options.ops)
+		goto bail;
+
+	ret = ocfs2_open(device, OCFS2_FLAG_RW, 0, 0, &fs);
+	if (ret) {
+		com_err(progname, ret, "while opening \"%s\"", device);
+		goto bail;
+	}
+
+	srand((unsigned int)fs);
+
+	switch (options.ops) {
+		case CREATE_LOCAL_ALLOC:
+			ret = create_local_alloc(fs, options.slot);
+			break;
+
+		case CREATE_ORPHAN_FILE:
+			ret = create_orphan_file(fs, options.slot);
+			break;
+
+		case CREATE_TRUNCATE_LOG:
+			ret = create_truncate_log(fs, options.slot);
+			break;
+	}
+bail:
+	if (fs)
+		ocfs2_close(fs);
+
+	return ret;
+}
+
+static inline uint32_t get_local_alloc_window_bits()
+{
+	/* just return a specific number for test */
+	return 256;
+}
+
+static errcode_t create_local_alloc(ocfs2_filesys *fs, uint16_t slot)
+{
+	errcode_t ret;
+	char *buf = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_local_alloc *la;
+	uint32_t la_size, found;
+	uint64_t la_off, blkno;
+
+	ret = ocfs2_lookup_system_inode(fs, LOCAL_ALLOC_SYSTEM_INODE,
+					slot, &blkno);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_read_inode(fs, blkno, buf);
+	if (ret)
+		goto bail;
+
+	di = (struct ocfs2_dinode *)buf;
+
+	if (!(di->i_flags & OCFS2_VALID_FL))
+		goto bail;
+
+	if (!(di->i_flags & OCFS2_LOCAL_ALLOC_FL))
+		goto bail;
+
+	if (di->id1.bitmap1.i_total > 0) {
+		fprintf(stderr, "local alloc#%"PRIu64" file not empty."
+			"Can't create a new one.\n", blkno);
+		goto bail;
+	}
+
+	la_size = get_local_alloc_window_bits();
+
+	ret = ocfs2_new_clusters(fs, 1, la_size, &la_off, &found);
+	if (ret)
+		goto bail;
+
+	if(la_size != found)
+		goto bail;
+
+	la = &(di->id2.i_lab);
+
+	la->la_bm_off = cpu_to_le32(ocfs2_blocks_to_clusters(fs, la_off));
+	di->id1.bitmap1.i_total = cpu_to_le32(la_size);
+	di->id1.bitmap1.i_used = 0;
+	memset(la->la_bitmap, 0, le16_to_cpu(la->la_size));
+	
+	ret = ocfs2_write_inode(fs, blkno, buf);
+
+bail:
+	if(buf)
+		ocfs2_free(&buf);
+	return ret;
+}
+
+static errcode_t create_orphan_file(ocfs2_filesys *fs, uint16_t slot)
+{
+	errcode_t ret;
+	uint64_t dir, tmp_blkno;
+	char name[OCFS2_MAX_FILENAME_LEN];
+	int namelen;
+
+	ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE,
+					slot, &dir);
+	if (ret)
+		return ret;
+
+	namelen = sprintf(name, "test%ld", random());
+
+	ret = ocfs2_lookup(fs, dir, name, namelen, NULL, &tmp_blkno);
+	if (!ret)
+		return 0;
+	else if (ret != OCFS2_ET_FILE_NOT_FOUND)
+		return ret;
+
+	ret = ocfs2_new_inode(fs, &tmp_blkno, S_IFREG | 0755);
+	if (ret)
+		return ret;
+
+	ret = ocfs2_link(fs, dir, name,
+			 tmp_blkno, OCFS2_FT_REG_FILE);
+	if (ret == OCFS2_ET_DIR_NO_SPACE) {
+		ret = ocfs2_expand_dir(fs, dir, fs->fs_root_blkno);
+		if (ret)
+			return ret;
+
+		ret = ocfs2_link(fs, dir, name,
+				 tmp_blkno, OCFS2_FT_REG_FILE);
+		if (ret)
+			return ret;
+	} else if (ret)
+		return ret;
+
+	return 0;
+}
+
+static errcode_t create_truncate_log(ocfs2_filesys *fs, uint16_t slot)
+{
+	errcode_t ret;
+	char *buf = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_truncate_log *tl;
+	uint16_t i, used = 10;
+	uint32_t found, clusters = 10;
+	uint64_t begin, blkno;
+
+	ret = ocfs2_lookup_system_inode(fs, TRUNCATE_LOG_SYSTEM_INODE,
+					slot, &blkno);
+	if (ret)
+		goto bail;
+	
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_read_inode(fs, blkno, buf);
+	if (ret)
+		goto bail;
+
+	di = (struct ocfs2_dinode *)buf;
+
+	if (!(di->i_flags & OCFS2_VALID_FL)) {
+		fprintf(stderr,"not a valid file\n");
+		goto bail;
+	}
+
+	if (!(di->i_flags & OCFS2_DEALLOC_FL)) {
+		fprintf(stderr,"not a valid truncate log\n");
+		goto bail;
+	}
+	
+	tl = &di->id2.i_dealloc;
+
+	if (le16_to_cpu(tl->tl_used) > 0) {
+		fprintf(stderr,"truncate log#%"PRIu64" file not empty."
+			"Can't create a new one.\n", blkno);
+		goto bail;
+	}
+
+	tl->tl_used = used;
+
+	for (i = 0; i < tl->tl_used; i++) {
+		ret = ocfs2_new_clusters(fs, 1, clusters, &begin, &found);
+		if (ret)
+			goto bail;
+		
+		tl->tl_recs[i].t_start = 
+			cpu_to_le32(ocfs2_blocks_to_clusters(fs, begin));
+		tl->tl_recs[i].t_clusters = cpu_to_le32(found);
+	}
+
+	ret = ocfs2_write_inode(fs, blkno, buf);
+
+bail:
+	if(buf)
+		ocfs2_free(&buf);
+	return ret;
+}
Index: programs/tunefs-test/remove-slot/Makefile
===================================================================
--- programs/tunefs-test/remove-slot/Makefile	(revision 0)
+++ programs/tunefs-test/remove-slot/Makefile	(revision 0)
@@ -0,0 +1,21 @@
+TOPDIR = ../../../
+
+include $(TOPDIR)/Preamble.make
+
+TESTS = test_remove
+
+CFLAGS = -O2 -Wall -g
+
+SOURCES = test_remove.c
+OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
+
+DIST_FILES = $(SOURCES) test_remove_slot.sh
+
+BIN_PROGRAMS = test_remove
+
+BIN_EXTRA = test_remove_slot.sh
+
+test_remove: $(OBJECTS)
+	$(LINK)  -locfs2 -lcom_err
+
+include $(TOPDIR)/Postamble.make


More information about the Ocfs2-tools-devel mailing list