From nobody Mon Nov 03 17:34:03 2025 X-Original-To: dev-commits-src-main@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 4d0dx72Zp7z6F9CK; Mon, 03 Nov 2025 17:34:03 +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 4d0dx71xy1z3scr; Mon, 03 Nov 2025 17:34:03 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1762191243; 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=N8vjAjHe3uy1KRQoqY/vEP/GW5z9VB8iCQKVmANmU9g=; b=En/TfSiw7/43sGfK+0sfi7FWYXEid3xWRgU9J5KuXT2/RbYJv0nE9rRF/bU5uANBAmp35O iVmphYlH65NZgIbwfrYtypZhrG/sHxh8y1HxefVdzVhxIN+RLjB8lhYBX3zjeY+/qmMqYr flIlGFQzR8KmNkaphMm65mrkge9C+9FQxSlVoWBRHUBMSM9JeYWamkYESILyjgDlp1MCRe gQWFZ4WElKgZYuv+1dsEE+nMn2QVgrHg4P8Wz06V1vzVzGXhXpduTmG3Iw70rN1La+irKZ RElizri3TKSv39j3gOXGItiOK47mGxEp97X4YXj4jvXYjAeGMy4jQGU7CrWwEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1762191243; 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=N8vjAjHe3uy1KRQoqY/vEP/GW5z9VB8iCQKVmANmU9g=; b=BFdCiA52v+JNX+m1NzzG7lWEdYNz2oSseR4byqvmbzCg7S6hoY4QmkwBUgW2p3msL3pDzN bmSHtlNDAMaS4dZpCNnRooBmXNCXhOH7MpKMrG9olTH1meHUm0TfNXhDqUSJ6RcCaimu3e Yrazl5AkCcExrdsYzWl67a1YWu7yL8kp6HqvgViEJzvOd9/qP9UMKkNzkf7JHRFriikV2I Z6v0kws3PLA1fkivIyeutUXzEc08JzbBPvSZk2oijar8cvOLZqQmKQ3x2n53QlZJvuR8aj z0BmBDg80wtNcGnj5OvyfZbxsdUYG9gCRO7X/04j/flJ0pmVU2CSIwumyEup/w== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1762191243; a=rsa-sha256; cv=none; b=Iu4X+WSsihNFo/B25XTyDccAcpl6k4DyZOIPADB82ol/C9TVs20gI8ZTuxmxcj9lOWe2ZE cSHPnxKVdawZ84c5iMkhxhMpWILIOprcs898O9IR4zejwFDVPoP7a+pOb9b4PRMfEahdkQ WK4ZIf0cgDmnpr3wyern2nWLKTaoO1rFTXeIR28Zkl4PMhzpRJjGAxRYWl04eZT7ZV2MFP b51RCCyPiodGElpROR7MclNSYbLLhhR3djxwxJpL6w6AGrjT2nBJpWcp6TT7vn8kU7zWfn 6xkBAXxA34rh4qC0xLNNcCq6ST7p7Jbc26htQ8zaJNxCfZqtKwieFA/UnoI6Zw== 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 4d0dx713Wcz5rM; Mon, 03 Nov 2025 17:34:03 +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 5A3HY3tj028750; Mon, 3 Nov 2025 17:34:03 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5A3HY3Fw028747; Mon, 3 Nov 2025 17:34:03 GMT (envelope-from git) Date: Mon, 3 Nov 2025 17:34:03 GMT Message-Id: <202511031734.5A3HY3Fw028747@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alan Somers Subject: git: e8449c0e0fcb - main - fusefs: respect the server's FUSE_SETXATTR_EXT flag List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: asomers X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e8449c0e0fcb8a3eb5872cbee5c3dde4b05a5f50 Auto-Submitted: auto-generated The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=e8449c0e0fcb8a3eb5872cbee5c3dde4b05a5f50 commit e8449c0e0fcb8a3eb5872cbee5c3dde4b05a5f50 Author: Alan Somers AuthorDate: 2025-10-26 18:06:51 +0000 Commit: Alan Somers CommitDate: 2025-11-03 17:14:35 +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. PR: 290547 Co-authored-by: CismonX Fixes: d5e3cf41e89 ("fusefs: Upgrade FUSE protocol to version 7.33") MFC after: 3 days --- 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 97aa23bfb0b0..6c79e646d2f3 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;