From: "Darrick J. Wong" <djwong@kernel.org>
To: Andrey Albershteyn <aalbersh@redhat.com>
Cc: fstests@vger.kernel.org, zlang@redhat.com,
linux-fsdevel@vger.kernel.org, linux-xfs@vger.kernel.org,
Andrey Albershteyn <aalbersh@kernel.org>
Subject: Re: [PATCH 1/3] file_attr: introduce program to set/get fsxattr
Date: Mon, 11 Aug 2025 08:23:40 -0700 [thread overview]
Message-ID: <20250811152340.GG7965@frogsfrogsfrogs> (raw)
In-Reply-To: <20250808-xattrat-syscall-v1-1-6a09c4f37f10@kernel.org>
On Fri, Aug 08, 2025 at 09:31:56PM +0200, Andrey Albershteyn wrote:
> This programs uses newly introduced file_getattr and file_setattr
> syscalls. This program is partially a test of invalid options. This will
> be used further in the test.
>
> Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
> ---
> .gitignore | 1 +
> configure.ac | 1 +
> include/builddefs.in | 1 +
> m4/package_libcdev.m4 | 16 +++
> src/Makefile | 5 +
> src/file_attr.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 301 insertions(+)
>
> diff --git a/.gitignore b/.gitignore
> index 4fd817243dca..1a578eab1ea0 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -210,6 +210,7 @@ tags
> /src/fiemap-fault
> /src/min_dio_alignment
> /src/dio-writeback-race
> +/src/file_attr
>
> # Symlinked files
> /tests/generic/035.out
> diff --git a/configure.ac b/configure.ac
> index f3c8c643f0eb..6fe54e8e1d54 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -73,6 +73,7 @@ AC_HAVE_RLIMIT_NOFILE
> AC_NEED_INTERNAL_XFS_IOC_EXCHANGE_RANGE
> AC_HAVE_FICLONE
> AC_HAVE_TRIVIAL_AUTO_VAR_INIT
> +AC_HAVE_FILE_ATTR
>
> AC_CHECK_FUNCS([renameat2])
> AC_CHECK_FUNCS([reallocarray])
> diff --git a/include/builddefs.in b/include/builddefs.in
> index 96d5ed25b3e2..821237339cc7 100644
> --- a/include/builddefs.in
> +++ b/include/builddefs.in
> @@ -74,6 +74,7 @@ HAVE_BMV_OF_SHARED = @have_bmv_of_shared@
> HAVE_RLIMIT_NOFILE = @have_rlimit_nofile@
> NEED_INTERNAL_XFS_IOC_EXCHANGE_RANGE = @need_internal_xfs_ioc_exchange_range@
> HAVE_FICLONE = @have_ficlone@
> +HAVE_FILE_ATTR = @have_file_attr@
>
> GCCFLAGS = -std=gnu11 -funsigned-char -fno-strict-aliasing -Wall
> SANITIZER_CFLAGS += @autovar_init_cflags@
> diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
> index ed8fe6e32ae0..e68a70f7d87e 100644
> --- a/m4/package_libcdev.m4
> +++ b/m4/package_libcdev.m4
> @@ -86,3 +86,19 @@ AC_DEFUN([AC_HAVE_TRIVIAL_AUTO_VAR_INIT],
> CFLAGS="${OLD_CFLAGS}"
> AC_SUBST(autovar_init_cflags)
> ])
> +
> +#
> +# Check if we have a file_getattr/file_setattr system call (Linux)
> +#
> +AC_DEFUN([AC_HAVE_FILE_ATTR],
> + [ AC_MSG_CHECKING([for file_getattr/file_setattr syscalls])
> + AC_LINK_IFELSE([AC_LANG_PROGRAM([[
> +#define _GNU_SOURCE
> +#include <sys/syscall.h>
> +#include <unistd.h>
> + ]], [[
> + syscall(__NR_file_getattr, 0, 0, 0, 0, 0, 0);
> + ]])],[have_file_attr=yes
> + AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)])
> + AC_SUBST(have_file_attr)
> + ])
> diff --git a/src/Makefile b/src/Makefile
> index 6ac72b366257..f3137acf687f 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -61,6 +61,11 @@ ifeq ($(HAVE_FALLOCATE), true)
> LCFLAGS += -DHAVE_FALLOCATE
> endif
>
> +ifeq ($(HAVE_FILE_ATTR), yes)
> +LINUX_TARGETS += file_attr
> +LCFLAGS += -DHAVE_FILE_ATTR
> +endif
> +
> ifeq ($(PKG_PLATFORM),linux)
> TARGETS += $(LINUX_TARGETS)
> endif
> diff --git a/src/file_attr.c b/src/file_attr.c
> new file mode 100644
> index 000000000000..9756ab265a57
> --- /dev/null
> +++ b/src/file_attr.c
> @@ -0,0 +1,277 @@
> +#include "global.h"
> +#include <sys/syscall.h>
> +#include <getopt.h>
> +#include <errno.h>
> +#include <linux/fs.h>
> +#include <sys/stat.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +#ifndef HAVE_FILE_ATTR
> +#define __NR_file_getattr 468
> +#define __NR_file_setattr 469
> +
> +struct file_attr {
> + __u32 fa_xflags; /* xflags field value (get/set) */
> + __u32 fa_extsize; /* extsize field value (get/set)*/
> + __u32 fa_nextents; /* nextents field value (get) */
> + __u32 fa_projid; /* project identifier (get/set) */
> + __u32 fa_cowextsize; /* CoW extsize field value (get/set) */
> +};
> +
> +#endif
> +
> +#define SPECIAL_FILE(x) \
> + (S_ISCHR((x)) \
> + || S_ISBLK((x)) \
> + || S_ISFIFO((x)) \
> + || S_ISLNK((x)) \
> + || S_ISSOCK((x)))
> +
> +static struct option long_options[] = {
> + {"set", no_argument, 0, 's' },
> + {"get", no_argument, 0, 'g' },
> + {"no-follow", no_argument, 0, 'n' },
> + {"at-cwd", no_argument, 0, 'a' },
> + {"set-nodump", no_argument, 0, 'd' },
> + {"invalid-at", no_argument, 0, 'i' },
> + {"too-big-arg", no_argument, 0, 'b' },
> + {"too-small-arg", no_argument, 0, 'm' },
> + {"new-fsx-flag", no_argument, 0, 'x' },
> + {0, 0, 0, 0 }
> +};
> +
> +static struct xflags {
> + uint flag;
> + char *shortname;
> + char *longname;
> +} xflags[] = {
> + { FS_XFLAG_REALTIME, "r", "realtime" },
> + { FS_XFLAG_PREALLOC, "p", "prealloc" },
> + { FS_XFLAG_IMMUTABLE, "i", "immutable" },
> + { FS_XFLAG_APPEND, "a", "append-only" },
> + { FS_XFLAG_SYNC, "s", "sync" },
> + { FS_XFLAG_NOATIME, "A", "no-atime" },
> + { FS_XFLAG_NODUMP, "d", "no-dump" },
> + { FS_XFLAG_RTINHERIT, "t", "rt-inherit" },
> + { FS_XFLAG_PROJINHERIT, "P", "proj-inherit" },
> + { FS_XFLAG_NOSYMLINKS, "n", "nosymlinks" },
> + { FS_XFLAG_EXTSIZE, "e", "extsize" },
> + { FS_XFLAG_EXTSZINHERIT, "E", "extsz-inherit" },
> + { FS_XFLAG_NODEFRAG, "f", "no-defrag" },
> + { FS_XFLAG_FILESTREAM, "S", "filestream" },
> + { FS_XFLAG_DAX, "x", "dax" },
> + { FS_XFLAG_COWEXTSIZE, "C", "cowextsize" },
> + { FS_XFLAG_HASATTR, "X", "has-xattr" },
> + { 0, NULL, NULL }
> +};
> +
> +static int
> +file_getattr(
> + int dfd,
> + const char *filename,
> + struct file_attr *fsx,
> + size_t usize,
> + unsigned int at_flags)
> +{
> + return syscall(__NR_file_getattr, dfd, filename, fsx, usize, at_flags);
> +}
> +
> +static int
> +file_setattr(
> + int dfd,
> + const char *filename,
> + struct file_attr *fsx,
> + size_t usize,
> + unsigned int at_flags)
> +{
> + return syscall(__NR_file_setattr, dfd, filename, fsx, usize, at_flags);
> +}
> +
> +void
> +printxattr(
> + uint flags,
> + int verbose,
> + int dofname,
> + const char *fname,
> + int dobraces,
> + int doeol)
> +{
> + struct xflags *p;
> + int first = 1;
> +
> + if (dobraces)
> + fputs("[", stdout);
> + for (p = xflags; p->flag; p++) {
> + if (flags & p->flag) {
> + if (verbose) {
> + if (first)
> + first = 0;
> + else
> + fputs(", ", stdout);
> + fputs(p->longname, stdout);
> + } else {
> + fputs(p->shortname, stdout);
> + }
> + } else if (!verbose) {
> + fputs("-", stdout);
> + }
> + }
> + if (dobraces)
> + fputs("]", stdout);
> + if (dofname)
> + printf(" %s ", fname);
> + if (doeol)
> + fputs("\n", stdout);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + int error;
> + int c;
> + const char *path = NULL;
> + const char *path1 = NULL;
> + const char *path2 = NULL;
> + unsigned int at_flags = 0;
> + unsigned int fa_xflags = 0;
> + int action = 0; /* 0 get; 1 set */
> + struct file_attr fsx = { };
> + int fa_size = sizeof(struct file_attr);
> + struct stat status;
> + int fd;
> + int at_fdcwd = 0;
> + int unknwon_fa_flag = 0;
> +
> + while (1) {
> + int option_index = 0;
> +
> + c = getopt_long_only(argc, argv, "", long_options, &option_index);
> + if (c == -1)
> + break;
> +
> + switch (c) {
> + case 's':
> + action = 1;
> + break;
> + case 'g':
> + action = 0;
> + break;
> + case 'n':
> + at_flags |= AT_SYMLINK_NOFOLLOW;
> + break;
> + case 'a':
> + at_fdcwd = 1;
> + break;
> + case 'd':
> + fa_xflags |= FS_XFLAG_NODUMP;
> + break;
> + case 'i':
> + at_flags |= (1 << 25);
> + break;
> + case 'b':
> + fa_size = getpagesize() + 1; /* max size if page size */
> + break;
> + case 'm':
> + fa_size = 19; /* VER0 size of fsxattr is 20 */
> + break;
> + case 'x':
> + unknwon_fa_flag = (1 << 27);
> + break;
> + default:
> + goto usage;
> + }
> + }
> +
> + if (!path1 && optind < argc)
> + path1 = argv[optind++];
> + if (!path2 && optind < argc)
> + path2 = argv[optind++];
> +
> + if (at_fdcwd) {
> + fd = AT_FDCWD;
> + path = path1;
> + } else if (!path2) {
> + error = stat(path1, &status);
> + if (error) {
> + fprintf(stderr,
> +"Can not get file status of %s: %s\n", path1, strerror(errno));
> + return error;
> + }
> +
> + if (SPECIAL_FILE(status.st_mode)) {
> + fprintf(stderr,
> +"Can not open special file %s without parent dir: %s\n", path1, strerror(errno));
> + return errno;
> + }
> +
> + fd = open(path1, O_RDONLY);
> + if (fd == -1) {
> + fprintf(stderr, "Can not open %s: %s\n", path1,
> + strerror(errno));
> + return errno;
> + }
> + } else {
> + fd = open(path1, O_RDONLY);
> + if (fd == -1) {
> + fprintf(stderr, "Can not open %s: %s\n", path1,
> + strerror(errno));
> + return errno;
> + }
> + path = path2;
> + }
> +
> + if (!path)
> + at_flags |= AT_EMPTY_PATH;
> +
> + if (action) {
> + error = file_getattr(fd, path, &fsx, fa_size,
> + at_flags);
> + if (error) {
> + fprintf(stderr, "Can not get fsxattr on %s: %s\n", path,
> + strerror(errno));
> + return error;
> + }
> +
> + fsx.fa_xflags |= (fa_xflags | unknwon_fa_flag);
> +
> + error = file_setattr(fd, path, &fsx, fa_size,
> + at_flags);
> + if (error) {
> + fprintf(stderr, "Can not set fsxattr on %s: %s\n", path,
> + strerror(errno));
> + return error;
> + }
> + } else {
> + error = file_getattr(fd, path, &fsx, fa_size,
> + at_flags);
> + if (error) {
> + fprintf(stderr, "Can not get fsxattr on %s: %s\n", path,
> + strerror(errno));
> + return error;
> + }
Can the file_getattr be lifted above the if (action) ?
> +
> + if (path2)
> + printxattr(fsx.fa_xflags, 0, 1, path, 0, 1);
> + else
> + printxattr(fsx.fa_xflags, 0, 1, path1, 0, 1);
> + }
> +
> + return error;
> +
> +usage:
> + printf("Usage: %s [options]\n", argv[0]);
> + printf("Options:\n");
> + printf("\t--get\t\tget filesystem inode attributes\n");
> + printf("\t--set\t\tset filesystem inode attributes\n");
> + printf("\t--at-cwd\t\topen file at current working directory\n");
> + printf("\t--no-follow\t\tdon't follow symlinks\n");
> + printf("\t--set-nodump\t\tset FS_XFLAG_NODUMP on an inode\n");
> + printf("\t--invalid-at\t\tUse invalida AT_* flag\n");
> + printf("\t--too-big-arg\t\tSet fsxattr size bigger than PAGE_SIZE\n");
> + printf("\t--too-small-arg\t\tSet fsxattr size to 27 bytes\n");
27? I thought you put in 19 above?
Also it'd be nice if the help listed the short and long versions.
(Or skip the short cli switches ;))
--D
> + printf("\t--new-fsx-flag\t\tUse unknown fa_flags flag\n");
> +
> + return 1;
> +}
>
> --
> 2.49.0
>
>
next prev parent reply other threads:[~2025-08-11 15:23 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-08 19:28 Tests for file_getattr()/file_setattr() and xfsprogs update Andrey Albershteyn
2025-08-08 19:30 ` [PATCH 0/4] xfsprogs: utilize file_getattr() and file_setattr() Andrey Albershteyn
2025-08-08 19:30 ` [PATCH 1/4] libfrog: add wrappers for file_getattr/file_setattr syscalls Andrey Albershteyn
2025-08-11 15:02 ` Darrick J. Wong
2025-08-11 17:44 ` Andrey Albershteyn
2025-08-12 14:53 ` Darrick J. Wong
2025-08-08 19:30 ` [PATCH 2/4] xfs_quota: utilize file_setattr to set prjid on special files Andrey Albershteyn
2025-08-11 15:07 ` Darrick J. Wong
2025-08-11 17:51 ` Andrey Albershteyn
2025-08-08 19:30 ` [PATCH 3/4] xfs_io: make ls/chattr work with " Andrey Albershteyn
2025-08-11 15:12 ` Darrick J. Wong
2025-08-11 17:57 ` Andrey Albershteyn
2025-08-12 17:28 ` Darrick J. Wong
2025-08-08 19:30 ` [PATCH 4/4] xfs_db: use file_setattr to copy attributes on special files with rdump Andrey Albershteyn
2025-08-11 15:14 ` Darrick J. Wong
2025-08-11 17:59 ` Andrey Albershteyn
2025-08-08 19:31 ` [PATCH 0/3] Test file_getattr and file_setattr syscalls Andrey Albershteyn
2025-08-08 19:31 ` [PATCH 1/3] file_attr: introduce program to set/get fsxattr Andrey Albershteyn
2025-08-11 15:23 ` Darrick J. Wong [this message]
2025-08-11 18:06 ` Andrey Albershteyn
2025-08-11 17:51 ` Zorro Lang
2025-08-11 18:12 ` Andrey Albershteyn
2025-08-08 19:31 ` [PATCH 2/3] generic: introduce test to test file_getattr/file_setattr syscalls Andrey Albershteyn
2025-08-11 15:17 ` Darrick J. Wong
2025-08-11 18:13 ` Andrey Albershteyn
2025-08-11 17:55 ` Zorro Lang
2025-08-11 18:18 ` Andrey Albershteyn
2025-08-11 18:43 ` Zorro Lang
2025-08-08 19:31 ` [PATCH 3/3] xfs: test quota's project ID on special files Andrey Albershteyn
2025-08-11 15:21 ` Darrick J. Wong
2025-08-11 18:21 ` Andrey Albershteyn
2025-08-11 17:46 ` Zorro Lang
2025-08-11 18:20 ` Andrey Albershteyn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250811152340.GG7965@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=aalbersh@kernel.org \
--cc=aalbersh@redhat.com \
--cc=fstests@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=zlang@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).