[RFC PATCH mtd-utils 099/110] tests: Add common libs for testing fsck.ubifs/mkfs.ubifs

From: Zhihao Cheng
Date: Fri Jun 07 2024 - 00:52:32 EST


This is a preparation for adding testcases for fsck.ubifs and
mkfs.ubifs. Add some common functions, for example: powercut,
load_mtdram, mount_ubifs, encryption operations, etc.

Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
---
.gitignore | 1 +
Makefile.am | 1 +
configure.ac | 3 +-
tests/ubifs_tools-tests/Makemodule.am | 2 +
tests/ubifs_tools-tests/lib/common.sh.in | 350 +++++++++++++++++++++++++++++++
5 files changed, 356 insertions(+), 1 deletion(-)
create mode 100644 tests/ubifs_tools-tests/Makemodule.am
create mode 100755 tests/ubifs_tools-tests/lib/common.sh.in

diff --git a/.gitignore b/.gitignore
index 3eb66c14..de0fce1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,6 +113,7 @@ tests/fs-tests/stress/fs_stress00.sh
tests/fs-tests/stress/fs_stress01.sh
tests/ubi-tests/runubitests.sh
tests/ubi-tests/ubi-stress-test.sh
+tests/ubifs_tools-tests/lib/common.sh

#
# Files generated by autotools
diff --git a/Makefile.am b/Makefile.am
index 887ce938..0ebd45bb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -63,6 +63,7 @@ include tests/jittertest/Makemodule.am
include tests/checkfs/Makemodule.am
include tests/fs-tests/Makemodule.am
include tests/mtd-tests/Makemodule.am
+include tests/ubifs_tools-tests/Makemodule.am
endif

if UNIT_TESTS
diff --git a/configure.ac b/configure.ac
index cf3a959e..d32541a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -289,7 +289,8 @@ AC_CONFIG_FILES([tests/fs-tests/fs_help_all.sh
tests/fs-tests/stress/fs_stress00.sh
tests/fs-tests/stress/fs_stress01.sh
tests/ubi-tests/runubitests.sh
- tests/ubi-tests/ubi-stress-test.sh])
+ tests/ubi-tests/ubi-stress-test.sh
+ tests/ubifs_tools-tests/lib/common.sh])

AC_OUTPUT([Makefile])

