| # |
| # ext4 specific common functions |
| # |
| |
| __generate_ext4_report_vars() { |
| __generate_blockdev_report_vars TEST_LOGDEV |
| __generate_blockdev_report_vars SCRATCH_LOGDEV |
| } |
| |
| _setup_large_ext4_fs() |
| { |
| local fs_size=$1 |
| local tmp_dir=/tmp/ |
| |
| [ "$LARGE_SCRATCH_DEV" != yes ] && return 0 |
| [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0 |
| [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0 |
| |
| # Default free space in the FS is 50GB, but you can specify more via |
| # SCRATCH_DEV_EMPTY_SPACE |
| local space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE)) |
| |
| # mount the filesystem and create 16TB - 4KB files until we consume |
| # all the necessary space. |
| _try_scratch_mount 2>&1 >$tmp_dir/mnt.err |
| local status=$? |
| if [ $status -ne 0 ]; then |
| echo "mount failed" |
| cat $tmp_dir/mnt.err >&2 |
| rm -f $tmp_dir/mnt.err |
| return $status |
| fi |
| rm -f $tmp_dir/mnt.err |
| |
| local file_size=$((16*1024*1024*1024*1024 - 4096)) |
| local nfiles=0 |
| while [ $space_to_consume -gt $file_size ]; do |
| |
| xfs_io -F -f \ |
| -c "truncate $file_size" \ |
| -c "falloc -k 0 $file_size" \ |
| $SCRATCH_MNT/.use_space.$nfiles 2>&1 |
| status=$? |
| if [ $status -ne 0 ]; then |
| break; |
| fi |
| |
| space_to_consume=$(( $space_to_consume - $file_size )) |
| nfiles=$(($nfiles + 1)) |
| done |
| |
| # consume the remaining space. |
| if [ $space_to_consume -gt 0 ]; then |
| xfs_io -F -f \ |
| -c "truncate $space_to_consume" \ |
| -c "falloc -k 0 $space_to_consume" \ |
| $SCRATCH_MNT/.use_space.$nfiles 2>&1 |
| status=$? |
| fi |
| export NUM_SPACE_FILES=$nfiles |
| |
| _scratch_unmount |
| if [ $status -ne 0 ]; then |
| echo "large file prealloc failed" |
| cat $tmp_dir/mnt.err >&2 |
| return $status |
| fi |
| return 0 |
| } |
| |
| _scratch_mkfs_ext4_opts() |
| { |
| mkfs_opts=$* |
| |
| _scratch_options mkfs |
| |
| echo "$MKFS_EXT4_PROG $SCRATCH_OPTIONS $mkfs_opts" |
| } |
| |
| _scratch_mkfs_ext4() |
| { |
| local mkfs_cmd="`_scratch_mkfs_ext4_opts`" |
| local mkfs_filter="grep -v -e ^Warning: -e \"^mke2fs \" | grep -v \"^$\"" |
| local tmp=`mktemp -u` |
| local mkfs_status |
| |
| if [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ]; then |
| $MKFS_EXT4_PROG -F -O journal_dev $MKFS_OPTIONS $* $SCRATCH_LOGDEV 2>$tmp.mkfserr 1>$tmp.mkfsstd |
| mkjournal_status=$? |
| |
| if [ $mkjournal_status -ne 0 ]; then |
| cat $tmp.mkfsstd |
| cat $tmp.mkfserr >&2 |
| return $mkjournal_status |
| fi |
| fi |
| |
| _scratch_do_mkfs "$mkfs_cmd" "$mkfs_filter" $* 2>$tmp.mkfserr 1>$tmp.mkfsstd |
| mkfs_status=$? |
| |
| if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then |
| # manually parse the mkfs output to get the fs size in bytes |
| local fs_size=`cat $tmp.mkfsstd | awk ' \ |
| /^Block size/ { split($2, a, "="); bs = a[2] ; } \ |
| / inodes, / { blks = $3 } \ |
| /reserved for the super user/ { resv = $1 } \ |
| END { fssize = bs * blks - resv; print fssize }'` |
| |
| _setup_large_ext4_fs $fs_size |
| mkfs_status=$? |
| fi |
| |
| # output mkfs stdout and stderr |
| cat $tmp.mkfsstd |
| cat $tmp.mkfserr >&2 |
| rm -f $tmp.mkfserr $tmp.mkfsstd |
| |
| return $mkfs_status |
| } |
| |
| _ext4_metadump() |
| { |
| local device="$1" |
| local dumpfile="$2" |
| local compressopt="$3" |
| |
| test -n "$E2IMAGE_PROG" || _fail "e2image not installed" |
| $E2IMAGE_PROG -Q "$device" "$dumpfile" |
| [ "$compressopt" = "compress" ] && [ -n "$DUMP_COMPRESSOR" ] && |
| $DUMP_COMPRESSOR -f "$dumpfile" &>> "$seqres.full" |
| } |
| |
| _ext4_mdrestore() |
| { |
| local metadump="$1" |
| local device="$2" |
| shift; shift |
| local options="$@" |
| |
| # If we're configured for compressed dumps and there isn't already an |
| # uncompressed dump, see if we can use DUMP_COMPRESSOR to decompress |
| # something. |
| if [ ! -e "$metadump" ] && [ -n "$DUMP_COMPRESSOR" ]; then |
| for compr in "$metadump".*; do |
| [ -e "$compr" ] && $DUMP_COMPRESSOR -d -f -k "$compr" && break |
| done |
| fi |
| test -r "$metadump" || return 1 |
| |
| $E2IMAGE_PROG $options -r "${metadump}" "${SCRATCH_DEV}" |
| } |
| |
| # this test requires the ext4 kernel support crc feature on scratch device |
| # |
| _require_scratch_ext4_crc() |
| { |
| _scratch_mkfs_ext4 >/dev/null 2>&1 |
| dumpe2fs -h $SCRATCH_DEV 2> /dev/null | grep -q metadata_csum || _notrun "metadata_csum not supported by this filesystem" |
| _try_scratch_mount >/dev/null 2>&1 \ |
| || _notrun "Kernel doesn't support metadata_csum feature" |
| _scratch_unmount |
| } |
| |
| # Check whether the specified feature whether it is supported by |
| # mkfs.ext4 and the kernel. |
| _require_scratch_ext4_feature() |
| { |
| if [ -z "$1" ]; then |
| echo "Usage: _require_scratch_ext4_feature feature" |
| exit 1 |
| fi |
| $MKFS_EXT4_PROG -F $MKFS_OPTIONS -O "$1" \ |
| $SCRATCH_DEV 512m >/dev/null 2>&1 \ |
| || _notrun "mkfs.ext4 doesn't support $1 feature" |
| _try_scratch_mount >/dev/null 2>&1 \ |
| || _notrun "Kernel doesn't support the ext4 feature(s): $1" |
| _scratch_unmount |
| } |
| |
| # Disable extent zeroing for ext4 on the given device |
| _ext4_disable_extent_zeroout() |
| { |
| local dev=${1:-$TEST_DEV} |
| local sdev=`_short_dev $dev` |
| |
| [ -f /sys/fs/ext4/$sdev/extent_max_zeroout_kb ] && \ |
| echo 0 >/sys/fs/ext4/$sdev/extent_max_zeroout_kb |
| } |
| |
| _scratch_ext4_options() |
| { |
| local type=$1 |
| local log_opt="" |
| |
| case $type in |
| mkfs) |
| SCRATCH_OPTIONS="$SCRATCH_OPTIONS -F" |
| log_opt="-J device=$SCRATCH_LOGDEV" |
| ;; |
| mount) |
| # As of kernel 5.19, the kernel mount option path parser only |
| # accepts direct paths to block devices--the final path |
| # component cannot be a symlink. |
| log_opt="-o journal_path=$(realpath -q "$SCRATCH_LOGDEV")" |
| ;; |
| esac |
| [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \ |
| SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}" |
| } |
| |
| # Get the inode flags for a particular inode number |
| _ext4_get_inum_iflags() { |
| local dev="$1" |
| local inumber="$2" |
| |
| debugfs -R "stat <${inumber}>" "${dev}" 2> /dev/null | \ |
| sed -n 's/^.*Flags: \([0-9a-fx]*\).*$/\1/p' |
| } |