]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_io: support a basic extent swap command
authorBrian Foster <bfoster@redhat.com>
Fri, 9 Mar 2018 02:35:20 +0000 (20:35 -0600)
committerEric Sandeen <sandeen@redhat.com>
Fri, 9 Mar 2018 02:35:20 +0000 (20:35 -0600)
Extent swap is a low level mechanism exported by XFS to facilitate
filesystem defragmentation. It is typically invoked by xfs_fsr under
conditions that will atomically adjust inode extent state without
loss of file data.

While xfs_fsr provides some debug capability to tailor its behavior,
it is not flexible enough to facilitate low level tests of the
extent swap mechanism. For example, xfs_fsr may skip swaps between
inodes that consist solely of preallocated extents because it
considers such files already 100% defragmented. Further, xfs_fsr
copies data between files where doing so may be unnecessary and thus
inefficient for lower level tests.

Add a basic swapext command to xfs_io that allows userspace
invocation of the command under more controlled conditions. This
facilites targeted tests without interference from xfs_fsr policy,
such as using files with only preallocated extents, known/expected
failure cases, etc. This command makes no effort to retain data
across the operation. As such, it is for testing purposes only.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
io/Makefile
io/init.c
io/io.h
io/swapext.c [new file with mode: 0644]
man/man8/xfs_io.8

index 8055d4bd3131a4dcece6a188d0abbc7adaca4bef..88e47517657f40e42df000c78d290c1a29994e34 100644 (file)
@@ -11,8 +11,8 @@ HFILES = init.h io.h
 CFILES = init.c \
        attr.c bmap.c cowextsize.c encrypt.c file.c freeze.c fsync.c \
        getrusage.c imap.c link.c mmap.c open.c parent.c pread.c prealloc.c \
-       pwrite.c reflink.c scrub.c seek.c shutdown.c stat.c sync.c truncate.c \
-       utimes.c
+       pwrite.c reflink.c scrub.c seek.c shutdown.c stat.c swapext.c sync.c \
+       truncate.c utimes.c
 
 LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
 LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG)
index 6f47ed250579ab0abf50688979502d42d594269c..0336c9623beb205927c06f8ff3b7aac8afe15d0f 100644 (file)
--- a/io/init.c
+++ b/io/init.c
@@ -90,6 +90,7 @@ init_commands(void)
        sendfile_init();
        shutdown_init();
        stat_init();
+       swapext_init();
        sync_init();
        sync_range_init();
        truncate_init();
diff --git a/io/io.h b/io/io.h
index 5cf7c3084b00fe440b13fccbffba81836dc69fb6..a26763610877117922681001a69c79dfcc1c1381 100644 (file)
--- a/io/io.h
+++ b/io/io.h
@@ -119,6 +119,7 @@ extern void         quit_init(void);
 extern void            seek_init(void);
 extern void            shutdown_init(void);
 extern void            stat_init(void);
+extern void            swapext_init(void);
 extern void            sync_init(void);
 extern void            truncate_init(void);
 extern void            utimes_init(void);
diff --git a/io/swapext.c b/io/swapext.c
new file mode 100644 (file)
index 0000000..5e161d6
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t swapext_cmd;
+
+static void
+swapext_help(void)
+{
+       printf(_(
+"\n"
+" Swaps extents between the open file descriptor and the supplied filename.\n"
+"\n"));
+}
+
+static int
+xfs_bulkstat_single(
+       int                     fd,
+       xfs_ino_t               *lastip,
+       struct xfs_bstat        *ubuffer)
+{
+       struct xfs_fsop_bulkreq bulkreq;
+
+       bulkreq.lastip = (__u64 *)lastip;
+       bulkreq.icount = 1;
+       bulkreq.ubuffer = ubuffer;
+       bulkreq.ocount = NULL;
+       return ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq);
+}
+
+static int
+swapext_f(
+       int                     argc,
+       char                    **argv)
+{
+       int                     fd;
+       int                     error;
+       struct xfs_swapext      sx;
+       struct stat             stat;
+
+       /* open the donor file */
+       fd = openfile(argv[1], NULL, 0, 0, NULL);
+       if (fd < 0)
+               return 0;
+
+       /*
+        * stat the target file to get the inode number and use the latter to
+        * get the bulkstat info for the swapext cmd.
+        */
+       error = fstat(file->fd, &stat);
+       if (error) {
+               perror("fstat");
+               goto out;
+       }
+
+       error = xfs_bulkstat_single(file->fd, &stat.st_ino, &sx.sx_stat);
+       if (error) {
+               perror("bulkstat");
+               goto out;
+       }
+       sx.sx_version = XFS_SX_VERSION;
+       sx.sx_fdtarget = file->fd;
+       sx.sx_fdtmp = fd;
+       sx.sx_offset = 0;
+       sx.sx_length = stat.st_size;
+       error = ioctl(file->fd, XFS_IOC_SWAPEXT, &sx);
+       if (error)
+               perror("swapext");
+
+out:
+       close(fd);
+       return 0;
+}
+
+void
+swapext_init(void)
+{
+       swapext_cmd.name = "swapext";
+       swapext_cmd.cfunc = swapext_f;
+       swapext_cmd.argmin = 1;
+       swapext_cmd.argmax = 1;
+       swapext_cmd.flags = CMD_NOMAP_OK;
+       swapext_cmd.args = _("<donorfile>");
+       swapext_cmd.oneline = _("Swap extents between files.");
+       swapext_cmd.help = swapext_help;
+
+       add_command(&swapext_cmd);
+}
index 8bf3f57bd30e8ea49b22d1da2855cfe6d0b8bb9a..364088c82cc6115ee7163b8e1ade901725f8522b 100644 (file)
@@ -773,6 +773,11 @@ sec uses UNIX timestamp notation and is the seconds elapsed since
 nsec is the nanoseconds since the sec. This value needs to be in
 the range 0-999999999 with UTIME_NOW and UTIME_OMIT being exceptions.
 Each (sec, nsec) pair constitutes a single timestamp value.
+.TP
+.BI swapext " donor_file "
+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)).
 
 .SH MEMORY MAPPED I/O COMMANDS
 .TP