]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_io: create exchangerange command to test file range exchange ioctl
authorDarrick J. Wong <djwong@kernel.org>
Mon, 29 Jul 2024 23:23:01 +0000 (16:23 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:01:06 +0000 (17:01 -0700)
Create a new xfs_io command to make raw calls to the
XFS_IOC_EXCHANGE_RANGE ioctl.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
io/Makefile
io/exchrange.c [new file with mode: 0644]
io/init.c
io/io.h
man/man8/xfs_io.8

index 17d499de9ab9888730663a254dcc679d2b972500..3192b813c7401af2296a7f64f69c1118ef153d61 100644 (file)
@@ -8,13 +8,47 @@ include $(TOPDIR)/include/builddefs
 LTCOMMAND = xfs_io
 LSRCFILES = xfs_bmap.sh xfs_freeze.sh xfs_mkfile.sh
 HFILES = init.h io.h
-CFILES = init.c \
-       attr.c bmap.c bulkstat.c crc32cselftest.c cowextsize.c encrypt.c \
-       file.c freeze.c fsuuid.c fsync.c getrusage.c imap.c inject.c label.c \
-       link.c mmap.c open.c parent.c pread.c prealloc.c pwrite.c reflink.c \
-       resblks.c scrub.c seek.c shutdown.c stat.c swapext.c sync.c \
-       truncate.c utimes.c fadvise.c sendfile.c madvise.c mincore.c fiemap.c \
-       sync_file_range.c readdir.c
+CFILES = \
+       attr.c \
+       bmap.c \
+       bulkstat.c \
+       cowextsize.c \
+       crc32cselftest.c \
+       encrypt.c \
+       exchrange.c \
+       fadvise.c \
+       fiemap.c \
+       file.c \
+       freeze.c \
+       fsuuid.c \
+       fsync.c \
+       getrusage.c \
+       imap.c \
+       init.c \
+       inject.c \
+       label.c \
+       link.c \
+       madvise.c \
+       mincore.c \
+       mmap.c \
+       open.c \
+       parent.c \
+       pread.c \
+       prealloc.c \
+       pwrite.c \
+       readdir.c \
+       reflink.c \
+       resblks.c \
+       scrub.c \
+       seek.c \
+       sendfile.c \
+       shutdown.c \
+       stat.c \
+       swapext.c \
+       sync.c \
+       sync_file_range.c \
+       truncate.c \
+       utimes.c
 
 LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBUUID)
 LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG)
