From: Darrick J. Wong Date: Tue, 25 Oct 2016 22:14:32 +0000 (-0700) Subject: xfs_io: get and set the CoW extent size hint X-Git-Tag: v4.9.0-rc1~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1e51132f332f43146929b1978d56cbeb0c45f283;p=thirdparty%2Fxfsprogs-dev.git xfs_io: get and set the CoW extent size hint Enable administrators to get or set the CoW extent size hint. Report the hint when we run stat. This also requires some autoconf magic to detect whether or not fsx_cowextsize exists. Signed-off-by: Darrick J. Wong --- v2: Use the internal fsxattr override to guarantee that the cowextsize field always exists inside of whatever struct fsxattr is. --- diff --git a/io/Makefile b/io/Makefile index 62bc03b8f..e948006b0 100644 --- a/io/Makefile +++ b/io/Makefile @@ -11,7 +11,7 @@ HFILES = init.h io.h CFILES = init.c \ attr.c bmap.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 seek.c shutdown.c \ - sync.c truncate.c reflink.c + sync.c truncate.c reflink.c cowextsize.c LLDLIBS = $(LIBXCMD) $(LIBHANDLE) LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) diff --git a/io/attr.c b/io/attr.c index d1962f3a8..b8eec1be5 100644 --- a/io/attr.c +++ b/io/attr.c @@ -48,9 +48,10 @@ static struct xflags { { FS_XFLAG_NODEFRAG, "f", "no-defrag" }, { FS_XFLAG_FILESTREAM, "S", "filestream" }, { FS_XFLAG_DAX, "x", "dax" }, + { FS_XFLAG_COWEXTSIZE, "C", "cowextsize" }, { 0, NULL, NULL } }; -#define CHATTR_XFLAG_LIST "r"/*p*/"iasAdtPneEfSx" +#define CHATTR_XFLAG_LIST "r"/*p*/"iasAdtPneEfSxC" static void lsattr_help(void) @@ -75,6 +76,7 @@ lsattr_help(void) " f -- do not include this file when defragmenting the filesystem\n" " S -- enable filestreams allocator for this directory\n" " x -- Use direct access (DAX) for data in this file\n" +" C -- for files with shared blocks, observe the inode CoW extent size value\n" "\n" " Options:\n" " -R -- recursively descend (useful when current file is a directory)\n" @@ -111,6 +113,7 @@ chattr_help(void) " +/-f -- set/clear the no-defrag flag\n" " +/-S -- set/clear the filestreams allocator flag\n" " +/-x -- set/clear the direct access (DAX) flag\n" +" +/-C -- set/clear the CoW extent-size flag\n" " Note1: user must have certain capabilities to modify immutable/append-only.\n" " Note2: immutable/append-only files cannot be deleted; removing these files\n" " requires the immutable/append-only flag to be cleared first.\n" diff --git a/io/cowextsize.c b/io/cowextsize.c new file mode 100644 index 000000000..b4a1c2ee8 --- /dev/null +++ b/io/cowextsize.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2016 Oracle. All Rights Reserved. + * + * Author: Darrick J. Wong + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + */ +/* + * If configure didn't find a struct fsxattr with fsx_cowextsize, + * disable the only other source (so far) of struct fsxattr. Thus, + * build with the internal definition of struct fsxattr, which has + * fsx_cowextsize. + */ +#include "platform_defs.h" +#include "command.h" +#include "init.h" +#include "io.h" +#include "input.h" +#include "path.h" + +static cmdinfo_t cowextsize_cmd; +static long cowextsize; + +static void +cowextsize_help(void) +{ + printf(_( +"\n" +" report or modify preferred CoW extent size (in bytes) for the current path\n" +"\n" +" -R -- recursively descend (useful when current path is a directory)\n" +" -D -- recursively descend, only modifying cowextsize on directories\n" +"\n")); +} + +static int +get_cowextsize(const char *path, int fd) +{ + struct fsxattr fsx; + + if ((xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) { + printf("%s: XFS_IOC_FSGETXATTR %s: %s\n", + progname, path, strerror(errno)); + return 0; + } + printf("[%u] %s\n", fsx.fsx_cowextsize, path); + return 0; +} + +static int +set_cowextsize(const char *path, int fd, long extsz) +{ + struct fsxattr fsx; + struct stat64 stat; + + if (fstat64(fd, &stat) < 0) { + perror("fstat64"); + return 0; + } + if ((xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) { + printf("%s: XFS_IOC_FSGETXATTR %s: %s\n", + progname, path, strerror(errno)); + return 0; + } + + if (S_ISREG(stat.st_mode) || S_ISDIR(stat.st_mode)) { + fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE; + } else { + printf(_("invalid target file type - file %s\n"), path); + return 0; + } + fsx.fsx_cowextsize = extsz; + + if ((xfsctl(path, fd, XFS_IOC_FSSETXATTR, &fsx)) < 0) { + printf("%s: XFS_IOC_FSSETXATTR %s: %s\n", + progname, path, strerror(errno)); + return 0; + } + + return 0; +} + +static int +get_cowextsize_callback( + const char *path, + const struct stat *stat, + int status, + struct FTW *data) +{ + int fd; + + if (recurse_dir && !S_ISDIR(stat->st_mode)) + return 0; + + fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, _("%s: cannot open %s: %s\n"), + progname, path, strerror(errno)); + } else { + get_cowextsize(path, fd); + close(fd); + } + return 0; +} + +static int +set_cowextsize_callback( + const char *path, + const struct stat *stat, + int status, + struct FTW *data) +{ + int fd; + + if (recurse_dir && !S_ISDIR(stat->st_mode)) + return 0; + + fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, _("%s: cannot open %s: %s\n"), + progname, path, strerror(errno)); + } else { + set_cowextsize(path, fd, cowextsize); + close(fd); + } + return 0; +} + +static int +cowextsize_f( + int argc, + char **argv) +{ + size_t blocksize, sectsize; + int c; + + recurse_all = recurse_dir = 0; + init_cvtnum(&blocksize, §size); + while ((c = getopt(argc, argv, "DR")) != EOF) { + switch (c) { + case 'D': + recurse_all = 0; + recurse_dir = 1; + break; + case 'R': + recurse_all = 1; + recurse_dir = 0; + break; + default: + return command_usage(&cowextsize_cmd); + } + } + + if (optind < argc) { + cowextsize = (long)cvtnum(blocksize, sectsize, argv[optind]); + if (cowextsize < 0) { + printf(_("non-numeric cowextsize argument -- %s\n"), + argv[optind]); + return 0; + } + } else { + cowextsize = -1; + } + + if (recurse_all || recurse_dir) + nftw(file->name, (cowextsize >= 0) ? + set_cowextsize_callback : get_cowextsize_callback, + 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); + else if (cowextsize >= 0) + set_cowextsize(file->name, file->fd, cowextsize); + else + get_cowextsize(file->name, file->fd); + return 0; +} + +void +cowextsize_init(void) +{ + cowextsize_cmd.name = "cowextsize"; + cowextsize_cmd.cfunc = cowextsize_f; + cowextsize_cmd.args = _("[-D | -R] [cowextsize]"); + cowextsize_cmd.argmin = 0; + cowextsize_cmd.argmax = -1; + cowextsize_cmd.flags = CMD_NOMAP_OK; + cowextsize_cmd.oneline = + _("get/set preferred CoW extent size (in bytes) for the open file"); + cowextsize_cmd.help = cowextsize_help; + + add_command(&cowextsize_cmd); +} diff --git a/io/init.c b/io/init.c index efe739051..6b88cc666 100644 --- a/io/init.c +++ b/io/init.c @@ -85,6 +85,7 @@ init_commands(void) sync_range_init(); truncate_init(); reflink_init(); + cowextsize_init(); } static int diff --git a/io/io.h b/io/io.h index 2bc7ac4a1..5d21314cf 100644 --- a/io/io.h +++ b/io/io.h @@ -169,3 +169,5 @@ extern void readdir_init(void); #endif extern void reflink_init(void); + +extern void cowextsize_init(void); diff --git a/io/open.c b/io/open.c index 8f934eedc..69ec38838 100644 --- a/io/open.c +++ b/io/open.c @@ -125,6 +125,7 @@ stat_f( printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1); printf(_("fsxattr.projid = %u\n"), fsx.fsx_projid); printf(_("fsxattr.extsize = %u\n"), fsx.fsx_extsize); + printf(_("fsxattr.cowextsize = %u\n"), fsx.fsx_cowextsize); printf(_("fsxattr.nextents = %u\n"), fsx.fsx_nextents); printf(_("fsxattr.naextents = %u\n"), fsxa.fsx_nextents); } diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4 index e0a95e2d8..6de665931 100644 --- a/m4/package_libcdev.m4 +++ b/m4/package_libcdev.m4 @@ -274,5 +274,15 @@ AC_DEFUN([AC_HAVE_MREMAP], # AC_DEFUN([AC_NEED_INTERNAL_FSXATTR], [ + AC_CHECK_TYPE(struct fsxattr, + [ + AC_CHECK_MEMBER(struct fsxattr.fsx_cowextsize, + , + need_internal_fsxattr=yes, + [#include ] + ) + ],, + [#include ] + ) AC_SUBST(need_internal_fsxattr) ]) diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index d0895240d..2365550b3 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -283,6 +283,22 @@ The should be specified in bytes, or using one of the usual units suffixes (k, m, g, b, etc). The extent size is always reported in units of bytes. .TP +.BI "cowextsize [ \-R | \-D ] [ " value " ]" +Display and/or modify the preferred copy-on-write extent size used +when allocating space for the currently open file. If the +.B \-R +option is specified, a recursive descent is performed +for all directory entries below the currently open file +.RB ( \-D +can be used to restrict the output to directories only). +If the target file is a directory, then the inherited CoW extent size +is set for that directory (new files created in that directory +inherit that CoW extent size). +The +.I value +should be specified in bytes, or using one of the usual units suffixes +(k, m, g, b, etc). The extent size is always reported in units of bytes. +.TP .BI "allocsp " size " 0" Sets the size of the file to .I size