fuzzy: capture core dumps from repair utilities
[xfstests-dev.git] / common / fuzzy
index 3d86e1c8654f14f0d6938a8d5b1d605748bfbae5..809dee5465c2d16df903b8004cd240219baf56f4 100644 (file)
@@ -1,24 +1,8 @@
 ##/bin/bash
-
-# Routines for fuzzing and scrubbing a filesystem.
-#
-#-----------------------------------------------------------------------
-#  Copyright (c) 2017 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.
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2017 Oracle.  All Rights Reserved.
 #
-#  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  02111-1307
-#  USA
-#-----------------------------------------------------------------------
+# Routines for fuzzing and scrubbing a filesystem.
 
 # Modify various files after a fuzzing operation
 _scratch_fuzz_modify() {
@@ -30,6 +14,8 @@ _scratch_fuzz_modify() {
        $XFS_IO_PROG -f -c "pwrite -S 0x63 0 ${blk_sz}" "/tmp/afile" > /dev/null
        date="$(date)"
        find "${SCRATCH_MNT}/" -type f 2> /dev/null | head -n "${nr}" | while read f; do
+               # try to remove append, immutable (and even dax) flag if exists
+               $XFS_IO_PROG -rc 'chattr -x -i -a' "$f" > /dev/null 2>&1
                setfattr -n "user.date" -v "${date}" "$f"
                cat "/tmp/afile" >> "$f"
                mv "$f" "$f.longer"
@@ -126,39 +112,6 @@ _scratch_xfs_list_metadata_fields() {
        _scratch_xfs_db "${cmds[@]}" -c print | __filter_xfs_db_print_fields "${filter}"
 }
 
-# Get a metadata field
-# The first arg is the field name
-# The rest of the arguments are xfs_db commands to find the metadata.
-_scratch_xfs_get_metadata_field() {
-       key="$1"
-       shift
-
-       grep_key="$(echo "${key}" | tr '[]()' '....')"
-       local cmds=()
-       for arg in "$@"; do
-               cmds+=("-c" "${arg}")
-       done
-       _scratch_xfs_db "${cmds[@]}" -c "print ${key}" | grep "^${grep_key}" | \
-               sed -e 's/^.* = //g'
-}
-
-# Set a metadata field
-# The first arg is the field name
-# The second arg is the new value
-# The rest of the arguments are xfs_db commands to find the metadata.
-_scratch_xfs_set_metadata_field() {
-       key="$1"
-       value="$2"
-       shift; shift
-
-       local cmds=()
-       for arg in "$@"; do
-               cmds+=("-c" "${arg}")
-       done
-       _scratch_xfs_db -x "${cmds[@]}" -c "write -d ${key} ${value}"
-       echo
-}
-
 # Fuzz a metadata field
 # The first arg is the field name
 # The second arg is the xfs_db fuzz verb
@@ -179,9 +132,14 @@ _scratch_xfs_fuzz_metadata_field() {
        for arg in "$@"; do
                cmds+=("-c" "${arg}")
        done
-       _scratch_xfs_db -x "${cmds[@]}" -c "fuzz ${fuzz_arg} ${key} ${value}"
-       echo
-       newval="$(_scratch_xfs_get_metadata_field "${key}" "$@" 2> /dev/null)"
+       while true; do
+               _scratch_xfs_db -x "${cmds[@]}" -c "fuzz ${fuzz_arg} ${key} ${value}"
+               echo
+               newval="$(_scratch_xfs_get_metadata_field "${key}" "$@" 2> /dev/null)"
+               if [ "${key}" != "random" ] || [ "${oldval}" != "${newval}" ]; then
+                       break;
+               fi
+       done
        if [ "${oldval}" = "${newval}" ]; then
                echo "Field ${key} already set to ${newval}, skipping test."
                return 1
@@ -212,7 +170,7 @@ __fuzz_notify() {
 # Fuzz one field of some piece of metadata.
 # First arg is the field name
 # Second arg is the fuzz verb (ones, zeroes, random, add, sub...)
-# Third arg is the repair mode (online, offline, both)
+# Third arg is the repair mode (online, offline, both, none)
 __scratch_xfs_fuzz_field_test() {
        field="$1"
        fuzzverb="$2"
@@ -228,23 +186,25 @@ __scratch_xfs_fuzz_field_test() {
 
        # Try to catch the error with scrub
        echo "+ Try to catch the error"
-       _scratch_mount 2>&1
+       _try_scratch_mount 2>&1
        res=$?
        if [ $res -eq 0 ]; then
                # Try an online scrub unless we're fuzzing ag 0's sb,
                # which scrub doesn't know how to fix.
-               echo "++ Online scrub"
-               if [ "$1" != "sb 0" ]; then
-                       _scratch_scrub -n -a 1 -e continue 2>&1
-                       res=$?
-                       test $res -eq 0 && \
-                               (>&2 echo "scrub didn't fail with ${field} = ${fuzzverb}.")
+               if [ "${repair}" != "none" ]; then
+                       echo "++ Online scrub"
+                       if [ "$1" != "sb 0" ]; then
+                               _scratch_scrub -n -a 1 -e continue 2>&1
+                               res=$?
+                               test $res -eq 0 && \
+                                       (>&2 echo "scrub didn't fail with ${field} = ${fuzzverb}.")
+                       fi
                fi
 
                # Try fixing the filesystem online?!
                if [ "${repair}" = "online" ] || [ "${repair}" = "both" ]; then
                        __fuzz_notify "++ Try to repair filesystem online"
-                       _scratch_scrub -y 2>&1
+                       _scratch_scrub 2>&1
                        res=$?
                        test $res -ne 0 && \
                                (>&2 echo "online repair failed ($res) with ${field} = ${fuzzverb}.")
@@ -265,25 +225,29 @@ __scratch_xfs_fuzz_field_test() {
        fi
 
        # See if repair finds a clean fs
-       echo "+ Make sure error is gone (offline)"
-        _scratch_xfs_repair -n 2>&1
-       res=$?
-       test $res -ne 0 && \
-               (>&2 echo "offline re-scrub ($res) with ${field} = ${fuzzverb}.")
+       if [ "${repair}" != "none" ]; then
+               echo "+ Make sure error is gone (offline)"
+               _scratch_xfs_repair -n 2>&1
+               res=$?
+               test $res -ne 0 && \
+                       (>&2 echo "offline re-scrub ($res) with ${field} = ${fuzzverb}.")
+       fi
 
        # See if scrub finds a clean fs
        echo "+ Make sure error is gone (online)"
-       _scratch_mount 2>&1
+       _try_scratch_mount 2>&1
        res=$?
        if [ $res -eq 0 ]; then
                # Try an online scrub unless we're fuzzing ag 0's sb,
                # which scrub doesn't know how to fix.
-               echo "++ Online scrub"
-               if [ "$1" != "sb 0" ]; then
-                       _scratch_scrub -n -e continue 2>&1
-                       res=$?
-                       test $res -ne 0 && \
-                               (>&2 echo "online re-scrub ($res) with ${field} = ${fuzzverb}.")
+               if [ "${repair}" != "none" ]; then
+                       echo "++ Online scrub"
+                       if [ "$1" != "sb 0" ]; then
+                               _scratch_scrub -n -e continue 2>&1
+                               res=$?
+                               test $res -ne 0 && \
+                                       (>&2 echo "online re-scrub ($res) with ${field} = ${fuzzverb}.")
+                       fi
                fi
 
                # Try modifying the filesystem again!
@@ -295,11 +259,13 @@ __scratch_xfs_fuzz_field_test() {
        fi
 
        # See if repair finds a clean fs
-       echo "+ Re-check the filesystem (offline)"
-       _scratch_xfs_repair -n 2>&1
-       res=$?
-       test $res -ne 0 && \
-               (>&2 echo "re-repair failed ($res) with ${field} = ${fuzzverb}.")
+       if [ "${repair}" != "none" ]; then
+               echo "+ Re-check the filesystem (offline)"
+               _scratch_xfs_repair -n 2>&1
+               res=$?
+               test $res -ne 0 && \
+                       (>&2 echo "re-repair failed ($res) with ${field} = ${fuzzverb}.")
+       fi
 }
 
 # Make sure we have all the pieces we need for field fuzzing
@@ -341,6 +307,9 @@ _scratch_xfs_fuzz_metadata() {
        echo "Verbs we propose to fuzz with:"
        echo $(echo "${verbs}")
 
+       # Always capture full core dumps from crashing tools
+       ulimit -c unlimited
+
        echo "${fields}" | while read field; do
                echo "${verbs}" | while read fuzzverb; do
                        __scratch_xfs_fuzz_mdrestore