[Ocfs2-tools-devel] Patch for journal truncate of ocfs2-tools.
tao.ma
tao.ma at oracle.com
Wed May 16 00:41:00 PDT 2007
Marcos,
I have added "-fy" in this new script. It works fine now with a
small volume.
Please check.
>>
>> tao.ma wrote:
>>> Sunil Mushran wrote:
>>>> Yes, that's correct.
>>>>
>>>> One solution is to expect this in your test script.
>>>> As in, run with -fy to clean this up after a new mkfs.
-------------- next part --------------
Index: programs/tunefs-test/tunefs-test.sh
===================================================================
--- programs/tunefs-test/tunefs-test.sh (revision 98)
+++ programs/tunefs-test/tunefs-test.sh (working copy)
@@ -437,6 +437,66 @@ Add_Backup_Super()
test_pass;
fi;
}
+
+#
+# Journal_Node_Change - Change journal size and node slots simultaneously.
+#
+Journal_Node_Change()
+{
+ LogMsg "tunefs_test : Testing Changing journal size and node slots simultaneously."
+
+ # Increase journal size and node slots.
+ (( ++NUM_OF_TESTS ))
+ Set_Volume_For_Test;
+ CURRENT_TEST="Increase Journal Size to ${JOURNAL3} and increase nodes to ${NNODES2}";
+ echo "y"|${TUNEFS_BIN} -N ${NNODES2} -J size=${JOURNAL3} ${DEVICE} 2>&1 >> ${TUNEFSLOG};
+
+ # Check whether we succeed.
+ Check_Volume;
+ SB_NNODES=`${DEBUGFS_BIN} -n -R "stats" ${DEVICE}|${GREP} Slots| \
+ ${GAWK} '{print \$4; exit}'`;
+ if [ ${SB_NNODES} -ne ${NNODES2} ]; then
+ test_fail;
+ LogMsg "tunefs_test : #of nodes change failed. \c"
+ LogMsg "Superblock number of nodes (${SB_NNODES})"
+ else
+ SB_JSIZE=`${DEBUGFS_BIN} -n -R "ls -l //" ${DEVICE}|${GREP} -i Journal:0001|
+ ${GAWK} '{print \$6; exit}'`;
+ if [ ${SB_JSIZE} -ne ${JOURNAL3} ]; then
+ test_fail;
+ LogMsg "tunefs_test : Journal size change failed.\c"
+ LogMsg " Superblock Journal Size (${SB_JSIZE})"
+ else
+ test_pass;
+ fi;
+ fi;
+
+
+ # Decrease journal size and increase the slot nums.
+ (( ++NUM_OF_TESTS ))
+ CURRENT_TEST="Decrease Journal Size to ${JOURNAL2} and increase nodes to ${NNODES3}";
+ echo "y"|${TUNEFS_BIN} -N ${NNODES3} -J size=${JOURNAL2} ${DEVICE} 2>&1 >> ${TUNEFSLOG};
+
+ # Check whether we succeed.
+ Check_Volume;
+ SB_NNODES=`${DEBUGFS_BIN} -n -R "stats" ${DEVICE}|${GREP} Slots| \
+ ${GAWK} '{print \$4; exit}'`;
+ if [ ${SB_NNODES} -ne ${NNODES3} ]; then
+ test_fail;
+ LogMsg "tunefs_test : #of nodes change failed. \c"
+ LogMsg "Superblock number of nodes (${SB_NNODES})"
+ else
+ SB_JSIZE=`${DEBUGFS_BIN} -n -R "ls -l //" ${DEVICE}|${GREP} -i Journal:0001|
+ ${GAWK} '{print \$6; exit}'`;
+ if [ ${SB_JSIZE} -ne ${JOURNAL2} ]; then
+ test_fail;
+ LogMsg "tunefs_test : Journal size change failed.\c"
+ LogMsg " Superblock Journal Size (${SB_JSIZE})"
+ else
+ test_pass;
+ fi;
+ fi;
+}
################################################################
#
@@ -522,6 +582,8 @@ Change_Mount_Type
Add_Backup_Super
+Journal_Node_Change
+
test_summary
LogMsg "\ntunefs_test: Ending test (`date +%F-%H-%M-%S`)\n"
Index: programs/truncate/ocfs2-tools/test_truncate.c
===================================================================
--- programs/truncate/ocfs2-tools/test_truncate.c (revision 0)
+++ programs/truncate/ocfs2-tools/test_truncate.c (revision 0)
@@ -0,0 +1,327 @@
+/*
+ * test_truncate.c
+ *
+ * test file for ocfs2_truncate
+ *
+ * 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 test whether ocfs2_truncate can truncate
+ * a file to a specified size.
+ *
+ * An additional option "c" is to create a file before we test truncating.
+ * We can give the tree depth so that the file can be created with the
+ * specified tree depth.
+ *
+ */
+#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 = 1,
+ SET_SIZE
+};
+
+struct{
+ char file_name[OCFS2_MAX_FILENAME_LEN];
+ enum operations ops;
+ uint64_t extras;
+} options;
+
+static char *device = NULL;
+
+static void usage (const char *progname)
+{
+ fprintf(stderr, "usage: %s -f file-name\n"
+ "\t\t[-c tree-depth] [-s new-size] 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, "f:c:s:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'f': /* file name */
+ strcpy(options.file_name, optarg);
+ break;
+
+ case 'c':
+ if (options.ops != 0)
+ usage(progname);
+ options.ops = CREATE;
+ options.extras = strtoull(optarg, NULL, 0);
+ if (options.extras > 4) {
+ com_err(progname, 0, "We can only create"
+ "a file with tree_depth <= 4");
+ exit(1);
+ }
+ break;
+
+ case 's':
+ if (options.ops != 0)
+ usage(progname);
+ options.ops = SET_SIZE;
+ options.extras = strtoull(optarg, NULL, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (optind < argc && argv[optind])
+ device = argv[optind];
+
+ return 0;
+}
+
+static errcode_t open_test_inode(ocfs2_filesys *fs, char *name, uint64_t *ino)
+{
+ errcode_t ret = 0;
+ uint64_t tmp_blkno = 0;
+ int namelen = strlen(name);
+
+ ret = ocfs2_lookup(fs, fs->fs_root_blkno, name, namelen,
+ NULL, &tmp_blkno);
+ if (!ret) {
+ *ino = tmp_blkno;
+ 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, fs->fs_root_blkno, name,
+ tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret == OCFS2_ET_DIR_NO_SPACE) {
+ ret = ocfs2_expand_dir(fs, fs->fs_root_blkno,
+ fs->fs_root_blkno);
+ if (ret)
+ return ret;
+
+ ret = ocfs2_link(fs, fs->fs_root_blkno, name,
+ tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ return ret;
+ } else if (ret)
+ return ret;
+
+ *ino = tmp_blkno;
+
+ return 0;
+}
+
+/*
+ * This function is similar to ocfs2_extend_allocation() as both extend files.
+ * However, this one ensures that the extent record tree grows much faster.
+ */
+static errcode_t custom_extend_allocation(ocfs2_filesys *fs, uint64_t ino,
+ uint32_t new_clusters)
+{
+ errcode_t ret;
+ uint32_t n_clusters;
+ uint32_t i;
+ uint64_t blkno;
+ uint64_t tmpblk;
+
+ while (new_clusters) {
+ ret = ocfs2_new_clusters(fs, 1, new_clusters, &blkno,
+ &n_clusters);
+ if (ret)
+ goto bail;
+
+ /* In order to ensure the extent records are not coalesced,
+ * we insert each cluster in reverse. */
+ for(i = n_clusters; i; --i) {
+ tmpblk = blkno + ocfs2_clusters_to_blocks(fs, i - 1);
+ ret = ocfs2_insert_extent(fs, ino, tmpblk, 1);
+ if (ret)
+ goto bail;
+ }
+ new_clusters -= n_clusters;
+ }
+
+bail:
+ return ret;
+}
+
+static inline int get_rand(int min, int max)
+{
+ if (min == max)
+ return min;
+
+ return min + (rand() % (max - min));
+}
+
+/* Create the file with the specified tree_depth. */
+static errcode_t create_file(ocfs2_filesys *fs, uint64_t ino, uint64_t tree_depth)
+{
+ errcode_t ret;
+ uint64_t size;
+ char *buf = NULL;
+ uint32_t clusters = 0;
+ struct ocfs2_dinode *di = NULL;
+ int random_rec_in_last_eb, random_rec_in_dinode;
+ int ext_rec_per_inode = ocfs2_extent_recs_per_inode(fs->fs_blocksize);
+ int ext_rec_per_eb = ocfs2_extent_recs_per_eb(fs->fs_blocksize);
+
+ srand((unsigned int)fs);
+ /* In order to build up the tree quickly, we allocate only 1 cluster
+ * to an extent, so we can calculate the extent numbers and set the
+ * clusters accordingly.
+ */
+ random_rec_in_dinode = get_rand(1, ext_rec_per_inode);
+
+ if (tree_depth == 0)
+ clusters = random_rec_in_dinode;
+ else {
+ /* Now we will create a tree with the tree_depth.
+ * we will increase the tree detph gradually.
+ *
+ * In order to speed up the generation, we just set
+ * the tree root to be "3"(there are only 2 extent rec
+ * in the dinode which are full.
+ */
+ clusters = 2;
+ while (tree_depth--) {
+ clusters *= ext_rec_per_eb;
+ random_rec_in_last_eb = get_rand(1, ext_rec_per_eb);
+ clusters += random_rec_in_last_eb;
+ }
+ }
+
+ if (clusters == 0)
+ return -1;
+
+ ret = custom_extend_allocation(fs, ino, clusters);
+ if (ret)
+ goto bail;
+
+ /* set the file size accordingly since ocfs2_truncate will
+ * check the size during its operation.
+ */
+ ret = ocfs2_malloc_block(fs->fs_io, &buf);
+ if (ret)
+ goto bail;
+
+ ret = ocfs2_read_inode(fs, ino, buf);
+ if (ret)
+ goto bail;
+
+ size = clusters * fs->fs_clustersize;
+ di = (struct ocfs2_dinode *)buf;
+ di->i_size = size;
+
+ ret = ocfs2_write_inode(fs, ino, buf);
+
+bail:
+ if (buf)
+ ocfs2_free(&buf);
+ return ret;
+}
+
+int main (int argc, char **argv)
+{
+ ocfs2_filesys *fs = NULL;
+ errcode_t ret = 1;
+ uint64_t inode;
+
+ 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 || !options.file_name[0])
+ goto bail;
+
+ ret = ocfs2_open(device, OCFS2_FLAG_RW, 0, 0, &fs);
+ if (ret) {
+ com_err(progname, ret, "while opening \"%s\"", device);
+ goto bail;
+ }
+
+ ret = open_test_inode(fs, options.file_name, &inode);
+ if (ret) {
+ com_err(progname, ret, "while open test inode");
+ goto bail;
+ }
+
+ if (options.ops == CREATE)
+ ret = create_file(fs, inode, options.extras);
+ else
+ ret = ocfs2_truncate(fs, inode, options.extras);
+
+ if (ret)
+ com_err(progname, ret, "while doing the test");
+bail:
+ if (fs)
+ ocfs2_close(fs);
+
+ return ret;
+}
Index: programs/truncate/ocfs2-tools/ocfs2_truncate.sh
===================================================================
--- programs/truncate/ocfs2-tools/ocfs2_truncate.sh (revision 0)
+++ programs/truncate/ocfs2-tools/ocfs2_truncate.sh (revision 0)
@@ -0,0 +1,247 @@
+#!/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 function of ocfs2_truncate in ocfs2-tools.
+#
+# The main test script is truncate_test and it works like this:
+# 1. Create a file with the specified tree depth.
+
+# 2. Truncate the file to some size.
+#
+# 3. Using fsck.ocfs2 to check whether the volume is corrupted.
+#
+# Please Note that this script much have the --with-truncate option to
+# do the truncate test.
+#
+
+MKFS_BIN=`which mkfs.ocfs2`
+FSCK_BIN=`which fsck.ocfs2`
+DEBUGFS_BIN=`which debugfs.ocfs2`
+TRUNCATE_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-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-truncate=PROGRAM use the PROGRAM as truncate tools
+
+ Examples:
+
+ $script --with-truncate=./test_truncate --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 "$rc"
+}
+
+#
+# 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 truncate_test()
+{
+ local tree_depth="$1"
+
+ test_file="test$RANDOM"
+ $TRUNCATE_BIN -c $tree_depth -f $test_file $DEVICE
+
+ $FSCK_BIN -fy $DEVICE>$FSCK_OUTPUT
+ diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+ exit_if_bad $? "0" "fsck find errors when creating file $test_file." $LINENO
+
+ # get the file size first.
+ new_size=`echo "stat $test_file"|$DEBUGFS_BIN $DEVICE|grep "Size:"|awk '{print $8}'`
+
+ # truncate the file for 5 times, every time truncate
+ # it to half size.
+ for((i=0;i<5;i++))
+ do
+ new_size=`expr $new_size / 2`
+ $TRUNCATE_BIN -f $test_file -s $new_size $DEVICE
+
+ $FSCK_BIN -fy $DEVICE>$FSCK_OUTPUT
+ diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+ exit_if_bad $? "0" "fail to truncate file to size $new_size." $LINENO
+ done
+
+ #truncate the file to 0.
+ $TRUNCATE_BIN -f $test_file -s 0 $DEVICE
+
+ $FSCK_BIN -fy $DEVICE>$FSCK_OUTPUT
+ diff $FSCK_OUTPUT $FSCK_OUTPUT_STANDARD
+ exit_if_bad $? "0" "fail to truncate file to size $new_size." $LINENO
+}
+
+function normal_test()
+{
+ local test_file=""
+ local new_size=""
+ local -i i=0
+
+ for blocksize in 512 1024 2048 4096
+ do
+ for clustersize in \
+ 4096 8192 16384 32768 65536 131072 262144 524288 1048576
+ do
+
+ dd if=/dev/zero of=$DEVICE bs=4096 count=3
+ $MKFS_BIN -b $blocksize -C $clustersize $DEVICE
+
+ # In some instance, fsck.ocfs2 will find "CHAIN_CPG"
+ # for a volume. So we fix it first.
+ $FSCK_BIN -fy $DEVICE>$FSCK_OUTPUT_STANDARD
+
+ #save the perfect fsck output first for our future use.
+ $FSCK_BIN -f $DEVICE>$FSCK_OUTPUT_STANDARD
+
+ truncate_test 0
+ truncate_test 1
+ done
+ done
+}
+
+################################################################
+
+#
+# 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-fsck="*)
+ FSCK_BIN="${1#--with-fsck=}"
+ ;;
+ "--with-mkfs="*)
+ MKFS_BIN="${1#--with-mkfs=}"
+ ;;
+ "--with-debugfs="*)
+ DEBUGFS_BIN="${1#--with-debugfs=}"
+ ;;
+ "--with-truncate="*)
+ TRUNCATE_BIN="${1#--with-truncate=}"
+ ;;
+ *)
+ DEVICE="$1"
+ ;;
+ esac
+ shift
+done
+
+if [ ! -b "$DEVICE" ]; then
+ echo "invalid block device - $DEVICE"
+ usage
+ exit 1
+fi
+
+which $TRUNCATE_BIN
+if [ "$?" != "0" ]; then
+ echo "$TRUNCATE_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
+
+normal_test
+
+exit 0
Property changes on: programs/truncate/ocfs2-tools/ocfs2_truncate.sh
___________________________________________________________________
Name: svn:executable
+ *
Index: programs/truncate/ocfs2-tools/Makefile
===================================================================
--- programs/truncate/ocfs2-tools/Makefile (revision 0)
+++ programs/truncate/ocfs2-tools/Makefile (revision 0)
@@ -0,0 +1,19 @@
+TOPDIR = ../../../
+
+include $(TOPDIR)/Preamble.make
+
+TESTS = test_truncate
+
+CFLAGS = -O2 -Wall -g
+
+SOURCES = test_truncate.c
+OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
+
+DIST_FILES = $(SOURCES)
+
+BIN_PROGRAMS = test_truncate
+
+test_truncate: $(OBJECTS)
+ $(LINK) -locfs2 -lcom_err
+
+include $(TOPDIR)/Postamble.make
More information about the Ocfs2-tools-devel
mailing list