diff --git a/tests/ubifs_tools-tests/Makemodule.am b/tests/ubifs_tools-tests/Makemodule.am
new file mode 100644
index 00000000..265c9cc7
--- /dev/null
+++ b/tests/ubifs_tools-tests/Makemodule.am
@@ -0,0 +1,2 @@
+test_SCRIPTS += \
+ tests/ubifs_tools-tests/lib/common.sh
diff --git a/tests/ubifs_tools-tests/lib/common.sh.in b/tests/ubifs_tools-tests/lib/common.sh.in
new file mode 100755
index 00000000..5a07ebcd
--- /dev/null
+++ b/tests/ubifs_tools-tests/lib/common.sh.in
@@ -0,0 +1,350 @@
+#!/bin/sh
+# Copyright (c), 2024, Huawei Technologies Co, Ltd.
+# Author: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
+#
+# Provide basic functions.
+
+UBI_NUM=0
+DEV=/dev/ubi0_0
+MNT=/mnt/test_file_system
+TMP_FILE=/tmp/ubifs_test_file
+LOG_FILE=/tmp/ubifs_log
+KEY_FILE=/tmp/key
+nandsim_patt="NAND simulator"
+mtdram_patt="mtdram test device"
+
+# fsck returning code
+FSCK_OK=0 # No errors
+FSCK_NONDESTRUCT=1 # File system errors corrected
+FSCK_REBOOT=2 # System should be rebooted
+FSCK_UNCORRECTED=4 # File system errors left uncorrected
+FSCK_ERROR=8 # Operational error
+FSCK_USAGE=16 # Usage or syntax error
+FSCK_CANCELED=32 # Aborted with a signal or ^
+FSCK_LIBRARY=128 # Shared library error
+
+function fatal()
+{
+ echo "Error: $1" 1>&2
+ exit 1
+}
+
+# All loaded modules(mtdram/nandsim/ubi/ubifs) won't be removed if errors
+# happen, it is useful to debug based on the UBIFS image.
+function cleanup_handler()
+{
+ local ret="$1"
+
+ if [ "$ret" == "0" ]; then
+ umount $MNT >/dev/null 2>&1 ||:
+ modprobe -r ubifs >/dev/null 2>&1 ||:
+ modprobe -r ubi >/dev/null 2>&1 ||:
+ modprobe -r nandsim >/dev/null 2>&1 ||:
+ modprobe -r mtdram >/dev/null 2>&1 ||:
+ rm -rf $MNT >/dev/null 2>&1 ||:
+ rm -f $TMP_FILE >/dev/null 2>&1 ||:
+ rm -f $KEY_FILE >/dev/null 2>&1 ||:
+ rm -f $LOG_FILE >/dev/null 2>&1 ||:
+ exit 0
+ else
+ exit 1
+ fi
+}
+trap 'cleanup_handler $?' EXIT
+trap 'cleanup_handler 1' HUP PIPE INT QUIT TERM
+
+function find_mtd_device()
+{
+ printf "%s" "$(grep "$1" /proc/mtd | sed -e "s/^mtd\([0-9]\+\):.*$/\1/")"
+}
+
+function powercut()
+{
+ dmesg -c > /dev/null
+ echo 1 > /sys/kernel/debug/ubifs/tst_recovery;
+ while true;
+ do
+ msg=`dmesg -c | grep "Power cut emulated"`;
+ if [[ "$msg" != "" ]];
+ then
+ break;
+ fi
+ ro_error=`cat /sys/kernel/debug/ubifs/ubi${UBI_NUM}_0/ro_error`
+ if [[ $ro_error != 0 ]]; then
+ break;
+ fi
+ done
+ echo 0 > /sys/kernel/debug/ubifs/tst_recovery
+}
+
+# Load mtdram with specified size and PEB size
+# Usage: load_mtdram <flash size> <PEB size>
+# 1. Flash size is specified in MiB
+# 2. PEB size is specified in KiB
+function load_mtdram()
+{
+ local size="$1"; shift
+ local peb_size="$1"; shift
+
+ size="$(($size * 1024))"
+ modprobe mtdram total_size="$size" erase_size="$peb_size"
+}
+
+function check_fsstress()
+{
+ cmd=`fsstress | grep "op_name"`
+ if ! [[ "$cmd" =~ "op_name" ]]; then
+ fatal "fsstress is not found"
+ fi
+}
+
+# Check error messages
+function check_err_msg()
+{
+ msg=`dmesg | grep -E "dump_stack|UBIFS error|switched to read-only mode"`;
+ if [[ "$msg" != "" ]]
+ then
+ dmesg
+ fatal "error message detected!"
+ fi
+ dmesg -c > /dev/null
+}
+
+# Iterate all files under certain dir
+# $1: dir
+# $2: "md5sum" means that need record md5 for regular file, otherwise don't record md5 for regular file
+function read_dir() {
+ for file in `ls -a $1`
+ do
+ cur_f=$1"/"$file
+ if [ -b $cur_f ]
+ then
+ major=`stat -c %t $cur_f`
+ minor=`stat -c %T $cur_f`
+ echo "block $cur_f $major $minor" >> $TMP_FILE
+ elif [ -c $cur_f ]
+ then
+ major=`stat -c %t $cur_f`
+ minor=`stat -c %T $cur_f`
+ echo "char $cur_f $major $minor" >> $TMP_FILE
+ elif [ -L $cur_f ]
+ then
+ link=`stat -c %N $cur_f`
+ echo "symlink $cur_f $link" >> $TMP_FILE
+ elif [ -S $cur_f ]
+ then
+ echo "sock $cur_f" >> $TMP_FILE
+ elif [ -p $cur_f ]
+ then
+ echo "fifo $cur_f" >> $TMP_FILE
+ elif [ -f $cur_f ]
+ then
+ sz=`stat -c %s $cur_f`
+ if [[ "$2" != "md5sum" ]]; then
+ echo "reg $cur_f $sz" >> $TMP_FILE
+ else
+ md5=`md5sum $cur_f | awk '{print $1}'`
+ echo "reg $cur_f $md5 $sz" >> $TMP_FILE
+ fi
+ elif [ -d $cur_f ]
+ then
+ if [[ $file != '.' && $file != '..' ]]
+ then
+ echo "dir $cur_f" >> $TMP_FILE
+ read_dir $1"/"$file $2
+ fi
+ else
+ fatal "record unknown file type $cur_f"
+ fi
+ done
+}
+
+# Check whether there are files lost after fsck/mkfs
+# $1: "md5sum" means need record md5 for regular file, otherwise don't check md5 for regular file
+function parse_dir()
+{
+ while read line
+ do
+ array=(${line//\ / });
+ f_type=${array[0]};
+ cur_f=${array[1]};
+ cur_info=""
+ if [[ "$f_type" =~ "block" ]]
+ then
+ major=`stat -c %t $cur_f`
+ minor=`stat -c %T $cur_f`
+ cur_info="block $cur_f $major $minor"
+ elif [[ "$f_type" =~ "char" ]]
+ then
+ major=`stat -c %t $cur_f`
+ minor=`stat -c %T $cur_f`
+ cur_info="char $cur_f $major $minor"
+ elif [[ "$f_type" =~ "symlink" ]]
+ then
+ link=`stat -c %N $cur_f`
+ cur_info="symlink $cur_f $link"
+ elif [[ "$f_type" =~ "sock" ]]
+ then
+ cur_info="sock $cur_f"
+ elif [[ "$f_type" =~ "fifo" ]]
+ then
+ cur_info="fifo $cur_f"
+ elif [[ "$f_type" =~ "reg" ]]
+ then
+ sz=`stat -c %s $cur_f`
+ if [[ "$1" != "md5sum" ]]; then
+ cur_info="reg $cur_f $sz"
+ else
+ md5=`md5sum $cur_f | awk '{print $1}'`
+ cur_info="reg $cur_f $md5 $sz"
+ fi
+ elif [[ "$f_type" =~ "dir" ]]
+ then
+ cur_info="dir $cur_f"
+ else
+ fatal "parse unknown file type $cur_f"
+ fi
+ if [[ "$cur_info" != "$line" ]]
+ then
+ fatal "current info $cur_info, but expect $line"
+ fi
+ done < $TMP_FILE
+}
+
+function authentication()
+{
+ keyctl clear @s
+ res=$?
+ if [[ $res != 0 ]]; then
+ fatal "keyctl is not found"
+ fi
+ keyctl add logon ubifs:foo 12345678901234567890123456789012 @s
+}
+
+function encryption_gen_key()
+{
+ # CONFIG_FS_ENCRYPTION=y
+ head -c 64 /dev/urandom > $KEY_FILE
+ cmd=`fscryptctl -h | grep "set_policy"`
+ if ! [[ "$cmd" =~ "set_policy" ]]; then
+ fatal "fscryptctl is not found"
+ fi
+}
+
+function encryption_set_key()
+{
+ mnt=$1
+ # https://github.com/google/fscryptctl
+ key=$(fscryptctl add_key $mnt < $KEY_FILE)
+ fscryptctl set_policy $key $mnt
+ #fscryptctl get_policy $mnt
+ ret=$?
+ if [[ $ret != 0 ]]; then
+ fatal "set encryption policy failed"
+ fi
+}
+
+function mount_ubifs()
+{
+ local dev=$1;
+ local mnt=$2;
+ local auth=$3;
+ local noatime=$4;
+ local option="";
+ if [[ "$noatime" == "noatime" ]]; then
+ option="-o noatime"
+ fi
+ if [[ "$auth" == "authentication" ]]; then
+ authentication
+ if [[ "$option" == "" ]]; then
+ option="-o auth_key=ubifs:foo,auth_hash_name=sha256"
+ else
+ option="$option,auth_key=ubifs:foo,auth_hash_name=sha256"
+ fi
+ fi
+ mount -t ubifs $option $dev $mnt
+}
+
+function enable_chkfs()
+{
+ echo 1 > /sys/kernel/debug/ubifs/chk_fs
+ echo 1 > /sys/kernel/debug/ubifs/chk_general
+ echo 1 > /sys/kernel/debug/ubifs/chk_index
+ echo 1 > /sys/kernel/debug/ubifs/chk_lprops
+ echo 1 > /sys/kernel/debug/ubifs/chk_orphans
+}
+
+function disable_chkfs()
+{
+ echo 0 > /sys/kernel/debug/ubifs/chk_fs
+ echo 0 > /sys/kernel/debug/ubifs/chk_general
+ echo 0 > /sys/kernel/debug/ubifs/chk_index
+ echo 0 > /sys/kernel/debug/ubifs/chk_lprops
+ echo 0 > /sys/kernel/debug/ubifs/chk_orphans
+}
+
+function inject_mem_err()
+{
+ # CONFIG_FAILSLAB=y
+ # CONFIG_FAIL_PAGE_ALLOC=y
+ local pid=$1;
+
+ if ! [ -f /sys/kernel/debug/failslab/probability ]; then
+ fatal "failslab is not enabled, injection failed"
+ fi
+ if ! [ -f /sys/kernel/debug/fail_page_alloc/probability ]; then
+ fatal "fail_page_alloc is not enabled, injection failed"
+ fi
+
+ echo 1 > /proc/$pid/make-it-fail
+
+ echo Y > /sys/kernel/debug/failslab/task-filter
+ echo 1 > /sys/kernel/debug/failslab/probability # 1% failure
+ echo 10000 > /sys/kernel/debug/failslab/times
+ echo 1 > /sys/kernel/debug/failslab/verbose
+ echo N > /sys/kernel/debug/failslab/ignore-gfp-wait
+
+ echo Y > /sys/kernel/debug/fail_page_alloc/task-filter
+ echo 1 > /sys/kernel/debug/fail_page_alloc/probability
+ echo 10000 > /sys/kernel/debug/fail_page_alloc/times
+ echo 0 > /sys/kernel/debug/fail_page_alloc/verbose
+ echo N > /sys/kernel/debug/fail_page_alloc/ignore-gfp-wait
+}
+
+function cancel_mem_err()
+{
+ echo 0 > /sys/kernel/debug/failslab/probability
+ echo 0 > /sys/kernel/debug/failslab/times
+ echo 0 > /sys/kernel/debug/failslab/verbose
+ echo N > /sys/kernel/debug/failslab/task-filter
+ echo Y > /sys/kernel/debug/failslab/ignore-gfp-wait
+
+ echo 0 > /sys/kernel/debug/fail_page_alloc/probability
+ echo 0 > /sys/kernel/debug/fail_page_alloc/times
+ echo 1 > /sys/kernel/debug/fail_page_alloc/verbose
+ echo N > /sys/kernel/debug/fail_page_alloc/task-filter
+ echo Y > /sys/kernel/debug/fail_page_alloc/ignore-gfp-wait
+}
+
+function inject_io_err()
+{
+ if ! [ -f /sys/kernel/debug/ubi/ubi$UBI_NUM/tst_emulate_io_failures ]; then
+ fatal "tst_emulate_io_failures is not enabled, skip injection"
+ fi
+
+ echo 1 > /sys/kernel/debug/ubi/ubi$UBI_NUM/tst_emulate_io_failures
+}
+
+function cancel_io_err()
+{
+ echo 0 > /sys/kernel/debug/ubi/ubi$UBI_NUM/tst_emulate_io_failures
+}
+
+if ! [ -d $MNT ]; then
+ mkdir -p $MNT
+fi
+
+modprobe ubi || fatal "common.sh: cannot load ubi"
+modprobe ubifs || fatal "common.sh: cannot load ubifs"
+modprobe -r ubifs
+modprobe -r ubi
--
2.13.6