[<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
 
