[PATCH 9/9] fuse: always cache ACLs when using iomap

Darrick J. Wong
2025-09-16T00:38:24Z

Keep ACLs cached in memory when we're using iomap, so that we don't have
to make a round trip to the fuse server. This might want to become a
FUSE_ATTR_ flag.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
fs/fuse/acl.c | 12 +++++++++---
fs/fuse/dir.c | 11 ++++++++---
fs/fuse/readdir.c | 3 ++-
3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c
index 9b24c53b510405..a9f152ddc1faec 100644
--- a/fs/fuse/acl.c
+++ b/fs/fuse/acl.c
@@ -210,10 +210,16 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
if (fc->posix_acl) {
/*
* Fuse daemons without FUSE_POSIX_ACL never cached POSIX ACLs
- * and didn't invalidate attributes. Retain that behavior.
+ * and didn't invalidate attributes. Retain that behavior
+ * except for iomap, where we assume that only the source of
+ * ACL changes is userspace.
*/
- forget_all_cached_acls(inode);
- fuse_invalidate_attr(inode);
+ if (!ret && is_iomap) {
+ set_cached_acl(inode, type, acl);
+ } else {
+ forget_all_cached_acls(inode);
+ fuse_invalidate_attr(inode);
+ }
}

return ret;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 58106f49395697..9adaf262bda975 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -261,7 +261,8 @@ static int fuse_dentry_revalidate(struct inode *dir, const struct qstr *name,
fuse_stale_inode(inode, outarg.generation, &outarg.attr))
goto invalid;

- forget_all_cached_acls(inode);
+ if (!fuse_inode_has_iomap(inode))
+ forget_all_cached_acls(inode);
fuse_change_attributes(inode, &outarg.attr, NULL,
ATTR_TIMEOUT(&outarg),
attr_version);
@@ -1470,7 +1471,8 @@ static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
sync = time_before64(fi->i_time, get_jiffies_64());

if (sync) {
- forget_all_cached_acls(inode);
+ if (!fuse_inode_has_iomap(inode))
+ forget_all_cached_acls(inode);
/* Try statx if a field not covered by regular stat is wanted */
if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) {
err = fuse_do_statx(idmap, inode, file, stat);
@@ -1648,6 +1650,9 @@ static int fuse_access(struct inode *inode, int mask)

static int fuse_perm_getattr(struct inode *inode, int mask)
{
+ if (fuse_inode_has_iomap(inode))
+ return 0;
+
if (mask & MAY_NOT_BLOCK)
return -ECHILD;

@@ -2325,7 +2330,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
* If filesystem supports acls it may have updated acl xattrs in
* the filesystem, so forget cached acls for the inode.
*/
- if (fc->posix_acl)
+ if (fc->posix_acl && !is_iomap)
forget_all_cached_acls(inode);

/* Directory mode changed, may need to revalidate access */
diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index 45dd932eb03a5e..f7c2a45f23678e 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -224,7 +224,8 @@ static int fuse_direntplus_link(struct file *file,
fi->nlookup++;
spin_unlock(&fi->lock);

- forget_all_cached_acls(inode);
+ if (!fuse_inode_has_iomap(inode))
+ forget_all_cached_acls(inode);
fuse_change_attributes(inode, &o->attr, NULL,
ATTR_TIMEOUT(o),
attr_version);