diff --git a/io/exchrange.c b/io/exchrange.c
new file mode 100644 (file)
index 0000000..0164292
--- /dev/null
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+#include "libfrog/logging.h"
+#include "libfrog/fsgeom.h"
+#include "libfrog/file_exchange.h"
+#include "libfrog/bulkstat.h"
+
+static void
+exchangerange_help(void)
+{
+       printf(_(
+"\n"
+" Exchange file data between the open file descriptor and the supplied filename.\n"
+" -C   -- Print timing information in a condensed format\n"
+" -d N -- Start exchanging contents at this position in the open file\n"
+" -f   -- Flush changed file data and metadata to disk\n"
+" -l N -- Exchange this many bytes between the two files instead of to EOF\n"
+" -n   -- Dry run; do all the parameter validation but do not change anything.\n"
+" -s N -- Start exchanging contents at this position in the supplied file\n"
+" -t   -- Print timing information\n"
+" -w   -- Only exchange written ranges in the supplied file\n"
+));
+}
+
+static int
+exchangerange_f(
+       int                     argc,
+       char                    **argv)
+{
+       struct xfs_exchange_range       fxr;
+       struct stat             stat;
+       struct timeval          t1, t2;
+       uint64_t                flags = XFS_EXCHANGE_RANGE_TO_EOF;
+       int64_t                 src_offset = 0;
+       int64_t                 dest_offset = 0;
+       int64_t                 length = -1;
+       size_t                  fsblocksize, fssectsize;
+       int                     condensed = 0, quiet_flag = 1;
+       int                     c;
+       int                     fd;
+       int                     ret;
+
+       init_cvtnum(&fsblocksize, &fssectsize);
+       while ((c = getopt(argc, argv, "Ccd:fl:ns:tw")) != -1) {
+               switch (c) {
+               case 'C':
+                       condensed = 1;
+                       break;
+               case 'd':
+                       dest_offset = cvtnum(fsblocksize, fssectsize, optarg);
+                       if (dest_offset < 0) {
+                               printf(
+                       _("non-numeric open file offset argument -- %s\n"),
+                                               optarg);
+                               return 0;
+                       }
+                       break;
+               case 'f':
+                       flags |= XFS_EXCHANGE_RANGE_DSYNC;
+                       break;
+               case 'l':
+                       length = cvtnum(fsblocksize, fssectsize, optarg);
+                       if (length < 0) {
+                               printf(
+                       _("non-numeric length argument -- %s\n"),
+                                               optarg);
+                               return 0;
+                       }
+                       flags &= ~XFS_EXCHANGE_RANGE_TO_EOF;
+                       break;
+               case 'n':
+                       flags |= XFS_EXCHANGE_RANGE_DRY_RUN;
+                       break;
+               case 's':
+                       src_offset = cvtnum(fsblocksize, fssectsize, optarg);
+                       if (src_offset < 0) {
+                               printf(
+                       _("non-numeric supplied file offset argument -- %s\n"),
+                                               optarg);
+                               return 0;
+                       }
+                       break;
+               case 't':
+                       quiet_flag = 0;
+                       break;
+               case 'w':
+                       flags |= XFS_EXCHANGE_RANGE_FILE1_WRITTEN;
+                       break;
+               default:
+                       exchangerange_help();
+                       return 0;
+               }
+       }
+       if (optind != argc - 1) {
+               exchangerange_help();
+               return 0;
+       }
+
+       /* open the donor file */
+       fd = openfile(argv[optind], NULL, 0, 0, NULL);
+       if (fd < 0)
+               return 0;
+
+       ret = fstat(file->fd, &stat);
+       if (ret) {
+               perror("fstat");
+               exitcode = 1;
+               goto out;
+       }
+       if (length < 0)
+               length = stat.st_size;
+
+       xfrog_exchangerange_prep(&fxr, dest_offset, fd, src_offset, length);
+       ret = xfrog_exchangerange(file->fd, &fxr, flags);
+       if (ret) {
+               xfrog_perror(ret, "exchangerange");
+               exitcode = 1;
+               goto out;
+       }
+       if (quiet_flag)
+               goto out;
+
+       gettimeofday(&t2, NULL);
+       t2 = tsub(t2, t1);
+
+       report_io_times("exchangerange", &t2, dest_offset, length, length, 1,
+                       condensed);
+out:
+       close(fd);
+       return 0;
+}
+
+static struct cmdinfo exchangerange_cmd = {
+       .name           = "exchangerange",
+       .cfunc          = exchangerange_f,
+       .argmin         = 1,
+       .argmax         = -1,
+       .flags          = CMD_FLAG_ONESHOT | CMD_NOMAP_OK,
+       .help           = exchangerange_help,
+};
+
+void
+exchangerange_init(void)
+{
+       exchangerange_cmd.args = _("[-Cfntw] [-d dest_offset] [-s src_offset] [-l length] <donorfile>");
+       exchangerange_cmd.oneline = _("Exchange contents between files.");
+
+       add_command(&exchangerange_cmd);
+}
index 104cd2c12152374964401eb5af025bb007667fea..37e0f093c526ddb6d72191e7736cbf4fe13b2b33 100644 (file)
--- a/io/init.c
+++ b/io/init.c
@@ -88,6 +88,7 @@ init_commands(void)
        truncate_init();
        utimes_init();
        crc32cselftest_init();
+       exchangerange_init();
 }
 
 /*
diff --git a/io/io.h b/io/io.h
index e06dff53f895a0909c670e4b37584eaa40e1dce6..fdb715ff09ab50618ba824a3a866b6b45e0e179c 100644 (file)
--- a/io/io.h
+++ b/io/io.h
@@ -149,3 +149,4 @@ extern void         scrub_init(void);
 extern void            repair_init(void);
 extern void            crc32cselftest_init(void);
 extern void            bulkstat_init(void);
+void                   exchangerange_init(void);
index 3ce280a75b4a1551f806a56fffec88613d8e6cf6..2a7c67f7cf3a2ab7b324157c07c4c7d3cb722f25 100644 (file)
@@ -713,6 +713,46 @@ Swaps extent forks between files. The current open file is the target. The donor
 file is specified by path. Note that file data is not copied (file content moves
 with the fork(s)).
 .TP
+.BI "exchangerange [OPTIONS]" donor_file "
+Exchanges contents between files.
+The current open file is the target.
+The donor file is specified by path.
+Note that file data is not copied (file content moves with the fork(s)).
+Options include:
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.TP
+.B \-C
+Print timing information in a condensed format.
+.TP
+.BI \-d " dest_offset"
+Swap extents with open file beginning at
+.IR dest_offset .
+.TP
+.B \-f
+Flush changed file data and file metadata to disk.
+.TP
+.BI \-l " length"
+Swap up to
+.I length
+bytes of data.
+.TP
+.B \-n
+Perform all the parameter validation checks but don't change anything.
+.TP
+.BI \-s " src_offset"
+Swap extents with donor file beginning at
+.IR src_offset .
+.TP
+.B \-t
+Print timing information.
+.TP
+.B \-w
+Only exchange written ranges in the supplied file.
+.RE
+.PD
+.TP
 .BI "set_encpolicy [ \-c " mode " ] [ \-n " mode " ] [ \-f " flags " ] [ \-s " log2_dusize " ] [ \-v " version " ] [ " keyspec " ]"
 On filesystems that support encryption, assign an encryption policy to the
 current file.