On Mon, Aug 17, 2026 at 4:11 PM Luis Henriques <[email protected]> wrote:
>
> This new file aims at documenting the caches that are used by FUSE. At
> the moment only symlink, attributes, ACLs and readdir caches are described.
>
> Signed-off-by: Luis Henriques <[email protected]>
> ---
> .../filesystems/fuse/fuse-caches.rst | 142 ++++++++++++++++++
> 1 file changed, 142 insertions(+)
> create mode 100644 Documentation/filesystems/fuse/fuse-caches.rst
>
> diff --git a/Documentation/filesystems/fuse/fuse-caches.rst
> b/Documentation/filesystems/fuse/fuse-caches.rst
> new file mode 100644
> index 000000000000..071febf45d00
> --- /dev/null
> +++ b/Documentation/filesystems/fuse/fuse-caches.rst
> @@ -0,0 +1,142 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +===========
> +FUSE Caches
> +===========
> +
> +Introduction
> +============
> +
> +This document summarises the different types of caches that are used in FUSE.
> +For each cache type, it attempts to document the rules that are followed to
> +insert, validate and invalidate data into the cache.
> +
> +symlink caching
> +===============
> +
> +Whenever there's a link resolution request, the VFS will call into
> +``fuse_get_link()`` which will then send a ``FUSE_READLINK`` request to the
> +user-space FUSE server. However, the server can ask the kernel to cache all
> +links resolutions by setting the ``FUSE_CACHE_SYMLINKS`` flag during the
> +``FUSE_INIT`` negotiation.
> +
> +If this flag is set, FUSE will immediately call into the VFS
> +``__page_get_link()`` from the ``->get_link()`` inode operation. The first
> time
> +this is done for a specific link, it will end-up sending the
> ``FUSE_READLINK``
> +to user-space but the link contents will then be added into page-cache. The
> next
> +time the link needs to be resolved, it will use the link content that is
> already
> +cached, and will only fallback into sending the request to use-space if the
> +folio isn't up-to-date.
> +
> +Attributes caching
> +==================
> +
> +Attributes obtained from user-space, for example when an inode is first
> +looked-up, are cached in the kernel. However, these attributes have a timeout
> +associated and once expired they are invalidated.
> +
> +Thus, the ``FUSE_GETATTR`` operation will be sent to user-space only if the
> +attributes aren't yet available, the attributes aren't valid (timeout), or if
> +there is an explicit request for doing so (for example, by using the
> +``AT_STATX_FORCE_SYNC`` flag in ``statx``). This may happen in the following
> +situations:
"This may happen" what may happen? I don't see it referring to anything.
> +
> +#. An explicit request from VFS to get the attributes for an inode (through
> the
> + ``->getattr()`` callback).
> +#. When an ``->llseek()`` is requested to FUSE with a type of request
> + (``whence``):
> +
> + - ``SEEK_{HOLE,DATA}`` and the user-space doesn't implement the
> + ``FUSE_LSEEK`` operation (it has returned ``ENOSYS``), or
> + - ``SEEK_END``
> +
> +#. When doing a buffered read past EOF or automatic page cache invalidation
> mode
> + is enabled (``FUSE_AUTO_INVAL_DATA``).
> +#. When doing a buffered write with write-back cache enabled
> + (``FUSE_CAP_WRITEBACK_CACHE``).
This list is incomplete and strange. it has post EOF write for
writeback which is the exception
and leaves out every non writeback write.
If you composed this list yourself I highly recommend an LLM for this task
if you used LLM I suggest a stronger model.
Generally speaking, I find that today's robots are much better at writing these
sorts of docs than I am - as long as I sit at the helm and guide them
about where to expand on and where to keep it concise.
> +
> +ACL caching
> +===========
> +
> +FUSE has allowed the usage of POSIX ACLs for a long time as they could be set
> +and accessed simply as extended attributes. However, it was only with the
> +addition of the ``FUSE_POSIX_ACL`` flag that ACLs started to be fully
> supported.
> +Without this flag, ACLs can still be set, but the VFS won't use them for
> +performing permission checks - that would be the user-space server's
> +responsibility.
> +
> +Also, without setting ``FUSE_POSIX_ACL``, ACLs will not be cached by the
> kernel.
> +In this case, new inodes ``i_acl`` and ``i_default_acl`` fields will be set
> to
> +``ACL_DONT_CACHE``.
> +
> +On the other hand, if ``FUSE_POSIX_ACL`` is set during ``FUSE_INIT``, when an
> +ACL is accessed the VFS layer will first check if it's already cached. If it
> is
> +not, FUSE ``->get_acl`` operation is called, which will eventually send a
> +user-space request. Future accesses to this inode ACL will then use the
> cached
> +data.
> +
> +Setting an ACL in an inode, however, won't cache it immediately. It will send
> +user-space a request with the new ACL, and the FUSE server may perform some
> +modifications before storing it.
Do not encourage this by documenting it please.
It reinforces that this was by design, rather than an oversight which
we don't know.
> +
> +On the other hand, ACLs will be removed for the cache in the following
> +situations:
> +
> +- When setting an ACL in an inode and the user-space server has set the
> + ``FUSE_POSIX_ACL`` flag, all previously cached ACLs for this inode will be
> + invalidated.
> +- When invalidating an inode through the ``FUSE_NOTIFY_INVAL_INODE``
> operation.
> +- When ``->d_revalidate()`` is called for a dentry that requires a lookup
> (e.g.
> + it has expired) and that lookup operation is successful.
> +- When the VFS needs to check access rights for an inode (by calling
> + ``->permission()``), attributes may need to be refreshed. If that happens,
> + any cached ACLs for that inode will be invalidated.
> +- After setting an inode attribute (i.e. operation ``FUSE_SETATTR`` is sent
> to
> + user-space), the user-space server may have also updated the ACLs, so any
> + cached ACLs for this inode are also invalidated.
> +- While processing ``FUSE_READDIRPLUS`` and a new dentry is added (unless
> this
> + dentry is already being looked up (``DCACHE_PAR_LOOKUP``))
> +- In general, when there is the need to sent a ``FUSE_STATX`` or
> + ``FUSE_GETATTR`` to user-space (e.g. because the attributes have expired).
> + This may happen in the following cases:
> +
> + - When doing an ``->llseek()`` on a file with ``SEEK_END``,
> ``SEEK_HOLE`` or
> + ``SEEK_DATA``.
> + - When the ``FUSE_AUTO_INVAL_DATA`` flag is set at ``INIT`` time (to
> + automatically invalidate cached pages), and a buffered read
> + (``->read_iter()``) past EOF is done on a non-passthrough file.
> + - When the ``FUSE_WRITEBACK_CACHE`` flag is set at ``INIT`` time, and a
> + buffered write (``->write_iter()``) past EOF is done on a
> non-passthrough
> + file.
> + - When the ``FUSE_AUTO_INVAL_DATA`` flag is set at ``INIT`` time and the
> VFS
> + needs to read a directory contents (``->iterate_shared()``) for a
> + directory that is allowed to be cached.
No reason to repeat the reasons for attr cache invalidation that were
just listed above
> +
> +readdir caching
> +===============
> +
> +When opening a directory for doing a readdir, a ``FUSE_OPENDIR`` will be sent
> +and the user-space server will be responsible for setting the open flags
> related
> +with caching, namely ``FOPEN_KEEP_CACHE`` and ``FOPEN_CACHE_DIR``.
> +
> +If neither flags are set by the user-space FUSE server, then every
> ``readdir``
> +will result in a ``FUSE_READDIR`` (or ``FUSE_READDIRPLUS``) request being
> sent.
> +If ``FOPEN_CACHE_DIR`` is set by the server, then the result of a ``readdir``
> +will be cached by the kernel and reused. However, if ``FOPEN_KEEP_CACHE``
> isn't
> +also set, the cache will be invalidated next time the directory is open.
Confusing.
FOPEN_KEEP_CACHE is about keeping the cache on THIS open not on
some NEXT open.
Thanks,
Amir.