From nobody Thu Nov 06 23:11:49 2025 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4d2dHV1GBrz6Ft2N; Thu, 06 Nov 2025 23:11:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4d2dHT6wWdz3gwp; Thu, 06 Nov 2025 23:11:49 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1762470710; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=90SZMqlBxf3FgIco7d2gUff/TAsfOknW2tsLeTCXX0A=; b=u3/1Bn6gRl3M3A9OgZugyJ4WyIsSXGsNQoJDRvHWuywp7WSXQpRVzXODLtmtqHZAEhSGUf SYxbnLD/SccZD/kF8AKJ2cPiTMkiIemwcr2dFS0T8kdpWCE5WSfqkTfmZpRFpQGwhCjd7q QzVZV1iVq3tvOYkdBe/AXEvONv3TnNE8oklTfnSzRb7MlxLAX24414YyITjuyqb5lRtZK6 n7ZurMnYGm0YCFW3vdK6QzRLK4YALNDJ8QymyJdz6dltTL0ytNtSiStDqzhRqf38Nvch/h 2gjszc3jLGwuVvyt1/acKDpJyOo7MPfMOOg0tK7RG/YL+15BOb2OXO6McDZbzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1762470710; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=90SZMqlBxf3FgIco7d2gUff/TAsfOknW2tsLeTCXX0A=; b=xg4NRHw8OhyVY7uTuS/+EjPMavGvoEx0doEnlMKTO72cg3A2MiDAker3pbqa7ZUu4Z6bz0 YilxkKcnuqXfhNGowKeZZjllbw3mg0h9qntlC4uslRIQvRFqnVH0ENtHUg+hqaJ3PTxBVn g+Fgqn8xDQX7n++fAHLNoKDHOQSqSJlm1DpS5KdHDPhf4VHxXl2Yd7xw6G3X+/JP6V6jcb RYsqrkXndMGwmnaXsu0h1dZOUZeyBc16tGuLe0Ovckz7UlGmWWj5ZoKzEjIPd8orXr4hv0 hRSIJPRpVGY+QbFA0MRUGcy/acgiM4yOUTl0+tI+PMfvROdPHTWGLxlAmtOCJw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1762470710; a=rsa-sha256; cv=none; b=wd4uQpdwa8vEAtK+ARhUXlXThrUj0mSK5nKVdiq5jOA2Q4/ZO/kcZQOKRz05KKd8s7Zm7N SmGqk6W28aV8gUkum1WhPWTTcLl0FaFRUiK9aNdNw5Ap3q+63exIlk62CdkZ2ClhtZs3v3 Yz06C6UZ4/YvKZrwVwnDfF42noUH7Qn3SwFL8rP/0ldf7pMXVFkMZSoWxZNpiSBddim4+P UtPDHYL6ao7k9M6lhRMnXUrF2tt+Plwf+/zPSo/JbAzkZ9htSwpqIDTwNJnzHL/gzaw73B 1+ZAi/0CUQFphsaHo9GLhMwccte8gpWn69hTfvXUV56YhlK6Gvorgpeh5bvZsg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4d2dHT6X5Wzb33; Thu, 06 Nov 2025 23:11:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 5A6NBnh5010333; Thu, 6 Nov 2025 23:11:49 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5A6NBnk0010330; Thu, 6 Nov 2025 23:11:49 GMT (envelope-from git) Date: Thu, 6 Nov 2025 23:11:49 GMT Message-Id: <202511062311.5A6NBnk0010330@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Colin Percival Subject: git: a711949115b5 - releng/15.0 - fusefs: respect the server's FUSE_SETXATTR_EXT flag List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: cperciva X-Git-Repository: src X-Git-Refname: refs/heads/releng/15.0 X-Git-Reftype: branch X-Git-Commit: a711949115b589590c19db8489e0a4ab80a6673c Auto-Submitted: auto-generated The branch releng/15.0 has been updated by cperciva: URL: https://cgit.FreeBSD.org/src/commit/?id=a711949115b589590c19db8489e0a4ab80a6673c commit a711949115b589590c19db8489e0a4ab80a6673c Author: Alan Somers AuthorDate: 2025-10-26 18:06:51 +0000 Commit: Colin Percival CommitDate: 2025-11-06 23:10:51 +0000 fusefs: respect the server's FUSE_SETXATTR_EXT flag FUSE protocol 7.33 extended the FUSE_SETXATTR request format. But the extension is optional. The server must opt-in by setting the FUSE_SETXATTR_IN flag during FUSE_INIT. We were wrongly using the extended format for any server using protocol 7.33 or later. Approved by: re (cperciva) PR: 290547 Co-authored-by: CismonX Fixes: d5e3cf41e89 ("fusefs: Upgrade FUSE protocol to version 7.33") MFC after: 3 days (cherry picked from commit e8449c0e0fcb8a3eb5872cbee5c3dde4b05a5f50) (cherry picked from commit a23bd71deaad478cbe41ae756b96ea7a32537311) --- sys/fs/fuse/fuse_internal.c | 5 +++- sys/fs/fuse/fuse_ipc.h | 1 + sys/fs/fuse/fuse_vnops.c | 4 +-- tests/sys/fs/fusefs/xattr.cc | 67 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c index 61fe2ed032f6..eba0a8a79ff3 100644 --- a/sys/fs/fuse/fuse_internal.c +++ b/sys/fs/fuse/fuse_internal.c @@ -1063,6 +1063,8 @@ fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio) if (!fuse_libabi_geq(data, 7, 28)) fsess_set_notimpl(data->mp, FUSE_COPY_FILE_RANGE); + if (fuse_libabi_geq(data, 7, 33) && (fiio->flags & FUSE_SETXATTR_EXT)) + data->dataflags |= FSESS_SETXATTR_EXT; out: if (err) { fdata_set_dead(data); @@ -1115,7 +1117,8 @@ fuse_internal_send_init(struct fuse_data *data, struct thread *td) */ fiii->flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_WRITEBACK_CACHE - | FUSE_NO_OPEN_SUPPORT | FUSE_NO_OPENDIR_SUPPORT; + | FUSE_NO_OPEN_SUPPORT | FUSE_NO_OPENDIR_SUPPORT + | FUSE_SETXATTR_EXT; fuse_insert_callback(fdi.tick, fuse_internal_init_callback); fuse_insert_message(fdi.tick, false); diff --git a/sys/fs/fuse/fuse_ipc.h b/sys/fs/fuse/fuse_ipc.h index 3bfc859dbac9..d9d79f38c269 100644 --- a/sys/fs/fuse/fuse_ipc.h +++ b/sys/fs/fuse/fuse_ipc.h @@ -243,6 +243,7 @@ struct fuse_data { #define FSESS_MNTOPTS_MASK ( \ FSESS_DAEMON_CAN_SPY | FSESS_PUSH_SYMLINKS_IN | \ FSESS_DEFAULT_PERMISSIONS | FSESS_INTR) +#define FSESS_SETXATTR_EXT 0x8000000 /* extended fuse_setxattr_in */ extern int fuse_data_cache_mode; diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index be600b57f0a3..00ad11108ee0 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -2777,7 +2777,7 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap) strlen(ap->a_name) + 1; /* older FUSE servers use a smaller fuse_setxattr_in struct*/ - if (fuse_libabi_geq(fuse_get_mpdata(mp), 7, 33)) + if (fuse_get_mpdata(mp)->dataflags & FSESS_SETXATTR_EXT) struct_size = sizeof(*set_xattr_in); fdisp_init(&fdi, len + struct_size + uio->uio_resid); @@ -2786,7 +2786,7 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap) set_xattr_in = fdi.indata; set_xattr_in->size = uio->uio_resid; - if (fuse_libabi_geq(fuse_get_mpdata(mp), 7, 33)) { + if (fuse_get_mpdata(mp)->dataflags & FSESS_SETXATTR_EXT) { set_xattr_in->setxattr_flags = 0; set_xattr_in->padding = 0; } diff --git a/tests/sys/fs/fusefs/xattr.cc b/tests/sys/fs/fusefs/xattr.cc index 0ab203c96254..afeacd4a249e 100644 --- a/tests/sys/fs/fusefs/xattr.cc +++ b/tests/sys/fs/fusefs/xattr.cc @@ -100,7 +100,11 @@ void expect_removexattr(uint64_t ino, const char *attr, int error) ).WillOnce(Invoke(ReturnErrno(error))); } -void expect_setxattr(uint64_t ino, const char *attr, const char *value, +/* + * Expect a FUSE_SETXATTR request in the format used by protocol 7.33 and + * later, with the FUSE_SETXATTR_EXT bit set. + */ +void expect_setxattr_ext(uint64_t ino, const char *attr, const char *value, ProcessMockerT r) { EXPECT_CALL(*m_mock, process( @@ -119,16 +123,10 @@ void expect_setxattr(uint64_t ino, const char *attr, const char *value, ).WillOnce(Invoke(r)); } -}; - -class Xattr_7_32:public FuseTest { -public: -virtual void SetUp() -{ - m_kernel_minor_version = 32; - FuseTest::SetUp(); -} - +/* + * Expect a FUSE_SETXATTR request in the format used by protocol 7.32 and + * earlier. + */ void expect_setxattr_7_32(uint64_t ino, const char *attr, const char *value, ProcessMockerT r) { @@ -148,6 +146,15 @@ void expect_setxattr_7_32(uint64_t ino, const char *attr, const char *value, } }; +class Xattr_7_32: public Xattr { +public: +virtual void SetUp() +{ + m_kernel_minor_version = 32; + Xattr::SetUp(); +} +}; + class Getxattr: public Xattr {}; class Listxattr: public Xattr {}; @@ -182,6 +189,13 @@ void TearDown() { class Removexattr: public Xattr {}; class Setxattr: public Xattr {}; +class SetxattrExt: public Setxattr { +public: +virtual void SetUp() { + m_init_flags |= FUSE_SETXATTR_EXT; + Setxattr::SetUp(); +} +}; class Setxattr_7_32:public Xattr_7_32 {}; class RofsXattr: public Xattr { public: @@ -773,7 +787,7 @@ TEST_F(Setxattr, enosys) ssize_t r; expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 2); - expect_setxattr(ino, "user.foo", value, ReturnErrno(ENOSYS)); + expect_setxattr_7_32(ino, "user.foo", value, ReturnErrno(ENOSYS)); r = extattr_set_file(FULLPATH, ns, "foo", (const void*)value, value_len); @@ -800,7 +814,7 @@ TEST_F(Setxattr, enotsup) ssize_t r; expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1); - expect_setxattr(ino, "user.foo", value, ReturnErrno(ENOTSUP)); + expect_setxattr_7_32(ino, "user.foo", value, ReturnErrno(ENOTSUP)); r = extattr_set_file(FULLPATH, ns, "foo", (const void*)value, value_len); @@ -820,7 +834,7 @@ TEST_F(Setxattr, user) ssize_t r; expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1); - expect_setxattr(ino, "user.foo", value, ReturnErrno(0)); + expect_setxattr_7_32(ino, "user.foo", value, ReturnErrno(0)); r = extattr_set_file(FULLPATH, ns, "foo", (const void*)value, value_len); @@ -839,7 +853,7 @@ TEST_F(Setxattr, system) ssize_t r; expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1); - expect_setxattr(ino, "system.foo", value, ReturnErrno(0)); + expect_setxattr_7_32(ino, "system.foo", value, ReturnErrno(0)); r = extattr_set_file(FULLPATH, ns, "foo", (const void*)value, value_len); @@ -847,6 +861,10 @@ TEST_F(Setxattr, system) } +/* + * For servers using protocol 7.32 and older, the kernel should use the older + * FUSE_SETXATTR format. + */ TEST_F(Setxattr_7_32, ok) { uint64_t ino = 42; @@ -863,6 +881,25 @@ TEST_F(Setxattr_7_32, ok) ASSERT_EQ(value_len, r) << strerror(errno); } +/* + * Successfully set a user attribute using the extended format + */ +TEST_F(SetxattrExt, user) +{ + uint64_t ino = 42; + const char value[] = "whatever"; + ssize_t value_len = strlen(value) + 1; + int ns = EXTATTR_NAMESPACE_USER; + ssize_t r; + + expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1); + expect_setxattr_ext(ino, "user.foo", value, ReturnErrno(0)); + + r = extattr_set_file(FULLPATH, ns, "foo", (const void*)value, + value_len); + ASSERT_EQ(value_len, r) << strerror(errno); +} + TEST_F(RofsXattr, deleteextattr_erofs) { uint64_t ino = 42;