All of lore.kernel.org
 help / color / mirror / Atom feed
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
> 
> 

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.