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

Reply via email to