* [RFC 0/2] fuse/passthrough: simplify daemon crash recovery
@ 2026-01-15 7:20 Chunsheng Luo
2026-01-15 7:20 ` [RFC 1/2] fuse: add close all in passthrough backing close for " Chunsheng Luo
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-15 7:20 UTC (permalink / raw)
To: miklos; +Cc: linux-fsdevel, linux-kernel, Chunsheng Luo
To simplify FUSE daemon crash recovery and reduce performance overhead,
passthrough backing_id information is not persisted. However, this
approach introduces two challenges after daemon restart:
1. Non-persistent backing_ids prevent proper resource cleanup, leading
to resource leaks.
2. New backing_ids allocated for the same FUSE file cause -EIO errors
due to strict fuse_backing validation in
fuse_inode_uncached_io_start(), even when accessing the same
backing file. This persists until all previously opened files are
closed.
There are common scenarios where reusing the cached fuse_inode->fb is
safe:
Scenario 1: The same backing file (with identical inode) is
re-registered after recovery.
Scenario 2: In a read-only FUSE filesystem, the backing file may be
cleaned up and re-downloaded (resulting in a different
inode, but identical content).
Proposed Solution:
1. Enhance fuse_dev_ioctl_backing_close() to support closing all
backing_ids at once, enabling comprehensive resource cleanup after
restart.
2. Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag. When set during
fuse_open(), the kernel prioritizes reusing the existing
fuse_backing cached in fuse_inode, falling back to the
backing_id-associated fb only if the cache is empty.
I'd appreciate any feedback on whether there are better approaches or
potential improvements to this solution.
Thanks.
---
Chunsheng Luo (2):
fuse: add close all in passthrough backing close for crash recovery
fuse: Add new flag to reuse the backing file of fuse_inode
fs/fuse/backing.c | 14 ++++++++++++++
fs/fuse/dev.c | 5 +++++
fs/fuse/fuse_i.h | 1 +
fs/fuse/iomode.c | 2 +-
fs/fuse/passthrough.c | 11 +++++++++++
include/uapi/linux/fuse.h | 2 ++
6 files changed, 34 insertions(+), 1 deletion(-)
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 1/2] fuse: add close all in passthrough backing close for crash recovery
2026-01-15 7:20 [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Chunsheng Luo
@ 2026-01-15 7:20 ` Chunsheng Luo
2026-01-15 12:23 ` Amir Goldstein
2026-01-15 7:20 ` [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode Chunsheng Luo
2026-01-15 15:43 ` [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Amir Goldstein
2 siblings, 1 reply; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-15 7:20 UTC (permalink / raw)
To: miklos; +Cc: linux-fsdevel, linux-kernel, Chunsheng Luo
Simplify FUSE daemon crash recovery by avoiding persistence of
backing_ids, thereby improving availability and reducing performance
overhead.
Non-persistent backing_ids after crash recovery may lead to resource
leaks if backing file resources are not properly cleaned up during
daemon restart.
Add a close_all handler to the backing close operation. This ensures
comprehensive cleanup of all backing file resources when the FUSE
daemon restarts, preventing resource leaks while maintaining the
simplified recovery approach.
Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
---
fs/fuse/backing.c | 14 ++++++++++++++
fs/fuse/dev.c | 5 +++++
fs/fuse/fuse_i.h | 1 +
3 files changed, 20 insertions(+)
diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 4afda419dd14..34d0ea62fb9b 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -166,6 +166,20 @@ int fuse_backing_close(struct fuse_conn *fc, int backing_id)
return err;
}
+static int fuse_backing_close_one(int id, void *p, void *data)
+{
+ struct fuse_conn *fc = data;
+
+ fuse_backing_close(fc, id);
+
+ return 0;
+}
+
+void fuse_backing_close_all(struct fuse_conn *fc)
+{
+ idr_for_each(&fc->backing_files_map, fuse_backing_close_one, fc);
+}
+
struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id)
{
struct fuse_backing *fb;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 6d59cbc877c6..25f6bb58623d 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -2651,6 +2651,11 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
if (get_user(backing_id, argp))
return -EFAULT;
+ if (backing_id == -1) {
+ fuse_backing_close_all(fud->fc);
+ return 0;
+ }
+
return fuse_backing_close(fud->fc, backing_id);
}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 7f16049387d1..6191c02b9ccc 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1573,6 +1573,7 @@ void fuse_backing_files_init(struct fuse_conn *fc);
void fuse_backing_files_free(struct fuse_conn *fc);
int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map);
int fuse_backing_close(struct fuse_conn *fc, int backing_id);
+void fuse_backing_close_all(struct fuse_conn *fc);
/* passthrough.c */
static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi)
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-15 7:20 [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Chunsheng Luo
2026-01-15 7:20 ` [RFC 1/2] fuse: add close all in passthrough backing close for " Chunsheng Luo
@ 2026-01-15 7:20 ` Chunsheng Luo
2026-01-15 13:09 ` Amir Goldstein
2026-01-15 15:43 ` [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Amir Goldstein
2 siblings, 1 reply; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-15 7:20 UTC (permalink / raw)
To: miklos; +Cc: linux-fsdevel, linux-kernel, Chunsheng Luo
To simplify crash recovery and reduce performance impact, backing_ids
are not persisted across daemon restarts. However, this creates a
problem: when the daemon restarts and a process opens the same FUSE
file, a new backing_id may be allocated for the same backing file. If
the inode already has a cached backing file from before the restart,
subsequent open requests with the new backing_id will fail in
fuse_inode_uncached_io_start() due to fb mismatch, even though both
IDs reference the identical underlying file.
Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
issue. When set, the kernel reuses the backing file already cached in
the inode.
Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
---
fs/fuse/iomode.c | 2 +-
fs/fuse/passthrough.c | 11 +++++++++++
include/uapi/linux/fuse.h | 2 ++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
index 3728933188f3..b200bb248598 100644
--- a/fs/fuse/iomode.c
+++ b/fs/fuse/iomode.c
@@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
*/
#define FOPEN_PASSTHROUGH_MASK \
(FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
- FOPEN_NOFLUSH)
+ FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
{
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index 72de97c03d0e..fde4ac0c5737 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
/*
* Setup passthrough to a backing file.
*
+ * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
+ * is set, try to reuse it first before looking up backing_id.
+ *
* Returns an fb object with elevated refcount to be stored in fuse inode.
*/
struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
{
struct fuse_file *ff = file->private_data;
struct fuse_conn *fc = ff->fm->fc;
+ struct fuse_inode *fi = get_fuse_inode(file->f_inode);
struct fuse_backing *fb = NULL;
struct file *backing_file;
int err;
+ if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
+ fb = fuse_backing_get(fuse_inode_backing(fi));
+ if (fb)
+ goto do_open;
+ }
+
err = -EINVAL;
if (backing_id <= 0)
goto out;
@@ -166,6 +176,7 @@ struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
if (!fb)
goto out;
+do_open:
/* Allocate backing file per fuse file to store fuse path */
backing_file = backing_file_open(&file->f_path, file->f_flags,
&fb->file->f_path, fb->cred);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index c13e1f9a2f12..3b681d502fc1 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -383,6 +383,7 @@ struct fuse_file_lock {
* FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
* FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode
* FOPEN_PASSTHROUGH: passthrough read/write io for this open file
+ * FOPEN_PASSTHROUGH_INODE_CACHE: reuse the backing file for passthrough reads/writes
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
@@ -392,6 +393,7 @@ struct fuse_file_lock {
#define FOPEN_NOFLUSH (1 << 5)
#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6)
#define FOPEN_PASSTHROUGH (1 << 7)
+#define FOPEN_PASSTHROUGH_INODE_CACHE (1 << 8)
/**
* INIT request/reply flags
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 1/2] fuse: add close all in passthrough backing close for crash recovery
2026-01-15 7:20 ` [RFC 1/2] fuse: add close all in passthrough backing close for " Chunsheng Luo
@ 2026-01-15 12:23 ` Amir Goldstein
2026-01-15 13:30 ` Chunsheng Luo
0 siblings, 1 reply; 13+ messages in thread
From: Amir Goldstein @ 2026-01-15 12:23 UTC (permalink / raw)
To: Chunsheng Luo; +Cc: miklos, linux-fsdevel, linux-kernel
On Thu, Jan 15, 2026 at 03:20:30PM +0800, Chunsheng Luo wrote:
> Simplify FUSE daemon crash recovery by avoiding persistence of
> backing_ids, thereby improving availability and reducing performance
> overhead.
>
> Non-persistent backing_ids after crash recovery may lead to resource
> leaks if backing file resources are not properly cleaned up during
> daemon restart.
>
> Add a close_all handler to the backing close operation. This ensures
> comprehensive cleanup of all backing file resources when the FUSE
> daemon restarts, preventing resource leaks while maintaining the
> simplified recovery approach.
Am I correct to assume that you are referring to FUSE server restart
where the /dev/fuse fd is stored in an external fd store and reused by
the new FUSE server instance?
>
> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
> ---
> fs/fuse/backing.c | 14 ++++++++++++++
> fs/fuse/dev.c | 5 +++++
> fs/fuse/fuse_i.h | 1 +
> 3 files changed, 20 insertions(+)
>
> diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
> index 4afda419dd14..34d0ea62fb9b 100644
> --- a/fs/fuse/backing.c
> +++ b/fs/fuse/backing.c
> @@ -166,6 +166,20 @@ int fuse_backing_close(struct fuse_conn *fc, int backing_id)
> return err;
> }
>
> +static int fuse_backing_close_one(int id, void *p, void *data)
> +{
> + struct fuse_conn *fc = data;
> +
> + fuse_backing_close(fc, id);
> +
> + return 0;
> +}
> +
> +void fuse_backing_close_all(struct fuse_conn *fc)
> +{
> + idr_for_each(&fc->backing_files_map, fuse_backing_close_one, fc);
> +}
> +
> struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id)
> {
> struct fuse_backing *fb;
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 6d59cbc877c6..25f6bb58623d 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -2651,6 +2651,11 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
> if (get_user(backing_id, argp))
> return -EFAULT;
>
> + if (backing_id == -1) {
> + fuse_backing_close_all(fud->fc);
> + return 0;
> + }
> +
I think that an explicit new ioctl FUSE_DEV_IOC_BACKING_CLOSE_ALL
is called for this very intrusive operation.
Sending FUSE_DEV_IOC_BACKING_CLOSE with backing_id -1 could
just as well happen by mistake.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-15 7:20 ` [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode Chunsheng Luo
@ 2026-01-15 13:09 ` Amir Goldstein
2026-01-15 14:34 ` Chunsheng Luo
0 siblings, 1 reply; 13+ messages in thread
From: Amir Goldstein @ 2026-01-15 13:09 UTC (permalink / raw)
To: Chunsheng Luo; +Cc: miklos, linux-fsdevel, linux-kernel, paullawrence
Hi Chunsheng,
Please CC me for future fuse passthrough patch sets.
On Thu, Jan 15, 2026 at 03:20:31PM +0800, Chunsheng Luo wrote:
> To simplify crash recovery and reduce performance impact, backing_ids
> are not persisted across daemon restarts. However, this creates a
> problem: when the daemon restarts and a process opens the same FUSE
> file, a new backing_id may be allocated for the same backing file. If
> the inode already has a cached backing file from before the restart,
> subsequent open requests with the new backing_id will fail in
> fuse_inode_uncached_io_start() due to fb mismatch, even though both
> IDs reference the identical underlying file.
I don't think that your proposal makes this guaranty.
>
> Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
> issue. When set, the kernel reuses the backing file already cached in
> the inode.
>
> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
> ---
> fs/fuse/iomode.c | 2 +-
> fs/fuse/passthrough.c | 11 +++++++++++
> include/uapi/linux/fuse.h | 2 ++
> 3 files changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> index 3728933188f3..b200bb248598 100644
> --- a/fs/fuse/iomode.c
> +++ b/fs/fuse/iomode.c
> @@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
> */
> #define FOPEN_PASSTHROUGH_MASK \
> (FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
> - FOPEN_NOFLUSH)
> + FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
>
> static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
> {
> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index 72de97c03d0e..fde4ac0c5737 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
> /*
> * Setup passthrough to a backing file.
> *
> + * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
> + * is set, try to reuse it first before looking up backing_id.
> + *
> * Returns an fb object with elevated refcount to be stored in fuse inode.
> */
> struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
> {
> struct fuse_file *ff = file->private_data;
> struct fuse_conn *fc = ff->fm->fc;
> + struct fuse_inode *fi = get_fuse_inode(file->f_inode);
> struct fuse_backing *fb = NULL;
> struct file *backing_file;
> int err;
>
> + if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
> + fb = fuse_backing_get(fuse_inode_backing(fi));
> + if (fb)
> + goto do_open;
> + }
> +
Maybe an explicit FOPEN_PASSTHROUGH_INODE_CACHE flag is a good idea,
but just FYI, I intentionally reserved backing_id 0 for this purpose.
For example, for setting up the backing id on lookup [1] and then
open does not need to specify the backing_id.
[1] https://lore.kernel.org/linux-fsdevel/20250804173228.1990317-1-paullawrence@google.com/
But what you are proposing is a little bit odd API IMO:
"Use this backing_id with this backing file, unless you find another
backing file so use that one instead" - this sounds a bit awkward to me.
I think it would be saner and simpler to relax the check in
fuse_inode_uncached_io_start() to check that old and new fuse_backing
objects refer to the same backing inode:
diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
index 3728933188f30..c6070c361d855 100644
--- a/fs/fuse/iomode.c
+++ b/fs/fuse/iomode.c
@@ -88,9 +88,9 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
int err = 0;
spin_lock(&fi->lock);
- /* deny conflicting backing files on same fuse inode */
+ /* deny conflicting backing inodes on same fuse inode */
oldfb = fuse_inode_backing(fi);
- if (fb && oldfb && oldfb != fb) {
+ if (fb && oldfb && file_inode(oldfb->file) != file_inode(fb->file)) {
err = -EBUSY;
goto unlock;
}
--
I don't think that this requires opt-in flag.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 1/2] fuse: add close all in passthrough backing close for crash recovery
2026-01-15 12:23 ` Amir Goldstein
@ 2026-01-15 13:30 ` Chunsheng Luo
0 siblings, 0 replies; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-15 13:30 UTC (permalink / raw)
To: Amir Goldstein; +Cc: miklos, linux-fsdevel, linux-kernel
On 1/15/26 8:23 PM, Amir Goldstein wrote:
> On Thu, Jan 15, 2026 at 03:20:30PM +0800, Chunsheng Luo wrote:
>> Simplify FUSE daemon crash recovery by avoiding persistence of
>> backing_ids, thereby improving availability and reducing performance
>> overhead.
>>
>> Non-persistent backing_ids after crash recovery may lead to resource
>> leaks if backing file resources are not properly cleaned up during
>> daemon restart.
>>
>> Add a close_all handler to the backing close operation. This ensures
>> comprehensive cleanup of all backing file resources when the FUSE
>> daemon restarts, preventing resource leaks while maintaining the
>> simplified recovery approach.
>
> Am I correct to assume that you are referring to FUSE server restart
> where the /dev/fuse fd is stored in an external fd store and reused by
> the new FUSE server instance?
>
Yes, that's correct.
>>
>> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
>> ---
>> fs/fuse/backing.c | 14 ++++++++++++++
>> fs/fuse/dev.c | 5 +++++
>> fs/fuse/fuse_i.h | 1 +
>> 3 files changed, 20 insertions(+)
>>
>> diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
>> index 4afda419dd14..34d0ea62fb9b 100644
>> --- a/fs/fuse/backing.c
>> +++ b/fs/fuse/backing.c
>> @@ -166,6 +166,20 @@ int fuse_backing_close(struct fuse_conn *fc, int backing_id)
>> return err;
>> }
>>
>> +static int fuse_backing_close_one(int id, void *p, void *data)
>> +{
>> + struct fuse_conn *fc = data;
>> +
>> + fuse_backing_close(fc, id);
>> +
>> + return 0;
>> +}
>> +
>> +void fuse_backing_close_all(struct fuse_conn *fc)
>> +{
>> + idr_for_each(&fc->backing_files_map, fuse_backing_close_one, fc);
>> +}
>> +
>> struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id)
>> {
>> struct fuse_backing *fb;
>> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
>> index 6d59cbc877c6..25f6bb58623d 100644
>> --- a/fs/fuse/dev.c
>> +++ b/fs/fuse/dev.c
>> @@ -2651,6 +2651,11 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
>> if (get_user(backing_id, argp))
>> return -EFAULT;
>>
>> + if (backing_id == -1) {
>> + fuse_backing_close_all(fud->fc);
>> + return 0;
>> + }
>> +
>
> I think that an explicit new ioctl FUSE_DEV_IOC_BACKING_CLOSE_ALL
> is called for this very intrusive operation.
>
> Sending FUSE_DEV_IOC_BACKING_CLOSE with backing_id -1 could
> just as well happen by mistake.
>
> Thanks,
> Amir.
>
>
Okay, thank you for the suggestion.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-15 13:09 ` Amir Goldstein
@ 2026-01-15 14:34 ` Chunsheng Luo
2026-01-15 15:31 ` Amir Goldstein
0 siblings, 1 reply; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-15 14:34 UTC (permalink / raw)
To: Amir Goldstein; +Cc: miklos, linux-fsdevel, linux-kernel, paullawrence
On 1/15/26 9:09 PM, Amir Goldstein wrote:
> Hi Chunsheng,
>
> Please CC me for future fuse passthrough patch sets.
>
Ok.
> On Thu, Jan 15, 2026 at 03:20:31PM +0800, Chunsheng Luo wrote:
>> To simplify crash recovery and reduce performance impact, backing_ids
>> are not persisted across daemon restarts. However, this creates a
>> problem: when the daemon restarts and a process opens the same FUSE
>> file, a new backing_id may be allocated for the same backing file. If
>> the inode already has a cached backing file from before the restart,
>> subsequent open requests with the new backing_id will fail in
>> fuse_inode_uncached_io_start() due to fb mismatch, even though both
>> IDs reference the identical underlying file.
>
> I don't think that your proposal makes this guaranty.
>
Yes, this proposal does not apply to all situations.
>>
>> Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
>> issue. When set, the kernel reuses the backing file already cached in
>> the inode.
>>
>> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
>> ---
>> fs/fuse/iomode.c | 2 +-
>> fs/fuse/passthrough.c | 11 +++++++++++
>> include/uapi/linux/fuse.h | 2 ++
>> 3 files changed, 14 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
>> index 3728933188f3..b200bb248598 100644
>> --- a/fs/fuse/iomode.c
>> +++ b/fs/fuse/iomode.c
>> @@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
>> */
>> #define FOPEN_PASSTHROUGH_MASK \
>> (FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
>> - FOPEN_NOFLUSH)
>> + FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
>>
>> static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
>> {
>> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
>> index 72de97c03d0e..fde4ac0c5737 100644
>> --- a/fs/fuse/passthrough.c
>> +++ b/fs/fuse/passthrough.c
>> @@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
>> /*
>> * Setup passthrough to a backing file.
>> *
>> + * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
>> + * is set, try to reuse it first before looking up backing_id.
>> + *
>> * Returns an fb object with elevated refcount to be stored in fuse inode.
>> */
>> struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
>> {
>> struct fuse_file *ff = file->private_data;
>> struct fuse_conn *fc = ff->fm->fc;
>> + struct fuse_inode *fi = get_fuse_inode(file->f_inode);
>> struct fuse_backing *fb = NULL;
>> struct file *backing_file;
>> int err;
>>
>> + if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
>> + fb = fuse_backing_get(fuse_inode_backing(fi));
>> + if (fb)
>> + goto do_open;
>> + }
>> +
>
> Maybe an explicit FOPEN_PASSTHROUGH_INODE_CACHE flag is a good idea,
> but just FYI, I intentionally reserved backing_id 0 for this purpose.
> For example, for setting up the backing id on lookup [1] and then
> open does not need to specify the backing_id.
>
> [1] https://lore.kernel.org/linux-fsdevel/20250804173228.1990317-1-paullawrence@google.com/
>
This is a great idea. However, we need to consider the lifecycle
management of the backing file associated with a FUSE inode.
Specifically, will the same backing_idbe retained for the entire
lifetime of the FUSE inode until it is deleted?
Additionally, since each backing_idcorresponds to an open file
descriptor (fd) for the backing file, if a fuse_inode holds onto a
backing_id indefinitely without a suitable release mechanism, could this
accumulation of file descriptors cause the process to exceed its open
files limit?
> But what you are proposing is a little bit odd API IMO:
> "Use this backing_id with this backing file, unless you find another
> backing file so use that one instead" - this sounds a bit awkward to me.
>
> I think it would be saner and simpler to relax the check in
> fuse_inode_uncached_io_start() to check that old and new fuse_backing
> objects refer to the same backing inode:
>
> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> index 3728933188f30..c6070c361d855 100644
> --- a/fs/fuse/iomode.c
> +++ b/fs/fuse/iomode.c
> @@ -88,9 +88,9 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
> int err = 0;
>
> spin_lock(&fi->lock);
> - /* deny conflicting backing files on same fuse inode */
> + /* deny conflicting backing inodes on same fuse inode */
> oldfb = fuse_inode_backing(fi);
> - if (fb && oldfb && oldfb != fb) {
> + if (fb && oldfb && file_inode(oldfb->file) != file_inode(fb->file)) {
> err = -EBUSY;
> goto unlock;
> }
> --
>
> I don't think that this requires opt-in flag.
>
> Thanks,
> Amir.
I agree that modifying the condition to `file_inode(oldfb->file) !=
file_inode(fb->file)` is a reasonable fix, and it does address the first
scenario I described.
However, it doesn't fully resolve the second scenario: in a read-only
FUSE filesystem, the backing file itself might be cleaned up and
re-downloaded (resulting in a new inode with identical content). In this
case, reusing the cached fuse_inode's fb after a daemon restart still be
safe, but the inode comparison would incorrectly reject it. Is there a
more robust approach for handling this scenario?
Thanks.
Chunsheng Luo
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-15 14:34 ` Chunsheng Luo
@ 2026-01-15 15:31 ` Amir Goldstein
2026-01-16 2:43 ` Chunsheng Luo
0 siblings, 1 reply; 13+ messages in thread
From: Amir Goldstein @ 2026-01-15 15:31 UTC (permalink / raw)
To: Chunsheng Luo; +Cc: miklos, linux-fsdevel, linux-kernel, paullawrence
On Thu, Jan 15, 2026 at 3:35 PM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>
>
>
> On 1/15/26 9:09 PM, Amir Goldstein wrote:
> > Hi Chunsheng,
> >
> > Please CC me for future fuse passthrough patch sets.
> >
> Ok.
>
> > On Thu, Jan 15, 2026 at 03:20:31PM +0800, Chunsheng Luo wrote:
> >> To simplify crash recovery and reduce performance impact, backing_ids
> >> are not persisted across daemon restarts. However, this creates a
> >> problem: when the daemon restarts and a process opens the same FUSE
> >> file, a new backing_id may be allocated for the same backing file. If
> >> the inode already has a cached backing file from before the restart,
> >> subsequent open requests with the new backing_id will fail in
> >> fuse_inode_uncached_io_start() due to fb mismatch, even though both
> >> IDs reference the identical underlying file.
> >
> > I don't think that your proposal makes this guaranty.
> >
>
> Yes, this proposal does not apply to all situations.
>
> >>
> >> Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
> >> issue. When set, the kernel reuses the backing file already cached in
> >> the inode.
> >>
> >> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
> >> ---
> >> fs/fuse/iomode.c | 2 +-
> >> fs/fuse/passthrough.c | 11 +++++++++++
> >> include/uapi/linux/fuse.h | 2 ++
> >> 3 files changed, 14 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> >> index 3728933188f3..b200bb248598 100644
> >> --- a/fs/fuse/iomode.c
> >> +++ b/fs/fuse/iomode.c
> >> @@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
> >> */
> >> #define FOPEN_PASSTHROUGH_MASK \
> >> (FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
> >> - FOPEN_NOFLUSH)
> >> + FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
> >>
> >> static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
> >> {
> >> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> >> index 72de97c03d0e..fde4ac0c5737 100644
> >> --- a/fs/fuse/passthrough.c
> >> +++ b/fs/fuse/passthrough.c
> >> @@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
> >> /*
> >> * Setup passthrough to a backing file.
> >> *
> >> + * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
> >> + * is set, try to reuse it first before looking up backing_id.
> >> + *
> >> * Returns an fb object with elevated refcount to be stored in fuse inode.
> >> */
> >> struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
> >> {
> >> struct fuse_file *ff = file->private_data;
> >> struct fuse_conn *fc = ff->fm->fc;
> >> + struct fuse_inode *fi = get_fuse_inode(file->f_inode);
> >> struct fuse_backing *fb = NULL;
> >> struct file *backing_file;
> >> int err;
> >>
> >> + if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
> >> + fb = fuse_backing_get(fuse_inode_backing(fi));
> >> + if (fb)
> >> + goto do_open;
> >> + }
> >> +
> >
> > Maybe an explicit FOPEN_PASSTHROUGH_INODE_CACHE flag is a good idea,
> > but just FYI, I intentionally reserved backing_id 0 for this purpose.
> > For example, for setting up the backing id on lookup [1] and then
> > open does not need to specify the backing_id.
> >
> > [1] https://lore.kernel.org/linux-fsdevel/20250804173228.1990317-1-paullawrence@google.com/
> >
>
> This is a great idea. However, we need to consider the lifecycle
> management of the backing file associated with a FUSE inode.
> Specifically, will the same backing_idbe retained for the entire
> lifetime of the FUSE inode until it is deleted?
It's not a good fit for servers that want to change the backing file
(like re-download). For these servers we have the existing file
open-to-close life cycle.
>
> Additionally, since each backing_idcorresponds to an open file
> descriptor (fd) for the backing file, if a fuse_inode holds onto a
> backing_id indefinitely without a suitable release mechanism, could this
> accumulation of file descriptors cause the process to exceed its open
> files limit?
>
There is no such accumulation.
fuse_inode refers to a single fuse_backing object.
fuse_file refers to a single fuse_backing object.
It can be the same (refcounted) object.
> > But what you are proposing is a little bit odd API IMO:
> > "Use this backing_id with this backing file, unless you find another
> > backing file so use that one instead" - this sounds a bit awkward to me.
> >
> > I think it would be saner and simpler to relax the check in
> > fuse_inode_uncached_io_start() to check that old and new fuse_backing
> > objects refer to the same backing inode:
> >
> > diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> > index 3728933188f30..c6070c361d855 100644
> > --- a/fs/fuse/iomode.c
> > +++ b/fs/fuse/iomode.c
> > @@ -88,9 +88,9 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
> > int err = 0;
> >
> > spin_lock(&fi->lock);
> > - /* deny conflicting backing files on same fuse inode */
> > + /* deny conflicting backing inodes on same fuse inode */
> > oldfb = fuse_inode_backing(fi);
> > - if (fb && oldfb && oldfb != fb) {
> > + if (fb && oldfb && file_inode(oldfb->file) != file_inode(fb->file)) {
> > err = -EBUSY;
> > goto unlock;
> > }
> > --
> >
> > I don't think that this requires opt-in flag.
> >
> > Thanks,
> > Amir.
>
> I agree that modifying the condition to `file_inode(oldfb->file) !=
> file_inode(fb->file)` is a reasonable fix, and it does address the first
> scenario I described.
>
> However, it doesn't fully resolve the second scenario: in a read-only
> FUSE filesystem, the backing file itself might be cleaned up and
> re-downloaded (resulting in a new inode with identical content). In this
> case, reusing the cached fuse_inode's fb after a daemon restart still be
> safe, but the inode comparison would incorrectly reject it. Is there a
> more robust approach for handling this scenario?
>
There is a reason we added the restriction against associating
fuse file to different backing inodes.
mmap and reads from different files to the same inode need to be
cache coherent.
IOW, we intentionally do not support this setup without server restart
there is no reason for us to allow that after server restarts because
the consequense will be the same.
It does not sound like a good idea for the server to cleanup files
that are currently opened via fuse passthrough - is that something
that happens intentionally? after server restarts?
You could try to take a write lease to check if the file is currently
open for read/write to avoid cleanup in this case?
Thanks,
Amir.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 0/2] fuse/passthrough: simplify daemon crash recovery
2026-01-15 7:20 [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Chunsheng Luo
2026-01-15 7:20 ` [RFC 1/2] fuse: add close all in passthrough backing close for " Chunsheng Luo
2026-01-15 7:20 ` [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode Chunsheng Luo
@ 2026-01-15 15:43 ` Amir Goldstein
2026-01-16 1:57 ` Chunsheng Luo
2 siblings, 1 reply; 13+ messages in thread
From: Amir Goldstein @ 2026-01-15 15:43 UTC (permalink / raw)
To: Chunsheng Luo; +Cc: miklos, linux-fsdevel, linux-kernel
On Thu, Jan 15, 2026 at 03:20:29PM +0800, Chunsheng Luo wrote:
> To simplify FUSE daemon crash recovery and reduce performance overhead,
> passthrough backing_id information is not persisted. However, this
> approach introduces two challenges after daemon restart:
>
> 1. Non-persistent backing_ids prevent proper resource cleanup, leading
> to resource leaks.
> 2. New backing_ids allocated for the same FUSE file cause -EIO errors
> due to strict fuse_backing validation in
> fuse_inode_uncached_io_start(), even when accessing the same
> backing file. This persists until all previously opened files are
> closed.
>
> There are common scenarios where reusing the cached fuse_inode->fb is
> safe:
>
> Scenario 1: The same backing file (with identical inode) is
> re-registered after recovery.
> Scenario 2: In a read-only FUSE filesystem, the backing file may be
> cleaned up and re-downloaded (resulting in a different
> inode, but identical content).
That is just not acceptable by design, regardless of server restart.
fuse passthrough may be configured per individual file open, but
all fd referring to the same fuse inode need to passthrough to the
same backing inode.
If your server want to serve different fd of same fuse inode from
different backing files (no matter if they claim to have the same content),
server needs to do that with FOPEN_DIRECT_IO, it cannot do that with
FOPEN_PASSTHROUGH.
Thanks,
Amir.
>
> Proposed Solution:
>
> 1. Enhance fuse_dev_ioctl_backing_close() to support closing all
> backing_ids at once, enabling comprehensive resource cleanup after
> restart.
>
> 2. Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag. When set during
> fuse_open(), the kernel prioritizes reusing the existing
> fuse_backing cached in fuse_inode, falling back to the
> backing_id-associated fb only if the cache is empty.
>
> I'd appreciate any feedback on whether there are better approaches or
> potential improvements to this solution.
>
> Thanks.
> ---
> Chunsheng Luo (2):
> fuse: add close all in passthrough backing close for crash recovery
> fuse: Add new flag to reuse the backing file of fuse_inode
>
> fs/fuse/backing.c | 14 ++++++++++++++
> fs/fuse/dev.c | 5 +++++
> fs/fuse/fuse_i.h | 1 +
> fs/fuse/iomode.c | 2 +-
> fs/fuse/passthrough.c | 11 +++++++++++
> include/uapi/linux/fuse.h | 2 ++
> 6 files changed, 34 insertions(+), 1 deletion(-)
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 0/2] fuse/passthrough: simplify daemon crash recovery
2026-01-15 15:43 ` [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Amir Goldstein
@ 2026-01-16 1:57 ` Chunsheng Luo
0 siblings, 0 replies; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-16 1:57 UTC (permalink / raw)
To: Amir Goldstein; +Cc: miklos, linux-fsdevel, linux-kernel
On 1/15/26 11:43 PM, Amir Goldstein wrote:
> On Thu, Jan 15, 2026 at 03:20:29PM +0800, Chunsheng Luo wrote:
>> To simplify FUSE daemon crash recovery and reduce performance overhead,
>> passthrough backing_id information is not persisted. However, this
>> approach introduces two challenges after daemon restart:
>>
>> 1. Non-persistent backing_ids prevent proper resource cleanup, leading
>> to resource leaks.
>> 2. New backing_ids allocated for the same FUSE file cause -EIO errors
>> due to strict fuse_backing validation in
>> fuse_inode_uncached_io_start(), even when accessing the same
>> backing file. This persists until all previously opened files are
>> closed.
>>
>> There are common scenarios where reusing the cached fuse_inode->fb is
>> safe:
>>
>> Scenario 1: The same backing file (with identical inode) is
>> re-registered after recovery.
>> Scenario 2: In a read-only FUSE filesystem, the backing file may be
>> cleaned up and re-downloaded (resulting in a different
>> inode, but identical content).
>
> That is just not acceptable by design, regardless of server restart.
>
> fuse passthrough may be configured per individual file open, but
> all fd referring to the same fuse inode need to passthrough to the
> same backing inode.
>
> If your server want to serve different fd of same fuse inode from
> different backing files (no matter if they claim to have the same content),
> server needs to do that with FOPEN_DIRECT_IO, it cannot do that with
> FOPEN_PASSTHROUGH.
>
> Thanks,
> Amir.
>
That's correct. A reference count for the backing files is certainly
maintained before crash to prevent them from being garbage collected and
to avoid different opens of the same fuse_inode from using different
backing files. However, this count does not survive the crash recovery
process. Consequently, the disk's garbage collection mechanism could
subsequently delete these files.
In this situation, we should consider how to prevent these files from
being mistakenly garbage collected after a crash recovery.
Thanks.
Chunsheng Luo
>>
>> Proposed Solution:
>>
>> 1. Enhance fuse_dev_ioctl_backing_close() to support closing all
>> backing_ids at once, enabling comprehensive resource cleanup after
>> restart.
>>
>> 2. Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag. When set during
>> fuse_open(), the kernel prioritizes reusing the existing
>> fuse_backing cached in fuse_inode, falling back to the
>> backing_id-associated fb only if the cache is empty.
>>
>> I'd appreciate any feedback on whether there are better approaches or
>> potential improvements to this solution.
>>
>> Thanks.
>> ---
>> Chunsheng Luo (2):
>> fuse: add close all in passthrough backing close for crash recovery
>> fuse: Add new flag to reuse the backing file of fuse_inode
>>
>> fs/fuse/backing.c | 14 ++++++++++++++
>> fs/fuse/dev.c | 5 +++++
>> fs/fuse/fuse_i.h | 1 +
>> fs/fuse/iomode.c | 2 +-
>> fs/fuse/passthrough.c | 11 +++++++++++
>> include/uapi/linux/fuse.h | 2 ++
>> 6 files changed, 34 insertions(+), 1 deletion(-)
>>
>> --
>> 2.43.0
>>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-15 15:31 ` Amir Goldstein
@ 2026-01-16 2:43 ` Chunsheng Luo
2026-01-16 19:08 ` Amir Goldstein
0 siblings, 1 reply; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-16 2:43 UTC (permalink / raw)
To: Amir Goldstein; +Cc: miklos, linux-fsdevel, linux-kernel, paullawrence
On 1/15/26 11:31 PM, Amir Goldstein wrote:
> On Thu, Jan 15, 2026 at 3:35 PM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>>
>>
>>
>> On 1/15/26 9:09 PM, Amir Goldstein wrote:
>>> Hi Chunsheng,
>>>
>>> Please CC me for future fuse passthrough patch sets.
>>>
>> Ok.
>>
>>> On Thu, Jan 15, 2026 at 03:20:31PM +0800, Chunsheng Luo wrote:
>>>> To simplify crash recovery and reduce performance impact, backing_ids
>>>> are not persisted across daemon restarts. However, this creates a
>>>> problem: when the daemon restarts and a process opens the same FUSE
>>>> file, a new backing_id may be allocated for the same backing file. If
>>>> the inode already has a cached backing file from before the restart,
>>>> subsequent open requests with the new backing_id will fail in
>>>> fuse_inode_uncached_io_start() due to fb mismatch, even though both
>>>> IDs reference the identical underlying file.
>>>
>>> I don't think that your proposal makes this guaranty.
>>>
>>
>> Yes, this proposal does not apply to all situations.
>>
>>>>
>>>> Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
>>>> issue. When set, the kernel reuses the backing file already cached in
>>>> the inode.
>>>>
>>>> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
>>>> ---
>>>> fs/fuse/iomode.c | 2 +-
>>>> fs/fuse/passthrough.c | 11 +++++++++++
>>>> include/uapi/linux/fuse.h | 2 ++
>>>> 3 files changed, 14 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
>>>> index 3728933188f3..b200bb248598 100644
>>>> --- a/fs/fuse/iomode.c
>>>> +++ b/fs/fuse/iomode.c
>>>> @@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
>>>> */
>>>> #define FOPEN_PASSTHROUGH_MASK \
>>>> (FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
>>>> - FOPEN_NOFLUSH)
>>>> + FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
>>>>
>>>> static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
>>>> {
>>>> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
>>>> index 72de97c03d0e..fde4ac0c5737 100644
>>>> --- a/fs/fuse/passthrough.c
>>>> +++ b/fs/fuse/passthrough.c
>>>> @@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
>>>> /*
>>>> * Setup passthrough to a backing file.
>>>> *
>>>> + * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
>>>> + * is set, try to reuse it first before looking up backing_id.
>>>> + *
>>>> * Returns an fb object with elevated refcount to be stored in fuse inode.
>>>> */
>>>> struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
>>>> {
>>>> struct fuse_file *ff = file->private_data;
>>>> struct fuse_conn *fc = ff->fm->fc;
>>>> + struct fuse_inode *fi = get_fuse_inode(file->f_inode);
>>>> struct fuse_backing *fb = NULL;
>>>> struct file *backing_file;
>>>> int err;
>>>>
>>>> + if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
>>>> + fb = fuse_backing_get(fuse_inode_backing(fi));
>>>> + if (fb)
>>>> + goto do_open;
>>>> + }
>>>> +
>>>
>>> Maybe an explicit FOPEN_PASSTHROUGH_INODE_CACHE flag is a good idea,
>>> but just FYI, I intentionally reserved backing_id 0 for this purpose.
>>> For example, for setting up the backing id on lookup [1] and then
>>> open does not need to specify the backing_id.
>>>
>>> [1] https://lore.kernel.org/linux-fsdevel/20250804173228.1990317-1-paullawrence@google.com/
>>>
>>
>> This is a great idea. However, we need to consider the lifecycle
>> management of the backing file associated with a FUSE inode.
>> Specifically, will the same backing_idbe retained for the entire
>> lifetime of the FUSE inode until it is deleted?
>
> It's not a good fit for servers that want to change the backing file
> (like re-download). For these servers we have the existing file
> open-to-close life cycle.
>
>>
>> Additionally, since each backing_idcorresponds to an open file
>> descriptor (fd) for the backing file, if a fuse_inode holds onto a
>> backing_id indefinitely without a suitable release mechanism, could this
>> accumulation of file descriptors cause the process to exceed its open
>> files limit?
>>
>
> There is no such accumulation.
> fuse_inode refers to a single fuse_backing object.
> fuse_file refers to a single fuse_backing object.
> It can be the same (refcounted) object.
>
Sorry, I wasn't referring to `fuse_backing` refs.
If the lifecycle of `fuse_backing` is the same as `fuse_inode`, and
there are a large number of FUSE files on the file system, then when I
iterate through and open the backing files, register the `fuse_backing`,
and then set it to the `fuse_inode`, the FUSE service will hold a large
number of backing file file descriptors (FDs). These backing file FDs
will only be released when the FUSE files are deleted.
For example, if there are 1000 FUSE files on the file system, and I
iterate through and set the backing file for each `fuse_inode`, then the
FUSE service will hold 1000 backing file FDs for a long time. Extending
this further, if there are even more files, could the FUSE service
process exceed the `ulimit` configuration for open files?
```shell
[root@localhost home]# ulimit -a |grep "open files"
open files (-n) 1024
```
>>> But what you are proposing is a little bit odd API IMO:
>>> "Use this backing_id with this backing file, unless you find another
>>> backing file so use that one instead" - this sounds a bit awkward to me.
>>>
>>> I think it would be saner and simpler to relax the check in
>>> fuse_inode_uncached_io_start() to check that old and new fuse_backing
>>> objects refer to the same backing inode:
>>>
>>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
>>> index 3728933188f30..c6070c361d855 100644
>>> --- a/fs/fuse/iomode.c
>>> +++ b/fs/fuse/iomode.c
>>> @@ -88,9 +88,9 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
>>> int err = 0;
>>>
>>> spin_lock(&fi->lock);
>>> - /* deny conflicting backing files on same fuse inode */
>>> + /* deny conflicting backing inodes on same fuse inode */
>>> oldfb = fuse_inode_backing(fi);
>>> - if (fb && oldfb && oldfb != fb) {
>>> + if (fb && oldfb && file_inode(oldfb->file) != file_inode(fb->file)) {
>>> err = -EBUSY;
>>> goto unlock;
>>> }
>>> --
>>>
>>> I don't think that this requires opt-in flag.
>>>
>>> Thanks,
>>> Amir.
>>
>> I agree that modifying the condition to `file_inode(oldfb->file) !=
>> file_inode(fb->file)` is a reasonable fix, and it does address the first
>> scenario I described.
>>
>> However, it doesn't fully resolve the second scenario: in a read-only
>> FUSE filesystem, the backing file itself might be cleaned up and
>> re-downloaded (resulting in a new inode with identical content). In this
>> case, reusing the cached fuse_inode's fb after a daemon restart still be
>> safe, but the inode comparison would incorrectly reject it. Is there a
>> more robust approach for handling this scenario?
>>
>
> There is a reason we added the restriction against associating
> fuse file to different backing inodes.
>
> mmap and reads from different files to the same inode need to be
> cache coherent.
>
> IOW, we intentionally do not support this setup without server restart
> there is no reason for us to allow that after server restarts because
> the consequense will be the same.
>
> It does not sound like a good idea for the server to cleanup files
> that are currently opened via fuse passthrough - is that something
> that happens intentionally? after server restarts?
>
> You could try to take a write lease to check if the file is currently
> open for read/write to avoid cleanup in this case?
>
> Thanks,
> Amir.
>
>
Yes, it happened after the fuse service crash recovery restart, because
the refs of the backup files were cleaned up, causing them to be
mistakenly garbage collected.
I will consider how to prevent it from being mistakenly garbage
collected by the fuse server.
I will resend the patch, modifying only the condition in
`fuse_inode_uncached_io_start`, changing it to `file_inode(oldfb->file)
!= file_inode(fb->file)`.
Thanks.
Chunsheng Luo
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-16 2:43 ` Chunsheng Luo
@ 2026-01-16 19:08 ` Amir Goldstein
2026-01-17 15:26 ` Chunsheng Luo
0 siblings, 1 reply; 13+ messages in thread
From: Amir Goldstein @ 2026-01-16 19:08 UTC (permalink / raw)
To: Chunsheng Luo; +Cc: miklos, linux-fsdevel, linux-kernel, paullawrence
On Fri, Jan 16, 2026 at 3:43 AM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>
>
>
> On 1/15/26 11:31 PM, Amir Goldstein wrote:
> > On Thu, Jan 15, 2026 at 3:35 PM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
> >>
> >>
> >>
> >> On 1/15/26 9:09 PM, Amir Goldstein wrote:
> >>> Hi Chunsheng,
> >>>
> >>> Please CC me for future fuse passthrough patch sets.
> >>>
> >> Ok.
> >>
> >>> On Thu, Jan 15, 2026 at 03:20:31PM +0800, Chunsheng Luo wrote:
> >>>> To simplify crash recovery and reduce performance impact, backing_ids
> >>>> are not persisted across daemon restarts. However, this creates a
> >>>> problem: when the daemon restarts and a process opens the same FUSE
> >>>> file, a new backing_id may be allocated for the same backing file. If
> >>>> the inode already has a cached backing file from before the restart,
> >>>> subsequent open requests with the new backing_id will fail in
> >>>> fuse_inode_uncached_io_start() due to fb mismatch, even though both
> >>>> IDs reference the identical underlying file.
> >>>
> >>> I don't think that your proposal makes this guaranty.
> >>>
> >>
> >> Yes, this proposal does not apply to all situations.
> >>
> >>>>
> >>>> Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
> >>>> issue. When set, the kernel reuses the backing file already cached in
> >>>> the inode.
> >>>>
> >>>> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
> >>>> ---
> >>>> fs/fuse/iomode.c | 2 +-
> >>>> fs/fuse/passthrough.c | 11 +++++++++++
> >>>> include/uapi/linux/fuse.h | 2 ++
> >>>> 3 files changed, 14 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> >>>> index 3728933188f3..b200bb248598 100644
> >>>> --- a/fs/fuse/iomode.c
> >>>> +++ b/fs/fuse/iomode.c
> >>>> @@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
> >>>> */
> >>>> #define FOPEN_PASSTHROUGH_MASK \
> >>>> (FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
> >>>> - FOPEN_NOFLUSH)
> >>>> + FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
> >>>>
> >>>> static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
> >>>> {
> >>>> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> >>>> index 72de97c03d0e..fde4ac0c5737 100644
> >>>> --- a/fs/fuse/passthrough.c
> >>>> +++ b/fs/fuse/passthrough.c
> >>>> @@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
> >>>> /*
> >>>> * Setup passthrough to a backing file.
> >>>> *
> >>>> + * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
> >>>> + * is set, try to reuse it first before looking up backing_id.
> >>>> + *
> >>>> * Returns an fb object with elevated refcount to be stored in fuse inode.
> >>>> */
> >>>> struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
> >>>> {
> >>>> struct fuse_file *ff = file->private_data;
> >>>> struct fuse_conn *fc = ff->fm->fc;
> >>>> + struct fuse_inode *fi = get_fuse_inode(file->f_inode);
> >>>> struct fuse_backing *fb = NULL;
> >>>> struct file *backing_file;
> >>>> int err;
> >>>>
> >>>> + if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
> >>>> + fb = fuse_backing_get(fuse_inode_backing(fi));
> >>>> + if (fb)
> >>>> + goto do_open;
> >>>> + }
> >>>> +
> >>>
> >>> Maybe an explicit FOPEN_PASSTHROUGH_INODE_CACHE flag is a good idea,
> >>> but just FYI, I intentionally reserved backing_id 0 for this purpose.
> >>> For example, for setting up the backing id on lookup [1] and then
> >>> open does not need to specify the backing_id.
> >>>
> >>> [1] https://lore.kernel.org/linux-fsdevel/20250804173228.1990317-1-paullawrence@google.com/
> >>>
> >>
> >> This is a great idea. However, we need to consider the lifecycle
> >> management of the backing file associated with a FUSE inode.
> >> Specifically, will the same backing_idbe retained for the entire
> >> lifetime of the FUSE inode until it is deleted?
> >
> > It's not a good fit for servers that want to change the backing file
> > (like re-download). For these servers we have the existing file
> > open-to-close life cycle.
> >
> >>
> >> Additionally, since each backing_idcorresponds to an open file
> >> descriptor (fd) for the backing file, if a fuse_inode holds onto a
> >> backing_id indefinitely without a suitable release mechanism, could this
> >> accumulation of file descriptors cause the process to exceed its open
> >> files limit?
> >>
> >
> > There is no such accumulation.
> > fuse_inode refers to a single fuse_backing object.
> > fuse_file refers to a single fuse_backing object.
> > It can be the same (refcounted) object.
> >
>
> Sorry, I wasn't referring to `fuse_backing` refs.
>
> If the lifecycle of `fuse_backing` is the same as `fuse_inode`, and
> there are a large number of FUSE files on the file system, then when I
> iterate through and open the backing files, register the `fuse_backing`,
> and then set it to the `fuse_inode`, the FUSE service will hold a large
> number of backing file file descriptors (FDs). These backing file FDs
> will only be released when the FUSE files are deleted.
>
Not until files are deleted. Until fuse inodes are evicted from inode cache.
FWIW, fuse_inode is ~900 bytes and filp is ~256 bytes, and when memory
is needed, memory shrinker will evict fuse inodes and backing file, so sure
backing files take up memory but not a game changer.
> For example, if there are 1000 FUSE files on the file system, and I
> iterate through and set the backing file for each `fuse_inode`, then the
> FUSE service will hold 1000 backing file FDs for a long time. Extending
> this further, if there are even more files, could the FUSE service
> process exceed the `ulimit` configuration for open files?
>
> ```shell
> [root@localhost home]# ulimit -a |grep "open files"
> open files (-n) 1024
> ```
>
backing files do not account for the open files limit of the FUSE server
that's one of the design issues, but it is by design.
> >>> But what you are proposing is a little bit odd API IMO:
> >>> "Use this backing_id with this backing file, unless you find another
> >>> backing file so use that one instead" - this sounds a bit awkward to me.
> >>>
> >>> I think it would be saner and simpler to relax the check in
> >>> fuse_inode_uncached_io_start() to check that old and new fuse_backing
> >>> objects refer to the same backing inode:
> >>>
> >>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> >>> index 3728933188f30..c6070c361d855 100644
> >>> --- a/fs/fuse/iomode.c
> >>> +++ b/fs/fuse/iomode.c
> >>> @@ -88,9 +88,9 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
> >>> int err = 0;
> >>>
> >>> spin_lock(&fi->lock);
> >>> - /* deny conflicting backing files on same fuse inode */
> >>> + /* deny conflicting backing inodes on same fuse inode */
> >>> oldfb = fuse_inode_backing(fi);
> >>> - if (fb && oldfb && oldfb != fb) {
> >>> + if (fb && oldfb && file_inode(oldfb->file) != file_inode(fb->file)) {
> >>> err = -EBUSY;
> >>> goto unlock;
> >>> }
> >>> --
> >>>
> >>> I don't think that this requires opt-in flag.
> >>>
> >>> Thanks,
> >>> Amir.
> >>
> >> I agree that modifying the condition to `file_inode(oldfb->file) !=
> >> file_inode(fb->file)` is a reasonable fix, and it does address the first
> >> scenario I described.
> >>
> >> However, it doesn't fully resolve the second scenario: in a read-only
> >> FUSE filesystem, the backing file itself might be cleaned up and
> >> re-downloaded (resulting in a new inode with identical content). In this
> >> case, reusing the cached fuse_inode's fb after a daemon restart still be
> >> safe, but the inode comparison would incorrectly reject it. Is there a
> >> more robust approach for handling this scenario?
> >>
> >
> > There is a reason we added the restriction against associating
> > fuse file to different backing inodes.
> >
> > mmap and reads from different files to the same inode need to be
> > cache coherent.
> >
> > IOW, we intentionally do not support this setup without server restart
> > there is no reason for us to allow that after server restarts because
> > the consequense will be the same.
> >
> > It does not sound like a good idea for the server to cleanup files
> > that are currently opened via fuse passthrough - is that something
> > that happens intentionally? after server restarts?
> >
> > You could try to take a write lease to check if the file is currently
> > open for read/write to avoid cleanup in this case?
> >
> > Thanks,
> > Amir.
> >
> >
>
> Yes, it happened after the fuse service crash recovery restart, because
> the refs of the backup files were cleaned up, causing them to be
> mistakenly garbage collected.
>
> I will consider how to prevent it from being mistakenly garbage
> collected by the fuse server.
See here https://github.com/amir73il/fsnotify-utils/wiki/Hierarchical-Storage-Management-API#evicting-file-content
explanation how you can use F_SETLEASE to synchronize evicting
file content with file content readers.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode
2026-01-16 19:08 ` Amir Goldstein
@ 2026-01-17 15:26 ` Chunsheng Luo
0 siblings, 0 replies; 13+ messages in thread
From: Chunsheng Luo @ 2026-01-17 15:26 UTC (permalink / raw)
To: Amir Goldstein; +Cc: miklos, linux-fsdevel, linux-kernel, paullawrence
On 1/17/26 3:08 AM, Amir Goldstein wrote:
> On Fri, Jan 16, 2026 at 3:43 AM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>>
>>
>>
>> On 1/15/26 11:31 PM, Amir Goldstein wrote:
>>> On Thu, Jan 15, 2026 at 3:35 PM Chunsheng Luo <luochunsheng@ustc.edu> wrote:
>>>>
>>>>
>>>>
>>>> On 1/15/26 9:09 PM, Amir Goldstein wrote:
>>>>> Hi Chunsheng,
>>>>>
>>>>> Please CC me for future fuse passthrough patch sets.
>>>>>
>>>> Ok.
>>>>
>>>>> On Thu, Jan 15, 2026 at 03:20:31PM +0800, Chunsheng Luo wrote:
>>>>>> To simplify crash recovery and reduce performance impact, backing_ids
>>>>>> are not persisted across daemon restarts. However, this creates a
>>>>>> problem: when the daemon restarts and a process opens the same FUSE
>>>>>> file, a new backing_id may be allocated for the same backing file. If
>>>>>> the inode already has a cached backing file from before the restart,
>>>>>> subsequent open requests with the new backing_id will fail in
>>>>>> fuse_inode_uncached_io_start() due to fb mismatch, even though both
>>>>>> IDs reference the identical underlying file.
>>>>>
>>>>> I don't think that your proposal makes this guaranty.
>>>>>
>>>>
>>>> Yes, this proposal does not apply to all situations.
>>>>
>>>>>>
>>>>>> Introduce the FOPEN_PASSTHROUGH_INODE_CACHE flag to address this
>>>>>> issue. When set, the kernel reuses the backing file already cached in
>>>>>> the inode.
>>>>>>
>>>>>> Signed-off-by: Chunsheng Luo <luochunsheng@ustc.edu>
>>>>>> ---
>>>>>> fs/fuse/iomode.c | 2 +-
>>>>>> fs/fuse/passthrough.c | 11 +++++++++++
>>>>>> include/uapi/linux/fuse.h | 2 ++
>>>>>> 3 files changed, 14 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
>>>>>> index 3728933188f3..b200bb248598 100644
>>>>>> --- a/fs/fuse/iomode.c
>>>>>> +++ b/fs/fuse/iomode.c
>>>>>> @@ -163,7 +163,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
>>>>>> */
>>>>>> #define FOPEN_PASSTHROUGH_MASK \
>>>>>> (FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
>>>>>> - FOPEN_NOFLUSH)
>>>>>> + FOPEN_NOFLUSH | FOPEN_PASSTHROUGH_INODE_CACHE)
>>>>>>
>>>>>> static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
>>>>>> {
>>>>>> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
>>>>>> index 72de97c03d0e..fde4ac0c5737 100644
>>>>>> --- a/fs/fuse/passthrough.c
>>>>>> +++ b/fs/fuse/passthrough.c
>>>>>> @@ -147,16 +147,26 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
>>>>>> /*
>>>>>> * Setup passthrough to a backing file.
>>>>>> *
>>>>>> + * If fuse inode backing is provided and FOPEN_PASSTHROUGH_INODE_CACHE flag
>>>>>> + * is set, try to reuse it first before looking up backing_id.
>>>>>> + *
>>>>>> * Returns an fb object with elevated refcount to be stored in fuse inode.
>>>>>> */
>>>>>> struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
>>>>>> {
>>>>>> struct fuse_file *ff = file->private_data;
>>>>>> struct fuse_conn *fc = ff->fm->fc;
>>>>>> + struct fuse_inode *fi = get_fuse_inode(file->f_inode);
>>>>>> struct fuse_backing *fb = NULL;
>>>>>> struct file *backing_file;
>>>>>> int err;
>>>>>>
>>>>>> + if (ff->open_flags & FOPEN_PASSTHROUGH_INODE_CACHE) {
>>>>>> + fb = fuse_backing_get(fuse_inode_backing(fi));
>>>>>> + if (fb)
>>>>>> + goto do_open;
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Maybe an explicit FOPEN_PASSTHROUGH_INODE_CACHE flag is a good idea,
>>>>> but just FYI, I intentionally reserved backing_id 0 for this purpose.
>>>>> For example, for setting up the backing id on lookup [1] and then
>>>>> open does not need to specify the backing_id.
>>>>>
>>>>> [1] https://lore.kernel.org/linux-fsdevel/20250804173228.1990317-1-paullawrence@google.com/
>>>>>
>>>>
>>>> This is a great idea. However, we need to consider the lifecycle
>>>> management of the backing file associated with a FUSE inode.
>>>> Specifically, will the same backing_idbe retained for the entire
>>>> lifetime of the FUSE inode until it is deleted?
>>>
>>> It's not a good fit for servers that want to change the backing file
>>> (like re-download). For these servers we have the existing file
>>> open-to-close life cycle.
>>>
>>>>
>>>> Additionally, since each backing_idcorresponds to an open file
>>>> descriptor (fd) for the backing file, if a fuse_inode holds onto a
>>>> backing_id indefinitely without a suitable release mechanism, could this
>>>> accumulation of file descriptors cause the process to exceed its open
>>>> files limit?
>>>>
>>>
>>> There is no such accumulation.
>>> fuse_inode refers to a single fuse_backing object.
>>> fuse_file refers to a single fuse_backing object.
>>> It can be the same (refcounted) object.
>>>
>>
>> Sorry, I wasn't referring to `fuse_backing` refs.
>>
>> If the lifecycle of `fuse_backing` is the same as `fuse_inode`, and
>> there are a large number of FUSE files on the file system, then when I
>> iterate through and open the backing files, register the `fuse_backing`,
>> and then set it to the `fuse_inode`, the FUSE service will hold a large
>> number of backing file file descriptors (FDs). These backing file FDs
>> will only be released when the FUSE files are deleted.
>>
>
> Not until files are deleted. Until fuse inodes are evicted from inode cache.
> FWIW, fuse_inode is ~900 bytes and filp is ~256 bytes, and when memory
> is needed, memory shrinker will evict fuse inodes and backing file, so sure
> backing files take up memory but not a game changer.
>
>> For example, if there are 1000 FUSE files on the file system, and I
>> iterate through and set the backing file for each `fuse_inode`, then the
>> FUSE service will hold 1000 backing file FDs for a long time. Extending
>> this further, if there are even more files, could the FUSE service
>> process exceed the `ulimit` configuration for open files?
>>
>> ```shell
>> [root@localhost home]# ulimit -a |grep "open files"
>> open files (-n) 1024
>> ```
>>
>
> backing files do not account for the open files limit of the FUSE server
> that's one of the design issues, but it is by design.
>
Thank you for the explanation.
I understand.
>>>>> But what you are proposing is a little bit odd API IMO:
>>>>> "Use this backing_id with this backing file, unless you find another
>>>>> backing file so use that one instead" - this sounds a bit awkward to me.
>>>>>
>>>>> I think it would be saner and simpler to relax the check in
>>>>> fuse_inode_uncached_io_start() to check that old and new fuse_backing
>>>>> objects refer to the same backing inode:
>>>>>
>>>>> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
>>>>> index 3728933188f30..c6070c361d855 100644
>>>>> --- a/fs/fuse/iomode.c
>>>>> +++ b/fs/fuse/iomode.c
>>>>> @@ -88,9 +88,9 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
>>>>> int err = 0;
>>>>>
>>>>> spin_lock(&fi->lock);
>>>>> - /* deny conflicting backing files on same fuse inode */
>>>>> + /* deny conflicting backing inodes on same fuse inode */
>>>>> oldfb = fuse_inode_backing(fi);
>>>>> - if (fb && oldfb && oldfb != fb) {
>>>>> + if (fb && oldfb && file_inode(oldfb->file) != file_inode(fb->file)) {
>>>>> err = -EBUSY;
>>>>> goto unlock;
>>>>> }
>>>>> --
>>>>>
>>>>> I don't think that this requires opt-in flag.
>>>>>
>>>>> Thanks,
>>>>> Amir.
>>>>
>>>> I agree that modifying the condition to `file_inode(oldfb->file) !=
>>>> file_inode(fb->file)` is a reasonable fix, and it does address the first
>>>> scenario I described.
>>>>
>>>> However, it doesn't fully resolve the second scenario: in a read-only
>>>> FUSE filesystem, the backing file itself might be cleaned up and
>>>> re-downloaded (resulting in a new inode with identical content). In this
>>>> case, reusing the cached fuse_inode's fb after a daemon restart still be
>>>> safe, but the inode comparison would incorrectly reject it. Is there a
>>>> more robust approach for handling this scenario?
>>>>
>>>
>>> There is a reason we added the restriction against associating
>>> fuse file to different backing inodes.
>>>
>>> mmap and reads from different files to the same inode need to be
>>> cache coherent.
>>>
>>> IOW, we intentionally do not support this setup without server restart
>>> there is no reason for us to allow that after server restarts because
>>> the consequense will be the same.
>>>
>>> It does not sound like a good idea for the server to cleanup files
>>> that are currently opened via fuse passthrough - is that something
>>> that happens intentionally? after server restarts?
>>>
>>> You could try to take a write lease to check if the file is currently
>>> open for read/write to avoid cleanup in this case?
>>>
>>> Thanks,
>>> Amir.
>>>
>>>
>>
>> Yes, it happened after the fuse service crash recovery restart, because
>> the refs of the backup files were cleaned up, causing them to be
>> mistakenly garbage collected.
>>
>> I will consider how to prevent it from being mistakenly garbage
>> collected by the fuse server.
>
> See here https://github.com/amir73il/fsnotify-utils/wiki/Hierarchical-Storage-Management-API#evicting-file-content
> explanation how you can use F_SETLEASE to synchronize evicting
> file content with file content readers.
>
> Thanks,
> Amir.
>
>
This is very helpful.
Thanks,
Chunsheng Luo
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-01-17 15:26 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-15 7:20 [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Chunsheng Luo
2026-01-15 7:20 ` [RFC 1/2] fuse: add close all in passthrough backing close for " Chunsheng Luo
2026-01-15 12:23 ` Amir Goldstein
2026-01-15 13:30 ` Chunsheng Luo
2026-01-15 7:20 ` [RFC 2/2] fuse: Add new flag to reuse the backing file of fuse_inode Chunsheng Luo
2026-01-15 13:09 ` Amir Goldstein
2026-01-15 14:34 ` Chunsheng Luo
2026-01-15 15:31 ` Amir Goldstein
2026-01-16 2:43 ` Chunsheng Luo
2026-01-16 19:08 ` Amir Goldstein
2026-01-17 15:26 ` Chunsheng Luo
2026-01-15 15:43 ` [RFC 0/2] fuse/passthrough: simplify daemon crash recovery Amir Goldstein
2026-01-16 1:57 ` Chunsheng Luo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®