From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3D32285CAB for ; Fri, 3 Oct 2025 09:35:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759484122; cv=none; b=kAbMen8rbirKHO0q1BWXVxv0tjmSYtcvhcKXG/Miv/mBjEQ5zHURA8EoawDBBG6ZNaEp0LN0ovnqyp92LeDcq6fORNJBF40f0IFP9Fqdi/uLaJ2990meke2zUf0XixJ96kiAjl9nMk25WpEwpOgTLdMXqfbVESRgUoZvGjWd23k= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759484122; c=relaxed/simple; bh=1g0F8G0ZJ3aQR1QOcer4WbbNZ4zedOeqU7qRg83YmYs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qXF+tBhDyhluaCgabss/fL+cPnoyxapRKO45IRLIVPK01BT6a3lgJ1quxDBBRzq1sZaXxly0yemLkCs91Qt/oI8j9AhBKbEPHhilwwnlfzxUq4imL2oeV1CHmdaomnjtssZ1mQUhuNA/MOYcfAtupC13L6wbbRalhPd13+4Wst8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=YEbhdqwh; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="YEbhdqwh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1759484118; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TOc2kyXwkfyHFjkUB0VqkLUggJ+gZJQWX3oPeW8H3Q4=; b=YEbhdqwhQaWqxNn+NKnbGZKK8YDadKuiBdemOJvB7rJFoztPAWZ7zKrJRXNuQHO36N7IZw fjyYjcY0BhCDgfE9kp+zFB1IZgJVWg4Z17/zMNiaKqBnDc2D1bJ3Vo1y79jD2MdXJn1d/l dvp/yz8IvOPJu565SH2qfW/0175quPw= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-592-bj_t5p6KPZ22Sap5Ymo3nA-1; Fri, 03 Oct 2025 05:35:17 -0400 X-MC-Unique: bj_t5p6KPZ22Sap5Ymo3nA-1 X-Mimecast-MFC-AGG-ID: bj_t5p6KPZ22Sap5Ymo3nA_1759484116 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-42558f501adso932036f8f.1 for ; Fri, 03 Oct 2025 02:35:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759484116; x=1760088916; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TOc2kyXwkfyHFjkUB0VqkLUggJ+gZJQWX3oPeW8H3Q4=; b=CJff64kX9KM+pSU9xQFfF6kw5blgip/VC+GIVZAok6t8hQlnts/Fl4MrNwMK/riJz8 J61+ing3bWZM3rkPC8AtwG3guk0C5mMJeY8ONAOdXru8Px5Dn513e1J1xozKq6IRlGkb EGG2lpHc1PNg6pWGbqKObQgMmgPETL7lqlzO2NF00/DnkuveIn8c3xaf6v4vZyR/3xPe uK2471dI5yeBdMwrMSsLLOGGnqWttVmSVSciPxKsFbA0CAsveDZzCSFhXAvuBiSZyk6i jR1BdGW5YNx6pSlwFr7UgWZlVu7q40oSJ6r90J20NcNKUFj3uxN0bL2FfZn3dKMkEm5G tfpA== X-Forwarded-Encrypted: i=1; AJvYcCXjEF3cj+VGpSP+kwbXaAdKB3RIrwhoPoQujgwuNYq8pOWO7Us1CHilgXrA3K7EqvKdX9YFDnB/Qxs=@vger.kernel.org X-Gm-Message-State: AOJu0YxuX9Ulep9yXPx3YozV+FSq0cNsAZsa12dYQNwgMiUApgseGsjM deGCQ5dxdTXY3HGMt3qsaVONavXQWaxTqczOii4/x55DAiHC2B0pgAEtbQCPke9BrfI1vPfmCCg k+vCkD2Xk2ZlyM8lg8YQ5K3Xr6j5YlMcH2Sf2HG1MCEXBWp8DgEv6zA8MALZU X-Gm-Gg: ASbGncvb5ZW0CpazPNCgnSZ5LpuMDuKOr2j3JV09CFgP1vxyltYXyUTEAVeAGK4JXjD UfF9TKalzYpMHmBYCCL2bkjkS4E2+4730IZkMJsk+3yaeY4MpEzOEkSVOFZft8h37h9Hyu7WCbZ t20JwW3beDxmtAEVfvuqhhzh45XwrN/SAeAe6Js+4voKjgofs70CLGbagK9v6bWKVMAC4jlVwG5 6F54pxPkQiai4c6gXpL8d+E4AH323fB69ZPopVoesqBrWhMy2WxHIfaQ470tYQZbn/vysPxrw8C VNf6ePC0AKCLGy62yvnnaSa373mkgYkU8HoBx44biq/hAxqAJ3tyOJvQyPXjH0qSQBL9v+G2 X-Received: by 2002:a05:6000:186f:b0:405:3028:1be4 with SMTP id ffacd0b85a97d-42567137c45mr1224017f8f.8.1759484115928; Fri, 03 Oct 2025 02:35:15 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGMaTE01e/q99DbFJ42R9UEeit7urvP487lT806X0Mcy4v5aEZn0ijayMhPp/VypTI+LTBUfw== X-Received: by 2002:a05:6000:186f:b0:405:3028:1be4 with SMTP id ffacd0b85a97d-42567137c45mr1223986f8f.8.1759484115222; Fri, 03 Oct 2025 02:35:15 -0700 (PDT) Received: from [127.0.0.2] (ip-217-030-074-039.aim-net.cz. [217.30.74.39]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-46e61a020a3sm121695005e9.10.2025.10.03.02.35.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Oct 2025 02:35:14 -0700 (PDT) From: Andrey Albershteyn X-Google-Original-From: Andrey Albershteyn Date: Fri, 03 Oct 2025 11:32:44 +0200 Subject: [PATCH v4 1/3] file_attr: introduce program to set/get fsxattr Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20251003-xattrat-syscall-v4-1-1cfe6411c05f@kernel.org> References: <20251003-xattrat-syscall-v4-0-1cfe6411c05f@kernel.org> In-Reply-To: <20251003-xattrat-syscall-v4-0-1cfe6411c05f@kernel.org> To: fstests@vger.kernel.org Cc: zlang@redhat.com, linux-fsdevel@vger.kernel.org, linux-xfs@vger.kernel.org, Andrey Albershteyn X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=9766; i=aalbersh@kernel.org; h=from:subject:message-id; bh=1g0F8G0ZJ3aQR1QOcer4WbbNZ4zedOeqU7qRg83YmYs=; b=kA0DAAoWRqfqGKwz4QgByyZiAGjfmNGglTwF+pprIDFjZ/x9jv8H27qD9FBGuIXM2CF9sZato oh1BAAWCgAdFiEErhsqlWJyGm/EMHwfRqfqGKwz4QgFAmjfmNEACgkQRqfqGKwz4QidogEA7jAu TrCyZMJvjbJs23OW7VgHMOGl9ie2ozc4bvNSVrwA/0bVSFoVR2hD4h35Q2X62tITm4dwLvxQcFw 1fGZavyoK X-Developer-Key: i=aalbersh@kernel.org; a=openpgp; fpr=AE1B2A9562721A6FC4307C1F46A7EA18AC33E108 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 --- .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 +#include + ]], [[ + 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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