[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <176169809317.1424347.1031452366030061035.stgit@frogsfrogsfrogs>
Date: Tue, 28 Oct 2025 17:43:39 -0700
From: "Darrick J. Wong" <djwong@...nel.org>
To: djwong@...nel.org, miklos@...redi.hu
Cc: joannelkoong@...il.com, joannelkoong@...il.com, bernd@...ernd.com,
neal@...pa.dev, linux-ext4@...r.kernel.org, linux-fsdevel@...r.kernel.org
Subject: [PATCH 3/5] fuse: implement file attributes mask for statx
From: Darrick J. Wong <djwong@...nel.org>
Actually copy the attributes/attributes_mask from userspace. Ignore
file attributes bits that the VFS sets (or doesn't set) on its own.
Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
Reviewed-by: Joanne Koong <joannelkoong@...il.com>
---
fs/fuse/fuse_i.h | 37 +++++++++++++++++++++++++++++++++++++
fs/fuse/dir.c | 4 ++++
fs/fuse/inode.c | 4 ++++
3 files changed, 45 insertions(+)
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a8068bee90af57..8c47d103c8ffa6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -140,6 +140,10 @@ struct fuse_inode {
/** Version of last attribute change */
u64 attr_version;
+ /** statx file attributes */
+ u64 statx_attributes;
+ u64 statx_attributes_mask;
+
union {
/* read/write io cache (regular file only) */
struct {
@@ -1235,6 +1239,39 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid, u32 cache_mask,
u64 evict_ctr);
+/*
+ * These statx attribute flags are set by the VFS so mask them out of replies
+ * from the fuse server for local filesystems. Nonlocal filesystems are
+ * responsible for enforcing and advertising these flags themselves.
+ */
+#define FUSE_STATX_LOCAL_VFS_ATTRIBUTES (STATX_ATTR_IMMUTABLE | \
+ STATX_ATTR_APPEND)
+
+/*
+ * These statx attribute flags are set by the VFS so mask them out of replies
+ * from the fuse server.
+ */
+#define FUSE_STATX_VFS_ATTRIBUTES (STATX_ATTR_AUTOMOUNT | STATX_ATTR_DAX | \
+ STATX_ATTR_MOUNT_ROOT)
+
+static inline u64 fuse_statx_attributes_mask(const struct inode *inode,
+ const struct fuse_statx *sx)
+{
+ if (fuse_inode_is_exclusive(inode))
+ return sx->attributes_mask & ~(FUSE_STATX_VFS_ATTRIBUTES |
+ FUSE_STATX_LOCAL_VFS_ATTRIBUTES);
+ return sx->attributes_mask & ~FUSE_STATX_VFS_ATTRIBUTES;
+}
+
+static inline u64 fuse_statx_attributes(const struct inode *inode,
+ const struct fuse_statx *sx)
+{
+ if (fuse_inode_is_exclusive(inode))
+ return sx->attributes & ~(FUSE_STATX_VFS_ATTRIBUTES |
+ FUSE_STATX_LOCAL_VFS_ATTRIBUTES);
+ return sx->attributes & ~FUSE_STATX_VFS_ATTRIBUTES;
+}
+
u32 fuse_get_cache_mask(struct inode *inode);
/**
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index ecaec0fea3a132..636d47a5127ca1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1271,6 +1271,8 @@ static int fuse_do_statx(struct mnt_idmap *idmap, struct inode *inode,
stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
stat->btime.tv_sec = sx->btime.tv_sec;
stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1);
+ stat->attributes |= fuse_statx_attributes(inode, sx);
+ stat->attributes_mask |= fuse_statx_attributes_mask(inode, sx);
fuse_fillattr(idmap, inode, &attr, stat);
stat->result_mask |= STATX_TYPE;
}
@@ -1375,6 +1377,8 @@ static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
stat->btime = fi->i_btime;
stat->result_mask |= STATX_BTIME;
}
+ stat->attributes = fi->statx_attributes;
+ stat->attributes_mask = fi->statx_attributes_mask;
}
return err;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index d048d634ef46f5..76e5b7f5c980c2 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -286,6 +286,10 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
fi->i_btime.tv_sec = sx->btime.tv_sec;
fi->i_btime.tv_nsec = sx->btime.tv_nsec;
}
+
+ fi->statx_attributes = fuse_statx_attributes(inode, sx);
+ fi->statx_attributes_mask = fuse_statx_attributes_mask(inode,
+ sx);
}
if (attr->blksize)
Powered by blists - more mailing lists