]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Merge patch series "fs: introduce file_getattr and file_setattr syscalls"
authorChristian Brauner <brauner@kernel.org>
Tue, 1 Jul 2025 12:15:14 +0000 (14:15 +0200)
committerChristian Brauner <brauner@kernel.org>
Wed, 2 Jul 2025 15:05:39 +0000 (17:05 +0200)
Andrey Albershteyn <aalbersh@redhat.com> says:

This patchset introduced two new syscalls file_getattr() and
file_setattr(). These syscalls are similar to FS_IOC_FSSETXATTR ioctl()
except they use *at() semantics. Therefore, there's no need to open the
file to get a fd.

These syscalls allow userspace to set filesystem inode attributes on
special files. One of the usage examples is XFS quota projects.

XFS has project quotas which could be attached to a directory. All
new inodes in these directories inherit project ID set on parent
directory.

The project is created from userspace by opening and calling
FS_IOC_FSSETXATTR on each inode. This is not possible for special
files such as FIFO, SOCK, BLK etc. Therefore, some inodes are left
with empty project ID. Those inodes then are not shown in the quota
accounting but still exist in the directory. This is not critical but in
the case when special files are created in the directory with already
existing project quota, these new inodes inherit extended attributes.
This creates a mix of special files with and without attributes.
Moreover, special files with attributes don't have a possibility to
become clear or change the attributes. This, in turn, prevents userspace
from re-creating quota project on these existing files.

An xfstests test generic/766 with basic coverage is at:
https://github.com/alberand/xfstests/commits/b4/file-attr/

NAME

file_getattr/file_setattr - get/set filesystem inode attributes

SYNOPSIS

#include <sys/syscall.h>    /* Definition of SYS_* constants */
#include <unistd.h>

long syscall(SYS_file_getattr, int dirfd, const char *pathname,
struct fsx_fileattr *fsx, size_t size,
unsigned int at_flags);
long syscall(SYS_file_setattr, int dirfd, const char *pathname,
struct fsx_fileattr *fsx, size_t size,
unsigned int at_flags);

Note: glibc doesn't provide for file_getattr()/file_setattr(),
use syscall(2) instead.

DESCRIPTION

The file_getattr()/file_setattr() are used to set extended file
attributes. These syscalls take dirfd in conjunction with the
pathname argument. The syscall then operates on inode opened
according to openat(2) semantics.

This is an alternative to FS_IOC_FSGETXATTR/FS_IOC_FSSETXATTR
ioctl with a difference that file don't need to be open as file
can be referenced with a path instead of fd. By having this one
can manipulated filesystem inode attributes not only on regular
files but also on special ones. This is not possible with
FS_IOC_FSSETXATTR ioctl as ioctl() can not be called on special
files directly for the filesystem inode.

at_flags can be set to AT_SYMLINK_NOFOLLOW or AT_EMPTY_PATH.

RETURN VALUE

On success, 0 is returned.  On error, -1 is returned, and errno
is set to indicate the error.

ERRORS

EINVAL Invalid at_flag specified (only
AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH is
supported).

EINVAL Size was smaller than any known version of
struct fsx_fileattr.

EINVAL Invalid combination of parameters provided in
fsx_fileattr for this type of file.

E2BIG Size of input argument struct fsx_fileattr
is too big.

EBADF Invalid file descriptor was provided.

EPERM No permission to change this file.

EOPNOTSUPP Filesystem does not support setting attributes
on this type of inode

HISTORY

Added in Linux 6.16.

EXAMPLE

Create directory and file "mkdir ./dir && touch ./dir/foo" and then
execute the following program:

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <linux/fs.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>

#if !defined(SYS_file_getattr) && defined(__x86_64__)
#define SYS_file_getattr 468
#define SYS_file_setattr 469

struct fsx_fileattr {
       __u32           fsx_xflags;
       __u32           fsx_extsize;
       __u32           fsx_nextents;
       __u32           fsx_projid;
       __u32           fsx_cowextsize;
};
#endif

int
main(int argc, char **argv) {
        int dfd;
        int error;
        struct fsx_fileattr fsx;

        dfd = open("./dir", O_RDONLY);
        if (dfd == -1) {
                printf("can not open ./dir");
                return dfd;
        }

        error = syscall(SYS_file_getattr, dfd, "./foo", &fsx,
                        sizeof(struct fsx_fileattr), 0);
        if (error) {
                printf("can not call SYS_file_getattr: %s",
strerror(errno));
                return error;
        }

        printf("./dir/foo flags: %d\n", fsx.fsx_xflags);

        fsx.fsx_xflags |= FS_XFLAG_NODUMP;
        error = syscall(SYS_file_setattr, dfd, "./foo", &fsx,
                        sizeof(struct fsx_fileattr), 0);
        if (error) {
printf("can not call SYS_file_setattr: %s",
strerror(errno));
                return error;
        }

        printf("./dir/foo flags: %d\n", fsx.fsx_xflags);

        return error;
}

SEE ALSO

ioctl(2), ioctl_iflags(2), ioctl_xfs_fsgetxattr(2), openat(2)

* patches from https://lore.kernel.org/20250630-xattrat-syscall-v6-0-c4e3bc35227b@kernel.org:
  fs: introduce file_getattr and file_setattr syscalls
  fs: prepare for extending file_get/setattr()
  fs: make vfs_fileattr_[get|set] return -EOPNOSUPP
  selinux: implement inode_file_[g|s]etattr hooks
  lsm: introduce new hooks for setting/getting inode fsxattr
  fs: split fileattr related helpers into separate file

Link: https://lore.kernel.org/20250630-xattrat-syscall-v6-0-c4e3bc35227b@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

Trivial merge