aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2018-03-08 20:35:20 -0600
committerEric Sandeen <sandeen@redhat.com>2018-03-08 20:35:20 -0600
commit57e7138aa513b89813d042a5410d335baf39a009 (patch)
treedcc2565e95112e2fbf2772de280685daa6cd30db
parent99d6e84ff181d9944cd3eb4fe13c95d8277e026b (diff)
downloadxfsprogs-dev-57e7138aa513b89813d042a5410d335baf39a009.tar.gz
xfs_io: support a basic extent swap command
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>
-rw-r--r--io/Makefile4
-rw-r--r--io/init.c1
-rw-r--r--io/io.h1
-rw-r--r--io/swapext.c107
-rw-r--r--man/man8/xfs_io.85
5 files changed, 116 insertions, 2 deletions
diff --git a/io/Makefile b/io/Makefile
index 8055d4bd31..88e4751765 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -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)
diff --git a/io/init.c b/io/init.c
index 6f47ed2505..0336c9623b 100644
--- 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 5cf7c3084b..a267636108 100644
--- 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
index 0000000000..5e161d69ba
--- /dev/null
+++ b/io/swapext.c
@@ -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);
+}
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 8bf3f57bd3..364088c82c 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -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