xfs
[Top] [All Lists]

Re: [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems

To: david@xxxxxxxxxxxxx
Subject: Re: [PATCH 5/5] xfs_db: enable blocktrash for checksummed filesystems
From: "Darrick J. Wong" <darrick.wong@xxxxxxxxxx>
Date: Wed, 27 May 2015 22:08:15 -0700
Cc: xfs@xxxxxxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <20150526225159.26434.92261.stgit@xxxxxxxxxxxxxxxx>
References: <20150526225126.26434.69010.stgit@xxxxxxxxxxxxxxxx> <20150526225159.26434.92261.stgit@xxxxxxxxxxxxxxxx>
User-agent: Mutt/1.5.21 (2010-09-15)
On Tue, May 26, 2015 at 03:51:59PM -0700, Darrick J. Wong wrote:
> Disable the write verifiers when we're trashing a block.  With this
> in place, create a xfs fuzzer script that formats, populates, corrupts,
> tries to use, repairs, and tries again to use a crash test xfs image.
> Hopefully this will shake out some v5 filesystem bugs.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> ---
>  db/check.c    |    7 +
>  db/xfsfuzz.sh |  305 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 312 insertions(+)
>  create mode 100755 db/xfsfuzz.sh
> 
> 
> diff --git a/db/check.c b/db/check.c
> index 8f8096d..2c2a02e 100644
> --- a/db/check.c
> +++ b/db/check.c
> @@ -953,6 +953,7 @@ blocktrash_b(
>       int             mask;
>       int             newbit;
>       int             offset;
> +     const struct xfs_buf_ops *stashed_ops;
>       static char     *modestr[] = {
>               N_("zeroed"), N_("set"), N_("flipped"), N_("randomized")
>       };
> @@ -963,6 +964,8 @@ blocktrash_b(
>       push_cur();
>       set_cur(&typtab[DBM_UNKNOWN],

So... seeing as the the TYP_* and DBM_* values don't correspond and every other
user of typtab uses the TYP_ values for array index, what's the point of
unconditionally using the AGF verifier on this block?  Passing NULL as the
first argument doesn't seem to hurt anything.

(DBM_UNKNOWN == TYP_AGF)

Seeing as we're going to trash the block anyway, why bother?

>               XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL);
> +     stashed_ops = iocur_top->bp->b_ops;
> +     iocur_top->bp->b_ops = NULL;
>       if ((buf = iocur_top->data) == NULL) {
>               dbprintf(_("can't read block %u/%u for trashing\n"), agno, 
> agbno);
>               pop_cur();
> @@ -993,6 +996,7 @@ blocktrash_b(
>                       buf[byte] &= ~mask;
>       }
>       write_cur();
> +     iocur_top->bp->b_ops = stashed_ops;
>       pop_cur();
>       printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"),
>               agno, agbno, typename[type], len, len == 1 ? "" : "s",
> @@ -1049,9 +1053,12 @@ blocktrash_f(
>                  (1 << DBM_BTINO) |
>                  (1 << DBM_DIR) |
>                  (1 << DBM_INODE) |
> +                (1 << DBM_LOG) |

It's useful to be able to fuzz the log, but that'll bias the block selection
towards the log.  Maybe it should be masked off by default in tmask = goodmask
below?

>                  (1 << DBM_QUOTA) |
>                  (1 << DBM_RTBITMAP) |
>                  (1 << DBM_RTSUM) |
> +                (1 << DBM_SYMLINK) |
> +                (1 << DBM_BTFINO) |
>                  (1 << DBM_SB);
>       while ((c = getopt(argc, argv, "0123n:s:t:x:y:")) != EOF) {
>               switch (c) {
> diff --git a/db/xfsfuzz.sh b/db/xfsfuzz.sh
> new file mode 100755
> index 0000000..fc40e97
> --- /dev/null
> +++ b/db/xfsfuzz.sh

[working on stuffing this into xfstests]
[maybe I'll see about doing likewise for the ext4 fuzzer]

--D

> @@ -0,0 +1,305 @@
> +#!/bin/bash
> +
> +# Test harness to fuzz a filesystem over and over...
> +# Copyright (C) 2014 Oracle.
> +
> +DIR=/tmp
> +PASSES=10000
> +SZ=32m
> +SCRIPT_DIR="$(dirname "$0")"
> +FEATURES="-m crc=1,finobt=1"
> +xEATURES="-m crc=0"
> +BLK_SZ=4096
> +INODE_SZ=512
> +RUN_FSCK=1
> +OVERRIDE_PATH=1
> +MAX_FSCK=10
> +SRCDIR=/etc
> +FUZZ_ARGS="-3 -n 32"
> +XFS_REPAIR_OPTS="-P"
> +
> +print_help() {
> +     echo "Usage: $0 OPTIONS"
> +     echo "-b:       FS block size is this. (${BLK_SZ})"
> +     echo "-B:       Corrupt this many bytes per run."
> +     echo "-d:       Create test files in this directory. (${DIR})"
> +     echo "-f:       Do not run xfs_repair after each pass."
> +     echo "-I:       Create inodes of this size. (${INODE_SZ})"
> +     echo "-n:       Run this many passes. (${PASSES})"
> +     echo "-O:       Pass this to mkfs.xfs."
> +     echo "-p:       Use system's xfsprogs tools."
> +     echo "-s:       Create FS images of this size. (${SZ})"
> +     echo "-S:       Copy files from this dir. (${SRCDIR})"
> +     echo "-x:       Run xfs_repair at most this many times. (${MAX_FSCK})"
> +     exit 0
> +}
> +
> +GETOPT="d:n:s:O:I:b:B:fpx:S:"
> +
> +while getopts "${GETOPT}" opt; do
> +     case "${opt}" in
> +     "B")
> +             FUZZ_ARGS="-3 -n ${OPTARG}"
> +             ;;
> +     "d")
> +             DIR="${OPTARG}"
> +             ;;
> +     "n")
> +             PASSES="${OPTARG}"
> +             ;;
> +     "s")
> +             SZ="${OPTARG}"
> +             ;;
> +     "O")
> +             FEATURES="${OPTARG}"
> +             ;;
> +     "I")
> +             INODE_SZ="${OPTARG}"
> +             ;;
> +     "b")
> +             BLK_SZ="${OPTARG}"
> +             ;;
> +     "f")
> +             RUN_FSCK=0
> +             ;;
> +     "p")
> +             OVERRIDE_PATH=0
> +             ;;
> +     "x")
> +             MAX_FSCK="${OPTARG}"
> +             ;;
> +     "S")
> +             SRCDIR="${OPTARG}"
> +             ;;
> +     *)
> +             print_help
> +             ;;
> +     esac
> +done
> +
> +if [ "${OVERRIDE_PATH}" -gt 0 ]; then
> +     
> PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../repair/:${SCRIPT_DIR}/../db/:${SCRIPT_DIR}/../mkfs/:${PATH}"
> +     export PATH
> +fi
> +
> +TESTDIR="${DIR}/tests/"
> +TESTMNT="${DIR}/mnt/"
> +BASE_IMG="${DIR}/xfsfuzz.img"
> +
> +# Set up FS image
> +echo "+ create fs image"
> +umount "${TESTDIR}"
> +umount "${TESTMNT}"
> +rm -rf "${TESTDIR}"
> +rm -rf "${TESTMNT}"
> +mkdir -p "${TESTDIR}"
> +mkdir -p "${TESTMNT}"
> +rm -rf "${BASE_IMG}"
> +truncate -s "${SZ}" "${BASE_IMG}"
> +mkfs.xfs -f ${FEATURES} -b "size=${BLK_SZ}" -i "size=${INODE_SZ}" 
> "${BASE_IMG}"
> +if [ $? -ne 0 ]; then
> +     exit $?
> +fi
> +
> +# Populate FS image
> +echo "+ populate fs image"
> +modprobe loop
> +mount "${BASE_IMG}" "${TESTMNT}" -o loop
> +if [ $? -ne 0 ]; then
> +     exit $?
> +fi
> +SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')"
> +FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))"
> +NR="$(( (FS_SZ * 6 / 10) / SRC_SZ ))"
> +if [ "${NR}" -lt 1 ]; then
> +     NR=1
> +fi
> +echo "+ make ${NR} copies"
> +seq 1 "${NR}" | while read nr; do
> +     cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null
> +done
> +umount "${TESTMNT}"
> +xfs_repair ${XFS_REPAIR_OPTS} -vn "${BASE_IMG}"
> +if [ $? -ne 0 ]; then
> +     echo "fsck failed??"
> +     exit 1
> +fi
> +
> +# Run tests
> +echo "+ run test"
> +ret=0
> +seq 1 "${PASSES}" | while read pass; do
> +     echo "+ pass ${pass}"
> +     PASS_IMG="${TESTDIR}/xfsfuzz-${pass}.img"
> +     FSCK_IMG="${TESTDIR}/xfsfuzz-${pass}.fsck"
> +     FUZZ_LOG="${TESTDIR}/xfsfuzz-${pass}.fuzz.log"
> +     OPS_LOG="${TESTDIR}/xfsfuzz-${pass}.ops.log"
> +
> +     echo "++ copy image"
> +     cp "${BASE_IMG}" "${PASS_IMG}"
> +     if [ $? -ne 0 ]; then
> +             exit $?
> +     fi
> +     xfs_db -x -c "label xfsfuzz-${pass}" "${PASS_IMG}"
> +
> +     echo "++ corrupt image"
> +     xfs_db -x -c blockget -c "blocktrash ${FUZZ_ARGS}" "${PASS_IMG}" > 
> "${FUZZ_LOG}"
> +#    res=$?
> +#    if [ "${res}" -ne 0 ]; then
> +#            echo "blocktrash returns ${res}"
> +#            exit "${res}"
> +#    fi
> +
> +     echo "++ mount image"
> +     mount "${PASS_IMG}" "${TESTMNT}" -o loop
> +     res=$?
> +
> +     if [ "${res}" -eq 0 ]; then
> +             echo "+++ ls -laR"
> +             ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
> +
> +             echo "+++ cat files"
> +             find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | 
> xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
> +
> +             echo "+++ expand"
> +             find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while 
> read f; do
> +                     attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
> +                     if [ -f "$f" -a -w "$f" ]; then
> +                             dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 
> 2>> "${OPS_LOG}"
> +                     fi
> +                     mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
> +             done
> +             sync
> +
> +             echo "+++ create files"
> +             cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
> +             sync
> +
> +             echo "+++ remove files"
> +             rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
> +
> +             umount "${TESTMNT}"
> +             res=$?
> +             if [ "${res}" -ne 0 ]; then
> +                     ret=1
> +                     break
> +             fi
> +             sync
> +     fi
> +     if [ "${RUN_FSCK}" -gt 0 ]; then
> +             cp "${PASS_IMG}" "${FSCK_IMG}"
> +             pass_img_sz="$(stat -c '%s' "${PASS_IMG}")"
> +
> +             seq 1 "${MAX_FSCK}" | while read fsck_pass; do
> +                     echo "++ fsck pass ${fsck_pass}: $(which xfs_repair) -v 
> ${FSCK_IMG}"
> +                     FSCK_LOG="${TESTDIR}/xfsfuzz-${pass}-${fsck_pass}.log"
> +                     echo "repairing" > "${FSCK_LOG}"
> +                     xfs_repair ${XFS_REPAIR_OPTS} -v "${FSCK_IMG}" >> 
> "${FSCK_LOG}" 2>&1
> +                     res=$?
> +                     if [ "${res}" -eq 0 ]; then
> +                             echo "reverify" >> "${FSCK_LOG}"
> +                             xfs_repair ${XFS_REPAIR_OPTS} -v -n 
> "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1
> +                             res=$?
> +                     fi
> +                     echo "++ fsck returns ${res}"
> +                     if [ "${res}" -eq 0 ]; then
> +                             exit 0
> +                     elif [ "${res}" -eq 2 ]; then
> +                             # replay log?
> +                             echo "replaying log" >> "${FSCK_LOG}"
> +                             dmesg > /tmp/a
> +                             mount "${FSCK_IMG}" "${TESTMNT}" -o loop
> +                             res=$?
> +                             if [ "${res}" -gt 0 ]; then
> +                                     echo "+++ zeroing log"
> +                                     echo "zeroing log" >> "${FSCK_LOG}"
> +                                     xfs_repair ${XFS_REPAIR_OPTS} -L -v 
> "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1
> +                             else
> +                                     umount "${TESTMNT}"
> +                             fi
> +                             dmesg > /tmp/b
> +                             diff -u /tmp/a /tmp/b >> "${FSCK_LOG}"
> +                     elif [ "${fsck_pass}" -eq "${MAX_FSCK}" ]; then
> +                             echo "++ fsck did not fix in ${MAX_FSCK} 
> passes."
> +                             exit 1
> +                     fi
> +                     if [ "${fsck_pass}" -gt 1 ]; then
> +                             diff -u 
> "${TESTDIR}/xfsfuzz-${pass}-$((fsck_pass - 1)).log" "${FSCK_LOG}"
> +                             if [ $? -eq 0 ]; then
> +                                     echo "++ fsck makes no progress"
> +                                     exit 2
> +                             fi
> +                     fi
> +
> +                     fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")"
> +                     if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then
> +                             echo "++ fsck image size changed"
> +                             exit 3
> +                     fi
> +             done
> +             fsck_loop_ret=$?
> +             if [ "${fsck_loop_ret}" -gt 0 ]; then
> +                     break;
> +             fi
> +     fi
> +
> +     echo "+++ check fs for round 2"
> +     FSCK_LOG="${TESTDIR}/xfsfuzz-${pass}-round2.log"
> +     xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" > "${FSCK_LOG}" 2>&1
> +     res=$?
> +     if [ "${res}" -ne 0 ]; then
> +             echo "++++ fsck failed."
> +             exit 1
> +     fi
> +
> +     echo "++ mount image (2)"
> +     mount "${FSCK_IMG}" "${TESTMNT}" -o loop
> +     res=$?
> +
> +     if [ "${res}" -eq 0 ]; then
> +             echo "+++ ls -laR (2)"
> +             ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
> +
> +             echo "+++ cat files (2)"
> +             find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | 
> xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
> +
> +             echo "+++ expand (2)"
> +             find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while 
> read f; do
> +                     attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
> +                     if [ -f "$f" -a -w "$f" ]; then
> +                             dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 
> 2>> "${OPS_LOG}"
> +                     fi
> +                     mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
> +             done
> +             sync
> +
> +             echo "+++ create files (2)"
> +             cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
> +             sync
> +
> +             echo "+++ remove files (2)"
> +             rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
> +
> +             umount "${TESTMNT}"
> +             res=$?
> +             if [ "${res}" -ne 0 ]; then
> +                     ret=1
> +                     break
> +             fi
> +             sync
> +
> +             echo "+++ check fs (2)"
> +             xfs_repair ${XFS_REPAIR_OPTS} -v -n "${FSCK_IMG}" >> 
> "${FSCK_LOG}" 2>&1
> +             res=$?
> +             if [ "${res}" -ne 0 ]; then
> +                     echo "++++ fsck failed."
> +                     exit 1
> +             fi
> +     else
> +             echo "++ mount(2) failed with ${res}"
> +             exit 1
> +     fi
> +     rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" 
> "${TESTDIR}"/xfsfuzz*.log
> +done
> +
> +exit $ret
> 
> _______________________________________________
> xfs mailing list
> xfs@xxxxxxxxxxx
> http://oss.sgi.com/mailman/listinfo/xfs

<Prev in Thread] Current Thread [Next in Thread>