From: Darrick J. Wong <djwong@xxxxxxxxxx> Add some new subcommands to xfs_spaceman so that we can examine filesystem properties. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- man/man8/xfs_spaceman.8 | 27 ++++ spaceman/Makefile | 4 + spaceman/init.c | 1 spaceman/properties.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++ spaceman/space.h | 1 5 files changed, 375 insertions(+) create mode 100644 spaceman/properties.c diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8 index 0d299132a788..4615774de59e 100644 --- a/man/man8/xfs_spaceman.8 +++ b/man/man8/xfs_spaceman.8 @@ -217,3 +217,30 @@ Do not trim free space extents shorter than this length. Units can be appended to this argument. .PD .RE + +.SH FILESYSTEM PROPERTIES +If the opened file is the root directory of a filesystem, the following +commands can be used to read and write filesystem properties. +These properties allow system administrators to express their preferences for +the filesystem in question. +.TP +.BI "getfsprops name [ " names "... ]" +Retrieve the values of the given filesystem properties. +.TP +.BI "listfsprops" +List all filesystem properties that have been stored in the filesystem. +.TP +.BI "setfsprops " name = value " [ " name = value "... ]" +Set the given filesystem properties to the specified values. +.TP +.BI "removefsprops name [ " names "... ]" +Remove the given filesystem properties. + +.RE +Currently supported filesystem properties are: +.TP +.B self_healing +See the +.BR xfs_scrub (8) +manual for more information. +.RE diff --git a/spaceman/Makefile b/spaceman/Makefile index 358db9edf5cb..2688b37c770d 100644 --- a/spaceman/Makefile +++ b/spaceman/Makefile @@ -30,6 +30,10 @@ ifeq ($(HAVE_GETFSMAP),yes) CFILES += freesp.c endif +ifeq ($(HAVE_LIBATTR),yes) +CFILES += properties.c +endif + default: depend $(LTCOMMAND) include $(BUILDRULES) diff --git a/spaceman/init.c b/spaceman/init.c index cf1ff3cbb0ee..aff666cdb670 100644 --- a/spaceman/init.c +++ b/spaceman/init.c @@ -35,6 +35,7 @@ init_commands(void) trim_init(); freesp_init(); health_init(); + fsprops_init(); } static int diff --git a/spaceman/properties.c b/spaceman/properties.c new file mode 100644 index 000000000000..dbe628c1184a --- /dev/null +++ b/spaceman/properties.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong <djwong@xxxxxxxxxx> + */ +#include "platform_defs.h" +#include "command.h" +#include "init.h" +#include "libfrog/paths.h" +#include "input.h" +#include "libfrog/fsgeom.h" +#include "handle.h" +#include "space.h" +#include "libfrog/fsprops.h" +#include "libfrog/fsproperties.h" + +#include <attr/attributes.h> + +static void +listfsprops_help(void) +{ + printf(_( +"Print the names of the filesystem properties stored in this filesystem.\n" +"\n")); +} + +static int +print_fsprop( + struct fsprops_handle *fph, + const char *name, + size_t unused, + void *priv) +{ + bool *print_values = priv; + char valuebuf[ATTR_MAX_VALUELEN]; + size_t valuelen = ATTR_MAX_VALUELEN; + int ret; + + if (!(*print_values)) { + printf("%s\n", name); + return 0; + } + + ret = fsprops_get(fph, name, valuebuf, &valuelen); + if (ret) + return ret; + + printf("%s=%.*s\n", name, (int)valuelen, valuebuf); + return 0; +} + +static int +listfsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + bool print_values = false; + int c; + int ret; + + while ((c = getopt(argc, argv, "v")) != EOF) { + switch (c) { + case 'v': + print_values = true; + break; + default: + exitcode = 1; + listfsprops_help(); + return 0; + } + } + + ret = fsprops_open_handle(&file->xfd, &file->fs_path, &fph); + if (ret) { + if (errno == ESRMNT) + fprintf(stderr, + _("%s: Cannot find alleged XFS mount point %s.\n"), + file->name, file->fs_path.fs_dir); + else + perror(file->name); + exitcode = 1; + return 0; + } + + ret = fsprops_walk_names(&fph, print_fsprop, &print_values); + if (ret) { + perror(file->name); + exitcode = 1; + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo listfsprops_cmd = { + .name = "listfsprops", + .cfunc = listfsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT, + .args = "", + .help = listfsprops_help, +}; + +static void +getfsprops_help(void) +{ + printf(_( +"Print the values of filesystem properties stored in this filesystem.\n" +"\n" +"Pass property names as the arguments.\n" +"\n")); +} + +static int +getfsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + int c; + int ret; + + while ((c = getopt(argc, argv, "")) != EOF) { + switch (c) { + default: + exitcode = 1; + getfsprops_help(); + return 0; + } + } + + ret = fsprops_open_handle(&file->xfd, &file->fs_path, &fph); + if (ret) { + if (errno == ESRMNT) + fprintf(stderr, + _("%s: Cannot find alleged XFS mount point %s.\n"), + file->name, file->fs_path.fs_dir); + else + perror(file->name); + exitcode = 1; + return 0; + } + + for (c = optind; c < argc; c++) { + char valuebuf[ATTR_MAX_VALUELEN]; + size_t valuelen = ATTR_MAX_VALUELEN; + + ret = fsprops_get(&fph, argv[c], valuebuf, &valuelen); + if (ret) { + perror(argv[c]); + exitcode = 1; + break; + } + + printf("%s=%.*s\n", argv[c], (int)valuelen, valuebuf); + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo getfsprops_cmd = { + .name = "getfsprops", + .cfunc = getfsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT, + .args = "", + .help = getfsprops_help, +}; + +static void +setfsprops_help(void) +{ + printf(_( +"Set values of filesystem properties stored in this filesystem.\n" +"\n" +" -f Do not try to validate property value.\n" +"\n" +"Provide name=value tuples as the arguments.\n" +"\n")); +} + +static int +setfsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + bool force = false; + int c; + int ret; + + while ((c = getopt(argc, argv, "f")) != EOF) { + switch (c) { + case 'f': + force = true; + break; + default: + exitcode = 1; + getfsprops_help(); + return 0; + } + } + + ret = fsprops_open_handle(&file->xfd, &file->fs_path, &fph); + if (ret) { + if (errno == ESRMNT) + fprintf(stderr, + _("%s: Cannot find alleged XFS mount point %s.\n"), + file->name, file->fs_path.fs_dir); + else + perror(file->name); + exitcode = 1; + return 0; + } + + for (c = optind; c < argc; c ++) { + char *equals = strchr(argv[c], '='); + + if (!equals) { + fprintf(stderr, _("%s: property value required.\n"), + argv[c]); + exitcode = 1; + break; + } + + *equals = 0; + + if (!force && !fsprop_validate(argv[c], equals + 1)) { + fprintf(stderr, _("%s: invalid value \"%s\".\n"), + argv[c], equals + 1); + *equals = '='; + exitcode = 1; + break; + } + + ret = fsprops_set(&fph, argv[c], equals + 1, + strlen(equals + 1)); + if (ret) { + perror(argv[c]); + *equals = '='; + exitcode = 1; + break; + } + + printf("%s=%s\n", argv[c], equals + 1); + *equals = '='; + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo setfsprops_cmd = { + .name = "setfsprops", + .cfunc = setfsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT, + .args = "", + .help = setfsprops_help, +}; + +static void +removefsprops_help(void) +{ + printf(_( +"Unset a filesystem property.\n" +"\n" +"Pass property names as the arguments.\n" +"\n")); +} + +static int +removefsprops_f( + int argc, + char **argv) +{ + struct fsprops_handle fph = { }; + int c; + int ret; + + while ((c = getopt(argc, argv, "")) != EOF) { + switch (c) { + default: + exitcode = 1; + getfsprops_help(); + return 0; + } + } + + ret = fsprops_open_handle(&file->xfd, &file->fs_path, &fph); + if (ret) { + if (errno == ESRMNT) + fprintf(stderr, + _("%s: Cannot find alleged XFS mount point %s.\n"), + file->name, file->fs_path.fs_dir); + else + perror(file->name); + exitcode = 1; + return 0; + } + + for (c = optind; c < argc; c++) { + ret = fsprops_remove(&fph, argv[c]); + if (ret) { + perror(argv[c]); + exitcode = 1; + break; + } + } + + fsprops_free_handle(&fph); + return 0; +} + +static struct cmdinfo removefsprops_cmd = { + .name = "removefsprops", + .cfunc = removefsprops_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT, + .args = "", + .help = removefsprops_help, +}; + +void +fsprops_init(void) +{ + listfsprops_cmd.oneline = _("list file system properties"); + getfsprops_cmd.oneline = _("print file system properties"); + setfsprops_cmd.oneline = _("set file system properties"); + removefsprops_cmd.oneline = _("unset file system properties"); + + add_command(&listfsprops_cmd); + add_command(&getfsprops_cmd); + add_command(&setfsprops_cmd); + add_command(&removefsprops_cmd); +} diff --git a/spaceman/space.h b/spaceman/space.h index 28fa35a30479..c4beb5f489ff 100644 --- a/spaceman/space.h +++ b/spaceman/space.h @@ -36,5 +36,6 @@ extern void freesp_init(void); #endif extern void info_init(void); extern void health_init(void); +void fsprops_init(void); #endif /* XFS_SPACEMAN_SPACE_H_ */