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 <admin@cismon.net>
Fixes: d5e3cf41e8 ("fusefs: Upgrade FUSE protocol to version 7.33")
MFC after: 3 days
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user