ext4: test journal checkpoint ioctl

Test for commit "ext4: add ioctl EXT4_IOC_CHECKPOINT". Tests journal
checkpointing and journal erasing via EXT4_IOC_CHECKPOINT with flag
EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT set.

Signed-off-by: Leah Rumancik <leah.rumancik@gmail.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
Leah Rumancik
2021-06-07 21:55:09 +00:00
committed by Eryu Guan
parent 9ff5f0ccac
commit 66734233e5
6 changed files with 217 additions and 1 deletions
+1
View File
@@ -61,6 +61,7 @@ tags
/src/bulkstat_null_ocount
/src/bulkstat_unlink_test
/src/bulkstat_unlink_test_modified
/src/checkpoint_journal
/src/chprojid_fail
/src/cloner
/src/dbtest
+1 -1
View File
@@ -18,7 +18,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
t_ofd_locks t_mmap_collision mmap-write-concurrent \
t_get_file_time t_create_short_dirs t_create_long_dirs t_enospc \
t_mmap_writev_overlap
t_mmap_writev_overlap checkpoint_journal
LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
+97
View File
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 Google
* All Rights Reserved.
*
* checkpoint_journal.c
*
* Flush journal log and checkpoint journal for ext4 file system and
* optionally, issue discard or zeroout for the journal log blocks.
*
* Arguments:
* 1) mount point for device
* 2) flags (optional)
* set --erase=discard to enable discarding journal blocks
* set --erase=zeroout to enable zero-filling journal blocks
* set --dry-run flag to only perform input checking
*/
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <linux/fs.h>
#include <getopt.h>
#if !defined(EXT4_IOC_CHECKPOINT)
#define EXT4_IOC_CHECKPOINT _IOW('f', 43, __u32)
#endif
#if !defined(EXT4_IOC_CHECKPOINT_FLAG_DISCARD)
#define EXT4_IOC_CHECKPOINT_FLAG_DISCARD 1
#define EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT 2
#define EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN 4
#endif
int main(int argc, char** argv) {
int fd, c, ret = 0, option_index = 0;
char* rpath;
unsigned int flags = 0;
static struct option long_options[] =
{
{"dry-run", no_argument, 0, 'd'},
{"erase", required_argument, 0, 'e'},
{0, 0, 0, 0}
};
/* get optional flags */
while ((c = getopt_long(argc, argv, "de:", long_options,
&option_index)) != -1) {
switch (c) {
case 'd':
flags |= EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN;
break;
case 'e':
if (strcmp(optarg, "discard") == 0) {
flags |= EXT4_IOC_CHECKPOINT_FLAG_DISCARD;
} else if (strcmp(optarg, "zeroout") == 0) {
flags |= EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT;
} else {
fprintf(stderr, "Error: invalid erase option\n");
return 1;
}
break;
default:
return 1;
}
}
if (optind != argc - 1) {
fprintf(stderr, "Error: invalid number of arguments\n");
return 1;
}
/* get fd to file system */
rpath = realpath(argv[optind], NULL);
fd = open(rpath, O_RDONLY);
free(rpath);
if (fd == -1) {
fprintf(stderr, "Error: unable to open device %s: %s\n",
argv[optind], strerror(errno));
return 1;
}
ret = ioctl(fd, EXT4_IOC_CHECKPOINT, &flags);
if (ret)
fprintf(stderr, "checkpoint ioctl returned error: %s\n", strerror(errno));
close(fd);
return ret;
}
Executable
+115
View File
@@ -0,0 +1,115 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2021 Google, Inc. All Rights Reserved.
#
# FS QA Test No. 050
#
# Test checkpoint and zeroout of journal via ioctl EXT4_IOC_CHECKPOINT
#
seq=`basename $0`
seqres=$RESULT_DIR/$seq
echo "QA output created by $seq"
status=1 # failure is the default!
# get standard environment, filters and checks
. ./common/rc
. ./common/filter
# remove previous $seqres.full before test
rm -f $seqres.full
# real QA test starts here
_supported_fs ext4
_require_scratch
_require_command "$DEBUGFS_PROG" debugfs
checkpoint_journal=$here/src/checkpoint_journal
_require_test_program "checkpoint_journal"
# convert output from stat<journal_inode> to list of block numbers
get_journal_extents() {
inode_info=$($DEBUGFS_PROG $SCRATCH_DEV -R "stat <8>" 2>> $seqres.full)
echo -e "\nJournal info:" >> $seqres.full
echo "$inode_info" >> $seqres.full
extents_line=$(echo "$inode_info" | awk '/EXTENTS:/{ print NR; exit }')
get_extents=$(echo "$inode_info" | sed -n "$(($extents_line + 1))"p)
# get just the physical block numbers
get_extents=$(echo "$get_extents" | perl -pe 's|\(.*?\):||g' | sed -e 's/, /\n/g' | perl -pe 's|(\d+)-(\d+)|\1 \2|g')
echo "$get_extents"
}
# checks all extents are zero'd out except for the superblock
# arg 1: extents (output of get_journal_extents())
check_extents() {
echo -e "\nChecking extents:" >> $seqres.full
echo "$1" >> $seqres.full
super_block="true"
echo "$1" | while IFS= read line; do
start_block=$(echo $line | cut -f1 -d' ')
end_block=$(echo $line | cut -f2 -d' ' -s)
# if first block of journal, shouldn't be wiped
if [ "$super_block" == "true" ]; then
super_block="false"
#if super block only block in this extent, skip extent
if [ -z "$end_block" ]; then
continue;
fi
start_block=$(($start_block + 1))
fi
if [ ! -z "$end_block" ]; then
blocks=$(($end_block - $start_block + 1))
else
blocks=1
fi
check=$(od $SCRATCH_DEV --skip-bytes=$(($start_block * $blocksize)) --read-bytes=$(($blocks * $blocksize)) -An -v | sed -e 's/[0 \t\n\r]//g')
[ ! -z "$check" ] && echo "error" && break
done
}
testdir="${SCRATCH_MNT}/testdir"
_scratch_mkfs_sized $((64 * 1024 * 1024)) >> $seqres.full 2>&1
_require_metadata_journaling $SCRATCH_DEV
_scratch_mount >> $seqres.full 2>&1
blocksize=$(_get_block_size $SCRATCH_MNT)
mkdir $testdir
# check if ioctl present, skip test if not present
$checkpoint_journal $SCRATCH_MNT --dry-run || _notrun "journal checkpoint ioctl not present on device"
# create some files to add some entries to journal
for i in {1..100}; do
echo > $testdir/$i
done
# make sure these files get to the journal
sync --file-system $testdir/1
# call ioctl to checkpoint and zero-fill journal blocks
$checkpoint_journal $SCRATCH_MNT --erase=zeroout || _fail "ioctl returned error"
extents=$(get_journal_extents)
# check journal blocks zeroed out
ret=$(check_extents "$extents")
[ "$ret" = "error" ] && _fail "Journal was not zero-filled"
_scratch_unmount >> $seqres.full 2>&1
echo "Silence is golden"
status=0
exit
+2
View File
@@ -0,0 +1,2 @@
QA output created by 050
Silence is golden
+1
View File
@@ -52,6 +52,7 @@
047 auto quick dax
048 auto quick dir
049 auto quick
050 auto ioctl quick
271 auto rw quick
301 aio auto ioctl rw stress defrag
302 aio auto ioctl rw stress defrag