* [PATCH v4 0/3] Test file_getattr and file_setattr syscalls
@ 2025-10-03 9:32 Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr Andrey Albershteyn
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-03 9:32 UTC (permalink / raw)
To: fstests
Cc: zlang, linux-fsdevel, linux-xfs, Andrey Albershteyn,
Darrick J. Wong, Andrey Albershteyn
Add a test to check basic functionallity of file_getattr() and
file_setattr() syscalls. These syscalls are used to get/set filesystem
inode attributes (think of FS_IOC_SETFSXATTR ioctl()). The difference
from ioctl() is that these syscalls use *at() semantics and can be
called on any file without opening it, including special ones.
For XFS, with the use of these syscalls, xfs_quota now can
manipulate quota on special files such as sockets. Add a test to
check that special files are counted, which wasn't true before.
To: fstests@vger.kernel.org
Cc: zlang@redhat.com
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
---
Changes in v4:
- Use _filter_file_attributes to focus only on nodump in generic/2000
- Add _filter_file_attributes to common/filter
- Link to v3: https://lore.kernel.org/r/20250909-xattrat-syscall-v3-0-9ba483144789@kernel.org
Changes in v3:
- Fix tab vs spaces indents
- Update year in SPDX header
- Rename AC_HAVE_FILE_ATTR to AC_HAVE_FILE_GETATTR
Changes in v2:
- Improve help message for file_attr
- Refactor file_attr.c
- Drop _wants_*_commit
- Link to v1: https://lore.kernel.org/r/20250808-xattrat-syscall-v1-0-6a09c4f37f10@kernel.org
---
Andrey Albershteyn (3):
file_attr: introduce program to set/get fsxattr
generic: introduce test to test file_getattr/file_setattr syscalls
xfs: test quota's project ID on special files
.gitignore | 1 +
common/filter | 15 +++
configure.ac | 1 +
include/builddefs.in | 1 +
m4/package_libcdev.m4 | 16 +++
src/Makefile | 5 +
src/file_attr.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/2000 | 109 ++++++++++++++++++++
tests/generic/2000.out | 37 +++++++
tests/xfs/2000 | 73 +++++++++++++
tests/xfs/2000.out | 15 +++
11 files changed, 547 insertions(+)
---
base-commit: 3d57f543ae0c149eb460574dcfb8d688aeadbfff
change-id: 20250317-xattrat-syscall-ee8f5e2d6e18
Best regards,
--
Andrey Albershteyn <aalbersh@kernel.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr
2025-10-03 9:32 [PATCH v4 0/3] Test file_getattr and file_setattr syscalls Andrey Albershteyn
@ 2025-10-03 9:32 ` Andrey Albershteyn
2025-10-05 10:36 ` Zorro Lang
2025-10-03 9:32 ` [PATCH v4 2/3] generic: introduce test to test file_getattr/file_setattr syscalls Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 3/3] xfs: test quota's project ID on special files Andrey Albershteyn
2 siblings, 1 reply; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-03 9:32 UTC (permalink / raw)
To: fstests; +Cc: zlang, linux-fsdevel, linux-xfs, Andrey Albershteyn
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 | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 298 insertions(+)
diff --git a/.gitignore b/.gitignore
index 6948fd602f95..82c57f415301 100644
--- a/.gitignore
+++ b/.gitignore
@@ -211,6 +211,7 @@ tags
/src/min_dio_alignment
/src/dio-writeback-race
/src/unlink-fsync
+/src/file_attr
# Symlinked files
/tests/generic/035.out
diff --git a/configure.ac b/configure.ac
index f3c8c643f0eb..f7519fa97654 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_GETATTR
AC_CHECK_FUNCS([renameat2])
AC_CHECK_FUNCS([reallocarray])
diff --git a/include/builddefs.in b/include/builddefs.in
index 96d5ed25b3e2..708d75b24d76 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_GETATTR = @have_file_getattr@
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..17f57f427410 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 system call (Linux)
+#
+AC_DEFUN([AC_HAVE_FILE_GETATTR],
+ [ AC_MSG_CHECKING([for file_getattr syscall])
+ 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_getattr=yes
+ AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)])
+ AC_SUBST(have_file_getattr)
+ ])
diff --git a/src/Makefile b/src/Makefile
index 7080e34896c3..711dbb917b3a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -62,6 +62,11 @@ ifeq ($(HAVE_FALLOCATE), true)
LCFLAGS += -DHAVE_FALLOCATE
endif
+ifeq ($(HAVE_FILE_GETATTR), yes)
+LINUX_TARGETS += file_attr
+LCFLAGS += -DHAVE_FILE_GETATTR
+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..29bb6c903403
--- /dev/null
+++ b/src/file_attr.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Red Hat, Inc. All Rights Reserved.
+ */
+
+#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_GETATTR
+#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);
+}
+
+static void
+print_xflags(
+ 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;
+
+ 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;
+ }
+ if (action) {
+ 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 {
+ if (path2)
+ print_xflags(fsx.fa_xflags, 0, 1, path, 0, 1);
+ else
+ print_xflags(fsx.fa_xflags, 0, 1, path1, 0, 1);
+ }
+
+ return error;
+
+usage:
+ printf("Usage: %s [options]\n", argv[0]);
+ printf("Options:\n");
+ printf("\t--get, -g\t\tget filesystem inode attributes\n");
+ printf("\t--set, -s\t\tset filesystem inode attributes\n");
+ printf("\t--at-cwd, -a\t\topen file at current working directory\n");
+ printf("\t--no-follow, -n\t\tdon't follow symlinks\n");
+ printf("\t--set-nodump, -d\t\tset FS_XFLAG_NODUMP on an inode\n");
+ printf("\t--invalid-at, -i\t\tUse invalid AT_* flag\n");
+ printf("\t--too-big-arg, -b\t\tSet fsxattr size bigger than PAGE_SIZE\n");
+ printf("\t--too-small-arg, -m\t\tSet fsxattr size to 19 bytes\n");
+ printf("\t--new-fsx-flag, -x\t\tUse unknown fa_flags flag\n");
+
+ return 1;
+}
--
2.50.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 2/3] generic: introduce test to test file_getattr/file_setattr syscalls
2025-10-03 9:32 [PATCH v4 0/3] Test file_getattr and file_setattr syscalls Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr Andrey Albershteyn
@ 2025-10-03 9:32 ` Andrey Albershteyn
2025-10-06 9:55 ` Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 3/3] xfs: test quota's project ID on special files Andrey Albershteyn
2 siblings, 1 reply; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-03 9:32 UTC (permalink / raw)
To: fstests
Cc: zlang, linux-fsdevel, linux-xfs, Andrey Albershteyn,
Darrick J. Wong
Add a test to test basic functionality of file_getattr() and
file_setattr() syscalls. Most of the work is done in file_attr
utility.
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
---
common/filter | 15 +++++++
tests/generic/2000 | 109 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/2000.out | 37 +++++++++++++++++
3 files changed, 161 insertions(+)
diff --git a/common/filter b/common/filter
index bbe13f4c8a8d..b330b27827d0 100644
--- a/common/filter
+++ b/common/filter
@@ -683,5 +683,20 @@ _filter_sysfs_error()
sed 's/.*: \(.*\)$/\1/'
}
+# Filter file attributes (aka lsattr/chattr)
+# To filter X:
+# ... | _filter_file_attributes X
+# Or to filter all except X
+# ... | _filter_file_attributes ~X
+_filter_file_attributes()
+{
+ if [[ $1 == ~* ]]; then
+ regex=$(echo "[aAcCdDeEFijmNPsStTuxVX]" | tr -d "$1")
+ else
+ regex="$1"
+ fi
+ awk "{ printf \"%s \", gensub(\"$regex\", \"-\", \"g\", \$1) } {print \$2}"
+}
+
# make sure this script returns success
/bin/true
diff --git a/tests/generic/2000 b/tests/generic/2000
new file mode 100755
index 000000000000..16045829031a
--- /dev/null
+++ b/tests/generic/2000
@@ -0,0 +1,109 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Red Hat Inc. All Rights Reserved.
+#
+# FS QA Test No. 2000
+#
+# Test file_getattr/file_setattr syscalls
+#
+. ./common/preamble
+_begin_fstest auto
+
+. ./common/filter
+
+# Modify as appropriate.
+_require_scratch
+_require_test_program "af_unix"
+_require_test_program "file_attr"
+_require_symlinks
+_require_mknod
+
+_scratch_mkfs >>$seqres.full 2>&1
+_scratch_mount
+
+file_attr () {
+ $here/src/file_attr $*
+}
+
+create_af_unix () {
+ $here/src/af_unix $* || echo af_unix failed
+}
+
+projectdir=$SCRATCH_MNT/prj
+
+# Create normal files and special files
+mkdir $projectdir
+mkfifo $projectdir/fifo
+mknod $projectdir/chardev c 1 1
+mknod $projectdir/blockdev b 1 1
+create_af_unix $projectdir/socket
+touch $projectdir/foo
+ln -s $projectdir/foo $projectdir/symlink
+touch $projectdir/bar
+ln -s $projectdir/bar $projectdir/broken-symlink
+rm -f $projectdir/bar
+
+echo "Error codes"
+# wrong AT_ flags
+file_attr --get --invalid-at $projectdir ./foo
+file_attr --set --invalid-at $projectdir ./foo
+# wrong fsxattr size (too big, too small)
+file_attr --get --too-big-arg $projectdir ./foo
+file_attr --get --too-small-arg $projectdir ./foo
+file_attr --set --too-big-arg $projectdir ./foo
+file_attr --set --too-small-arg $projectdir ./foo
+# out of fsx_xflags mask
+file_attr --set --new-fsx-flag $projectdir ./foo
+
+echo "Initial attributes state"
+file_attr --get $projectdir | _filter_scratch | _filter_file_attributes ~d
+file_attr --get $projectdir ./fifo | _filter_file_attributes ~d
+file_attr --get $projectdir ./chardev | _filter_file_attributes ~d
+file_attr --get $projectdir ./blockdev | _filter_file_attributes ~d
+file_attr --get $projectdir ./socket | _filter_file_attributes ~d
+file_attr --get $projectdir ./foo | _filter_file_attributes ~d
+file_attr --get $projectdir ./symlink | _filter_file_attributes ~d
+
+echo "Set FS_XFLAG_NODUMP (d)"
+file_attr --set --set-nodump $projectdir
+file_attr --set --set-nodump $projectdir ./fifo
+file_attr --set --set-nodump $projectdir ./chardev
+file_attr --set --set-nodump $projectdir ./blockdev
+file_attr --set --set-nodump $projectdir ./socket
+file_attr --set --set-nodump $projectdir ./foo
+file_attr --set --set-nodump $projectdir ./symlink
+
+echo "Read attributes"
+file_attr --get $projectdir | _filter_scratch | _filter_file_attributes ~d
+file_attr --get $projectdir ./fifo | _filter_file_attributes ~d
+file_attr --get $projectdir ./chardev | _filter_file_attributes ~d
+file_attr --get $projectdir ./blockdev | _filter_file_attributes ~d
+file_attr --get $projectdir ./socket | _filter_file_attributes ~d
+file_attr --get $projectdir ./foo | _filter_file_attributes ~d
+file_attr --get $projectdir ./symlink | _filter_file_attributes ~d
+
+echo "Set attribute on broken link with AT_SYMLINK_NOFOLLOW"
+file_attr --set --set-nodump $projectdir ./broken-symlink
+file_attr --get $projectdir ./broken-symlink
+
+file_attr --set --no-follow --set-nodump $projectdir ./broken-symlink
+file_attr --get --no-follow $projectdir ./broken-symlink | _filter_file_attributes ~d
+
+cd $SCRATCH_MNT
+touch ./foo2
+echo "Initial state of foo2"
+file_attr --get --at-cwd ./foo2 | _filter_file_attributes ~d
+echo "Set attribute relative to AT_FDCWD"
+file_attr --set --at-cwd --set-nodump ./foo2
+file_attr --get --at-cwd ./foo2 | _filter_file_attributes ~d
+
+echo "Set attribute on AT_FDCWD"
+mkdir ./bar
+file_attr --get --at-cwd ./bar | _filter_file_attributes ~d
+cd ./bar
+file_attr --set --at-cwd --set-nodump ""
+file_attr --get --at-cwd . | _filter_file_attributes ~d
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/2000.out b/tests/generic/2000.out
new file mode 100644
index 000000000000..e6fc7381709b
--- /dev/null
+++ b/tests/generic/2000.out
@@ -0,0 +1,37 @@
+QA output created by 2000
+Error codes
+Can not get fsxattr on ./foo: Invalid argument
+Can not get fsxattr on ./foo: Invalid argument
+Can not get fsxattr on ./foo: Argument list too long
+Can not get fsxattr on ./foo: Invalid argument
+Can not get fsxattr on ./foo: Argument list too long
+Can not get fsxattr on ./foo: Invalid argument
+Can not set fsxattr on ./foo: Invalid argument
+Initial attributes state
+----------------- SCRATCH_MNT/prj
+----------------- ./fifo
+----------------- ./chardev
+----------------- ./blockdev
+----------------- ./socket
+----------------- ./foo
+----------------- ./symlink
+Set FS_XFLAG_NODUMP (d)
+Read attributes
+------d---------- SCRATCH_MNT/prj
+------d---------- ./fifo
+------d---------- ./chardev
+------d---------- ./blockdev
+------d---------- ./socket
+------d---------- ./foo
+------d---------- ./symlink
+Set attribute on broken link with AT_SYMLINK_NOFOLLOW
+Can not get fsxattr on ./broken-symlink: No such file or directory
+Can not get fsxattr on ./broken-symlink: No such file or directory
+------d---------- ./broken-symlink
+Initial state of foo2
+----------------- ./foo2
+Set attribute relative to AT_FDCWD
+------d---------- ./foo2
+Set attribute on AT_FDCWD
+----------------- ./bar
+------d---------- .
--
2.50.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 3/3] xfs: test quota's project ID on special files
2025-10-03 9:32 [PATCH v4 0/3] Test file_getattr and file_setattr syscalls Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 2/3] generic: introduce test to test file_getattr/file_setattr syscalls Andrey Albershteyn
@ 2025-10-03 9:32 ` Andrey Albershteyn
2 siblings, 0 replies; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-03 9:32 UTC (permalink / raw)
To: fstests
Cc: zlang, linux-fsdevel, linux-xfs, Andrey Albershteyn,
Andrey Albershteyn, Darrick J. Wong
From: Andrey Albershteyn <aalbersh@redhat.com>
With addition of file_getattr() and file_setattr(), xfs_quota now can
set project ID on filesystem inodes behind special files. Previously,
quota reporting didn't count inodes of special files created before
project initialization. Only new inodes had project ID set.
Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
---
tests/xfs/2000 | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/xfs/2000.out | 15 +++++++++++
2 files changed, 88 insertions(+)
diff --git a/tests/xfs/2000 b/tests/xfs/2000
new file mode 100755
index 000000000000..413022dd5d8a
--- /dev/null
+++ b/tests/xfs/2000
@@ -0,0 +1,73 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Red Hat. All Rights Reserved.
+#
+# FS QA Test No. 2000
+#
+# Test that XFS can set quota project ID on special files
+#
+. ./common/preamble
+_begin_fstest auto quota
+
+# Import common functions.
+. ./common/quota
+. ./common/filter
+
+# Modify as appropriate.
+_require_scratch
+_require_xfs_quota
+_require_test_program "af_unix"
+_require_test_program "file_attr"
+_require_symlinks
+_require_mknod
+
+_scratch_mkfs >>$seqres.full 2>&1
+_qmount_option "pquota"
+_scratch_mount
+
+create_af_unix () {
+ $here/src/af_unix $* || echo af_unix failed
+}
+
+filter_quota() {
+ _filter_quota | sed "s~$tmp.projects~PROJECTS_FILE~"
+}
+
+projectdir=$SCRATCH_MNT/prj
+id=42
+
+mkdir $projectdir
+mkfifo $projectdir/fifo
+mknod $projectdir/chardev c 1 1
+mknod $projectdir/blockdev b 1 1
+create_af_unix $projectdir/socket
+touch $projectdir/foo
+ln -s $projectdir/foo $projectdir/symlink
+touch $projectdir/bar
+ln -s $projectdir/bar $projectdir/broken-symlink
+rm -f $projectdir/bar
+
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "project -sp $projectdir $id" $SCRATCH_DEV | filter_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "limit -p isoft=20 ihard=20 $id " $SCRATCH_DEV | filter_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "project -cp $projectdir $id" $SCRATCH_DEV | filter_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "report -inN -p" $SCRATCH_DEV | _filter_project_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "project -Cp $projectdir $id" $SCRATCH_DEV | filter_quota
+
+# Let's check that we can recreate the project (flags were cleared out)
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "project -sp $projectdir $id" $SCRATCH_DEV | filter_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "limit -p isoft=20 ihard=20 $id " $SCRATCH_DEV | filter_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "report -inN -p" $SCRATCH_DEV | _filter_project_quota
+$XFS_QUOTA_PROG -D $tmp.projects -P $tmp.projid -x \
+ -c "project -Cp $projectdir $id" $SCRATCH_DEV | filter_quota
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/2000.out b/tests/xfs/2000.out
new file mode 100644
index 000000000000..e53ceb959775
--- /dev/null
+++ b/tests/xfs/2000.out
@@ -0,0 +1,15 @@
+QA output created by 2000
+Setting up project 42 (path SCRATCH_MNT/prj)...
+Processed 1 (PROJECTS_FILE and cmdline) paths for project 42 with recursion depth infinite (-1).
+Checking project 42 (path SCRATCH_MNT/prj)...
+Processed 1 (PROJECTS_FILE and cmdline) paths for project 42 with recursion depth infinite (-1).
+#42 8 20 20 00 [--------]
+
+Clearing project 42 (path SCRATCH_MNT/prj)...
+Processed 1 (PROJECTS_FILE and cmdline) paths for project 42 with recursion depth infinite (-1).
+Setting up project 42 (path SCRATCH_MNT/prj)...
+Processed 1 (PROJECTS_FILE and cmdline) paths for project 42 with recursion depth infinite (-1).
+#42 8 20 20 00 [--------]
+
+Clearing project 42 (path SCRATCH_MNT/prj)...
+Processed 1 (PROJECTS_FILE and cmdline) paths for project 42 with recursion depth infinite (-1).
--
2.50.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr
2025-10-03 9:32 ` [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr Andrey Albershteyn
@ 2025-10-05 10:36 ` Zorro Lang
2025-10-06 9:37 ` Andrey Albershteyn
0 siblings, 1 reply; 10+ messages in thread
From: Zorro Lang @ 2025-10-05 10:36 UTC (permalink / raw)
To: Andrey Albershteyn; +Cc: fstests, linux-fsdevel, linux-xfs, Andrey Albershteyn
On Fri, Oct 03, 2025 at 11:32:44AM +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>
> ---
[snap]
> + 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;
> +
> + 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;
> + }
We should have a _require_* helper to _notrun your generic and xfs test cases,
when system doesn't support the file_getattr/setattr feature. Or we always hit
something test errors like below on old system:
+Can not get fsxattr on ./fifo: Operation not supported
Maybe check if the errno is "Operation not supported", or any better idea?
Thanks,
Zorro
> + if (action) {
> + 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 {
> + if (path2)
> + print_xflags(fsx.fa_xflags, 0, 1, path, 0, 1);
> + else
> + print_xflags(fsx.fa_xflags, 0, 1, path1, 0, 1);
> + }
> +
> + return error;
> +
> +usage:
> + printf("Usage: %s [options]\n", argv[0]);
> + printf("Options:\n");
> + printf("\t--get, -g\t\tget filesystem inode attributes\n");
> + printf("\t--set, -s\t\tset filesystem inode attributes\n");
> + printf("\t--at-cwd, -a\t\topen file at current working directory\n");
> + printf("\t--no-follow, -n\t\tdon't follow symlinks\n");
> + printf("\t--set-nodump, -d\t\tset FS_XFLAG_NODUMP on an inode\n");
> + printf("\t--invalid-at, -i\t\tUse invalid AT_* flag\n");
> + printf("\t--too-big-arg, -b\t\tSet fsxattr size bigger than PAGE_SIZE\n");
> + printf("\t--too-small-arg, -m\t\tSet fsxattr size to 19 bytes\n");
> + printf("\t--new-fsx-flag, -x\t\tUse unknown fa_flags flag\n");
> +
> + return 1;
> +}
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr
2025-10-05 10:36 ` Zorro Lang
@ 2025-10-06 9:37 ` Andrey Albershteyn
2025-10-09 18:56 ` Darrick J. Wong
0 siblings, 1 reply; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-06 9:37 UTC (permalink / raw)
To: Zorro Lang; +Cc: fstests, linux-fsdevel, linux-xfs, Andrey Albershteyn
On 2025-10-05 18:36:56, Zorro Lang wrote:
> On Fri, Oct 03, 2025 at 11:32:44AM +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>
> > ---
>
> [snap]
>
> > + 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;
> > +
> > + 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;
> > + }
>
> We should have a _require_* helper to _notrun your generic and xfs test cases,
> when system doesn't support the file_getattr/setattr feature. Or we always hit
> something test errors like below on old system:
>
> +Can not get fsxattr on ./fifo: Operation not supported
>
> Maybe check if the errno is "Operation not supported", or any better idea?
There's build system check for file_getattr/setattr syscalls, so if
they aren't in the kernel file_attr will not compile.
Then there's _require_test_program "file_attr" in the tests, so
these will not run if kernel doesn't have these syscalls.
However, for XFS for example, there's [1] and [2] which are
necessary for these tests to pass.
So, there a few v6.17 kernels which would still run these tests but
fail for XFS (and still fails as these commits are in for-next now).
For other filesystems generic/ will also fail on newer kernels as it
requires similar modifications as in XFS to support changing file
attributes on special files.
I suppose it make sense for this test to fail for other fs which
don't implement changing file attributes on special files.
Otherwise, this test could be split into generic/ (file_get/setattr
on regular files) and xfs/ (file_get/setattr on special files).
What do you think?
[1]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=8a221004fe5288b66503699a329a6b623be13f91
[2]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=0239bd9fa445a21def88f7e76fe6e0414b2a4da0
>
>
> Thanks,
> Zorro
>
> > + if (action) {
> > + 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 {
> > + if (path2)
> > + print_xflags(fsx.fa_xflags, 0, 1, path, 0, 1);
> > + else
> > + print_xflags(fsx.fa_xflags, 0, 1, path1, 0, 1);
> > + }
> > +
> > + return error;
> > +
> > +usage:
> > + printf("Usage: %s [options]\n", argv[0]);
> > + printf("Options:\n");
> > + printf("\t--get, -g\t\tget filesystem inode attributes\n");
> > + printf("\t--set, -s\t\tset filesystem inode attributes\n");
> > + printf("\t--at-cwd, -a\t\topen file at current working directory\n");
> > + printf("\t--no-follow, -n\t\tdon't follow symlinks\n");
> > + printf("\t--set-nodump, -d\t\tset FS_XFLAG_NODUMP on an inode\n");
> > + printf("\t--invalid-at, -i\t\tUse invalid AT_* flag\n");
> > + printf("\t--too-big-arg, -b\t\tSet fsxattr size bigger than PAGE_SIZE\n");
> > + printf("\t--too-small-arg, -m\t\tSet fsxattr size to 19 bytes\n");
> > + printf("\t--new-fsx-flag, -x\t\tUse unknown fa_flags flag\n");
> > +
> > + return 1;
> > +}
> >
> > --
> > 2.50.1
> >
>
--
- Andrey
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] generic: introduce test to test file_getattr/file_setattr syscalls
2025-10-03 9:32 ` [PATCH v4 2/3] generic: introduce test to test file_getattr/file_setattr syscalls Andrey Albershteyn
@ 2025-10-06 9:55 ` Andrey Albershteyn
0 siblings, 0 replies; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-06 9:55 UTC (permalink / raw)
To: fstests
Cc: zlang, linux-fsdevel, linux-xfs, Andrey Albershteyn,
Darrick J. Wong
On 2025-10-03 11:32:45, Andrey Albershteyn wrote:
> Add a test to test basic functionality of file_getattr() and
> file_setattr() syscalls. Most of the work is done in file_attr
> utility.
>
> Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
ops, Darrick, I forgot to drop your rvb tag as I changed this a bit,
let me know if you have any comments or if I need to resend without
it
> ---
> common/filter | 15 +++++++
> tests/generic/2000 | 109 +++++++++++++++++++++++++++++++++++++++++++++++++
> tests/generic/2000.out | 37 +++++++++++++++++
> 3 files changed, 161 insertions(+)
>
> diff --git a/common/filter b/common/filter
> index bbe13f4c8a8d..b330b27827d0 100644
> --- a/common/filter
> +++ b/common/filter
> @@ -683,5 +683,20 @@ _filter_sysfs_error()
> sed 's/.*: \(.*\)$/\1/'
> }
>
> +# Filter file attributes (aka lsattr/chattr)
> +# To filter X:
> +# ... | _filter_file_attributes X
> +# Or to filter all except X
> +# ... | _filter_file_attributes ~X
> +_filter_file_attributes()
> +{
> + if [[ $1 == ~* ]]; then
> + regex=$(echo "[aAcCdDeEFijmNPsStTuxVX]" | tr -d "$1")
> + else
> + regex="$1"
> + fi
> + awk "{ printf \"%s \", gensub(\"$regex\", \"-\", \"g\", \$1) } {print \$2}"
> +}
> +
this is new
> # make sure this script returns success
> /bin/true
> diff --git a/tests/generic/2000 b/tests/generic/2000
> new file mode 100755
> index 000000000000..16045829031a
> --- /dev/null
> +++ b/tests/generic/2000
> @@ -0,0 +1,109 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2025 Red Hat Inc. All Rights Reserved.
> +#
> +# FS QA Test No. 2000
> +#
> +# Test file_getattr/file_setattr syscalls
> +#
> +. ./common/preamble
> +_begin_fstest auto
> +
> +. ./common/filter
> +
> +# Modify as appropriate.
> +_require_scratch
> +_require_test_program "af_unix"
> +_require_test_program "file_attr"
> +_require_symlinks
> +_require_mknod
> +
> +_scratch_mkfs >>$seqres.full 2>&1
> +_scratch_mount
> +
> +file_attr () {
> + $here/src/file_attr $*
> +}
> +
> +create_af_unix () {
> + $here/src/af_unix $* || echo af_unix failed
> +}
> +
> +projectdir=$SCRATCH_MNT/prj
> +
> +# Create normal files and special files
> +mkdir $projectdir
> +mkfifo $projectdir/fifo
> +mknod $projectdir/chardev c 1 1
> +mknod $projectdir/blockdev b 1 1
> +create_af_unix $projectdir/socket
> +touch $projectdir/foo
> +ln -s $projectdir/foo $projectdir/symlink
> +touch $projectdir/bar
> +ln -s $projectdir/bar $projectdir/broken-symlink
> +rm -f $projectdir/bar
> +
> +echo "Error codes"
> +# wrong AT_ flags
> +file_attr --get --invalid-at $projectdir ./foo
> +file_attr --set --invalid-at $projectdir ./foo
> +# wrong fsxattr size (too big, too small)
> +file_attr --get --too-big-arg $projectdir ./foo
> +file_attr --get --too-small-arg $projectdir ./foo
> +file_attr --set --too-big-arg $projectdir ./foo
> +file_attr --set --too-small-arg $projectdir ./foo
> +# out of fsx_xflags mask
> +file_attr --set --new-fsx-flag $projectdir ./foo
> +
> +echo "Initial attributes state"
> +file_attr --get $projectdir | _filter_scratch | _filter_file_attributes ~d
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
this filter is new
in the test
--
- Andrey
> +file_attr --get $projectdir ./fifo | _filter_file_attributes ~d
> +file_attr --get $projectdir ./chardev | _filter_file_attributes ~d
> +file_attr --get $projectdir ./blockdev | _filter_file_attributes ~d
> +file_attr --get $projectdir ./socket | _filter_file_attributes ~d
> +file_attr --get $projectdir ./foo | _filter_file_attributes ~d
> +file_attr --get $projectdir ./symlink | _filter_file_attributes ~d
> +
> +echo "Set FS_XFLAG_NODUMP (d)"
> +file_attr --set --set-nodump $projectdir
> +file_attr --set --set-nodump $projectdir ./fifo
> +file_attr --set --set-nodump $projectdir ./chardev
> +file_attr --set --set-nodump $projectdir ./blockdev
> +file_attr --set --set-nodump $projectdir ./socket
> +file_attr --set --set-nodump $projectdir ./foo
> +file_attr --set --set-nodump $projectdir ./symlink
> +
> +echo "Read attributes"
> +file_attr --get $projectdir | _filter_scratch | _filter_file_attributes ~d
> +file_attr --get $projectdir ./fifo | _filter_file_attributes ~d
> +file_attr --get $projectdir ./chardev | _filter_file_attributes ~d
> +file_attr --get $projectdir ./blockdev | _filter_file_attributes ~d
> +file_attr --get $projectdir ./socket | _filter_file_attributes ~d
> +file_attr --get $projectdir ./foo | _filter_file_attributes ~d
> +file_attr --get $projectdir ./symlink | _filter_file_attributes ~d
> +
> +echo "Set attribute on broken link with AT_SYMLINK_NOFOLLOW"
> +file_attr --set --set-nodump $projectdir ./broken-symlink
> +file_attr --get $projectdir ./broken-symlink
> +
> +file_attr --set --no-follow --set-nodump $projectdir ./broken-symlink
> +file_attr --get --no-follow $projectdir ./broken-symlink | _filter_file_attributes ~d
> +
> +cd $SCRATCH_MNT
> +touch ./foo2
> +echo "Initial state of foo2"
> +file_attr --get --at-cwd ./foo2 | _filter_file_attributes ~d
> +echo "Set attribute relative to AT_FDCWD"
> +file_attr --set --at-cwd --set-nodump ./foo2
> +file_attr --get --at-cwd ./foo2 | _filter_file_attributes ~d
> +
> +echo "Set attribute on AT_FDCWD"
> +mkdir ./bar
> +file_attr --get --at-cwd ./bar | _filter_file_attributes ~d
> +cd ./bar
> +file_attr --set --at-cwd --set-nodump ""
> +file_attr --get --at-cwd . | _filter_file_attributes ~d
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/2000.out b/tests/generic/2000.out
> new file mode 100644
> index 000000000000..e6fc7381709b
> --- /dev/null
> +++ b/tests/generic/2000.out
> @@ -0,0 +1,37 @@
> +QA output created by 2000
> +Error codes
> +Can not get fsxattr on ./foo: Invalid argument
> +Can not get fsxattr on ./foo: Invalid argument
> +Can not get fsxattr on ./foo: Argument list too long
> +Can not get fsxattr on ./foo: Invalid argument
> +Can not get fsxattr on ./foo: Argument list too long
> +Can not get fsxattr on ./foo: Invalid argument
> +Can not set fsxattr on ./foo: Invalid argument
> +Initial attributes state
> +----------------- SCRATCH_MNT/prj
> +----------------- ./fifo
> +----------------- ./chardev
> +----------------- ./blockdev
> +----------------- ./socket
> +----------------- ./foo
> +----------------- ./symlink
> +Set FS_XFLAG_NODUMP (d)
> +Read attributes
> +------d---------- SCRATCH_MNT/prj
> +------d---------- ./fifo
> +------d---------- ./chardev
> +------d---------- ./blockdev
> +------d---------- ./socket
> +------d---------- ./foo
> +------d---------- ./symlink
> +Set attribute on broken link with AT_SYMLINK_NOFOLLOW
> +Can not get fsxattr on ./broken-symlink: No such file or directory
> +Can not get fsxattr on ./broken-symlink: No such file or directory
> +------d---------- ./broken-symlink
> +Initial state of foo2
> +----------------- ./foo2
> +Set attribute relative to AT_FDCWD
> +------d---------- ./foo2
> +Set attribute on AT_FDCWD
> +----------------- ./bar
> +------d---------- .
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr
2025-10-06 9:37 ` Andrey Albershteyn
@ 2025-10-09 18:56 ` Darrick J. Wong
2025-10-10 9:30 ` Andrey Albershteyn
0 siblings, 1 reply; 10+ messages in thread
From: Darrick J. Wong @ 2025-10-09 18:56 UTC (permalink / raw)
To: Andrey Albershteyn
Cc: Zorro Lang, fstests, linux-fsdevel, linux-xfs, Andrey Albershteyn
On Mon, Oct 06, 2025 at 11:37:53AM +0200, Andrey Albershteyn wrote:
> On 2025-10-05 18:36:56, Zorro Lang wrote:
> > On Fri, Oct 03, 2025 at 11:32:44AM +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>
> > > ---
> >
> > [snap]
> >
> > > + 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;
> > > +
> > > + 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;
> > > + }
> >
> > We should have a _require_* helper to _notrun your generic and xfs test cases,
> > when system doesn't support the file_getattr/setattr feature. Or we always hit
> > something test errors like below on old system:
> >
> > +Can not get fsxattr on ./fifo: Operation not supported
> >
> > Maybe check if the errno is "Operation not supported", or any better idea?
>
> There's build system check for file_getattr/setattr syscalls, so if
> they aren't in the kernel file_attr will not compile.
>
> Then there's _require_test_program "file_attr" in the tests, so
> these will not run if kernel doesn't have these syscalls.
>
> However, for XFS for example, there's [1] and [2] which are
> necessary for these tests to pass.
>
> So, there a few v6.17 kernels which would still run these tests but
> fail for XFS (and still fails as these commits are in for-next now).
>
> For other filesystems generic/ will also fail on newer kernels as it
> requires similar modifications as in XFS to support changing file
> attributes on special files.
>
> I suppose it make sense for this test to fail for other fs which
> don't implement changing file attributes on special files.
> Otherwise, this test could be split into generic/ (file_get/setattr
> on regular files) and xfs/ (file_get/setattr on special files).
>
> What do you think?
generic/772 (and xfs/648) probably each ought to be split into two
pieces -- one for testing file_[gs]etattr on regular/directory files;
and a second one for the special files. All four of them ought to
_notrun if the kernel doesn't support the intended target.
Right now I have injected into both:
mkfifo $projectdir/fifo
$here/src/file_attr --get $projectdir ./fifo &>/dev/null || \
_notrun "file_getattr not supported on $FSTYP"
to make the failures go away on 6.17.
--D
> [1]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=8a221004fe5288b66503699a329a6b623be13f91
> [2]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=0239bd9fa445a21def88f7e76fe6e0414b2a4da0
>
> >
> >
> > Thanks,
> > Zorro
> >
> > > + if (action) {
> > > + 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 {
> > > + if (path2)
> > > + print_xflags(fsx.fa_xflags, 0, 1, path, 0, 1);
> > > + else
> > > + print_xflags(fsx.fa_xflags, 0, 1, path1, 0, 1);
> > > + }
> > > +
> > > + return error;
> > > +
> > > +usage:
> > > + printf("Usage: %s [options]\n", argv[0]);
> > > + printf("Options:\n");
> > > + printf("\t--get, -g\t\tget filesystem inode attributes\n");
> > > + printf("\t--set, -s\t\tset filesystem inode attributes\n");
> > > + printf("\t--at-cwd, -a\t\topen file at current working directory\n");
> > > + printf("\t--no-follow, -n\t\tdon't follow symlinks\n");
> > > + printf("\t--set-nodump, -d\t\tset FS_XFLAG_NODUMP on an inode\n");
> > > + printf("\t--invalid-at, -i\t\tUse invalid AT_* flag\n");
> > > + printf("\t--too-big-arg, -b\t\tSet fsxattr size bigger than PAGE_SIZE\n");
> > > + printf("\t--too-small-arg, -m\t\tSet fsxattr size to 19 bytes\n");
> > > + printf("\t--new-fsx-flag, -x\t\tUse unknown fa_flags flag\n");
> > > +
> > > + return 1;
> > > +}
> > >
> > > --
> > > 2.50.1
> > >
> >
>
> --
> - Andrey
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr
2025-10-09 18:56 ` Darrick J. Wong
@ 2025-10-10 9:30 ` Andrey Albershteyn
2025-10-10 15:30 ` Zorro Lang
0 siblings, 1 reply; 10+ messages in thread
From: Andrey Albershteyn @ 2025-10-10 9:30 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Zorro Lang, fstests, linux-fsdevel, linux-xfs, Andrey Albershteyn
On 2025-10-09 11:56:30, Darrick J. Wong wrote:
> On Mon, Oct 06, 2025 at 11:37:53AM +0200, Andrey Albershteyn wrote:
> > On 2025-10-05 18:36:56, Zorro Lang wrote:
> > > On Fri, Oct 03, 2025 at 11:32:44AM +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>
> > > > ---
> > >
> > > [snap]
> > >
> > > > + 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;
> > > > +
> > > > + 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;
> > > > + }
> > >
> > > We should have a _require_* helper to _notrun your generic and xfs test cases,
> > > when system doesn't support the file_getattr/setattr feature. Or we always hit
> > > something test errors like below on old system:
> > >
> > > +Can not get fsxattr on ./fifo: Operation not supported
> > >
> > > Maybe check if the errno is "Operation not supported", or any better idea?
> >
> > There's build system check for file_getattr/setattr syscalls, so if
> > they aren't in the kernel file_attr will not compile.
> >
> > Then there's _require_test_program "file_attr" in the tests, so
> > these will not run if kernel doesn't have these syscalls.
> >
> > However, for XFS for example, there's [1] and [2] which are
> > necessary for these tests to pass.
> >
> > So, there a few v6.17 kernels which would still run these tests but
> > fail for XFS (and still fails as these commits are in for-next now).
> >
> > For other filesystems generic/ will also fail on newer kernels as it
> > requires similar modifications as in XFS to support changing file
> > attributes on special files.
> >
> > I suppose it make sense for this test to fail for other fs which
> > don't implement changing file attributes on special files.
> > Otherwise, this test could be split into generic/ (file_get/setattr
> > on regular files) and xfs/ (file_get/setattr on special files).
> >
> > What do you think?
>
> generic/772 (and xfs/648) probably each ought to be split into two
> pieces -- one for testing file_[gs]etattr on regular/directory files;
> and a second one for the special files. All four of them ought to
> _notrun if the kernel doesn't support the intended target.
I see, yeah that's what I thought of, I will split them and send new
patchset soon
>
> Right now I have injected into both:
>
> mkfifo $projectdir/fifo
>
> $here/src/file_attr --get $projectdir ./fifo &>/dev/null || \
> _notrun "file_getattr not supported on $FSTYP"
Thanks! Looks like a good check to use
>
> to make the failures go away on 6.17.
>
> --D
>
> > [1]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=8a221004fe5288b66503699a329a6b623be13f91
> > [2]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=0239bd9fa445a21def88f7e76fe6e0414b2a4da0
> >
> > >
> > >
> > > Thanks,
> > > Zorro
> > >
> > > > + if (action) {
> > > > + 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 {
> > > > + if (path2)
> > > > + print_xflags(fsx.fa_xflags, 0, 1, path, 0, 1);
> > > > + else
> > > > + print_xflags(fsx.fa_xflags, 0, 1, path1, 0, 1);
> > > > + }
> > > > +
> > > > + return error;
> > > > +
> > > > +usage:
> > > > + printf("Usage: %s [options]\n", argv[0]);
> > > > + printf("Options:\n");
> > > > + printf("\t--get, -g\t\tget filesystem inode attributes\n");
> > > > + printf("\t--set, -s\t\tset filesystem inode attributes\n");
> > > > + printf("\t--at-cwd, -a\t\topen file at current working directory\n");
> > > > + printf("\t--no-follow, -n\t\tdon't follow symlinks\n");
> > > > + printf("\t--set-nodump, -d\t\tset FS_XFLAG_NODUMP on an inode\n");
> > > > + printf("\t--invalid-at, -i\t\tUse invalid AT_* flag\n");
> > > > + printf("\t--too-big-arg, -b\t\tSet fsxattr size bigger than PAGE_SIZE\n");
> > > > + printf("\t--too-small-arg, -m\t\tSet fsxattr size to 19 bytes\n");
> > > > + printf("\t--new-fsx-flag, -x\t\tUse unknown fa_flags flag\n");
> > > > +
> > > > + return 1;
> > > > +}
> > > >
> > > > --
> > > > 2.50.1
> > > >
> > >
> >
> > --
> > - Andrey
> >
> >
>
--
- Andrey
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr
2025-10-10 9:30 ` Andrey Albershteyn
@ 2025-10-10 15:30 ` Zorro Lang
0 siblings, 0 replies; 10+ messages in thread
From: Zorro Lang @ 2025-10-10 15:30 UTC (permalink / raw)
To: Andrey Albershteyn
Cc: Darrick J. Wong, fstests, linux-fsdevel, linux-xfs,
Andrey Albershteyn
On Fri, Oct 10, 2025 at 11:30:30AM +0200, Andrey Albershteyn wrote:
> On 2025-10-09 11:56:30, Darrick J. Wong wrote:
> > On Mon, Oct 06, 2025 at 11:37:53AM +0200, Andrey Albershteyn wrote:
> > > On 2025-10-05 18:36:56, Zorro Lang wrote:
> > > > On Fri, Oct 03, 2025 at 11:32:44AM +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>
> > > > > ---
> > > >
> > > > [snap]
> > > >
> > > > > + 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;
> > > > > +
> > > > > + 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;
> > > > > + }
> > > >
> > > > We should have a _require_* helper to _notrun your generic and xfs test cases,
> > > > when system doesn't support the file_getattr/setattr feature. Or we always hit
> > > > something test errors like below on old system:
> > > >
> > > > +Can not get fsxattr on ./fifo: Operation not supported
> > > >
> > > > Maybe check if the errno is "Operation not supported", or any better idea?
> > >
> > > There's build system check for file_getattr/setattr syscalls, so if
> > > they aren't in the kernel file_attr will not compile.
> > >
> > > Then there's _require_test_program "file_attr" in the tests, so
> > > these will not run if kernel doesn't have these syscalls.
> > >
> > > However, for XFS for example, there's [1] and [2] which are
> > > necessary for these tests to pass.
> > >
> > > So, there a few v6.17 kernels which would still run these tests but
> > > fail for XFS (and still fails as these commits are in for-next now).
> > >
> > > For other filesystems generic/ will also fail on newer kernels as it
> > > requires similar modifications as in XFS to support changing file
> > > attributes on special files.
> > >
> > > I suppose it make sense for this test to fail for other fs which
> > > don't implement changing file attributes on special files.
> > > Otherwise, this test could be split into generic/ (file_get/setattr
> > > on regular files) and xfs/ (file_get/setattr on special files).
> > >
> > > What do you think?
> >
> > generic/772 (and xfs/648) probably each ought to be split into two
> > pieces -- one for testing file_[gs]etattr on regular/directory files;
> > and a second one for the special files. All four of them ought to
> > _notrun if the kernel doesn't support the intended target.
>
> I see, yeah that's what I thought of, I will split them and send new
> patchset soon
This patchset has been merged, as the feature has been merged, so let's
have the coverage at first. Please feel free to change the cases base on
the newest for-next branch.
>
> >
> > Right now I have injected into both:
> >
> > mkfifo $projectdir/fifo
> >
> > $here/src/file_attr --get $projectdir ./fifo &>/dev/null || \
> > _notrun "file_getattr not supported on $FSTYP"
>
> Thanks! Looks like a good check to use
Yes, use you src/file_attr program in the _require_ helper, refer to
_require_idmapped_mounts or _require_seek_data_hole or others.
Thanks,
Zorro
>
> >
> > to make the failures go away on 6.17.
> >
> > --D
> >
> > > [1]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=8a221004fe5288b66503699a329a6b623be13f91
> > > [2]: https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/commit/?h=for-next&id=0239bd9fa445a21def88f7e76fe6e0414b2a4da0
> > >
> > > >
> > > >
> > > > Thanks,
> > > > Zorro
> > > >
> > > > > + if (action) {
> > > > > + 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 {
> > > > > + if (path2)
> > > > > + print_xflags(fsx.fa_xflags, 0, 1, path, 0, 1);
> > > > > + else
> > > > > + print_xflags(fsx.fa_xflags, 0, 1, path1, 0, 1);
> > > > > + }
> > > > > +
> > > > > + return error;
> > > > > +
> > > > > +usage:
> > > > > + printf("Usage: %s [options]\n", argv[0]);
> > > > > + printf("Options:\n");
> > > > > + printf("\t--get, -g\t\tget filesystem inode attributes\n");
> > > > > + printf("\t--set, -s\t\tset filesystem inode attributes\n");
> > > > > + printf("\t--at-cwd, -a\t\topen file at current working directory\n");
> > > > > + printf("\t--no-follow, -n\t\tdon't follow symlinks\n");
> > > > > + printf("\t--set-nodump, -d\t\tset FS_XFLAG_NODUMP on an inode\n");
> > > > > + printf("\t--invalid-at, -i\t\tUse invalid AT_* flag\n");
> > > > > + printf("\t--too-big-arg, -b\t\tSet fsxattr size bigger than PAGE_SIZE\n");
> > > > > + printf("\t--too-small-arg, -m\t\tSet fsxattr size to 19 bytes\n");
> > > > > + printf("\t--new-fsx-flag, -x\t\tUse unknown fa_flags flag\n");
> > > > > +
> > > > > + return 1;
> > > > > +}
> > > > >
> > > > > --
> > > > > 2.50.1
> > > > >
> > > >
> > >
> > > --
> > > - Andrey
> > >
> > >
> >
>
> --
> - Andrey
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-10-10 15:30 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-03 9:32 [PATCH v4 0/3] Test file_getattr and file_setattr syscalls Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr Andrey Albershteyn
2025-10-05 10:36 ` Zorro Lang
2025-10-06 9:37 ` Andrey Albershteyn
2025-10-09 18:56 ` Darrick J. Wong
2025-10-10 9:30 ` Andrey Albershteyn
2025-10-10 15:30 ` Zorro Lang
2025-10-03 9:32 ` [PATCH v4 2/3] generic: introduce test to test file_getattr/file_setattr syscalls Andrey Albershteyn
2025-10-06 9:55 ` Andrey Albershteyn
2025-10-03 9:32 ` [PATCH v4 3/3] xfs: test quota's project ID on special files Andrey Albershteyn
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).