diff mbox series

[2/7] xfs_spaceman: edit filesystem properties

Message ID 172230940600.1543753.11770032596501355577.stgit@frogsfrogsfrogs (mailing list archive)
State Accepted, archived
Headers show
Series [1/7] libfrog: support editing filesystem property sets | expand

Commit Message

Darrick J. Wong July 30, 2024, 3:20 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Add some new subcommands to xfs_spaceman so that we can examine
filesystem properties.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 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

Comments

Christoph Hellwig July 30, 2024, 9:41 p.m. UTC | #1
Is this really a xfs_spaceman thingy?  The code itself looks fine,
but the association with space management is kinda weird.
Darrick J. Wong July 30, 2024, 10:37 p.m. UTC | #2
On Tue, Jul 30, 2024 at 02:41:41PM -0700, Christoph Hellwig wrote:
> Is this really a xfs_spaceman thingy?  The code itself looks fine,
> but the association with space management is kinda weird.

I dunno.  It could just as easily go into xfs_io I suppose; the tiny
advantage of putting it in spaceman is that spaceman grabs the
fsgeometry structure on file open so we don't have to do that again.

--D
Christoph Hellwig July 31, 2024, 3:41 p.m. UTC | #3
On Tue, Jul 30, 2024 at 03:37:25PM -0700, Darrick J. Wong wrote:
> On Tue, Jul 30, 2024 at 02:41:41PM -0700, Christoph Hellwig wrote:
> > Is this really a xfs_spaceman thingy?  The code itself looks fine,
> > but the association with space management is kinda weird.
> 
> I dunno.  It could just as easily go into xfs_io I suppose; the tiny
> advantage of putting it in spaceman is that spaceman grabs the
> fsgeometry structure on file open so we don't have to do that again.

For the online changes xfs_io seems ok, and for the offline ones xfs_db
seems like a perfevt fit anyway.
Dave Chinner Aug. 2, 2024, 12:16 a.m. UTC | #4
On Wed, Jul 31, 2024 at 08:41:58AM -0700, Christoph Hellwig wrote:
> On Tue, Jul 30, 2024 at 03:37:25PM -0700, Darrick J. Wong wrote:
> > On Tue, Jul 30, 2024 at 02:41:41PM -0700, Christoph Hellwig wrote:
> > > Is this really a xfs_spaceman thingy?  The code itself looks fine,
> > > but the association with space management is kinda weird.
> > 
> > I dunno.  It could just as easily go into xfs_io I suppose; the tiny
> > advantage of putting it in spaceman is that spaceman grabs the
> > fsgeometry structure on file open so we don't have to do that again.
> 
> For the online changes xfs_io seems ok, and for the offline ones xfs_db
> seems like a perfevt fit anyway.

If fsprops can be managed both online and offline,
then xfs_admin is probably the right user facing interface
to document.  i.e. We already have xfs_admin vectoring between
xfs_io when the filesystem is online and xfs_db when the filesystem
is offline to do things like change UUIDs and labels. This would
make setting fsprops somewhat simpler for admins and scripts as they
then only have to learn/code one mechanism instead of two...

-Dave.
diff mbox series

Patch

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@kernel.org>
+ */
+#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_ */