From: "Darrick J. Wong" <djwong@kernel.org>
To: Hironori Shiina <shiina.hironori@gmail.com>
Cc: fstests@vger.kernel.org, linux-xfs@vger.kernel.org,
Hironori Shiina <shiina.hironori@fujitsu.com>
Subject: Re: [PATCH V2] xfs: test for fixing wrong root inode number in dump
Date: Thu, 13 Oct 2022 11:37:04 -0700 [thread overview]
Message-ID: <Y0ha0LTKCKpkag8y@magnolia> (raw)
In-Reply-To: <20221013160434.130152-1-shiina.hironori@fujitsu.com>
On Thu, Oct 13, 2022 at 12:04:34PM -0400, Hironori Shiina wrote:
> Test '-x' option of xfsrestore. With this option, a wrong root inode
> number in a dump file is corrected. A root inode number can be wrong
> in a dump created by problematic xfsdump (v3.1.7 - v3.1.9) with
> bulkstat misuse. In this test, a corrupted dump file is created by
> overwriting a root inode number in a header.
>
> Signed-off-by: Hironori Shiina <shiina.hironori@fujitsu.com>
> ---
> changes since RFC v1:
> - Skip the test if xfsrestore does not support '-x' flag.
> - Create a corrupted dump by overwriting a root inode number in a dump
> file with a new tool instead of checking in a binary dump file.
>
> common/dump | 2 +-
> common/xfs | 6 +++
> src/Makefile | 2 +-
> src/fake-dump-rootino.c | 85 +++++++++++++++++++++++++++++++++++++++++
> tests/xfs/554 | 73 +++++++++++++++++++++++++++++++++++
> tests/xfs/554.out | 40 +++++++++++++++++++
> 6 files changed, 206 insertions(+), 2 deletions(-)
> create mode 100644 src/fake-dump-rootino.c
> create mode 100755 tests/xfs/554
> create mode 100644 tests/xfs/554.out
>
> diff --git a/common/dump b/common/dump
> index 8e0446d9..50b2ba03 100644
> --- a/common/dump
> +++ b/common/dump
> @@ -1003,7 +1003,7 @@ _parse_restore_args()
> --no-check-quota)
> do_quota_check=false
> ;;
> - -K|-R)
> + -K|-R|-x)
> restore_args="$restore_args $1"
> ;;
> *)
> diff --git a/common/xfs b/common/xfs
> index e1c15d3d..8334880e 100644
> --- a/common/xfs
> +++ b/common/xfs
> @@ -1402,3 +1402,9 @@ _xfs_filter_mkfs()
> print STDOUT "realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX\n";
> }'
> }
> +
> +_require_xfsrestore_xflag()
> +{
> + $XFSRESTORE_PROG -h 2>&1 | grep -q -e '-x' || \
> + _notrun 'xfsrestore does not support -x flag.'
> +}
> diff --git a/src/Makefile b/src/Makefile
> index 5f565e73..afdf6b30 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -19,7 +19,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
> 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 checkpoint_journal mmap-rw-fault allocstale \
> - t_mmap_cow_memory_failure
> + t_mmap_cow_memory_failure fake-dump-rootino
>
> LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
> preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
> diff --git a/src/fake-dump-rootino.c b/src/fake-dump-rootino.c
> new file mode 100644
> index 00000000..b89351b8
> --- /dev/null
> +++ b/src/fake-dump-rootino.c
> @@ -0,0 +1,85 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2022 Fujitsu Limited. All Rights Reserved. */
> +#include <fcntl.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +
> +// Values for size of dump file header from xfsdump
> +#define PGSZLOG2 12
> +#define PGSZ (1 << PGSZLOG2)
> +#define GLOBAL_HDR_SZ PGSZ
> +
> +static inline uint32_t convert_endian_32(uint32_t val) {
> +#if __BYTE_ORDER == __BIG_ENDIAN
> + return val;
> +#else
> + return ((val & 0xff000000u) >> 24 |
> + (val & 0x00ff0000u) >> 8 |
> + (val & 0x0000ff00u) << 8 |
> + (val & 0x000000ffu) << 24);
> +#endif
> +}
be32_to_cpu?
> +
> +static inline uint64_t convert_endian_64(uint64_t val) {
> +#if __BYTE_ORDER == __BIG_ENDIAN
> + return val;
> +#else
> + return (uint64_t) convert_endian_32(val >> 32) |
> + (uint64_t) convert_endian_32(val & 0x00000000ffffffff) << 32;
> +#endif
> +}
be64_to_cpu?
> +
> +/*
> + * Offset to checksum in dump file header
> + * global_hdr_t.gh_checksum (0xc)
> + */
> +#define OFFSET_CHECKSUM 0xc
> +
> +/*
> + * Offset to root inode number in dump file header
> + * global_hdr_t.gh_upper (0x400) + drive_hdr_t.dh_upper (0x400) +
> + * media_hdr_t.mh_upper (0x400) + content_hdr_t.ch_specific (0x340) +
> + * content_inode_hdr_t.cih_rootino (0x18)
> + */
> +#define OFFSET_ROOTINO 0xf58
Since you're now using a C program, I think it makes more sense to copy
the structure definitions directly into the C file.
> +
> +int main(int argc, char *argv[]) {
> +
> + if (argc < 3) {
> + fprintf(stderr, "Usage: %s <path/to/dumpfile> <fake rootino>\n", argv[0]);
> + exit(1);
> + }
> +
> + const char *filepath = argv[1];
> + const uint64_t fake_root_ino = (uint64_t) strtol(argv[2], NULL, 10);
> +
> + int fd = open(filepath, O_RDWR);
> + if (fd < 0) {
> + perror("open");
> + exit(1);
> + }
> + char *header = mmap(NULL, GLOBAL_HDR_SZ, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
> + if (header == MAP_FAILED) {
> + perror("mmap");
> + exit(1);
> + }
> +
> + uint32_t *checksum_ptr = (uint32_t *) (header + OFFSET_CHECKSUM);
> + uint64_t *rootino_ptr = (uint64_t *) (header + OFFSET_ROOTINO);
> + int32_t checksum = (int32_t) convert_endian_32(*checksum_ptr);
> + uint64_t orig_rootino = convert_endian_64(*rootino_ptr);
> +
> + // Fake root inode number
> + *rootino_ptr = convert_endian_64(fake_root_ino);
> +
> + // Update checksum along with overwriting rootino.
> + uint64_t gap = orig_rootino - fake_root_ino;
> + checksum += (gap >> 32) + (gap & 0x00000000ffffffff);
> + *checksum_ptr = convert_endian_32(checksum);
> +
> + munmap(header, GLOBAL_HDR_SZ);
> + close(fd);
> +}
> diff --git a/tests/xfs/554 b/tests/xfs/554
> new file mode 100755
> index 00000000..fcfaa699
> --- /dev/null
> +++ b/tests/xfs/554
> @@ -0,0 +1,73 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2022 Fujitsu Limited. All Rights Reserved.
> +#
> +# FS QA Test No. 554
> +#
> +# Create a filesystem which contains an inode with a lower number
> +# than the root inode. Set the lower number to a dump file as the root inode
> +# and ensure that 'xfsrestore -x' handles this wrong inode.
> +#
> +. ./common/preamble
> +_begin_fstest auto quick dump
> +
> +# Import common functions.
> +. ./common/dump
> +
> +_supported_fs xfs
> +_require_xfs_io_command "falloc"
> +_require_scratch
> +_require_xfsrestore_xflag
_require_test_program fake-dump-rootino
> +
> +# A large stripe unit will put the root inode out quite far
> +# due to alignment, leaving free blocks ahead of it.
> +_scratch_mkfs_xfs -d sunit=1024,swidth=1024 > $seqres.full 2>&1
> +
> +# Mounting /without/ a stripe should allow inodes to be allocated
> +# in lower free blocks, without the stripe alignment.
> +_scratch_mount -o sunit=0,swidth=0
> +
> +root_inum=$(stat -c %i $SCRATCH_MNT)
> +
> +# Consume space after the root inode so that the blocks before
> +# root look "close" for the next inode chunk allocation
> +$XFS_IO_PROG -f -c "falloc 0 16m" $SCRATCH_MNT/fillfile
> +
> +# And make a bunch of inodes until we (hopefully) get one lower
> +# than root, in a new inode chunk.
> +echo "root_inum: $root_inum" >> $seqres.full
> +for i in $(seq 0 4096) ; do
> + fname=$SCRATCH_MNT/$(printf "FILE_%03d" $i)
> + touch $fname
> + inum=$(stat -c "%i" $fname)
> + [[ $inum -lt $root_inum ]] && break
> +done
> +
> +echo "created: $inum" >> $seqres.full
> +
> +[[ $inum -lt $root_inum ]] || _notrun "Could not set up test"
> +
> +# Now try a dump and restore. Cribbed from xfs/068
> +_create_dumpdir_stress
> +
> +echo -n "Before: " >> $seqres.full
> +_count_dumpdir_files | tee $tmp.before >> $seqres.full
> +
> +_do_dump_file
> +
> +# Set the wrong root inode number to the dump file
> +# as problematic xfsdump used to do.
> +$here/src/fake-dump-rootino $dump_file $inum
> +
> +_do_restore_file -x | \
> +sed -e "s/rootino #${inum}/rootino #FAKENO/g" \
> + -e "s/# to ${root_inum}/# to ROOTNO/g" \
> + -e "/entries processed$/s/[0-9][0-9]*/NUM/g"
> +
> +echo -n "After: " >> $seqres.full
> +_count_restoredir_files | tee $tmp.after >> $seqres.full
> +diff -u $tmp.before $tmp.after
The rest of this logic looks reasonable to me though. :)
--D
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/554.out b/tests/xfs/554.out
> new file mode 100644
> index 00000000..c5e8c4c5
> --- /dev/null
> +++ b/tests/xfs/554.out
> @@ -0,0 +1,40 @@
> +QA output created by 554
> +Creating directory system to dump using fsstress.
> +
> +-----------------------------------------------
> +fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10
> +-----------------------------------------------
> +Dumping to file...
> +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_554 SCRATCH_MNT
> +xfsdump: using file dump (drive_simple) strategy
> +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT
> +xfsdump: dump date: DATE
> +xfsdump: session id: ID
> +xfsdump: session label: "stress_554"
> +xfsdump: ino map <PHASES>
> +xfsdump: ino map construction complete
> +xfsdump: estimated dump size: NUM bytes
> +xfsdump: /var/xfsdump/inventory created
> +xfsdump: creating dump session media file 0 (media 0, file 0)
> +xfsdump: dumping ino map
> +xfsdump: dumping directories
> +xfsdump: dumping non-directory files
> +xfsdump: ending media file
> +xfsdump: media file size NUM bytes
> +xfsdump: dump size (non-dir files) : NUM bytes
> +xfsdump: dump complete: SECS seconds elapsed
> +xfsdump: Dump Status: SUCCESS
> +Restoring from file...
> +xfsrestore -x -f DUMP_FILE -L stress_554 RESTORE_DIR
> +xfsrestore: using file dump (drive_simple) strategy
> +xfsrestore: using online session inventory
> +xfsrestore: searching media for directory dump
> +xfsrestore: examining media file 0
> +xfsrestore: reading directories
> +xfsrestore: found fake rootino #FAKENO, will fix.
> +xfsrestore: fix root # to ROOTNO (bind mount?)
> +xfsrestore: NUM directories and NUM entries processed
> +xfsrestore: directory post-processing
> +xfsrestore: restoring non-directory files
> +xfsrestore: restore complete: SECS seconds elapsed
> +xfsrestore: Restore Status: SUCCESS
> --
> 2.37.3
>
next prev parent reply other threads:[~2022-10-13 18:41 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-28 21:03 [RFC PATCH] xfs: test for fixing wrong root inode number Hironori Shiina
2022-09-29 1:49 ` Zorro Lang
2022-09-30 15:01 ` Hironori Shiina
2022-10-02 4:27 ` Zorro Lang
2022-10-03 22:04 ` Darrick J. Wong
2022-10-08 1:59 ` Hironori Shiina
2022-10-11 17:49 ` Darrick J. Wong
2022-10-13 16:04 ` [PATCH V2] xfs: test for fixing wrong root inode number in dump Hironori Shiina
2022-10-13 18:37 ` Darrick J. Wong [this message]
2022-10-14 16:09 ` [PATCH V3] " Hironori Shiina
2022-10-14 18:28 ` Darrick J. Wong
2022-10-15 2:06 ` Hironori Shiina
2022-10-15 2:04 ` [PATCH V4] " Hironori Shiina
2022-10-15 4:34 ` Zorro Lang
2022-10-17 15:11 ` [PATCH V5] " Hironori Shiina
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Y0ha0LTKCKpkag8y@magnolia \
--to=djwong@kernel.org \
--cc=fstests@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=shiina.hironori@fujitsu.com \
--cc=shiina.hironori@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox