Control: tags -1 confirmed On 2025-05-24 14:37:26 +0200, László Böszörményi (GCS) wrote: > Package: release.debian.org > Severity: normal > Tags: d-i > User: release.debian....@packages.debian.org > Usertags: unblock > X-Debbugs-Cc: k...@debian.org > Control: affects -1 + src:fuse3 > > Hi RMs, > > Please pre-approve unblocking of package fuse3.
Please go ahead. Cheers > > [ Reason ] > There is still a regression in ceph-fuse due to this library. Upstream > fixed it with three small patches. Also contains a small change in > d/rules which adds sh4 architecture to ones which need to link with > atomic. > Then I've updated the symbols file (also filed as RC bug) to use the > current package version. As the minimal version of the package name > (libfuse3-4) is already 3.17.2 it is more of a formal change. > > [ Impact ] > Without this change, ceph-fuse would not work correctly. Then makes > sh4 architecture in sync with the Trixie release. > > [ Tests ] > I've tested it myself and Jakob Haufe (another DD) also tested this. > > [ Risks ] > This affects the installer due to an udeb, but none of these changes > risk it in my opinion. > > [ Checklist ] > [x] all changes are documented in the d/changelog > [x] I reviewed all changes and I approve them > [x] attach debdiff against the package in testing > > Regards, > Laszlo/GCS > diff -Nru fuse3-3.17.2/debian/changelog fuse3-3.17.2/debian/changelog > --- fuse3-3.17.2/debian/changelog 2025-04-27 08:10:01.000000000 +0200 > +++ fuse3-3.17.2/debian/changelog 2025-05-19 20:39:08.000000000 +0200 > @@ -1,3 +1,17 @@ > +fuse3 (3.17.2-2) unstable; urgency=medium > + > + [ Laszlo Boszormenyi (GCS) ] > + * Backport upstream fixes (closes: #1101305): > + - make conn->want/want_ext conversion non fatal, > + - add container_of and ROUND_UP macros, > + - conn->want conversion: Fix fuse_apply_conn_info_opts() . > + * Update symbols file (closes: #1105099). > + > + [ Helmut Grohne <hel...@subdivi.de> ] > + * Update -latomic architecture list (closes: #1105150). > + > + -- Laszlo Boszormenyi (GCS) <g...@debian.org> Mon, 19 May 2025 20:39:08 > +0200 > + > fuse3 (3.17.2-1) unstable; urgency=medium > > * New upstream release: > diff -Nru fuse3-3.17.2/debian/libfuse3-4.symbols > fuse3-3.17.2/debian/libfuse3-4.symbols > --- fuse3-3.17.2/debian/libfuse3-4.symbols 2025-02-14 22:49:04.000000000 > +0100 > +++ fuse3-3.17.2/debian/libfuse3-4.symbols 2025-05-19 20:39:08.000000000 > +0200 > @@ -1,10 +1,11 @@ > libfuse3.so.4 #PACKAGE# #MINVER# > -* Build-Depends-Package: libfuse-dev > - (symver)FUSE_3.0 3.2.3 > - (symver)FUSE_3.1 3.2.3 > - (symver)FUSE_3.2 3.2.3 > - (symver)FUSE_3.3 3.4.1 > - (symver)FUSE_3.4 3.4.1 > - (symver)FUSE_3.7 3.7.0 > - (symver)FUSE_3.12 3.12.0 > - (symver)FUSE_3.17 3.17.1~rc0 > +* Build-Depends-Package: libfuse3-dev > + (symver)FUSE_3.0 3.17.2 > + (symver)FUSE_3.1 3.17.2 > + (symver)FUSE_3.2 3.17.2 > + (symver)FUSE_3.3 3.17.2 > + (symver)FUSE_3.4 3.17.2 > + (symver)FUSE_3.7 3.17.2 > + (symver)FUSE_3.12 3.17.2 > + (symver)FUSE_3.17 3.17.2 > + (symver)FUSE_3.17.3 3.17.2 > diff -Nru > fuse3-3.17.2/debian/patches/Add-container_of-and-ROUND_UP-macros.patch > fuse3-3.17.2/debian/patches/Add-container_of-and-ROUND_UP-macros.patch > --- fuse3-3.17.2/debian/patches/Add-container_of-and-ROUND_UP-macros.patch > 1970-01-01 01:00:00.000000000 +0100 > +++ fuse3-3.17.2/debian/patches/Add-container_of-and-ROUND_UP-macros.patch > 2025-05-19 20:39:08.000000000 +0200 > @@ -0,0 +1,61 @@ > +From d6a9799fc04e6ada5fd7fd7bbde14fb14981fc8b Mon Sep 17 00:00:00 2001 > +From: Bernd Schubert <bschub...@ddn.com> > +Date: Tue, 15 Apr 2025 22:03:09 +0200 > +Subject: [PATCH] Add container_of and ROUND_UP macros > + > +Needed by follow up commits. container_of is actually > +just moved/consolidated to util.h. > + > +Signed-off-by: Bernd Schubert <bschub...@ddn.com> > +(cherry picked from commit c5a032b3410d7225ac0355355faa63565a209943) > +--- > + lib/fuse.c | 4 ---- > + lib/fuse_lowlevel.c | 4 ---- > + lib/util.h | 6 ++++++ > + 3 files changed, 6 insertions(+), 8 deletions(-) > + > +diff --git a/lib/fuse.c b/lib/fuse.c > +index c0d00edbc..4964de20f 100644 > +--- a/lib/fuse.c > ++++ b/lib/fuse.c > +@@ -92,10 +92,6 @@ struct node_table { > + size_t split; > + }; > + > +-#define container_of(ptr, type, member) ({ \ > +- const typeof( ((type *)0)->member ) *__mptr = (ptr); \ > +- (type *)( (char *)__mptr - offsetof(type,member) );}) > +- > + #define list_entry(ptr, type, member) \ > + container_of(ptr, type, member) > + > +diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c > +index 9ee88b160..cb046aae0 100644 > +--- a/lib/fuse_lowlevel.c > ++++ b/lib/fuse_lowlevel.c > +@@ -44,10 +44,6 @@ > + #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) > + #define OFFSET_MAX 0x7fffffffffffffffLL > + > +-#define container_of(ptr, type, member) ({ \ > +- const typeof( ((type *)0)->member ) *__mptr = (ptr); \ > +- (type *)( (char *)__mptr - offsetof(type,member) );}) > +- > + struct fuse_pollhandle { > + uint64_t kh; > + struct fuse_session *se; > +diff --git a/lib/util.h b/lib/util.h > +index 508fafb12..ed03ad40e 100644 > +--- a/lib/util.h > ++++ b/lib/util.h > +@@ -30,4 +30,10 @@ static inline uint64_t fuse_higher_32_bits(uint64_t nr) > + #define FUSE_VAR_UNUSED(var) (__attribute__((unused)) var) > + #endif > + > ++#define container_of(ptr, type, member) \ > ++ ({ \ > ++ unsigned long __mptr = (unsigned long)(ptr); \ > ++ ((type *)(__mptr - offsetof(type, member))); \ > ++ }) > ++ > + #endif > diff -Nru fuse3-3.17.2/debian/patches/Fix-fuse_apply_conn_info_opts.patch > fuse3-3.17.2/debian/patches/Fix-fuse_apply_conn_info_opts.patch > --- fuse3-3.17.2/debian/patches/Fix-fuse_apply_conn_info_opts.patch > 1970-01-01 01:00:00.000000000 +0100 > +++ fuse3-3.17.2/debian/patches/Fix-fuse_apply_conn_info_opts.patch > 2025-05-19 20:39:08.000000000 +0200 > @@ -0,0 +1,559 @@ > +From 066e8111f0ff522e4682a31bd63b5a3532e8af86 Mon Sep 17 00:00:00 2001 > +From: Bernd Schubert <bschub...@ddn.com> > +Date: Sun, 18 May 2025 00:24:07 +0200 > +Subject: [PATCH] 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 <bschub...@ddn.com> > +--- > + include/fuse_common.h | 50 +++++++++++-------- > + lib/fuse.c | 9 +--- > + lib/fuse_i.h | 38 +++------------ > + lib/fuse_lowlevel.c | 78 ++++++++++++++++++++++++++--- > + lib/fuse_versionscript | 10 ++++ > + lib/helper.c | 15 ++++-- > + lib/util.c | 8 +++ > + lib/util.h | 3 ++ > + test/test_want_conversion.c | 97 ++++++++++++++++++++++--------------- > + 9 files changed, 200 insertions(+), 108 deletions(-) > + > +diff --git a/include/fuse_common.h b/include/fuse_common.h > +index 582505fa9..dd08f444a 100644 > +--- a/include/fuse_common.h > ++++ b/include/fuse_common.h > +@@ -1096,28 +1096,40 @@ void fuse_loop_cfg_convert(struct fuse_loop_config > *config, > + struct fuse_loop_config_v1 *v1_conf); > + #endif > + > ++/** > ++ * Set a feature flag in the want_ext field of fuse_conn_info. > ++ * > ++ * @param conn connection information > ++ * @param flag feature flag to be set > ++ * @return true if the flag was set, false if the flag is not supported > ++ */ > ++bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag); > + > +-static inline bool fuse_set_feature_flag(struct fuse_conn_info *conn, > +- uint64_t flag) > +-{ > +- if (conn->capable_ext & flag) { > +- conn->want_ext |= flag; > +- return true; > +- } > +- return false; > +-} > ++/** > ++ * Unset a feature flag in the want_ext field of fuse_conn_info. > ++ * > ++ * @param conn connection information > ++ * @param flag feature flag to be unset > ++ */ > ++void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag); > ++ > ++/** > ++ * Get the value of a feature flag in the want_ext field of fuse_conn_info. > ++ * > ++ * @param conn connection information > ++ * @param flag feature flag to be checked > ++ * @return true if the flag is set, false otherwise > ++ */ > ++bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag); > ++ > ++/* > ++ * DO NOT USE: Not part of public API, for internal test use only. > ++ * The function signature or any use of it is not guaranteeed to > ++ * remain stable. And neither are results of what this function does. > ++ */ > ++int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn); > + > +-static inline void fuse_unset_feature_flag(struct fuse_conn_info *conn, > +- uint64_t flag) > +-{ > +- conn->want_ext &= ~flag; > +-} > + > +-static inline bool fuse_get_feature_flag(struct fuse_conn_info *conn, > +- uint64_t flag) > +-{ > +- return conn->capable_ext & flag ? true : false; > +-} > + > + /* ----------------------------------------------------------- * > + * Compatibility stuff * > +diff --git a/lib/fuse.c b/lib/fuse.c > +index 4964de20f..85914546e 100644 > +--- a/lib/fuse.c > ++++ b/lib/fuse.c > +@@ -2611,15 +2611,8 @@ void fuse_fs_init(struct fuse_fs *fs, struct > fuse_conn_info *conn, > + fuse_unset_feature_flag(conn, FUSE_CAP_POSIX_LOCKS); > + if (!fs->op.flock) > + fuse_unset_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS); > +- if (fs->op.init) { > +- uint64_t want_ext_default = conn->want_ext; > +- uint32_t want_default = fuse_lower_32_bits(conn->want_ext); > +- > +- conn->want = want_default; > ++ if (fs->op.init) > + fs->user_data = fs->op.init(conn, cfg); > +- > +- convert_to_conn_want_ext(conn, want_ext_default, want_default); > +- } > + } > + > + static int fuse_init_intr_signal(int signum, int *installed); > +diff --git a/lib/fuse_i.h b/lib/fuse_i.h > +index bf5e2ca41..718fa142c 100644 > +--- a/lib/fuse_i.h > ++++ b/lib/fuse_i.h > +@@ -85,6 +85,13 @@ struct fuse_session { > + > + /* true if reading requests from /dev/fuse are handled internally */ > + bool buf_reallocable; > ++ > ++ /* > ++ * conn->want and conn_want_ext options set by libfuse , needed > ++ * to correctly convert want to want_ext > ++ */ > ++ uint32_t conn_want; > ++ uint64_t conn_want_ext; > + }; > + > + struct fuse_chan { > +@@ -227,34 +234,3 @@ int fuse_loop_cfg_verify(struct fuse_loop_config > *config); > + /* room needed in buffer to accommodate header */ > + #define FUSE_BUFFER_HEADER_SIZE 0x1000 > + > +-/** > +- * Get the wanted capability flags, converting from old format if necessary > +- */ > +-static inline int convert_to_conn_want_ext(struct fuse_conn_info *conn, > +- uint64_t want_ext_default, > +- uint32_t want_default) > +-{ > +- /* > +- * Convert want to want_ext if necessary. > +- * For the high level interface this function might be called > +- * twice, once from the high level interface and once from the > +- * low level interface. Both, with different want_ext_default and > +- * want_default values. In order to suppress a failure for the > +- * second call, we check if the lower 32 bits of want_ext are > +- * already set to the value of want. > +- */ > +- if (conn->want != want_default && > +- fuse_lower_32_bits(conn->want_ext) != conn->want) { > +- if (conn->want_ext != want_ext_default) > +- return -EINVAL; > +- > +- /* high bits from want_ext, low bits from want */ > +- conn->want_ext = fuse_higher_32_bits(conn->want_ext) | > +- conn->want; > +- } > +- > +- /* ensure there won't be a second conversion */ > +- conn->want = fuse_lower_32_bits(conn->want_ext); > +- > +- return 0; > +-} > +diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c > +index cb046aae0..1276a0fd9 100644 > +--- a/lib/fuse_lowlevel.c > ++++ b/lib/fuse_lowlevel.c > +@@ -1994,6 +1994,77 @@ static bool want_flags_valid(uint64_t capable, > uint64_t want) > + return true; > + } > + > ++/** > ++ * Get the wanted capability flags, converting from old format if necessary > ++ */ > ++int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn) > ++{ > ++ struct fuse_session *se = container_of(conn, struct fuse_session, conn); > ++ > ++ /* > ++ * Convert want to want_ext if necessary. > ++ * For the high level interface this function might be called > ++ * twice, once from the high level interface and once from the > ++ * low level interface. Both, with different want_ext_default and > ++ * want_default values. In order to suppress a failure for the > ++ * second call, we check if the lower 32 bits of want_ext are > ++ * already set to the value of want. > ++ */ > ++ if (conn->want != se->conn_want && > ++ fuse_lower_32_bits(conn->want_ext) != conn->want) { > ++ if (conn->want_ext != se->conn_want_ext) { > ++ fuse_log(FUSE_LOG_ERR, > ++ "%s: Both conn->want_ext and conn->want are > set.\n" > ++ "want=%x, want_ext=%lx, se->want=%lx > se->want_ext=%lx\n", > ++ __func__, conn->want, conn->want_ext, > ++ se->conn_want, se->conn_want_ext); > ++ return -EINVAL; > ++ } > ++ > ++ /* high bits from want_ext, low bits from want */ > ++ conn->want_ext = fuse_higher_32_bits(conn->want_ext) | > ++ conn->want; > ++ } > ++ > ++ /* ensure there won't be a second conversion */ > ++ conn->want = fuse_lower_32_bits(conn->want_ext); > ++ > ++ return 0; > ++} > ++ > ++bool fuse_set_feature_flag(struct fuse_conn_info *conn, > ++ uint64_t flag) > ++{ > ++ struct fuse_session *se = container_of(conn, struct fuse_session, conn); > ++ > ++ if (conn->capable_ext & flag) { > ++ conn->want_ext |= flag; > ++ se->conn_want_ext |= flag; > ++ conn->want |= flag; > ++ se->conn_want |= flag; > ++ return true; > ++ } > ++ return false; > ++} > ++ > ++void fuse_unset_feature_flag(struct fuse_conn_info *conn, > ++ uint64_t flag) > ++{ > ++ struct fuse_session *se = container_of(conn, struct fuse_session, conn); > ++ > ++ conn->want_ext &= ~flag; > ++ se->conn_want_ext &= ~flag; > ++ conn->want &= ~flag; > ++ se->conn_want &= ~flag; > ++} > ++ > ++bool fuse_get_feature_flag(struct fuse_conn_info *conn, > ++ uint64_t flag) > ++{ > ++ return conn->capable_ext & flag ? true : false; > ++} > ++ > ++ > + /* Prevent bogus data races (bogus since "init" is called before > + * multi-threading becomes relevant */ > + static __attribute__((no_sanitize("thread"))) > +@@ -2154,12 +2225,8 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const > void *inarg) > + > + se->got_init = 1; > + if (se->op.init) { > +- uint64_t want_ext_default = se->conn.want_ext; > +- uint32_t want_default = fuse_lower_32_bits(se->conn.want_ext); > +- > + // Apply the first 32 bits of capable_ext to capable > + se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext); > +- se->conn.want = want_default; > + > + se->op.init(se->userdata, &se->conn); > + > +@@ -2168,8 +2235,7 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const > void *inarg) > + * se->conn.want_ext > + * Userspace might still use conn.want - we need to convert it > + */ > +- convert_to_conn_want_ext(&se->conn, want_ext_default, > +- want_default); > ++ fuse_convert_to_conn_want_ext(&se->conn); > + } > + > + if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) { > +diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript > +index 6c5fc83eb..a2653fcdd 100644 > +--- a/lib/fuse_versionscript > ++++ b/lib/fuse_versionscript > +@@ -202,6 +202,16 @@ FUSE_3.17 { > + fuse_log_close_syslog; > + } FUSE_3.12; > + > ++FUSE_3.17.3 { > ++ global: > ++ fuse_set_feature_flag; > ++ fuse_unset_feature_flag; > ++ fuse_get_feature_flag; > ++ > ++ # Not part of public API, for internal test use only > ++ fuse_convert_to_conn_want_ext; > ++} FUSE_3.17; > ++ > + # Local Variables: > + # indent-tabs-mode: t > + # End: > +diff --git a/lib/helper.c b/lib/helper.c > +index 59dd48881..aceff9fd5 100644 > +--- a/lib/helper.c > ++++ b/lib/helper.c > +@@ -423,10 +423,17 @@ void fuse_apply_conn_info_opts(struct > fuse_conn_info_opts *opts, > + if(opts->set_max_readahead) > + conn->max_readahead = opts->max_readahead; > + > +-#define LL_ENABLE(cond,cap) \ > +- if (cond) conn->want_ext |= (cap) > +-#define LL_DISABLE(cond,cap) \ > +- if (cond) conn->want_ext &= ~(cap) > ++#define LL_ENABLE(cond, cap) \ > ++ do { \ > ++ if (cond) \ > ++ fuse_set_feature_flag(conn, cap); \ > ++ } while (0) > ++ > ++#define LL_DISABLE(cond, cap) \ > ++ do { \ > ++ if (cond) \ > ++ fuse_unset_feature_flag(conn, cap); \ > ++ } while (0) > + > + LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ); > + LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ); > +diff --git a/lib/util.c b/lib/util.c > +index a529d383c..956c3d2e9 100644 > +--- a/lib/util.c > ++++ b/lib/util.c > +@@ -1,7 +1,14 @@ > + #include <stdlib.h> > + #include <errno.h> > + > ++#ifndef FUSE_USE_VERSION > ++#define FUSE_USE_VERSION (FUSE_MAKE_VERSION(3, 18)) > ++#endif > ++ > + #include "util.h" > ++#include "fuse_log.h" > ++#include "fuse_lowlevel.h" > ++#include <stdio.h> > + > + int libfuse_strtol(const char *str, long *res) > + { > +@@ -25,3 +32,4 @@ int libfuse_strtol(const char *str, long *res) > + *res = val; > + return 0; > + } > ++ > +diff --git a/lib/util.h b/lib/util.h > +index ed03ad40e..f24401a29 100644 > +--- a/lib/util.h > ++++ b/lib/util.h > +@@ -2,12 +2,15 @@ > + #define FUSE_UTIL_H_ > + > + #include <stdint.h> > ++#include <stdbool.h> > + > + #define ROUND_UP(val, round_to) (((val) + (round_to - 1)) & ~(round_to - 1)) > + > + #define likely(x) __builtin_expect(!!(x), 1) > + #define unlikely(x) __builtin_expect(!!(x), 0) > + > ++struct fuse_conn_info; > ++ > + int libfuse_strtol(const char *str, long *res); > + > + /** > +diff --git a/test/test_want_conversion.c b/test/test_want_conversion.c > +index bee23cc6e..db731edbf 100644 > +--- a/test/test_want_conversion.c > ++++ b/test/test_want_conversion.c > +@@ -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); > diff -Nru > fuse3-3.17.2/debian/patches/Make_conn-want-want_ext_conversion_non_fatal.patch > > fuse3-3.17.2/debian/patches/Make_conn-want-want_ext_conversion_non_fatal.patch > --- > fuse3-3.17.2/debian/patches/Make_conn-want-want_ext_conversion_non_fatal.patch > 1970-01-01 01:00:00.000000000 +0100 > +++ > fuse3-3.17.2/debian/patches/Make_conn-want-want_ext_conversion_non_fatal.patch > 2025-05-19 20:39:08.000000000 +0200 > @@ -0,0 +1,92 @@ > +From 28a6e40302fbd3eeac1aee9434e1bcf69b1a8e25 Mon Sep 17 00:00:00 2001 > +From: Bernd Schubert <bschub...@ddn.com> > +Date: Sat, 17 May 2025 23:52:47 +0200 > +Subject: [PATCH] Make conn->want/want_ext conversion non fatal > + > +there are too many issues with conn->want and conn->want_ext > +conversion, for now just log a warning, but setting both > +flags is now not fatal anymore. > + > +Signed-off-by: Bernd Schubert <bschub...@ddn.com> > +--- > + lib/fuse.c | 16 +--------------- > + lib/fuse_i.h | 5 +---- > + lib/fuse_lowlevel.c | 9 +-------- > + 3 files changed, 3 insertions(+), 27 deletions(-) > + > +diff --git a/lib/fuse.c b/lib/fuse.c > +index 49f57112a..c0d00edbc 100644 > +--- a/lib/fuse.c > ++++ b/lib/fuse.c > +@@ -2618,25 +2618,11 @@ void fuse_fs_init(struct fuse_fs *fs, struct > fuse_conn_info *conn, > + if (fs->op.init) { > + 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; > + fs->user_data = fs->op.init(conn, cfg); > + > +- rc = convert_to_conn_want_ext(conn, want_ext_default, > +- want_default); > +- > +- if (rc != 0) { > +- /* > +- * This is a grave developer error, but > +- * we cannot return an error here, as the function > +- * signature does not allow it. > +- */ > +- fuse_log( > +- FUSE_LOG_ERR, > +- "fuse: Aborting due to invalid conn want > flags.\n"); > +- _exit(EXIT_FAILURE); > +- } > ++ convert_to_conn_want_ext(conn, want_ext_default, want_default); > + } > + } > + > +diff --git a/lib/fuse_i.h b/lib/fuse_i.h > +index 48b8294f3..bf5e2ca41 100644 > +--- a/lib/fuse_i.h > ++++ b/lib/fuse_i.h > +@@ -245,11 +245,8 @@ static inline int convert_to_conn_want_ext(struct > fuse_conn_info *conn, > + */ > + if (conn->want != want_default && > + fuse_lower_32_bits(conn->want_ext) != conn->want) { > +- if (conn->want_ext != want_ext_default) { > +- fuse_log(FUSE_LOG_ERR, > +- "fuse: both 'want' and 'want_ext' are set\n"); > ++ if (conn->want_ext != want_ext_default) > + return -EINVAL; > +- } > + > + /* high bits from want_ext, low bits from want */ > + conn->want_ext = fuse_higher_32_bits(conn->want_ext) | > +diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c > +index 9ebaaf08e..9ee88b160 100644 > +--- a/lib/fuse_lowlevel.c > ++++ b/lib/fuse_lowlevel.c > +@@ -2160,7 +2160,6 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const > void *inarg) > + if (se->op.init) { > + uint64_t want_ext_default = se->conn.want_ext; > + uint32_t want_default = fuse_lower_32_bits(se->conn.want_ext); > +- int rc; > + > + // Apply the first 32 bits of capable_ext to capable > + se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext); > +@@ -2173,14 +2172,8 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const > void *inarg) > + * se->conn.want_ext > + * Userspace might still use conn.want - we need to convert it > + */ > +- rc = convert_to_conn_want_ext(&se->conn, want_ext_default, > ++ convert_to_conn_want_ext(&se->conn, want_ext_default, > + want_default); > +- if (rc != 0) { > +- fuse_reply_err(req, EPROTO); > +- se->error = -EPROTO; > +- fuse_session_exit(se); > +- return; > +- } > + } > + > + if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) { > diff -Nru fuse3-3.17.2/debian/patches/series > fuse3-3.17.2/debian/patches/series > --- fuse3-3.17.2/debian/patches/series 2025-04-27 08:10:01.000000000 > +0200 > +++ fuse3-3.17.2/debian/patches/series 2025-05-19 20:39:08.000000000 > +0200 > @@ -1,2 +1,5 @@ > Fix_meson_function_tests.patch > meson.build-make-special_funcs-check-more-reliable.patch > +Make_conn-want-want_ext_conversion_non_fatal.patch > +Add-container_of-and-ROUND_UP-macros.patch > +Fix-fuse_apply_conn_info_opts.patch > diff -Nru fuse3-3.17.2/debian/rules fuse3-3.17.2/debian/rules > --- fuse3-3.17.2/debian/rules 2025-02-22 07:44:45.000000000 +0100 > +++ fuse3-3.17.2/debian/rules 2025-05-19 20:39:08.000000000 +0200 > @@ -10,7 +10,7 @@ > > export DEB_BUILD_MAINT_OPTIONS = hardening=+all > > -ifneq (,$(filter $(DEB_HOST_ARCH), armel m68k powerpc)) > +ifneq (,$(filter $(DEB_HOST_ARCH), arc armel m68k mips mipsel powerpc sh3 > sh4 sparc)) > export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed -latomic > endif > -- Sebastian Ramacher