diff options
author | Brian Foster <bfoster@redhat.com> | 2018-03-08 20:35:20 -0600 |
---|---|---|
committer | Eric Sandeen <sandeen@redhat.com> | 2018-03-08 20:35:20 -0600 |
commit | 57e7138aa513b89813d042a5410d335baf39a009 (patch) | |
tree | dcc2565e95112e2fbf2772de280685daa6cd30db | |
parent | 99d6e84ff181d9944cd3eb4fe13c95d8277e026b (diff) | |
download | xfsprogs-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/Makefile | 4 | ||||
-rw-r--r-- | io/init.c | 1 | ||||
-rw-r--r-- | io/io.h | 1 | ||||
-rw-r--r-- | io/swapext.c | 107 | ||||
-rw-r--r-- | man/man8/xfs_io.8 | 5 |
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) @@ -90,6 +90,7 @@ init_commands(void) sendfile_init(); shutdown_init(); stat_init(); + swapext_init(); sync_init(); sync_range_init(); truncate_init(); @@ -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 |