mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
conn->want conversion: Fix fuse_apply_conn_info_opts()
fuse_apply_conn_info_opts() was applying to 'want_ext',
which would cause conflicts with 'want' if the application
applied its own flags to 'conn->want'.
Solution is:
- to move fuse_{set,unset,get}_feature_flag and
convert_to_conn_want_ext() to fuse_lowlevel.c and
to define them as part of the public API, although
convert_to_conn_want_ext() should not be used - it is
currently needed to be a public function due as it needs
to be defined for the tests.
Related to https://github.com/libfuse/libfuse/issues/1171 and
https://github.com/libfuse/libfuse/pull/1172.
Closes: https://github.com/libfuse/libfuse/issues/1171
Signed-off-by: Bernd Schubert <bschubert@ddn.com>
This commit is contained in:
committed by
Bernd Schubert
parent
eadd6a5454
commit
baadab0492
+57
-40
@@ -1,16 +1,22 @@
|
||||
#include "util.h"
|
||||
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17)
|
||||
|
||||
#include "util.h"
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <err.h>
|
||||
|
||||
static void print_conn_info(const char *prefix, struct fuse_conn_info *conn)
|
||||
{
|
||||
printf("%s: want=0x%" PRIx32 " want_ext=0x%" PRIx64 "\n", prefix,
|
||||
conn->want, conn->want_ext);
|
||||
struct fuse_session *se = container_of(conn, struct fuse_session, conn);
|
||||
|
||||
printf("%s: want=0x%" PRIx32 " want_ext=0x%" PRIx64
|
||||
" want_default=0x%" PRIx32 " want_ext_default=0x%" PRIx64 "\n",
|
||||
prefix, conn->want, conn->want_ext, se->conn_want,
|
||||
se->conn_want_ext);
|
||||
}
|
||||
|
||||
static void application_init_old_style(struct fuse_conn_info *conn)
|
||||
@@ -18,33 +24,31 @@ static void application_init_old_style(struct fuse_conn_info *conn)
|
||||
/* Simulate application init the old style */
|
||||
conn->want |= FUSE_CAP_ASYNC_READ;
|
||||
conn->want &= ~FUSE_CAP_SPLICE_READ;
|
||||
|
||||
/*
|
||||
* Also use new style API, as that might happen through
|
||||
* fuse_apply_conn_info_opts()
|
||||
*/
|
||||
fuse_set_feature_flag(conn, FUSE_CAP_IOCTL_DIR);
|
||||
}
|
||||
|
||||
static void application_init_new_style(struct fuse_conn_info *conn)
|
||||
{
|
||||
/* Simulate application init the new style */
|
||||
fuse_set_feature_flag(conn, FUSE_CAP_ASYNC_READ);
|
||||
fuse_set_feature_flag(conn, FUSE_CAP_IOCTL_DIR);
|
||||
fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ);
|
||||
}
|
||||
|
||||
static void test_fuse_fs_init(struct fuse_conn_info *conn, bool new_style)
|
||||
{
|
||||
uint64_t want_ext_default = conn->want_ext;
|
||||
uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
|
||||
int rc;
|
||||
|
||||
/* High-level init */
|
||||
fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT);
|
||||
|
||||
conn->want = want_default;
|
||||
|
||||
if (new_style)
|
||||
application_init_new_style(conn);
|
||||
else
|
||||
application_init_old_style(conn);
|
||||
|
||||
rc = convert_to_conn_want_ext(conn, want_ext_default, want_default);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
static void test_do_init(struct fuse_conn_info *conn, bool new_style)
|
||||
@@ -53,49 +57,71 @@ static void test_do_init(struct fuse_conn_info *conn, bool new_style)
|
||||
conn->capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE |
|
||||
FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS |
|
||||
FUSE_CAP_FLOCK_LOCKS | FUSE_CAP_EXPORT_SUPPORT |
|
||||
FUSE_CAP_ASYNC_READ;
|
||||
FUSE_CAP_ASYNC_READ | FUSE_CAP_IOCTL_DIR;
|
||||
conn->capable = fuse_lower_32_bits(conn->capable_ext);
|
||||
conn->want_ext = conn->capable_ext;
|
||||
|
||||
fuse_set_feature_flag(conn, FUSE_CAP_SPLICE_READ |
|
||||
FUSE_CAP_SPLICE_WRITE |
|
||||
FUSE_CAP_SPLICE_MOVE);
|
||||
|
||||
print_conn_info("Initial state", conn);
|
||||
|
||||
uint64_t want_ext_default = conn->want_ext;
|
||||
uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
|
||||
int rc;
|
||||
|
||||
conn->want = want_default;
|
||||
conn->capable = fuse_lower_32_bits(conn->capable_ext);
|
||||
|
||||
test_fuse_fs_init(conn, new_style);
|
||||
print_conn_info("After init", conn);
|
||||
|
||||
rc = convert_to_conn_want_ext(conn, want_ext_default, want_default);
|
||||
rc = fuse_convert_to_conn_want_ext(conn);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Verify all expected flags are set */
|
||||
assert(!(conn->want_ext & FUSE_CAP_SPLICE_READ));
|
||||
assert(conn->want_ext & FUSE_CAP_SPLICE_WRITE);
|
||||
assert(conn->want_ext & FUSE_CAP_SPLICE_MOVE);
|
||||
assert(conn->want_ext & FUSE_CAP_POSIX_LOCKS);
|
||||
assert(conn->want_ext & FUSE_CAP_FLOCK_LOCKS);
|
||||
assert(conn->want_ext & FUSE_CAP_EXPORT_SUPPORT);
|
||||
assert(conn->want_ext & FUSE_CAP_ASYNC_READ);
|
||||
assert(conn->want_ext & FUSE_CAP_IOCTL_DIR);
|
||||
|
||||
/* Verify no other flags are set */
|
||||
assert(conn->want_ext ==
|
||||
(FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE |
|
||||
FUSE_CAP_POSIX_LOCKS | FUSE_CAP_FLOCK_LOCKS |
|
||||
FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_ASYNC_READ));
|
||||
FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_ASYNC_READ |
|
||||
FUSE_CAP_IOCTL_DIR));
|
||||
|
||||
print_conn_info("After init", conn);
|
||||
}
|
||||
|
||||
static void test_want_conversion_basic(void)
|
||||
{
|
||||
struct fuse_conn_info conn = { 0 };
|
||||
const struct fuse_lowlevel_ops ops = { 0 };
|
||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
||||
struct fuse_session *se;
|
||||
struct fuse_conn_info *conn;
|
||||
|
||||
/* Add the program name to arg[0] */
|
||||
if (fuse_opt_add_arg(&args, "test_signals")) {
|
||||
fprintf(stderr, "Failed to add argument\n");
|
||||
errx(1, "Failed to add argument");
|
||||
}
|
||||
|
||||
|
||||
se = fuse_session_new(&args, &ops, sizeof(ops), NULL);
|
||||
assert(se);
|
||||
conn = &se->conn;
|
||||
printf("\nTesting basic want conversion, old style:\n");
|
||||
test_do_init(conn, false);
|
||||
fuse_session_destroy(se);
|
||||
|
||||
se = fuse_session_new(&args, &ops, sizeof(ops), NULL);
|
||||
assert(se);
|
||||
conn = &se->conn;
|
||||
printf("\nTesting basic want conversion, new style:\n");
|
||||
test_do_init(conn, true);
|
||||
print_conn_info("After init", conn);
|
||||
fuse_session_destroy(se);
|
||||
|
||||
fuse_opt_free_args(&args);
|
||||
|
||||
printf("\nTesting basic want conversion:\n");
|
||||
test_do_init(&conn, false);
|
||||
test_do_init(&conn, true);
|
||||
print_conn_info("After init", &conn);
|
||||
}
|
||||
|
||||
static void test_want_conversion_conflict(void)
|
||||
@@ -115,16 +141,11 @@ static void test_want_conversion_conflict(void)
|
||||
conn.want = fuse_lower_32_bits(conn.want_ext);
|
||||
print_conn_info("Test conflict initial", &conn);
|
||||
|
||||
/* Initialize default values like in basic test */
|
||||
uint64_t want_ext_default_ll = conn.want_ext;
|
||||
uint32_t want_default_ll = fuse_lower_32_bits(want_ext_default_ll);
|
||||
|
||||
/* Simulate application init modifying capabilities */
|
||||
conn.want_ext |= FUSE_CAP_ATOMIC_O_TRUNC; /* Add new capability */
|
||||
conn.want &= ~FUSE_CAP_SPLICE_READ; /* Remove a capability */
|
||||
|
||||
rc = convert_to_conn_want_ext(&conn, want_ext_default_ll,
|
||||
want_default_ll);
|
||||
rc = fuse_convert_to_conn_want_ext(&conn);
|
||||
assert(rc == -EINVAL);
|
||||
print_conn_info("Test conflict after", &conn);
|
||||
|
||||
@@ -143,11 +164,7 @@ static void test_want_conversion_high_bits(void)
|
||||
conn.want = fuse_lower_32_bits(conn.want_ext);
|
||||
print_conn_info("Test high bits initial", &conn);
|
||||
|
||||
uint64_t want_ext_default_ll = conn.want_ext;
|
||||
uint32_t want_default_ll = fuse_lower_32_bits(want_ext_default_ll);
|
||||
|
||||
rc = convert_to_conn_want_ext(&conn, want_ext_default_ll,
|
||||
want_default_ll);
|
||||
rc = fuse_convert_to_conn_want_ext(&conn);
|
||||
assert(rc == 0);
|
||||
assert(conn.want_ext == ((1ULL << 33) | FUSE_CAP_ASYNC_READ));
|
||||
print_conn_info("Test high bits after", &conn);
|
||||
|
||||
Reference in New Issue
Block a user