From: Luis Henriques <luis@igalia.com>
To: Amir Goldstein <amir73il@gmail.com>
Cc: Russell Harmon <russ@har.mn>,
miklos@szeredi.hu, corbet@lwn.net, skhan@linuxfoundation.org,
rdunlap@infradead.org, fuse-devel@lists.linux.dev,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Bernd Schubert <bernd@bsbernd.com>
Subject: Re: [PATCH v2] fuse: add inode generation number support
Date: Tue, 29 Sep 2026 14:07:17 +0100 [thread overview]
Message-ID: <87tsn89pfe.fsf@igalia.com> (raw)
In-Reply-To: <CAOQ4uxiD9ofGEG+CkjszGaHygPWH7S4nob03XRNXUCrze5n91w@mail.gmail.com>
On Mon, Sep 28 2026, Amir Goldstein wrote:
> On Mon, Sep 28, 2026 at 3:44 AM Russell Harmon <russ@har.mn> wrote:
>>
>> This patch adds support for propagating the inode generation number from
>> the FUSE server to the kernel.
>
> Incomplete statement.
> Without the mention of GETATTR/SETATTR this is a misleading statement.
>
>> This is useful for exporting FUSE
>> filesystems over NFS, where the generation number is used to detect
>> stale file handles (ESTALE) when inodes are recycled.
>
> How exactly does it help?
> I am not trying to troll you, I am really curious. how?
>
> Context: I have been trying to improve FUSE NFS export support for a while
> I have built a library that provides reliable NFS export for FUSE passthrough fs
> for specific backing file system types [1].
>
> [1] https://github.com/amir73il/libfuse/tree/libfuse_passthrough/passthrough
>
> It is broadly understood that real NFS export support requires extending the
> FUSE protocol to identify objects using file handles and Luis has
> already started
> with this work [2]
I just want to add that this work is mostly stale at the moment. It was
decided that it needs to be done on top of fusex, the next major protocol
version bump. Also note that the initial draft of fusex lacked a bunch of
features (e.g., it was available for local-filesystems only), so it may
take a while before a LOOKUP_HANDLE operation is available.
Cheers,
--
Luís
> [2] https://lore.kernel.org/linux-fsdevel/20260225112439.27276-1-luis@igalia.com/
>
> So my question is, what does adding generation id to GETATTR/SETATTR
> improve for FUSE filesystem writers that wish to export their filesystem to NFS?
>
>>
>> Key changes:
>> - Bump FUSE protocol version to 7.47.
>> - Repurpose the unused `dummy` field in `struct fuse_attr_out` as
>> `generation`.
>> - Add a `FUSE_ATTR_GENERATION` INIT flag with which the filesystem opts
>> into the kernel consuming that field. Gating on the protocol minor
>> version alone would break existing filesystems: the minor version only
>> reflects the library, not whether the individual filesystem fills the
>> field, and a zero there would look like a generation change for any
>> filesystem that reports nonzero generations in LOOKUP.
>> - Update `fuse_change_attributes` and related functions to accept and set
>> `inode->i_generation`.
>> - Populate `i_generation` from `LOOKUP`, `GETATTR`, and `READDIRPLUS`
>> responses.
>> - Detect nodeid recycling on `GETATTR` and `SETATTR` responses via
>> `fuse_stale_inode()`, the same check already used by the `LOOKUP` and
>> `READDIRPLUS` paths, and mark the inode bad (EIO) instead of merging
>> the recycled file's attributes into the existing, possibly still-open,
>> inode.
>> - Update `fuse_get_dentry` to validate the generation number against the
>> file handle, returning ESTALE on mismatch.
>> - Maintain backward compatibility: without `FUSE_ATTR_GENERATION` the
>> generation field in attr replies is ignored.
>>
>> Verification:
>> Tested with a QEMU harness in fuse-generation-qemu against a patched
>> libfuse (FUSE_CAP_ATTR_GENERATION, fuse_reply_attr_with_generation) and
>> its passthrough_ll example reporting real backing-filesystem generation
>> numbers. The suite verifies that:
>> 1. The generation from `LOOKUP` reaches `name_to_handle_at()` file
>> handles and matches the backing filesystem's FS_IOC_GETVERSION.
>> 2. `open_by_handle_at()` succeeds for a valid handle and fails with
>> ESTALE for a handle whose generation does not match, both while the
>> inode is cached and after cache eviction.
>
> 1 and 2 should work on upstream FUSE right?
> This is something worth mentioning.
>
>> 3. When a `GETATTR` reply reports a new generation for a cached inode
>> (inode recycling), the kernel marks the inode bad: fstat() on an
>> open fd fails with EIO, while a fresh path lookup recovers and
>> pre-recycling file handles fail with ESTALE.
>
> How did the inode recycle happen with passtrhough_ll which keeps
> open fds for fuse inodes?
> Something is missing from this test report.
> If you just used a mock filesystem which makes no sense in the real world
> then the value of this change is questionable.
>
>>
>> Signed-off-by: Russell Harmon <russ@har.mn>
>> Assisted-by: Gemini:gemini-3.1
>> ---
>> v2:
>> - Bump FUSE_KERNEL_MINOR_VERSION to 47 to match the new 7.47 changelog
>> entry (v1 added the entry but left the minor at 46).
>>
>> v1: https://lore.kernel.org/all/20260927141437.1432584-1-russ@har.mn/
>>
>> Documentation/filesystems/fuse/fuse.rst | 32 +++++++++++++++++++++++++
>> fs/fuse/dir.c | 21 +++++++++++-----
>> fs/fuse/fuse_i.h | 10 ++++++--
>> fs/fuse/inode.c | 23 ++++++++++++------
>> fs/fuse/readdir.c | 2 +-
>> include/uapi/linux/fuse.h | 11 +++++++--
>> 6 files changed, 81 insertions(+), 18 deletions(-)
>>
>> diff --git a/Documentation/filesystems/fuse/fuse.rst b/Documentation/filesystems/fuse/fuse.rst
>> index 0fbd5a03fdc9..f67bc9fc6316 100644
>> --- a/Documentation/filesystems/fuse/fuse.rst
>> +++ b/Documentation/filesystems/fuse/fuse.rst
>> @@ -49,6 +49,38 @@ using the sftp protocol.
>> The userspace library and utilities are available from the
>> `FUSE homepage: <https://github.com/libfuse/>`_
>>
>> +NFS export support
>> +==================
>> +
>> +FUSE filesystems can be exported via NFS if the filesystem daemon supports it.
>> +For reliable NFS export, the filesystem should provide a unique inode
>> +generation number for each inode. This generation number is used by the
>> +NFS server to distinguish between different file instances that may
>> +share the same inode number (e.g. after an inode number is reused).
>> +
>> +The inode generation number is provided by the filesystem daemon in the
>> +following messages:
>> +
>> +- `FUSE_LOOKUP`
>> +- `FUSE_GETATTR` (see below)
>> +- `FUSE_SETATTR` (see below)
>> +- `FUSE_READDIRPLUS`
>> +- `FUSE_CREATE` / `FUSE_TMPFILE` / `FUSE_MKNOD` / `FUSE_MKDIR` / `FUSE_SYMLINK` / `FUSE_LINK`
>> +
>> +A daemon that keeps the generation number in its `FUSE_GETATTR` and
>> +`FUSE_SETATTR` replies (the `generation` field of `fuse_attr_out`,
>> +protocol 7.46) must announce this by setting `FUSE_ATTR_GENERATION` in
>> +its `FUSE_INIT` reply flags. When the flag is negotiated, the kernel
>> +compares the generation in every getattr/setattr reply against the
>> +cached inode: a mismatch means the daemon has reused the node ID for a
>> +different file, and the cached inode is marked bad (subsequent
>> +operations on it fail with EIO). Without the flag, the field is ignored
>> +and the generation is only taken from lookup-type replies, preserving
>> +the behavior of existing filesystems.
>> +
>> +If the filesystem daemon does not provide a generation number, the kernel
>> +will use a default value of 0.
>> +
>
> On the one hand, I still need to understand the value of reporting generation
> in GETATTR/SETATTR.
>
> On the other hand, I do see the value in the server negotiating at init time the
> fact that "Generation values are reliable".
>
> What happens today is that NFS exporting is allowed for all FUSE filesystems
> regardless of the reliability of generation id, so after inode evict
> and recycle,
> an NFSv3 client that had access to inode X.Y may get access to a completely
> different file or even a directory with inode X.Y, where X is the recycle nodeid
> and Y is an unreliable generation provided by the server.
>
> The problem is that FUSE does not require opt-in for NFS export, it only
> allows servers to opt-out of NFS export (FUSE_NO_EXPORT_SUPPORT).
>
> So what can be done given a declaration of the server that generation
> is reliable?
>
> One option is to set a non-zero uuid/fsid to the fuse filesystem.
> This will allow exporting the fuse filesystem without the opt-in uuid/fsid=
> in /etc/exports.
> This will also allow setting fanotify FAN_MARK_FILESYSTEM watches
> on this fuse filesystem, whose file handles could be trusted to be a genuine
> unique identity of the filesystem objects.
>
> But if we take this route, it is better to take it one step further
> and allow the
> server to determine the filesystem uuid/fsid during negotiation.
>
> In any case, I am not convinced there is value in doing all this
> without extending
> the protocol with LOOKUP_HANDLE/LOOKUPX lookup by file handle, so if you
> have compelling use cases, please spell them out.
>
> Thanks,
> Amir.
prev parent reply other threads:[~2026-09-29 13:06 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 14:14 [PATCH] " Russell Harmon
2026-09-28 1:43 ` [PATCH v2] " Russell Harmon
2026-09-28 9:38 ` Amir Goldstein
2026-09-28 16:03 ` Russell Harmon
2026-09-28 16:54 ` Amir Goldstein
2026-09-29 20:55 ` Russell Harmon
2026-09-30 6:01 ` Amir Goldstein
2026-09-29 13:07 ` Luis Henriques [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87tsn89pfe.fsf@igalia.com \
--to=luis@igalia.com \
--cc=amir73il@gmail.com \
--cc=bernd@bsbernd.com \
--cc=corbet@lwn.net \
--cc=fuse-devel@lists.linux.dev \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=rdunlap@infradead.org \
--cc=russ@har.mn \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®