From patchwork Tue Aug 6 18:19:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755236 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 824173C485; Tue, 6 Aug 2024 18:19:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968375; cv=none; b=IjOm1Hw8xs68Lw4GN3X4BcnZJ/gmEfk/5qAE/gWSeqzcr9+YQNakEVUO/aNTbuoo2arnIT0hgsEKDgmNN4j652Ghf6YGdmYvPgZIo29ZMSn37CELKKuX5TgYllGtdpcJMA1wTTpC8LkCv8fwxHMgdtKMCh1ze8tAOeFsw0sAegw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968375; c=relaxed/simple; bh=u6axq2G0pOoR4P4kzRJU8r7zbnD4TxxXS6ylSue88DM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rxjLYbU10+V4Npxv1hjhwcfZCZC4tOqjvcFL4p75S6S3lZKPigIUn/GM5hCvGMinOfVAL1pmbGrtLNAFzZjw8a6exVjPgcAxjudvCoTjNuypT6zP1tT2MkOSf/bd6Kf2RlTzEJ+mB3ktPxWzFyvfKDG69VhTzsM9YogmTaGbxqA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rsk8IiI0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rsk8IiI0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 56C7FC32786; Tue, 6 Aug 2024 18:19:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968375; bh=u6axq2G0pOoR4P4kzRJU8r7zbnD4TxxXS6ylSue88DM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=rsk8IiI0okYUm6HAYGEKHAFTsr5Wpp+hpFVGXKslGgZLsQH+jCbgEWi86zXywonE9 tVCIrIPxr9f1XIVwzLuM3xQcxPhecw5w7RRjfiPs5m8va08TS/7uX6/Lod0Aapbpb5 0GFEO7cFJTjxfca2CiGMjtHIpVuzOjjGFEnlKUD0yRCyy9MH7yAZoz9B9G8GyEv3dR ut270JrK+tyKvSCQ20pwhRdMaGVlUuERenPen9GaX3cqNzZ2CI44vjJkCfdZ1IFbo9 zYjL6TaYs9HXhOvnR6PTHdjXJWdhSToOhufRnpplaIIcRLPvSwrsgl1rcCbStkBQtk Cko73O9gZNd/A== Date: Tue, 06 Aug 2024 11:19:34 -0700 Subject: [PATCH 1/7] libfrog: support editing filesystem property sets From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825204.3193059.1793290126322543570.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add some library functions so that spaceman and scrub can share the same code to edit and retrieve filesystem properties. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Acked-by: Dave Chinner --- libfrog/Makefile | 7 ++ libfrog/fsproperties.c | 39 +++++++++ libfrog/fsproperties.h | 53 +++++++++++++ libfrog/fsprops.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++ libfrog/fsprops.h | 34 ++++++++ 5 files changed, 335 insertions(+) create mode 100644 libfrog/fsproperties.c create mode 100644 libfrog/fsproperties.h create mode 100644 libfrog/fsprops.c create mode 100644 libfrog/fsprops.h diff --git a/libfrog/Makefile b/libfrog/Makefile index 0b5b23893..acddc894e 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -20,6 +20,7 @@ convert.c \ crc32.c \ file_exchange.c \ fsgeom.c \ +fsproperties.c \ getparents.c \ histogram.c \ list_sort.c \ @@ -47,6 +48,7 @@ dahashselftest.h \ div64.h \ file_exchange.h \ fsgeom.h \ +fsproperties.h \ getparents.h \ histogram.h \ logging.h \ @@ -60,6 +62,11 @@ workqueue.h LSRCFILES += gen_crc32table.c +ifeq ($(HAVE_LIBATTR),yes) +CFILES+=fsprops.c +HFILES+=fsprops.h +endif + LDIRT = gen_crc32table crc32table.h default: ltdepend $(LTLIBRARY) diff --git a/libfrog/fsproperties.c b/libfrog/fsproperties.c new file mode 100644 index 000000000..c317d15c1 --- /dev/null +++ b/libfrog/fsproperties.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include +#include "xfs.h" +#include "libfrog/fsgeom.h" +#include "libfrog/fsproperties.h" +#include "list.h" + +/* Return the offset of a string in a string table, or -1 if not found. */ +static inline int +__fsprops_lookup( + const char *values[], + unsigned int nr_values, + const char *value) +{ + unsigned int i; + + for (i = 0; i < nr_values; i++) { + if (values[i] && !strcmp(value, values[i])) + return i; + } + + return -1; +} + +#define fsprops_lookup(values, value) \ + __fsprops_lookup((values), ARRAY_SIZE(values), (value)) + +/* Return true if a fs property name=value tuple is allowed. */ +bool +fsprop_validate( + const char *name, + const char *value) +{ + return true; +} diff --git a/libfrog/fsproperties.h b/libfrog/fsproperties.h new file mode 100644 index 000000000..b1ac4cdd7 --- /dev/null +++ b/libfrog/fsproperties.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __LIBFROG_FSPROPERTIES_H__ +#define __LIBFROG_FSPROPERTIES_H__ + +/* Name space for filesystem properties. */ +#define FSPROP_NAMESPACE "trusted." + +/* + * All filesystem property xattr names must have this string after the + * namespace. For example, the VFS xattr calls should use the name + * "trusted.xfs:fubar". The xfs xattr ioctls would set ATTR_ROOT and use the + * name "xfs:fubar". + */ +#define FSPROP_NAME_PREFIX "xfs:" + +/* Maximum size the value of a filesystem property. */ +#define FSPROP_MAX_VALUELEN (65536) + +static inline int +fsprop_name_to_attr_name( + const char *prop_name, + char **attr_name) +{ + return asprintf(attr_name, FSPROP_NAME_PREFIX "%s", prop_name); +} + +static inline const char * +attr_name_to_fsprop_name( + const char *attr_name) +{ + const size_t bytes = sizeof(FSPROP_NAME_PREFIX) - 1; + unsigned int i; + + for (i = 0; i < bytes; i++) { + if (attr_name[i] == 0) + return NULL; + } + + if (memcmp(attr_name, FSPROP_NAME_PREFIX, bytes) != 0) + return NULL; + + return attr_name + bytes; +} + +bool fsprop_validate(const char *name, const char *value); + +/* Specific Filesystem Properties */ + +#endif /* __LIBFROG_FSPROPERTIES_H__ */ diff --git a/libfrog/fsprops.c b/libfrog/fsprops.c new file mode 100644 index 000000000..88046b7a0 --- /dev/null +++ b/libfrog/fsprops.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "xfs.h" +#include "handle.h" +#include "libfrog/fsgeom.h" +#include "libfrog/paths.h" +#include "libfrog/bulkstat.h" +#include "libfrog/fsprops.h" +#include "libfrog/fsproperties.h" + +#include + +/* + * Given an xfd and a mount table path, get us the handle for the root dir so + * we can set filesystem properties. + */ +int +fsprops_open_handle( + struct xfs_fd *xfd, + struct fs_path *fs_path, + struct fsprops_handle *fph) +{ + struct xfs_bulkstat bulkstat; + struct stat sb; + int ret; + + /* fs properties only supported on V5 filesystems */ + if (!(xfd->fsgeom.flags & XFS_FSOP_GEOM_FLAGS_V5SB)) { + errno = EOPNOTSUPP; + return -1; + } + + ret = -xfrog_bulkstat_single(xfd, XFS_BULK_IREQ_SPECIAL_ROOT, + XFS_BULK_IREQ_SPECIAL, &bulkstat); + if (ret) + return ret; + + ret = fstat(xfd->fd, &sb); + if (ret) + return ret; + + if (sb.st_ino != bulkstat.bs_ino) { + errno = ESRMNT; + return -1; + } + + return fd_to_handle(xfd->fd, &fph->hanp, &fph->hlen); +} + +/* Free a fsproperties handle. */ +void +fsprops_free_handle( + struct fsprops_handle *fph) +{ + if (fph->hanp) + free_handle(fph->hanp, fph->hlen); + fph->hanp = NULL; + fph->hlen = 0; +} + +/* Call the given callback on every fs property accessible through the handle. */ +int +fsprops_walk_names( + struct fsprops_handle *fph, + fsprops_name_walk_fn walk_fn, + void *priv) +{ + struct attrlist_cursor cur = { }; + char attrbuf[XFS_XATTR_LIST_MAX]; + struct attrlist *attrlist = (struct attrlist *)attrbuf; + int ret; + + memset(attrbuf, 0, XFS_XATTR_LIST_MAX); + + while ((ret = attr_list_by_handle(fph->hanp, fph->hlen, attrbuf, + XFS_XATTR_LIST_MAX, XFS_IOC_ATTR_ROOT, + &cur)) == 0) { + unsigned int i; + + for (i = 0; i < attrlist->al_count; i++) { + struct attrlist_ent *ent = ATTR_ENTRY(attrlist, i); + const char *p = + attr_name_to_fsprop_name(ent->a_name); + + if (p) { + ret = walk_fn(fph, p, ent->a_valuelen, priv); + if (ret) + break; + } + } + + if (!attrlist->al_more) + break; + } + + return ret; +} + +/* Retrieve the value of a specific fileystem property. */ +int +fsprops_get( + struct fsprops_handle *fph, + const char *name, + void *valuebuf, + size_t *valuelen) +{ + struct xfs_attr_multiop ops = { + .am_opcode = ATTR_OP_GET, + .am_attrvalue = valuebuf, + .am_length = *valuelen, + .am_flags = XFS_IOC_ATTR_ROOT, + }; + int ret; + + ret = fsprop_name_to_attr_name(name, (char **)&ops.am_attrname); + if (ret < 0) + return ret; + + ret = attr_multi_by_handle(fph->hanp, fph->hlen, &ops, 1, 0); + if (ret < 0) + goto out_name; + + if (ops.am_error) { + errno = -ops.am_error; + ret = -1; + goto out_name; + } + + *valuelen = ops.am_length; +out_name: + free(ops.am_attrname); + return ret; +} + +/* Set the value of a specific fileystem property. */ +int +fsprops_set( + struct fsprops_handle *fph, + const char *name, + void *valuebuf, + size_t valuelen) +{ + struct xfs_attr_multiop ops = { + .am_opcode = ATTR_OP_SET, + .am_attrvalue = valuebuf, + .am_length = valuelen, + .am_flags = XFS_IOC_ATTR_ROOT, + }; + int ret; + + ret = fsprop_name_to_attr_name(name, (char **)&ops.am_attrname); + if (ret < 0) + return ret; + + ret = attr_multi_by_handle(fph->hanp, fph->hlen, &ops, 1, 0); + if (ret < 0) + goto out_name; + + if (ops.am_error) { + errno = -ops.am_error; + ret = -1; + goto out_name; + } + +out_name: + free(ops.am_attrname); + return ret; +} + +/* Unset the value of a specific fileystem property. */ +int +fsprops_remove( + struct fsprops_handle *fph, + const char *name) +{ + struct xfs_attr_multiop ops = { + .am_opcode = ATTR_OP_REMOVE, + .am_flags = XFS_IOC_ATTR_ROOT, + }; + int ret; + + ret = fsprop_name_to_attr_name(name, (char **)&ops.am_attrname); + if (ret < 0) + return ret; + + ret = attr_multi_by_handle(fph->hanp, fph->hlen, &ops, 1, 0); + if (ret < 0) + goto out_name; + + if (ops.am_error) { + errno = -ops.am_error; + ret = -1; + goto out_name; + } + +out_name: + free(ops.am_attrname); + return ret; +} diff --git a/libfrog/fsprops.h b/libfrog/fsprops.h new file mode 100644 index 000000000..9276f2425 --- /dev/null +++ b/libfrog/fsprops.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __LIBFROG_FSPROPS_H__ +#define __LIBFROG_FSPROPS_H__ + +/* Edit and view filesystem property sets. */ + +struct fsprops_handle { + void *hanp; + size_t hlen; +}; + +struct xfs_fd; +struct fs_path; + +int fsprops_open_handle(struct xfs_fd *xfd, struct fs_path *fspath, + struct fsprops_handle *fph); +void fsprops_free_handle(struct fsprops_handle *fph); + +typedef int (*fsprops_name_walk_fn)(struct fsprops_handle *fph, + const char *name, size_t valuelen, void *priv); + +int fsprops_walk_names(struct fsprops_handle *fph, fsprops_name_walk_fn walk_fn, + void *priv); +int fsprops_get(struct fsprops_handle *fph, const char *name, void *attrbuf, + size_t *attrlen); +int fsprops_set(struct fsprops_handle *fph, const char *name, void *attrbuf, + size_t attrlen); +int fsprops_remove(struct fsprops_handle *fph, const char *name); + +#endif /* __LIBFROG_FSPROPS_H__ */ From patchwork Tue Aug 6 18:19:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755237 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D88728DD1; Tue, 6 Aug 2024 18:19:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968391; cv=none; b=EdiuhSYCOo5UCXtw8ChI20IspgDnBcIgo5DWbJHdnHUBnWIqWSvIa0B2LuMKcHeRWQvmUOMD7TntobKwJ106oKN5JQZ4OCifTVkndtxCfsXuEctVOUR93zwz2j6uGFOYOFfSUL3uCKOyYjPRYAuNGx+sID34Pgn4DwQy9CDIXeQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968391; c=relaxed/simple; bh=S39ucGh+UzX0G9XVmmKU9OvKj98sTAn/2xzgMyVBL5U=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eBmDDuvhmBowq9Gp6oxFUwv3sYnJdO3rsYBfsEl6sBf3aYQWfp4JG/q22D3u7LAwzXfv5J08sYEJGLQX0dMU/LOq5jCSd9Q5Hn9cEJalI+G295pDyBmKJDinlrenQf8q1sJaQ9lpSsoazc3FwUDRJzWHda89Xr0SXJZ130IL+jQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L5+GYG7C; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L5+GYG7C" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 03CFAC32786; Tue, 6 Aug 2024 18:19:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968391; bh=S39ucGh+UzX0G9XVmmKU9OvKj98sTAn/2xzgMyVBL5U=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=L5+GYG7Cyh4cgioFIDvxBeY/+yAqV+K19sToO3sCrZzegQkAOKOesMb60WPfDNuVu GYUh8NquWrh3I74wp9cU75Tuq8nAEAHPpB5w/0GHHzMHRRa5wtWrhpRDYiK/cHe+Yi /RbEKX2FbKak6u25a/ejI/Lw/bUkvG2Djhcmu0kLjRoOmy4LmdVHkKt9uyB1xvBZ00 u4KinAjnynssTHH89bR9T3Hj9TKtZOsZyMu7pDC8MtiFF7P81o0EWDpwMv/7imv6tY VsWB1f5zxqt7z8eOli2QZxw8fA0yDQlDK5zVI/RspkEL17TvyceTRKzk3ovyTLemJd b9T4exWlikXlA== Date: Tue, 06 Aug 2024 11:19:50 -0700 Subject: [PATCH 2/7] xfs_io: edit filesystem properties From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825218.3193059.5122114124530927395.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add some new subcommands to xfs_io so that users can administer filesystem properties. Signed-off-by: Darrick J. Wong Acked-by: Dave Chinner Reviewed-by: Christoph Hellwig --- io/Makefile | 1 io/fsproperties.c | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++ io/init.c | 1 io/io.h | 1 man/man8/xfs_io.8 | 16 ++ 5 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 io/fsproperties.c diff --git a/io/Makefile b/io/Makefile index 3192b813c..0bdd05b57 100644 --- a/io/Makefile +++ b/io/Makefile @@ -20,6 +20,7 @@ CFILES = \ fiemap.c \ file.c \ freeze.c \ + fsproperties.c \ fsuuid.c \ fsync.c \ getrusage.c \ diff --git a/io/fsproperties.c b/io/fsproperties.c new file mode 100644 index 000000000..79837132e --- /dev/null +++ b/io/fsproperties.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#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 "io.h" +#include "libfrog/fsprops.h" +#include "libfrog/fsproperties.h" + +static void +listfsprops_help(void) +{ + printf(_( +"Print the names of the filesystem properties stored in this filesystem.\n" +"\n")); +} + +static int +fileio_to_fsprops_handle( + struct fileio *file, + struct fsprops_handle *fph) +{ + struct xfs_fd xfd = XFS_FD_INIT(file->fd); + struct fs_path *fs; + void *hanp = NULL; + size_t hlen; + int ret; + + /* + * Look up the mount point info for the open file, which confirms that + * we were passed a mount point. + */ + fs = fs_table_lookup(file->name, FS_MOUNT_POINT); + if (!fs) { + fprintf(stderr, _("%s: Not a XFS mount point.\n"), + file->name); + goto bad; + } + + /* + * Register the mountpoint in the fsfd cache so we can use handle + * functions later. + */ + ret = path_to_fshandle(fs->fs_dir, &hanp, &hlen); + if (ret) { + perror(fs->fs_dir); + goto bad; + } + + ret = -xfd_prepare_geometry(&xfd); + if (ret) { + perror(file->name); + goto free_handle; + } + + ret = fsprops_open_handle(&xfd, &file->fs_path, fph); + if (ret) { + if (errno == ESRMNT) + fprintf(stderr, _("%s: Not a XFS mount point.\n"), + file->name); + else + perror(file->name); + goto free_handle; + } + + free_handle(hanp, hlen); + return 0; +free_handle: + free_handle(hanp, hlen); +bad: + exitcode = 1; + return 1; +} + +static int +print_fsprop( + struct fsprops_handle *fph, + const char *name, + size_t unused, + void *priv) +{ + bool *print_values = priv; + char valuebuf[FSPROP_MAX_VALUELEN]; + size_t valuelen = FSPROP_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 = fileio_to_fsprops_handle(file, &fph); + if (ret) + return 1; + + 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_NOMAP_OK, + .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 = fileio_to_fsprops_handle(file, &fph); + if (ret) + return ret; + + for (c = optind; c < argc; c++) { + char valuebuf[FSPROP_MAX_VALUELEN]; + size_t valuelen = FSPROP_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_NOMAP_OK, + .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 = fileio_to_fsprops_handle(file, &fph); + if (ret) + return ret; + + 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_NOMAP_OK, + .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 = fileio_to_fsprops_handle(file, &fph); + if (ret) + return ret; + + 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_NOMAP_OK, + .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/io/init.c b/io/init.c index 37e0f093c..5727f7351 100644 --- a/io/init.c +++ b/io/init.c @@ -89,6 +89,7 @@ init_commands(void) utimes_init(); crc32cselftest_init(); exchangerange_init(); + fsprops_init(); } /* diff --git a/io/io.h b/io/io.h index fdb715ff0..8c5e59100 100644 --- a/io/io.h +++ b/io/io.h @@ -150,3 +150,4 @@ extern void repair_init(void); extern void crc32cselftest_init(void); extern void bulkstat_init(void); void exchangerange_init(void); +void fsprops_init(void); diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 657bdaec4..303c64478 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1578,7 +1578,21 @@ Print the sysfs or debugfs path for the mounted filesystem. The .B -d option selects debugfs instead of sysfs. - +.TP +.BI "getfsprops " name " [ " names "... ]" +Retrieve the values of the given filesystem properties. +.TP +.BI "listfsprops [ " \-v " ]" +List all filesystem properties that have been stored in the filesystem. +If the +.B \-v +flag is specified, prints the values of the properties. +.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. .SH OTHER COMMANDS .TP From patchwork Tue Aug 6 18:20:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755238 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D6AE928DD1; Tue, 6 Aug 2024 18:20:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968406; cv=none; b=qxhVqNw1i0jL+zXwbnaJDO774oGAZ0zHIZAUENxhWS0v07IHWMCgxIwZ5tcKNYRviV9CEarqYB+in1pb0zceXN5TjN/36J4Nkd7y/K3fpfL5zy+mKV26iDc5S1hVpSSZTp2drOPkgb5EciUnxKY8XpnwxKbvyg9OPMUZwh6Aex0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968406; c=relaxed/simple; bh=1EdpIWZob+RI+oMU4q2FcBu1flC8rhpOeyVRYGTZHQc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ig3J/yErEkT++lxsLZsbJifOcATQYZuRFnc/+M4FDfKFRvCt8RC1qoiny+AnASetM4XYx1Y7BmFliWDRAHQY8iZfBkcmnJg+WV8WxczMOonPczapGq9HCZcBpEXQgTXvdoJmgKrENYaVjSaBbn/VZfFj/AoyRUxXtiYdChiu780= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PoC1txa0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PoC1txa0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD75BC32786; Tue, 6 Aug 2024 18:20:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968406; bh=1EdpIWZob+RI+oMU4q2FcBu1flC8rhpOeyVRYGTZHQc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=PoC1txa0EGuqeNVj2YLTA4Lr06yCjxS45r1a1E7tqvx/5BSDud/rOORDAeh0TSO35 6CWRaT+GPROeBnVpgi8BUzJbtc3P4uVdlJhsW8HoeS5QhcRo78aRS3TjcO7oBXwF5q 87HO6NC/lXrPEvVTw0hgSKGqkJ7RglyYAJLPnIiKCDjAdLHygkw2hEbHoZtXus3Q5C 4t3vIig7ItxsMR9hrEs0B660npDtZx59EWsiuh4rDDOZk7MQXPHxwzWn8+PJPjto4I NBY100L1Cq9AYpGMkhLRoU5CU2vE0vtFLCFlV4EhYW/T5xMIFQ5SKv4wfHKthiKJ9n 0YnTzP+Z93TWA== Date: Tue, 06 Aug 2024 11:20:06 -0700 Subject: [PATCH 3/7] xfs_db: improve getting and setting extended attributes From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , Christoph Hellwig , Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825234.3193059.7895487674250550849.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add an attr_get command to retrieve the value of an xattr from a file; and extend the attr_set command to allow passing of string values. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Acked-by: Dave Chinner --- db/attrset.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++- man/man8/xfs_db.8 | 40 ++++++++ 2 files changed, 293 insertions(+), 9 deletions(-) diff --git a/db/attrset.c b/db/attrset.c index 81d530055..9e53e63c9 100644 --- a/db/attrset.c +++ b/db/attrset.c @@ -17,20 +17,43 @@ #include "inode.h" #include "malloc.h" #include +#include "libfrog/fsproperties.h" +static int attr_get_f(int argc, char **argv); static int attr_set_f(int argc, char **argv); static int attr_remove_f(int argc, char **argv); +static void attrget_help(void); static void attrset_help(void); +static const cmdinfo_t attr_get_cmd = + { "attr_get", "aget", attr_get_f, 1, -1, 0, + N_("[-r|-s|-u|-p|-Z] name"), + N_("get the named attribute on the current inode"), attrget_help }; static const cmdinfo_t attr_set_cmd = { "attr_set", "aset", attr_set_f, 1, -1, 0, - N_("[-r|-s|-u|-p] [-n] [-R|-C] [-v n] name"), + N_("[-r|-s|-u|-p|-Z] [-n] [-R|-C] [-v n] name"), N_("set the named attribute on the current inode"), attrset_help }; static const cmdinfo_t attr_remove_cmd = { "attr_remove", "aremove", attr_remove_f, 1, -1, 0, - N_("[-r|-s|-u|-p] [-n] name"), + N_("[-r|-s|-u|-p|-Z] [-n] name"), N_("remove the named attribute from the current inode"), attrset_help }; +static void +attrget_help(void) +{ + dbprintf(_( +"\n" +" The attr_get command provide interfaces for retrieving the values of extended\n" +" attributes of a file. This command requires attribute names to be specified.\n" +" There are 4 namespace flags:\n" +" -r -- 'root'\n" +" -u -- 'user' (default)\n" +" -s -- 'secure'\n" +" -p -- 'parent'\n" +" -Z -- fs property\n" +"\n")); +} + static void attrset_help(void) { @@ -45,10 +68,15 @@ attrset_help(void) " -u -- 'user' (default)\n" " -s -- 'secure'\n" " -p -- 'parent'\n" +" -Z -- fs property\n" "\n" " For attr_set, these options further define the type of set operation:\n" " -C -- 'create' - create attribute, fail if it already exists\n" " -R -- 'replace' - replace attribute, fail if it does not exist\n" +"\n" +" If the attribute value is a string, it can be specified after the\n" +" attribute name.\n" +"\n" " The backward compatibility mode 'noattr2' can be emulated (-n) also.\n" "\n")); } @@ -59,6 +87,7 @@ attrset_init(void) if (!expert_mode) return; + add_command(&attr_get_cmd); add_command(&attr_set_cmd); add_command(&attr_remove_cmd); } @@ -106,6 +135,58 @@ get_buf_from_file( LIBXFS_ATTR_ROOT | \ LIBXFS_ATTR_PARENT) +static bool +adjust_fsprop_attr_name( + struct xfs_da_args *args, + bool *free_name) +{ + const char *o = (const char *)args->name; + char *p; + int ret; + + if ((args->attr_filter & LIBXFS_ATTR_NS) != LIBXFS_ATTR_ROOT) { + dbprintf(_("fs properties must be ATTR_ROOT\n")); + return false; + } + + ret = fsprop_name_to_attr_name(o, &p); + if (ret < 0) { + dbprintf(_("could not allocate fs property name string\n")); + return false; + } + args->namelen = ret; + args->name = (const uint8_t *)p; + + if (*free_name) + free((void *)o); + *free_name = true; + + if (args->namelen > MAXNAMELEN) { + dbprintf(_("%s: name too long\n"), args->name); + return false; + } + + if (args->valuelen > ATTR_MAX_VALUELEN) { + dbprintf(_("%s: value too long\n"), args->name); + return false; + } + + return true; +} + +static void +print_fsprop( + struct xfs_da_args *args) +{ + const char *p = + attr_name_to_fsprop_name((const char *)args->name); + + if (p) + printf("%s=%.*s\n", p, args->valuelen, (char *)args->value); + else + fprintf(stderr, _("%s: not a fs property?\n"), args->name); +} + static int attr_set_f( int argc, @@ -119,7 +200,9 @@ attr_set_f( char *sp; char *name_from_file = NULL; char *value_from_file = NULL; + bool free_name = false; enum xfs_attr_update op = XFS_ATTRUPDATE_UPSERT; + bool fsprop = false; int c; int error; @@ -132,9 +215,12 @@ attr_set_f( return 0; } - while ((c = getopt(argc, argv, "ruspCRnN:v:V:")) != EOF) { + while ((c = getopt(argc, argv, "ruspCRnN:v:V:Z")) != EOF) { switch (c) { /* namespaces */ + case 'Z': + fsprop = true; + fallthrough; case 'r': args.attr_filter &= ~LIBXFS_ATTR_NS; args.attr_filter |= LIBXFS_ATTR_ROOT; @@ -213,9 +299,10 @@ attr_set_f( if (!args.name) return 0; + free_name = true; args.namelen = namelen; } else { - if (optind != argc - 1) { + if (optind != argc - 1 && optind != argc - 2) { dbprintf(_("too few options for attr_set (no name given)\n")); return 0; } @@ -250,6 +337,25 @@ attr_set_f( goto out; } memset(args.value, 'v', args.valuelen); + } else if (optind == argc - 2) { + args.valuelen = strlen(argv[optind + 1]); + args.value = strdup(argv[optind + 1]); + if (!args.value) { + dbprintf(_("cannot allocate buffer (%d)\n"), + args.valuelen); + goto out; + } + } + + if (fsprop) { + if (!fsprop_validate((const char *)args.name, args.value)) { + dbprintf(_("%s: invalid value \"%s\"\n"), + args.name, args.value); + goto out; + } + + if (!adjust_fsprop_attr_name(&args, &free_name)) + goto out; } if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &args.dp)) { @@ -269,6 +375,9 @@ attr_set_f( goto out; } + if (fsprop) + print_fsprop(&args); + /* refresh with updated inode contents */ set_cur_inode(iocur_top->ino); @@ -277,7 +386,7 @@ attr_set_f( libxfs_irele(args.dp); if (args.value) free(args.value); - if (name_from_file) + if (free_name) free((void *)args.name); return 0; } @@ -293,6 +402,8 @@ attr_remove_f( .op_flags = XFS_DA_OP_OKNOENT, }; char *name_from_file = NULL; + bool free_name = false; + bool fsprop = false; int c; int error; @@ -305,9 +416,12 @@ attr_remove_f( return 0; } - while ((c = getopt(argc, argv, "ruspnN:")) != EOF) { + while ((c = getopt(argc, argv, "ruspnN:Z")) != EOF) { switch (c) { /* namespaces */ + case 'Z': + fsprop = true; + fallthrough; case 'r': args.attr_filter &= ~LIBXFS_ATTR_NS; args.attr_filter |= LIBXFS_ATTR_ROOT; @@ -354,6 +468,7 @@ attr_remove_f( if (!args.name) return 0; + free_name = true; args.namelen = namelen; } else { if (optind != argc - 1) { @@ -374,6 +489,9 @@ attr_remove_f( } } + if (fsprop && !adjust_fsprop_attr_name(&args, &free_name)) + goto out; + if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &args.dp)) { dbprintf(_("failed to iget inode %llu\n"), (unsigned long long)iocur_top->ino); @@ -398,7 +516,137 @@ attr_remove_f( out: if (args.dp) libxfs_irele(args.dp); - if (name_from_file) + if (free_name) + free((void *)args.name); + return 0; +} + +static int +attr_get_f( + int argc, + char **argv) +{ + struct xfs_da_args args = { + .geo = mp->m_attr_geo, + .whichfork = XFS_ATTR_FORK, + .op_flags = XFS_DA_OP_OKNOENT, + }; + char *name_from_file = NULL; + bool free_name = false; + bool fsprop = false; + int c; + int error; + + if (cur_typ == NULL) { + dbprintf(_("no current type\n")); + return 0; + } + if (cur_typ->typnm != TYP_INODE) { + dbprintf(_("current type is not inode\n")); + return 0; + } + + while ((c = getopt(argc, argv, "ruspN:Z")) != EOF) { + switch (c) { + /* namespaces */ + case 'Z': + fsprop = true; + fallthrough; + case 'r': + args.attr_filter &= ~LIBXFS_ATTR_NS; + args.attr_filter |= LIBXFS_ATTR_ROOT; + break; + case 'u': + args.attr_filter &= ~LIBXFS_ATTR_NS; + break; + case 's': + args.attr_filter &= ~LIBXFS_ATTR_NS; + args.attr_filter |= LIBXFS_ATTR_SECURE; + break; + case 'p': + args.attr_filter &= ~LIBXFS_ATTR_NS; + args.attr_filter |= XFS_ATTR_PARENT; + break; + + case 'N': + name_from_file = optarg; + break; + default: + dbprintf(_("bad option for attr_get command\n")); + return 0; + } + } + + if (name_from_file) { + int namelen; + + if (optind != argc) { + dbprintf(_("too many options for attr_get (no name needed)\n")); + return 0; + } + + args.name = get_buf_from_file(name_from_file, MAXNAMELEN, + &namelen); + if (!args.name) + return 0; + + free_name = true; + args.namelen = namelen; + } else { + if (optind != argc - 1) { + dbprintf(_("too few options for attr_get (no name given)\n")); + return 0; + } + + args.name = (const unsigned char *)argv[optind]; + if (!args.name) { + dbprintf(_("invalid name\n")); + return 0; + } + + args.namelen = strlen(argv[optind]); + if (args.namelen >= MAXNAMELEN) { + dbprintf(_("name too long\n")); + goto out; + } + } + + if (libxfs_iget(mp, NULL, iocur_top->ino, 0, &args.dp)) { + dbprintf(_("failed to iget inode %llu\n"), + (unsigned long long)iocur_top->ino); + goto out; + } + + if (fsprop && !adjust_fsprop_attr_name(&args, &free_name)) + goto out; + + args.owner = iocur_top->ino; + libxfs_attr_sethash(&args); + + /* + * Look up attr value with a maximally long length and a null buffer + * to return the value and the correct length. + */ + args.valuelen = XATTR_SIZE_MAX; + error = -libxfs_attr_get(&args); + if (error) { + dbprintf(_("failed to get attr %s on inode %llu: %s\n"), + args.name, (unsigned long long)iocur_top->ino, + strerror(error)); + goto out; + } + + if (fsprop) + print_fsprop(&args); + else + printf("%.*s\n", args.valuelen, (char *)args.value); + +out: + if (args.dp) + libxfs_irele(args.dp); + if (args.value) + free(args.value); + if (free_name) free((void *)args.name); return 0; } diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 9f6fea574..f0865b2df 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -184,7 +184,35 @@ Displays the length, free block count, per-AG reservation size, and per-AG reservation usage for a given AG. If no argument is given, display information for all AGs. .TP -.BI "attr_remove [\-p|\-r|\-u|\-s] [\-n] [\-N " namefile "|" name "] " +.BI "attr_get [\-p|\-r|\-u|\-s|\-Z] [\-N " namefile "|" name "] " +Print the value of the specified extended attribute from the current file. +.RS 1.0i +.TP 0.4i +.B \-p +Sets the attribute in the parent namespace. +Only one namespace option can be specified. +.TP +.B \-r +Sets the attribute in the root namespace. +Only one namespace option can be specified. +.TP +.B \-u +Sets the attribute in the user namespace. +Only one namespace option can be specified. +.TP +.B \-s +Sets the attribute in the secure namespace. +Only one namespace option can be specified. +.TP +.B \-Z +Sets a filesystem property in the root namespace. +Only one namespace option can be specified. +.TP +.B \-N +Read the name from this file. +.RE +.TP +.BI "attr_remove [\-p|\-r|\-u|\-s|\-Z] [\-n] [\-N " namefile "|" name "] " Remove the specified extended attribute from the current file. .RS 1.0i .TP 0.4i @@ -204,6 +232,10 @@ Only one namespace option can be specified. Sets the attribute in the secure namespace. Only one namespace option can be specified. .TP +.B \-Z +Sets a filesystem property in the root namespace. +Only one namespace option can be specified. +.TP .B \-N Read the name from this file. .TP @@ -211,7 +243,7 @@ Read the name from this file. Do not enable 'noattr2' mode on V4 filesystems. .RE .TP -.BI "attr_set [\-p\-r|\-u|\-s] [\-n] [\-R|\-C] [\-v " valuelen "|\-V " valuefile "] [\-N " namefile "|" name "] " +.BI "attr_set [\-p\-r|\-u|\-s|\-Z] [\-n] [\-R|\-C] [\-v " valuelen "|\-V " valuefile "] [\-N " namefile "|" name "] [" value "]" Sets an extended attribute on the current file with the given name. .RS 1.0i .TP 0.4i @@ -231,6 +263,10 @@ Only one namespace option can be specified. Sets the attribute in the secure namespace. Only one namespace option can be specified. .TP +.B \-Z +Sets a filesystem property in the root namespace. +Only one namespace option can be specified. +.TP .B \-N Read the name from this file. .TP From patchwork Tue Aug 6 18:20:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755239 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB1633C485; Tue, 6 Aug 2024 18:20:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968422; cv=none; b=N4N1MwTVYUyqjm3lk0OeKZs5LZpDYiQgZE+sJgu6P3wj3X7vHiKJdsWz1KjMU8xptN/nmTTshSvB9qbNImYsWMmOZ8E/NSW5P/TSWK+MCWkyaOKnn+N/nPuVxnz7NX2Qk9n3zb4FPC97TXobWrIezs3HSXPBGAob+cdy3x7gazI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968422; c=relaxed/simple; bh=mE+EIDBUYsfgcYfsD1baFR1mHMySHYjIAjXzSx1LeM0=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=At1CsVr4LnW3GOxMq09TRgsUfLz7NusPKggIgdGvoAxFUQvJeHC41GGkuWn08t11MKKiA8eaSWA88+4zA3ttnUxxPHe9vLd3ukcoaijnEu3XD7i0OMHvZpEXtbGRMKnCJLAdNN80bn/F1hNbSKO5agPEEDEmz8MJH9EYmHsQjas= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZOp7vQZi; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZOp7vQZi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 57C29C32786; Tue, 6 Aug 2024 18:20:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968422; bh=mE+EIDBUYsfgcYfsD1baFR1mHMySHYjIAjXzSx1LeM0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZOp7vQZiRl0jN1xZNiijHSgCqVfQdzmhFV2El1O2bXVVKOFmXY3+YpIqg5EB65NyJ tTPD0D/Sa+HlxlAA+CPaeoCepqVczP7GfbjPKJDjc3BPNrxPWu3umlROdD81WPsHVq 163QecoMb+TsCSAtFLVL9aCPhwS2D1VASjHi+zWqU4SHjaHqwRoZpEHvWPTij85Hbp UBhtN+VEcvFUf4H6/iH3S55l9ACXzpQbq3bnljfatnJFPDR5WRmR6elbeMYYYmkYSU If4Dwoo/FDNBNvqTKAFo1f1o6yicopSg7JtFvqdvEE7RQq5vcUQsaeI5URiDk5+Dci oCb7cjaaMV2lA== Date: Tue, 06 Aug 2024 11:20:21 -0700 Subject: [PATCH 4/7] libxfs: hoist listxattr from xfs_repair From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825249.3193059.10081892807300202489.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Hoist the listxattr code from xfs_repair so that we can use it in xfs_db. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Acked-by: Dave Chinner --- libxfs/Makefile | 2 ++ libxfs/listxattr.c | 2 +- libxfs/listxattr.h | 6 +++--- repair/Makefile | 2 -- repair/pptr.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename repair/listxattr.c => libxfs/listxattr.c (99%) rename repair/listxattr.h => libxfs/listxattr.h (81%) diff --git a/libxfs/Makefile b/libxfs/Makefile index 4e8f9a135..2f2791cae 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -23,6 +23,7 @@ HFILES = \ defer_item.h \ libxfs_io.h \ libxfs_api_defs.h \ + listxattr.h \ init.h \ libxfs_priv.h \ linux-err.h \ @@ -69,6 +70,7 @@ CFILES = buf_mem.c \ defer_item.c \ init.c \ kmem.c \ + listxattr.c \ logitem.c \ rdwr.c \ topology.c \ diff --git a/repair/listxattr.c b/libxfs/listxattr.c similarity index 99% rename from repair/listxattr.c rename to libxfs/listxattr.c index 2af77b7b2..bedaca678 100644 --- a/repair/listxattr.c +++ b/libxfs/listxattr.c @@ -6,7 +6,7 @@ #include "libxfs.h" #include "libxlog.h" #include "libfrog/bitmap.h" -#include "repair/listxattr.h" +#include "listxattr.h" /* Call a function for every entry in a shortform xattr structure. */ STATIC int diff --git a/repair/listxattr.h b/libxfs/listxattr.h similarity index 81% rename from repair/listxattr.h rename to libxfs/listxattr.h index 2d26fce0f..cddd96af7 100644 --- a/repair/listxattr.h +++ b/libxfs/listxattr.h @@ -3,8 +3,8 @@ * Copyright (c) 2022-2024 Oracle. All Rights Reserved. * Author: Darrick J. Wong */ -#ifndef __REPAIR_LISTXATTR_H__ -#define __REPAIR_LISTXATTR_H__ +#ifndef __LIBXFS_LISTXATTR_H__ +#define __LIBXFS_LISTXATTR_H__ typedef int (*xattr_walk_fn)(struct xfs_inode *ip, unsigned int attr_flags, const unsigned char *name, unsigned int namelen, @@ -12,4 +12,4 @@ typedef int (*xattr_walk_fn)(struct xfs_inode *ip, unsigned int attr_flags, int xattr_walk(struct xfs_inode *ip, xattr_walk_fn attr_fn, void *priv); -#endif /* __REPAIR_LISTXATTR_H__ */ +#endif /* __LIBXFS_LISTXATTR_H__ */ diff --git a/repair/Makefile b/repair/Makefile index e7445d53e..a36a95e35 100644 --- a/repair/Makefile +++ b/repair/Makefile @@ -24,7 +24,6 @@ HFILES = \ err_protos.h \ globals.h \ incore.h \ - listxattr.h \ pptr.h \ prefetch.h \ progress.h \ @@ -59,7 +58,6 @@ CFILES = \ incore_ext.c \ incore_ino.c \ init.c \ - listxattr.c \ phase1.c \ phase2.c \ phase3.c \ diff --git a/repair/pptr.c b/repair/pptr.c index 8ec6a51d2..cc66e6372 100644 --- a/repair/pptr.c +++ b/repair/pptr.c @@ -11,7 +11,7 @@ #include "repair/globals.h" #include "repair/err_protos.h" #include "repair/slab.h" -#include "repair/listxattr.h" +#include "libxfs/listxattr.h" #include "repair/threads.h" #include "repair/incore.h" #include "repair/pptr.h" From patchwork Tue Aug 6 18:20:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755240 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 893C028DD1; Tue, 6 Aug 2024 18:20:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968438; cv=none; b=Q4wCU+sa0cFMh+WC+ERoM30RZPndKsswYQe4+1nH4EeFMNBu5+AJ0IZ4wN/1dlUzqjXk/W5tjFLZ56Cuhe0jUqJsJNpsQju2CUWZV0bRo5+dFjttpcLqOFHyVA3zaI0qsxY5p5VQvC+9x8PJ2vFPFnEdD7O7+yCWauUA+eWmoeQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968438; c=relaxed/simple; bh=WUm1KetTOQiyYMGKhBFj9/wHX+lbMFLrEIzwNIZiGkw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gEiUjCbNO31wk1G1QOSYv2XqZYZW4MWrzJFycbQ3qnChFvMEqRmpcEtxGLTMK0CgA/GUJGO2OLvxbNXx4CBT5hVTwRQuhqExmGaiEh5C/B2OQ4pjqHdNWuG8Ck9jWH/3UL2/4JT3PdcQg48tvmDmFDBQtWqCficrThBflyKdauI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XLfXt3cI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XLfXt3cI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 03C24C32786; Tue, 6 Aug 2024 18:20:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968438; bh=WUm1KetTOQiyYMGKhBFj9/wHX+lbMFLrEIzwNIZiGkw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=XLfXt3cIcwdbAvr2lT+4wgE4jUKuC5NFQgcU6ukCzFGdbVTV+S5hFm4aGdNfDgDCK My3+ervtBaGdUbQ4rUwoRKBzuLHjGKZgD1KitAlRmJF5TPJT7krFldl5WhCt4kkD3Q WLxoJ2T4MEfV7rB1qRCZbie40yNrqTLSnXtt2VZwzQwZjsKTC8mxirpkfAROpvfobY 5EE5y7LH8DyA+G7h1MXV97uA3vMGUGbN5EB8SJsH6yGwQyzAcQYrkhM0VHhq8AMuZr CuLPpKe5LgSiaYpiO42LRBngSXGd9A1Rm+yJc/BcfnjqOi0D93JLzyTajdWyUa4drb P52eDPhNV9VWw== Date: Tue, 06 Aug 2024 11:20:37 -0700 Subject: [PATCH 5/7] libxfs: pass a transaction context through listxattr From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825264.3193059.5289497905719296434.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Pass a transaction context so that a new caller can walk the attr names and query the values all in one go without deadlocking on nested buffer access. While we're at it, make the existing xfs_repair callers try to use empty transactions so that we don't deadlock on cycles in the xattr structure. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Acked-by: Dave Chinner --- libxfs/listxattr.c | 40 +++++++++++++++++++++++----------------- libxfs/listxattr.h | 6 ++++-- repair/pptr.c | 7 ++++++- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/libxfs/listxattr.c b/libxfs/listxattr.c index bedaca678..34205682f 100644 --- a/libxfs/listxattr.c +++ b/libxfs/listxattr.c @@ -11,6 +11,7 @@ /* Call a function for every entry in a shortform xattr structure. */ STATIC int xattr_walk_sf( + struct xfs_trans *tp, struct xfs_inode *ip, xattr_walk_fn attr_fn, void *priv) @@ -22,7 +23,7 @@ xattr_walk_sf( sfe = libxfs_attr_sf_firstentry(hdr); for (i = 0; i < hdr->count; i++) { - error = attr_fn(ip, sfe->flags, sfe->nameval, sfe->namelen, + error = attr_fn(tp, ip, sfe->flags, sfe->nameval, sfe->namelen, &sfe->nameval[sfe->namelen], sfe->valuelen, priv); if (error) @@ -37,6 +38,7 @@ xattr_walk_sf( /* Call a function for every entry in this xattr leaf block. */ STATIC int xattr_walk_leaf_entries( + struct xfs_trans *tp, struct xfs_inode *ip, xattr_walk_fn attr_fn, struct xfs_buf *bp, @@ -75,7 +77,7 @@ xattr_walk_leaf_entries( valuelen = be32_to_cpu(name_rmt->valuelen); } - error = attr_fn(ip, entry->flags, name, namelen, value, + error = attr_fn(tp, ip, entry->flags, name, namelen, value, valuelen, priv); if (error) return error; @@ -91,6 +93,7 @@ xattr_walk_leaf_entries( */ STATIC int xattr_walk_leaf( + struct xfs_trans *tp, struct xfs_inode *ip, xattr_walk_fn attr_fn, void *priv) @@ -98,18 +101,19 @@ xattr_walk_leaf( struct xfs_buf *leaf_bp; int error; - error = -libxfs_attr3_leaf_read(NULL, ip, ip->i_ino, 0, &leaf_bp); + error = -libxfs_attr3_leaf_read(tp, ip, ip->i_ino, 0, &leaf_bp); if (error) return error; - error = xattr_walk_leaf_entries(ip, attr_fn, leaf_bp, priv); - libxfs_trans_brelse(NULL, leaf_bp); + error = xattr_walk_leaf_entries(tp, ip, attr_fn, leaf_bp, priv); + libxfs_trans_brelse(tp, leaf_bp); return error; } /* Find the leftmost leaf in the xattr dabtree. */ STATIC int xattr_walk_find_leftmost_leaf( + struct xfs_trans *tp, struct xfs_inode *ip, struct bitmap *seen_blocks, struct xfs_buf **leaf_bpp) @@ -127,7 +131,7 @@ xattr_walk_find_leftmost_leaf( for (;;) { uint16_t magic; - error = -libxfs_da3_node_read(NULL, ip, blkno, &bp, + error = -libxfs_da3_node_read(tp, ip, blkno, &bp, XFS_ATTR_FORK); if (error) return error; @@ -164,7 +168,7 @@ xattr_walk_find_leftmost_leaf( /* Find the next level towards the leaves of the dabtree. */ btree = nodehdr.btree; blkno = be32_to_cpu(btree->before); - libxfs_trans_brelse(NULL, bp); + libxfs_trans_brelse(tp, bp); /* Make sure we haven't seen this new block already. */ if (bitmap_test(seen_blocks, blkno, 1)) @@ -184,13 +188,14 @@ xattr_walk_find_leftmost_leaf( return 0; out_buf: - libxfs_trans_brelse(NULL, bp); + libxfs_trans_brelse(tp, bp); return error; } /* Call a function for every entry in a node-format xattr structure. */ STATIC int xattr_walk_node( + struct xfs_trans *tp, struct xfs_inode *ip, xattr_walk_fn attr_fn, void *priv) @@ -204,12 +209,12 @@ xattr_walk_node( bitmap_alloc(&seen_blocks); - error = xattr_walk_find_leftmost_leaf(ip, seen_blocks, &leaf_bp); + error = xattr_walk_find_leftmost_leaf(tp, ip, seen_blocks, &leaf_bp); if (error) goto out_bitmap; for (;;) { - error = xattr_walk_leaf_entries(ip, attr_fn, leaf_bp, + error = xattr_walk_leaf_entries(tp, ip, attr_fn, leaf_bp, priv); if (error) goto out_leaf; @@ -220,13 +225,13 @@ xattr_walk_node( if (leafhdr.forw == 0) goto out_leaf; - libxfs_trans_brelse(NULL, leaf_bp); + libxfs_trans_brelse(tp, leaf_bp); /* Make sure we haven't seen this new leaf already. */ if (bitmap_test(seen_blocks, leafhdr.forw, 1)) goto out_bitmap; - error = -libxfs_attr3_leaf_read(NULL, ip, ip->i_ino, + error = -libxfs_attr3_leaf_read(tp, ip, ip->i_ino, leafhdr.forw, &leaf_bp); if (error) goto out_bitmap; @@ -238,7 +243,7 @@ xattr_walk_node( } out_leaf: - libxfs_trans_brelse(NULL, leaf_bp); + libxfs_trans_brelse(tp, leaf_bp); out_bitmap: bitmap_free(&seen_blocks); return error; @@ -247,6 +252,7 @@ xattr_walk_node( /* Call a function for every extended attribute in a file. */ int xattr_walk( + struct xfs_trans *tp, struct xfs_inode *ip, xattr_walk_fn attr_fn, void *priv) @@ -257,15 +263,15 @@ xattr_walk( return 0; if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL) - return xattr_walk_sf(ip, attr_fn, priv); + return xattr_walk_sf(tp, ip, attr_fn, priv); /* attr functions require that the attr fork is loaded */ - error = -libxfs_iread_extents(NULL, ip, XFS_ATTR_FORK); + error = -libxfs_iread_extents(tp, ip, XFS_ATTR_FORK); if (error) return error; if (libxfs_attr_is_leaf(ip)) - return xattr_walk_leaf(ip, attr_fn, priv); + return xattr_walk_leaf(tp, ip, attr_fn, priv); - return xattr_walk_node(ip, attr_fn, priv); + return xattr_walk_node(tp, ip, attr_fn, priv); } diff --git a/libxfs/listxattr.h b/libxfs/listxattr.h index cddd96af7..933e0f529 100644 --- a/libxfs/listxattr.h +++ b/libxfs/listxattr.h @@ -6,10 +6,12 @@ #ifndef __LIBXFS_LISTXATTR_H__ #define __LIBXFS_LISTXATTR_H__ -typedef int (*xattr_walk_fn)(struct xfs_inode *ip, unsigned int attr_flags, +typedef int (*xattr_walk_fn)(struct xfs_trans *tp, struct xfs_inode *ip, + unsigned int attr_flags, const unsigned char *name, unsigned int namelen, const void *value, unsigned int valuelen, void *priv); -int xattr_walk(struct xfs_inode *ip, xattr_walk_fn attr_fn, void *priv); +int xattr_walk(struct xfs_trans *tp, struct xfs_inode *ip, + xattr_walk_fn attr_fn, void *priv); #endif /* __LIBXFS_LISTXATTR_H__ */ diff --git a/repair/pptr.c b/repair/pptr.c index cc66e6372..ee29e47a8 100644 --- a/repair/pptr.c +++ b/repair/pptr.c @@ -593,6 +593,7 @@ store_file_pptr_name( /* Decide if this is a directory parent pointer and stash it if so. */ static int examine_xattr( + struct xfs_trans *tp, struct xfs_inode *ip, unsigned int attr_flags, const unsigned char *name, @@ -1205,6 +1206,7 @@ check_file_parent_ptrs( struct xfs_inode *ip, struct file_scan *fscan) { + struct xfs_trans *tp = NULL; int error; error = -init_slab(&fscan->file_pptr_recs, sizeof(struct file_pptr)); @@ -1215,7 +1217,10 @@ check_file_parent_ptrs( fscan->have_garbage = false; fscan->nr_file_pptrs = 0; - error = xattr_walk(ip, examine_xattr, fscan); + libxfs_trans_alloc_empty(ip->i_mount, &tp); + error = xattr_walk(tp, ip, examine_xattr, fscan); + if (tp) + libxfs_trans_cancel(tp); if (error && !no_modify) do_error(_("ino %llu parent pointer scan failed: %s\n"), (unsigned long long)ip->i_ino, From patchwork Tue Aug 6 18:20:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755241 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 275E828DD1; Tue, 6 Aug 2024 18:20:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968454; cv=none; b=PbeT1kZzFp+cWqGzoaRjf8VY8BchFXXsf0k96i518z/BApNpGbzh4aqT4JyztJV07CwrAjCKs6edKNGs/swDZUIG+eL+Z1LhX9EFzcN80EhoFXHABSVw0KkT3ROvk55WMAjCBSNb1JolgdmvHMGBWS2mVOYLeweq3yHfa+jfN44= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968454; c=relaxed/simple; bh=Hm7VWsZapkvuEjCdExNxDaefTI5ppztdrFz4zOwc+tw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YGAD0GGe+94ywEod608mkKn/viVG5JiAQDIIvIMEslRKI1cDcrOp0ewPNVLTZz+CwBN4MHCKmNAhybUg5a/F/ymYg+2ecFIFaIQt2xcCXISHnv7g7BpEdzWRPmnQ9lpuXm7W6iqoTZr0ArodbRg5intVBj3BYdBJI78jBCEKsNc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BJ+4x0DY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BJ+4x0DY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9B13EC32786; Tue, 6 Aug 2024 18:20:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968453; bh=Hm7VWsZapkvuEjCdExNxDaefTI5ppztdrFz4zOwc+tw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=BJ+4x0DYgmLamICRXjMWMzIrDFqp3hXgQXsAx4+A/GYAkjYp0I8EaYnZ7nDogMAUn Xv53Q/yDSPZ3oC4+Ecgcv8RphjI+CLpHml4od4xU1Fhd4FDtq9nkaWoliB+p6xElJz Cjduwez072OjNmoDUQs54Hz7o2KNOTvmCaG9aZ9LTW9GIqH/y1JS56EePqA6MwIaQR UO8laUp2/ENiCvdxu6ZW0zh9vjkjMPJ+59RDT9VpxYrEmmwSEAtTmknfbqjA3Mq/hp ISA9yr0usXzdo/lyUFqeFBEySA/m1FVQoHhkaoXQLQeyOgBTAc8y4DDrG2UBlSLYog vIfgPwVqjO5OQ== Date: Tue, 06 Aug 2024 11:20:53 -0700 Subject: [PATCH 6/7] xfs_db: add a command to list xattrs From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825279.3193059.16274209837031348230.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add a command to list extended attributes from xfs_db. We'll need this later to manage the fs properties when unmounted. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Acked-by: Dave Chinner --- db/attrset.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 28 +++++++ 2 files changed, 229 insertions(+) diff --git a/db/attrset.c b/db/attrset.c index 9e53e63c9..e3ffb75aa 100644 --- a/db/attrset.c +++ b/db/attrset.c @@ -18,13 +18,21 @@ #include "malloc.h" #include #include "libfrog/fsproperties.h" +#include "libxfs/listxattr.h" +static int attr_list_f(int argc, char **argv); static int attr_get_f(int argc, char **argv); static int attr_set_f(int argc, char **argv); static int attr_remove_f(int argc, char **argv); + +static void attrlist_help(void); static void attrget_help(void); static void attrset_help(void); +static const cmdinfo_t attr_list_cmd = + { "attr_list", "alist", attr_list_f, 0, -1, 0, + N_("[-r|-s|-u|-p|-Z] [-v]"), + N_("list attributes on the current inode"), attrlist_help }; static const cmdinfo_t attr_get_cmd = { "attr_get", "aget", attr_get_f, 1, -1, 0, N_("[-r|-s|-u|-p|-Z] name"), @@ -38,6 +46,24 @@ static const cmdinfo_t attr_remove_cmd = N_("[-r|-s|-u|-p|-Z] [-n] name"), N_("remove the named attribute from the current inode"), attrset_help }; +static void +attrlist_help(void) +{ + dbprintf(_( +"\n" +" The attr_list command provide interfaces for listing all extended attributes\n" +" attached to an inode.\n" +" There are 4 namespace flags:\n" +" -r -- 'root'\n" +" -u -- 'user' (default)\n" +" -s -- 'secure'\n" +" -p -- 'parent'\n" +" -Z -- fs property\n" +"\n" +" -v -- print the value of the attributes\n" +"\n")); +} + static void attrget_help(void) { @@ -87,6 +113,7 @@ attrset_init(void) if (!expert_mode) return; + add_command(&attr_list_cmd); add_command(&attr_get_cmd); add_command(&attr_set_cmd); add_command(&attr_remove_cmd); @@ -650,3 +677,177 @@ attr_get_f( free((void *)args.name); return 0; } + +struct attrlist_ctx { + unsigned int attr_filter; + bool print_values; + bool fsprop; +}; + +static int +attrlist_print( + struct xfs_trans *tp, + struct xfs_inode *ip, + unsigned int attr_flags, + const unsigned char *name, + unsigned int namelen, + const void *value, + unsigned int valuelen, + void *priv) +{ + struct attrlist_ctx *ctx = priv; + struct xfs_da_args args = { + .geo = mp->m_attr_geo, + .whichfork = XFS_ATTR_FORK, + .op_flags = XFS_DA_OP_OKNOENT, + .dp = ip, + .owner = ip->i_ino, + .trans = tp, + .attr_filter = attr_flags & XFS_ATTR_NSP_ONDISK_MASK, + .name = name, + .namelen = namelen, + }; + char namebuf[MAXNAMELEN + 1]; + const char *print_name = namebuf; + int error; + + if ((attr_flags & XFS_ATTR_NSP_ONDISK_MASK) != ctx->attr_filter) + return 0; + + /* Make sure the name is null terminated. */ + memcpy(namebuf, name, namelen); + namebuf[MAXNAMELEN] = 0; + + if (ctx->fsprop) { + const char *p = attr_name_to_fsprop_name(namebuf); + + if (!p) + return 0; + + namelen -= (p - namebuf); + print_name = p; + } + + if (!ctx->print_values) { + printf("%.*s\n", namelen, print_name); + return 0; + } + + if (value) { + printf("%.*s=%.*s\n", namelen, print_name, valuelen, + (char *)value); + return 0; + } + + libxfs_attr_sethash(&args); + + /* + * Look up attr value with a maximally long length and a null buffer + * to return the value and the correct length. + */ + args.valuelen = XATTR_SIZE_MAX; + error = -libxfs_attr_get(&args); + if (error) { + dbprintf(_("failed to get attr %s on inode %llu: %s\n"), + args.name, (unsigned long long)iocur_top->ino, + strerror(error)); + return error; + } + + printf("%.*s=%.*s\n", namelen, print_name, args.valuelen, + (char *)args.value); + kfree(args.value); + + return 0; +} + +static int +attr_list_f( + int argc, + char **argv) +{ + struct attrlist_ctx ctx = { }; + struct xfs_trans *tp; + struct xfs_inode *ip; + int c; + int error; + + if (cur_typ == NULL) { + dbprintf(_("no current type\n")); + return 0; + } + if (cur_typ->typnm != TYP_INODE) { + dbprintf(_("current type is not inode\n")); + return 0; + } + + while ((c = getopt(argc, argv, "ruspvZ")) != EOF) { + switch (c) { + /* namespaces */ + case 'Z': + ctx.fsprop = true; + fallthrough; + case 'r': + ctx.attr_filter &= ~LIBXFS_ATTR_NS; + ctx.attr_filter |= LIBXFS_ATTR_ROOT; + break; + case 'u': + ctx.attr_filter &= ~LIBXFS_ATTR_NS; + break; + case 's': + ctx.attr_filter &= ~LIBXFS_ATTR_NS; + ctx.attr_filter |= LIBXFS_ATTR_SECURE; + break; + case 'p': + ctx.attr_filter &= ~LIBXFS_ATTR_NS; + ctx.attr_filter |= XFS_ATTR_PARENT; + break; + + case 'v': + ctx.print_values = true; + break; + default: + dbprintf(_("bad option for attr_list command\n")); + return 0; + } + } + + if (ctx.fsprop && + (ctx.attr_filter & LIBXFS_ATTR_NS) != LIBXFS_ATTR_ROOT) { + dbprintf(_("fs properties must be ATTR_ROOT\n")); + return false; + } + + if (optind != argc) { + dbprintf(_("too many options for attr_list (no name needed)\n")); + return 0; + } + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) { + dbprintf(_("failed to allocate empty transaction\n")); + return 0; + } + + error = -libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip); + if (error) { + dbprintf(_("failed to iget inode %llu: %s\n"), + (unsigned long long)iocur_top->ino, + strerror(error)); + goto out_trans; + } + + error = xattr_walk(tp, ip, attrlist_print, &ctx); + if (error) { + dbprintf(_("walking inode %llu xattrs: %s\n"), + (unsigned long long)iocur_top->ino, + strerror(error)); + goto out_inode; + } + +out_inode: + libxfs_irele(ip); +out_trans: + libxfs_trans_cancel(tp); + return 0; +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index f0865b2df..291ec1c58 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -212,6 +212,34 @@ Only one namespace option can be specified. Read the name from this file. .RE .TP +.BI "attr_list [\-p|\-r|\-u|\-s|\-Z] [\-v] " +Lists the extended attributes of the current file. +.RS 1.0i +.TP 0.4i +.B \-p +Sets the attribute in the parent namespace. +Only one namespace option can be specified. +.TP +.B \-r +Sets the attribute in the root namespace. +Only one namespace option can be specified. +.TP +.B \-u +Sets the attribute in the user namespace. +Only one namespace option can be specified. +.TP +.B \-s +Sets the attribute in the secure namespace. +Only one namespace option can be specified. +.TP +.B \-Z +Sets a filesystem property in the root namespace. +Only one namespace option can be specified. +.TP +.B \-v +Print the extended attribute values too. +.RE +.TP .BI "attr_remove [\-p|\-r|\-u|\-s|\-Z] [\-n] [\-N " namefile "|" name "] " Remove the specified extended attribute from the current file. .RS 1.0i From patchwork Tue Aug 6 18:21:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13755242 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3A7662A02; Tue, 6 Aug 2024 18:21:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968469; cv=none; b=mkjno3qyQ8By7lGWKaCtPAMVOScelFH7oC4r+N4YYlSEDFInLcT4PxUEENzxt1DfSLZewnPCYadZPToK+CuoaANgfQg59xubHJwgeVX/Btne+y49g9neRerD4ftf5isnHr0UswjYMMEo6EQiT0vj0Y7gZmU8mAsIX2jbkD/gZZo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1722968469; c=relaxed/simple; bh=uqcjpf2o7546mReVzdEBsAL0m4K90/rgFgCWi0mg2fs=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VoYZleRo6gomrPJAjJzNM3oLUbOkWy99GMPtn9OiMsZNe3zR0P0bpsEh21I6ikaZMkuGt9rgSHlDlEa1wrIO10f6f3+MmurXnFqtl2mnE7dIkM4RtN+IzzQ43T6hY7KJBXG61gjy/JGtxfhnOamUG3fgpIRXBJQWV84XUIX0dmc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RScTdpAh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RScTdpAh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4B556C32786; Tue, 6 Aug 2024 18:21:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722968469; bh=uqcjpf2o7546mReVzdEBsAL0m4K90/rgFgCWi0mg2fs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=RScTdpAhDeK7Aibhk7Wudch5+g55l0/9PYVXaqS+28FWYR4d3VMHPn8y/1GcBUJqn ClN7HnKCmvZk2k+sYRVwQRIleTdL8zK++d1v57ipQAoke04pE4lx3ppThXQ5JZqUn+ 1nm6ZlN/tmS1+px4jJmDooXWH3tSQPnjX97eYGwSYyI26VTUlgkysp1g9ECSyXQBFx niTLfp0iCoSgOnKebL86JQS+MMDS2x4wSV2DzKKMG56Gn3dMng18UPYpAj7ew+XwbE 1IqxXReVvxyoJBRCEMD7r1cVbDFkcWO+ASGSDbcUSX2K5jzhTIdLG6Oq/v/v8lKZ72 lmFLjYUvRHjEw== Date: Tue, 06 Aug 2024 11:21:08 -0700 Subject: [PATCH 7/7] xfs_property: add a new tool to administer fs properties From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , hch@lst.de, dchinner@redhat.com, fstests@vger.kernel.org, linux-xfs@vger.kernel.org Message-ID: <172296825294.3193059.14566423047686344749.stgit@frogsfrogsfrogs> In-Reply-To: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> References: <172296825181.3193059.14803487307894313362.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fstests@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a tool to list, get, set, and remove filesystem properties. Signed-off-by: Darrick J. Wong Acked-by: Dave Chinner Reviewed-by: Christoph Hellwig --- io/Makefile | 3 +- io/xfs_property | 77 +++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_property.8 | 61 +++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100755 io/xfs_property create mode 100644 man/man8/xfs_property.8 diff --git a/io/Makefile b/io/Makefile index 0bdd05b57..c33d57f5e 100644 --- a/io/Makefile +++ b/io/Makefile @@ -6,7 +6,7 @@ TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_io -LSRCFILES = xfs_bmap.sh xfs_freeze.sh xfs_mkfile.sh +LSRCFILES = xfs_bmap.sh xfs_freeze.sh xfs_mkfile.sh xfs_property HFILES = init.h io.h CFILES = \ attr.c \ @@ -92,6 +92,7 @@ install: default $(LTINSTALL) -m 755 xfs_bmap.sh $(PKG_SBIN_DIR)/xfs_bmap $(LTINSTALL) -m 755 xfs_freeze.sh $(PKG_SBIN_DIR)/xfs_freeze $(LTINSTALL) -m 755 xfs_mkfile.sh $(PKG_SBIN_DIR)/xfs_mkfile + $(LTINSTALL) -m 755 xfs_property $(PKG_SBIN_DIR)/xfs_property install-dev: -include .dep diff --git a/io/xfs_property b/io/xfs_property new file mode 100755 index 000000000..6f630312a --- /dev/null +++ b/io/xfs_property @@ -0,0 +1,77 @@ +#!/bin/bash -f +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2024 Oracle. All Rights Reserved. +# Author: Darrick J. Wong +# + +OPTS="" +USAGE="Usage: xfs_property [-V] [mountpoint|device|file] [list [-v]|get name...|set name=value...|remove name...]" + +# Try to find a loop device associated with a file. We only want to return +# one loopdev (multiple loop devices can attach to a single file) so we grab +# the last line and return it if it's actually a block device. +try_find_loop_dev_for_file() { + local x="$(losetup -O NAME -j "$1" 2> /dev/null | tail -n 1)" + test -b "${x}" && echo "${x}" +} + +while getopts "V" c +do + case $c in + V) xfs_io -p xfs_info -V + status=$? + exit ${status} + ;; + *) echo "${USAGE}" 1>&2 + exit 2 + ;; + esac +done +set -- extra "$@" +shift $OPTIND + +if [ $# -lt 2 ]; then + echo "${USAGE}" 1>&2 + exit 2 +fi + +target="$1" +shift +subcommand="$1" +shift + +db_args=() +io_args=() + +case "$subcommand" in +"list") + vparam= + if [ $# -eq 1 ] && [ "$1" = "-v" ]; then + vparam=" -v" + fi + db_args+=('-c' "attr_list -Z${vparam}") + io_args+=('-c' "listfsprops${vparam}") + ;; +"get"|"remove"|"set") + for arg in "$@"; do + db_args+=('-c' "attr_${subcommand} -Z ${arg/=/ }") + io_args+=('-c' "${subcommand}fsprops ${arg}") + done + ;; +*) + echo "${USAGE}" 1>&2 + exit 2 +esac + +# See if we can map the arg to a loop device +loopdev="$(try_find_loop_dev_for_file "${target}")" +test -n "${loopdev}" && target="${loopdev}" + +# If we find a mountpoint for the device, do a live query; otherwise try +# reading the fs with xfs_db. +if mountpt="$(findmnt -t xfs -f -n -o TARGET "${target}" 2> /dev/null)"; then + exec xfs_io -p xfs_property "${io_args[@]}" "${mountpt}" +else + exec xfs_db -p xfs_property -x -c 'path /' "${db_args[@]}" "${target}" +fi diff --git a/man/man8/xfs_property.8 b/man/man8/xfs_property.8 new file mode 100644 index 000000000..19c1c0e37 --- /dev/null +++ b/man/man8/xfs_property.8 @@ -0,0 +1,61 @@ +.TH xfs_property 8 +.SH NAME +xfs_property \- examine and edit properties about an XFS filesystem +.SH SYNOPSIS +.B xfs_property +.I target +.B get +.IR name ... +.br +.B xfs_property +.I target +.B list [ \-v ] +.br +.B xfs_property +.I target +.B set +.IR name=value ... +.br +.B xfs_property +.I target +.B remove +.IR name ... +.br +.B xfs_property \-V +.SH DESCRIPTION +.B xfs_property +retrieves, lists, sets, or removes properties of an XFS filesystem. +Filesystem properties are root-controlled attributes set on the root directory +of the filesystem to enable the system administrator to coordinate with +userspace programs. + +.I target +is one of: the root directory of a mounted filesystem; a block device containing +an XFS filesystem; or a regular file containing an XFS filesystem. + +.SH OPTIONS +.TP +.B \-V +Print the version number and exits. + +.SH COMMANDS +.TP +.B get +.IR name ... +Prints the values of the given filesystem properties. +.TP +.B list +Lists the names of all filesystem properties. +If the +.B -v +flag is specified, prints the values as well. +.TP +.B set +.IR name = value ... +Sets the given filesystem properties to the specified values and prints what +was set. +.TP +.B +remove +.IR name ... +Unsets the given filesystem properties.