linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/7] fs: implement multigrain timestamps
@ 2023-07-25 14:58 Jeff Layton
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
                   ` (7 more replies)
  0 siblings, 8 replies; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

The VFS always uses coarse-grained timestamps when updating the
ctime and mtime after a change. This has the benefit of allowing
filesystems to optimize away a lot metadata updates, down to around 1
per jiffy, even when a file is under heavy writes.

Unfortunately, this coarseness has always been an issue when we're
exporting via NFSv3, which relies on timestamps to validate caches. A
lot of changes can happen in a jiffy, so timestamps aren't sufficient to
help the client decide to invalidate the cache.

Even with NFSv4, a lot of exported filesystems don't properly support a
change attribute and are subject to the same problems with timestamp
granularity. Other applications have similar issues with timestamps (e.g
backup applications).

If we were to always use fine-grained timestamps, that would improve the
situation, but that becomes rather expensive, as the underlying
filesystem would have to log a lot more metadata updates.

What we need is a way to only use fine-grained timestamps when they are
being actively queried. The idea is to use an unused bit in the ctime's
tv_nsec field to mark when the mtime or ctime has been queried via
getattr. Once that has been marked, the next m/ctime update will use a
fine-grained timestamp.

This patch series is based on top of Christian's vfs.all branch, which
has the recent conversion to the new ctime accessors. It should apply
cleanly on top of linux-next.

The first two patches should probably go in via the vfs tree. Should the
fs-specific patches go in that way as well, or should they go via
maintainer trees? Either should be fine.

The first two patches should probably go in via Christian's vfs tree.
The rest could go via maintainer trees or the vfs tree.

For now, I'd like to get these into linux-next. Christian, would you be
willing to pick these up for now? Alternately, I can feed them there via
the iversion branch that Stephen is already pulling in from my tree.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
base-commit: cf22d118b89a09a0160586412160d89098f7c4c7
---
Changes in v6:
- drop the patch that removed XFS_ICHGTIME_CHG
- change WARN_ON_ONCE to ASSERT in xfs conversion patch

---
Jeff Layton (7):
      fs: pass the request_mask to generic_fillattr
      fs: add infrastructure for multigrain timestamps
      tmpfs: bump the mtime/ctime/iversion when page becomes writeable
      tmpfs: add support for multigrain timestamps
      xfs: switch to multigrain timestamps
      ext4: switch to multigrain timestamps
      btrfs: convert to multigrain timestamps

 fs/9p/vfs_inode.c               |  4 +-
 fs/9p/vfs_inode_dotl.c          |  4 +-
 fs/afs/inode.c                  |  2 +-
 fs/btrfs/file.c                 | 24 ++--------
 fs/btrfs/inode.c                |  2 +-
 fs/btrfs/super.c                |  5 ++-
 fs/ceph/inode.c                 |  2 +-
 fs/coda/inode.c                 |  3 +-
 fs/ecryptfs/inode.c             |  5 ++-
 fs/erofs/inode.c                |  2 +-
 fs/exfat/file.c                 |  2 +-
 fs/ext2/inode.c                 |  2 +-
 fs/ext4/inode.c                 |  2 +-
 fs/ext4/super.c                 |  2 +-
 fs/f2fs/file.c                  |  2 +-
 fs/fat/file.c                   |  2 +-
 fs/fuse/dir.c                   |  2 +-
 fs/gfs2/inode.c                 |  2 +-
 fs/hfsplus/inode.c              |  2 +-
 fs/inode.c                      | 98 +++++++++++++++++++++++++++++------------
 fs/kernfs/inode.c               |  2 +-
 fs/libfs.c                      |  4 +-
 fs/minix/inode.c                |  2 +-
 fs/nfs/inode.c                  |  2 +-
 fs/nfs/namespace.c              |  3 +-
 fs/ntfs3/file.c                 |  2 +-
 fs/ocfs2/file.c                 |  2 +-
 fs/orangefs/inode.c             |  2 +-
 fs/proc/base.c                  |  4 +-
 fs/proc/fd.c                    |  2 +-
 fs/proc/generic.c               |  2 +-
 fs/proc/proc_net.c              |  2 +-
 fs/proc/proc_sysctl.c           |  2 +-
 fs/proc/root.c                  |  3 +-
 fs/smb/client/inode.c           |  2 +-
 fs/smb/server/smb2pdu.c         | 22 ++++-----
 fs/smb/server/vfs.c             |  3 +-
 fs/stat.c                       | 59 ++++++++++++++++++++-----
 fs/sysv/itree.c                 |  3 +-
 fs/ubifs/dir.c                  |  2 +-
 fs/udf/symlink.c                |  2 +-
 fs/vboxsf/utils.c               |  2 +-
 fs/xfs/libxfs/xfs_trans_inode.c |  6 +--
 fs/xfs/xfs_iops.c               |  4 +-
 fs/xfs/xfs_super.c              |  2 +-
 include/linux/fs.h              | 47 ++++++++++++++++++--
 mm/shmem.c                      | 16 ++++++-
 47 files changed, 248 insertions(+), 125 deletions(-)
---
base-commit: 810b5fff7917119ea82ff96e312e2d4350d6b681
change-id: 20230713-mgctime-f2a9fc324918

Best regards,
-- 
Jeff Layton <jlayton@kernel.org>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-07-26  2:46   ` Xiubo Li
                     ` (4 more replies)
  2023-07-25 14:58 ` [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps Jeff Layton
                   ` (6 subsequent siblings)
  7 siblings, 5 replies; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

generic_fillattr just fills in the entire stat struct indiscriminately
today, copying data from the inode. There is at least one attribute
(STATX_CHANGE_COOKIE) that can have side effects when it is reported,
and we're looking at adding more with the addition of multigrain
timestamps.

Add a request_mask argument to generic_fillattr and have most callers
just pass in the value that is passed to getattr. Have other callers
(e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
STATX_CHANGE_COOKIE into generic_fillattr.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/9p/vfs_inode.c       |  4 ++--
 fs/9p/vfs_inode_dotl.c  |  4 ++--
 fs/afs/inode.c          |  2 +-
 fs/btrfs/inode.c        |  2 +-
 fs/ceph/inode.c         |  2 +-
 fs/coda/inode.c         |  3 ++-
 fs/ecryptfs/inode.c     |  5 +++--
 fs/erofs/inode.c        |  2 +-
 fs/exfat/file.c         |  2 +-
 fs/ext2/inode.c         |  2 +-
 fs/ext4/inode.c         |  2 +-
 fs/f2fs/file.c          |  2 +-
 fs/fat/file.c           |  2 +-
 fs/fuse/dir.c           |  2 +-
 fs/gfs2/inode.c         |  2 +-
 fs/hfsplus/inode.c      |  2 +-
 fs/kernfs/inode.c       |  2 +-
 fs/libfs.c              |  4 ++--
 fs/minix/inode.c        |  2 +-
 fs/nfs/inode.c          |  2 +-
 fs/nfs/namespace.c      |  3 ++-
 fs/ntfs3/file.c         |  2 +-
 fs/ocfs2/file.c         |  2 +-
 fs/orangefs/inode.c     |  2 +-
 fs/proc/base.c          |  4 ++--
 fs/proc/fd.c            |  2 +-
 fs/proc/generic.c       |  2 +-
 fs/proc/proc_net.c      |  2 +-
 fs/proc/proc_sysctl.c   |  2 +-
 fs/proc/root.c          |  3 ++-
 fs/smb/client/inode.c   |  2 +-
 fs/smb/server/smb2pdu.c | 22 +++++++++++-----------
 fs/smb/server/vfs.c     |  3 ++-
 fs/stat.c               | 18 ++++++++++--------
 fs/sysv/itree.c         |  3 ++-
 fs/ubifs/dir.c          |  2 +-
 fs/udf/symlink.c        |  2 +-
 fs/vboxsf/utils.c       |  2 +-
 include/linux/fs.h      |  2 +-
 mm/shmem.c              |  2 +-
 40 files changed, 70 insertions(+), 62 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 16d85e6033a3..d24d1f20e922 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -1016,7 +1016,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
 	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
 	v9ses = v9fs_dentry2v9ses(dentry);
 	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
-		generic_fillattr(&nop_mnt_idmap, inode, stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 		return 0;
 	} else if (v9ses->cache & CACHE_WRITEBACK) {
 		if (S_ISREG(inode->i_mode)) {
@@ -1037,7 +1037,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
 		return PTR_ERR(st);
 
 	v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb, 0);
-	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
 
 	p9stat_free(st);
 	kfree(st);
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 464ea73d1bf8..8e8d5d2a13d8 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -451,7 +451,7 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
 	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
 	v9ses = v9fs_dentry2v9ses(dentry);
 	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
-		generic_fillattr(&nop_mnt_idmap, inode, stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 		return 0;
 	} else if (v9ses->cache) {
 		if (S_ISREG(inode->i_mode)) {
@@ -476,7 +476,7 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
 		return PTR_ERR(st);
 
 	v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
-	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
 	/* Change block size to what the server returned */
 	stat->blksize = st->st_blksize;
 
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 6b636f43f548..1c794a1896aa 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -773,7 +773,7 @@ int afs_getattr(struct mnt_idmap *idmap, const struct path *path,
 
 	do {
 		read_seqbegin_or_lock(&vnode->cb_lock, &seq);
-		generic_fillattr(&nop_mnt_idmap, inode, stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 		if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
 		    stat->nlink > 0)
 			stat->nlink -= 1;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index bcccd551f547..7346059209aa 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -8773,7 +8773,7 @@ static int btrfs_getattr(struct mnt_idmap *idmap,
 				  STATX_ATTR_IMMUTABLE |
 				  STATX_ATTR_NODUMP);
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 	stat->dev = BTRFS_I(inode)->root->anon_dev;
 
 	spin_lock(&BTRFS_I(inode)->lock);
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 5f6e93714f5a..fd05d68e2990 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -2467,7 +2467,7 @@ int ceph_getattr(struct mnt_idmap *idmap, const struct path *path,
 			return err;
 	}
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	stat->ino = ceph_present_inode(inode);
 
 	/*
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 3e64679c1620..0c7c2528791e 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -256,7 +256,8 @@ int coda_getattr(struct mnt_idmap *idmap, const struct path *path,
 {
 	int err = coda_revalidate_inode(d_inode(path->dentry));
 	if (!err)
-		generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask,
+				 d_inode(path->dentry), stat);
 	return err;
 }
 
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index b491bb239c8f..992d9c7e64ae 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -982,7 +982,7 @@ static int ecryptfs_getattr_link(struct mnt_idmap *idmap,
 
 	mount_crypt_stat = &ecryptfs_superblock_to_private(
 						dentry->d_sb)->mount_crypt_stat;
-	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
 	if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
 		char *target;
 		size_t targetsiz;
@@ -1011,7 +1011,8 @@ static int ecryptfs_getattr(struct mnt_idmap *idmap,
 	if (!rc) {
 		fsstack_copy_attr_all(d_inode(dentry),
 				      ecryptfs_inode_to_lower(d_inode(dentry)));
-		generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask,
+				 d_inode(dentry), stat);
 		stat->blocks = lower_stat.blocks;
 	}
 	return rc;
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index c9bbdf7c34db..edc8ec7581b8 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -369,7 +369,7 @@ int erofs_getattr(struct mnt_idmap *idmap, const struct path *path,
 	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
 				  STATX_ATTR_IMMUTABLE);
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 	return 0;
 }
 
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index f40ecfeee3a4..32395ef686a2 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -232,7 +232,7 @@ int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
 	struct inode *inode = d_backing_inode(path->dentry);
 	struct exfat_inode_info *ei = EXFAT_I(inode);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	exfat_truncate_atime(&stat->atime);
 	stat->result_mask |= STATX_BTIME;
 	stat->btime.tv_sec = ei->i_crtime.tv_sec;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 1259995977d2..acbab27fe957 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1628,7 +1628,7 @@ int ext2_getattr(struct mnt_idmap *idmap, const struct path *path,
 			STATX_ATTR_IMMUTABLE |
 			STATX_ATTR_NODUMP);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	return 0;
 }
 
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 86696b40c58f..6683076ecb2f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -5535,7 +5535,7 @@ int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
 				  STATX_ATTR_NODUMP |
 				  STATX_ATTR_VERITY);
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 	return 0;
 }
 
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index b018800223c4..35886a52edfb 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -882,7 +882,7 @@ int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path,
 				  STATX_ATTR_NODUMP |
 				  STATX_ATTR_VERITY);
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 
 	/* we need to show initial sectors used for inline_data/dentries */
 	if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 456477946dd9..e887e9ab7472 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -401,7 +401,7 @@ int fat_getattr(struct mnt_idmap *idmap, const struct path *path,
 	struct inode *inode = d_inode(path->dentry);
 	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 	stat->blksize = sbi->cluster_size;
 
 	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) {
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 672245ee0394..881524b9a55a 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1222,7 +1222,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
 		forget_all_cached_acls(inode);
 		err = fuse_do_getattr(inode, stat, file);
 	} else if (stat) {
-		generic_fillattr(&nop_mnt_idmap, inode, stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 		stat->mode = fi->orig_i_mode;
 		stat->ino = fi->orig_ino;
 	}
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 2ded6c813f20..200cabf3b393 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -2071,7 +2071,7 @@ static int gfs2_getattr(struct mnt_idmap *idmap,
 				  STATX_ATTR_IMMUTABLE |
 				  STATX_ATTR_NODUMP);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 
 	if (gfs2_holder_initialized(&gh))
 		gfs2_glock_dq_uninit(&gh);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 40c61ab4a918..c65c8c4b03dd 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -298,7 +298,7 @@ int hfsplus_getattr(struct mnt_idmap *idmap, const struct path *path,
 	stat->attributes_mask |= STATX_ATTR_APPEND | STATX_ATTR_IMMUTABLE |
 				 STATX_ATTR_NODUMP;
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	return 0;
 }
 
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 89a9b4dcf109..af37be68bf06 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -190,7 +190,7 @@ int kernfs_iop_getattr(struct mnt_idmap *idmap,
 
 	down_read(&root->kernfs_iattr_rwsem);
 	kernfs_refresh_inode(kn, inode);
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	up_read(&root->kernfs_iattr_rwsem);
 
 	return 0;
diff --git a/fs/libfs.c b/fs/libfs.c
index b27260e0c14a..0a9f3c426548 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -33,7 +33,7 @@ int simple_getattr(struct mnt_idmap *idmap, const struct path *path,
 		   unsigned int query_flags)
 {
 	struct inode *inode = d_inode(path->dentry);
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	stat->blocks = inode->i_mapping->nrpages << (PAGE_SHIFT - 9);
 	return 0;
 }
@@ -1585,7 +1585,7 @@ static int empty_dir_getattr(struct mnt_idmap *idmap,
 			     u32 request_mask, unsigned int query_flags)
 {
 	struct inode *inode = d_inode(path->dentry);
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	return 0;
 }
 
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 8a4fc9420b36..df575473c1cc 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -656,7 +656,7 @@ int minix_getattr(struct mnt_idmap *idmap, const struct path *path,
 	struct super_block *sb = path->dentry->d_sb;
 	struct inode *inode = d_inode(path->dentry);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	if (INODE_VERSION(inode) == MINIX_V1)
 		stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb);
 	else
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 1283fdfa4b0a..e21c073158e5 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -912,7 +912,7 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
 	/* Only return attributes that were revalidated. */
 	stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask;
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
 	stat->change_cookie = inode_peek_iversion_raw(inode);
 	stat->attributes_mask |= STATX_ATTR_CHANGE_MONOTONIC;
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 19d51ebf842c..e7494cdd957e 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -215,7 +215,8 @@ nfs_namespace_getattr(struct mnt_idmap *idmap,
 	if (NFS_FH(d_inode(path->dentry))->size != 0)
 		return nfs_getattr(idmap, path, stat, request_mask,
 				   query_flags);
-	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
+			 stat);
 	return 0;
 }
 
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 12788601dc84..962f12ce6c0a 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -85,7 +85,7 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
 
 	stat->attributes_mask |= STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED;
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 
 	stat->result_mask |= STATX_BTIME;
 	stat->btime = ni->i_crtime;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 1b337ebce4df..8184499ae7a5 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1319,7 +1319,7 @@ int ocfs2_getattr(struct mnt_idmap *idmap, const struct path *path,
 		goto bail;
 	}
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	/*
 	 * If there is inline data in the inode, the inode will normally not
 	 * have data blocks allocated (it may have an external xattr block).
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 9014bbcc8031..a52c30e80f45 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -871,7 +871,7 @@ int orangefs_getattr(struct mnt_idmap *idmap, const struct path *path,
 	ret = orangefs_inode_getattr(inode,
 	    request_mask & STATX_SIZE ? ORANGEFS_GETATTR_SIZE : 0);
 	if (ret == 0) {
-		generic_fillattr(&nop_mnt_idmap, inode, stat);
+		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 
 		/* override block size reported to stat */
 		if (!(request_mask & STATX_SIZE))
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d8388fc0a362..2bf67a0e0bcc 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1966,7 +1966,7 @@ int pid_getattr(struct mnt_idmap *idmap, const struct path *path,
 	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
 	struct task_struct *task;
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 
 	stat->uid = GLOBAL_ROOT_UID;
 	stat->gid = GLOBAL_ROOT_GID;
@@ -3900,7 +3900,7 @@ static int proc_task_getattr(struct mnt_idmap *idmap,
 {
 	struct inode *inode = d_inode(path->dentry);
 	struct task_struct *p = get_proc_task(inode);
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 
 	if (p) {
 		stat->nlink += get_nr_threads(p);
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index b3140deebbbf..6276b3938842 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -352,7 +352,7 @@ static int proc_fd_getattr(struct mnt_idmap *idmap,
 	struct inode *inode = d_inode(path->dentry);
 	int rv = 0;
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 
 	/* If it's a directory, put the number of open fds there */
 	if (S_ISDIR(inode->i_mode)) {
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 42ae38ff6e7e..775ce0bcf08c 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -146,7 +146,7 @@ static int proc_getattr(struct mnt_idmap *idmap,
 		}
 	}
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	return 0;
 }
 
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 78f9e6b469c0..2ba31b6d68c0 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -308,7 +308,7 @@ static int proc_tgid_net_getattr(struct mnt_idmap *idmap,
 
 	net = get_proc_task_net(inode);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 
 	if (net != NULL) {
 		stat->nlink = net->proc_net->nlink;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 6bc10e7e0ff7..bf06344a42cc 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -849,7 +849,7 @@ static int proc_sys_getattr(struct mnt_idmap *idmap,
 	if (IS_ERR(head))
 		return PTR_ERR(head);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	if (table)
 		stat->mode = (stat->mode & S_IFMT) | table->mode;
 
diff --git a/fs/proc/root.c b/fs/proc/root.c
index a86e65a608da..9191248f2dac 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -314,7 +314,8 @@ static int proc_root_getattr(struct mnt_idmap *idmap,
 			     const struct path *path, struct kstat *stat,
 			     u32 request_mask, unsigned int query_flags)
 {
-	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
+			 stat);
 	stat->nlink = proc_root.nlink + nr_processes();
 	return 0;
 }
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 218f03dd3f52..93fe43789d7a 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -2540,7 +2540,7 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
 			return rc;
 	}
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	stat->blksize = cifs_sb->ctx->bsize;
 	stat->ino = CIFS_I(inode)->uniqueid;
 
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index f9099831c8ff..2a084d35233a 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -4391,8 +4391,8 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
 	}
 
 	basic_info = (struct smb2_file_basic_info *)rsp->Buffer;
-	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
-			 &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
+			 file_inode(fp->filp), &stat);
 	basic_info->CreationTime = cpu_to_le64(fp->create_time);
 	time = ksmbd_UnixTimeToNT(stat.atime);
 	basic_info->LastAccessTime = cpu_to_le64(time);
@@ -4417,7 +4417,7 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
 	struct kstat stat;
 
 	inode = file_inode(fp->filp);
-	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
 
 	sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
 	delete_pending = ksmbd_inode_pending_delete(fp);
@@ -4471,7 +4471,7 @@ static int get_file_all_info(struct ksmbd_work *work,
 		return PTR_ERR(filename);
 
 	inode = file_inode(fp->filp);
-	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
 
 	ksmbd_debug(SMB, "filename = %s\n", filename);
 	delete_pending = ksmbd_inode_pending_delete(fp);
@@ -4548,8 +4548,8 @@ static void get_file_stream_info(struct ksmbd_work *work,
 	int buf_free_len;
 	struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
 
-	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
-			 &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
+			 file_inode(fp->filp), &stat);
 	file_info = (struct smb2_file_stream_info *)rsp->Buffer;
 
 	buf_free_len =
@@ -4639,8 +4639,8 @@ static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
 	struct smb2_file_internal_info *file_info;
 	struct kstat stat;
 
-	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
-			 &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
+			 file_inode(fp->filp), &stat);
 	file_info = (struct smb2_file_internal_info *)rsp->Buffer;
 	file_info->IndexNumber = cpu_to_le64(stat.ino);
 	rsp->OutputBufferLength =
@@ -4665,7 +4665,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
 	file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
 
 	inode = file_inode(fp->filp);
-	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
 
 	file_info->CreationTime = cpu_to_le64(fp->create_time);
 	time = ksmbd_UnixTimeToNT(stat.atime);
@@ -4726,8 +4726,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
 	struct smb2_file_comp_info *file_info;
 	struct kstat stat;
 
-	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
-			 &stat);
+	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
+			 file_inode(fp->filp), &stat);
 
 	file_info = (struct smb2_file_comp_info *)rsp->Buffer;
 	file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index e35914457350..d0e94b73931a 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1650,7 +1650,8 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
 	u64 time;
 	int rc;
 
-	generic_fillattr(idmap, d_inode(dentry), ksmbd_kstat->kstat);
+	generic_fillattr(idmap, STATX_BASIC_STATS, d_inode(dentry),
+			 ksmbd_kstat->kstat);
 
 	time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);
 	ksmbd_kstat->create_time = time;
diff --git a/fs/stat.c b/fs/stat.c
index 8c2b30af19f5..062f311b5386 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -29,6 +29,7 @@
 /**
  * generic_fillattr - Fill in the basic attributes from the inode struct
  * @idmap:	idmap of the mount the inode was found from
+ * @req_mask	statx request_mask
  * @inode:	Inode to use as the source
  * @stat:	Where to fill in the attributes
  *
@@ -42,8 +43,8 @@
  * uid and gid filds. On non-idmapped mounts or if permission checking is to be
  * performed on the raw inode simply passs @nop_mnt_idmap.
  */
-void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
-		      struct kstat *stat)
+void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
+		      struct inode *inode, struct kstat *stat)
 {
 	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
 	vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
@@ -61,6 +62,12 @@ void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
 	stat->ctime = inode_get_ctime(inode);
 	stat->blksize = i_blocksize(inode);
 	stat->blocks = inode->i_blocks;
+
+	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
+		stat->result_mask |= STATX_CHANGE_COOKIE;
+		stat->change_cookie = inode_query_iversion(inode);
+	}
+
 }
 EXPORT_SYMBOL(generic_fillattr);
 
@@ -123,17 +130,12 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
 	stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT |
 				  STATX_ATTR_DAX);
 
-	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
-		stat->result_mask |= STATX_CHANGE_COOKIE;
-		stat->change_cookie = inode_query_iversion(inode);
-	}
-
 	idmap = mnt_idmap(path->mnt);
 	if (inode->i_op->getattr)
 		return inode->i_op->getattr(idmap, path, stat,
 					    request_mask, query_flags);
 
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 	return 0;
 }
 EXPORT_SYMBOL(vfs_getattr_nosec);
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
index dba6a2ef26f1..edb94e55de8e 100644
--- a/fs/sysv/itree.c
+++ b/fs/sysv/itree.c
@@ -449,7 +449,8 @@ int sysv_getattr(struct mnt_idmap *idmap, const struct path *path,
 		 struct kstat *stat, u32 request_mask, unsigned int flags)
 {
 	struct super_block *s = path->dentry->d_sb;
-	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
+			 stat);
 	stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size);
 	stat->blksize = s->s_blocksize;
 	return 0;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 3a1ba8ba308a..2f48c58d47cd 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -1654,7 +1654,7 @@ int ubifs_getattr(struct mnt_idmap *idmap, const struct path *path,
 				STATX_ATTR_ENCRYPTED |
 				STATX_ATTR_IMMUTABLE);
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	stat->blksize = UBIFS_BLOCK_SIZE;
 	stat->size = ui->ui_size;
 
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 779b5c2c75f6..f7eaf7b14594 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -149,7 +149,7 @@ static int udf_symlink_getattr(struct mnt_idmap *idmap,
 	struct inode *inode = d_backing_inode(dentry);
 	struct page *page;
 
-	generic_fillattr(&nop_mnt_idmap, inode, stat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
 	page = read_mapping_page(inode->i_mapping, 0, NULL);
 	if (IS_ERR(page))
 		return PTR_ERR(page);
diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c
index 576b91d571c5..83f20dd15522 100644
--- a/fs/vboxsf/utils.c
+++ b/fs/vboxsf/utils.c
@@ -252,7 +252,7 @@ int vboxsf_getattr(struct mnt_idmap *idmap, const struct path *path,
 	if (err)
 		return err;
 
-	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), kstat);
+	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), kstat);
 	return 0;
 }
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 39076ea6a360..42d1434cc427 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2919,7 +2919,7 @@ extern void page_put_link(void *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
 extern void kfree_link(void *);
-void generic_fillattr(struct mnt_idmap *, struct inode *, struct kstat *);
+void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
 void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
 extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
 extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);
diff --git a/mm/shmem.c b/mm/shmem.c
index 310b0544eae3..b154af49d2df 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1073,7 +1073,7 @@ static int shmem_getattr(struct mnt_idmap *idmap,
 	stat->attributes_mask |= (STATX_ATTR_APPEND |
 			STATX_ATTR_IMMUTABLE |
 			STATX_ATTR_NODUMP);
-	generic_fillattr(idmap, inode, stat);
+	generic_fillattr(idmap, request_mask, inode, stat);
 
 	if (shmem_is_huge(inode, 0, false, NULL, 0))
 		stat->blksize = HPAGE_PMD_SIZE;

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-08-02 19:35   ` Jan Kara
  2023-07-25 14:58 ` [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable Jeff Layton
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

The VFS always uses coarse-grained timestamps when updating the ctime
and mtime after a change. This has the benefit of allowing filesystems
to optimize away a lot metadata updates, down to around 1 per jiffy,
even when a file is under heavy writes.

Unfortunately, this has always been an issue when we're exporting via
NFSv3, which relies on timestamps to validate caches. A lot of changes
can happen in a jiffy, so timestamps aren't sufficient to help the
client decide to invalidate the cache. Even with NFSv4, a lot of
exported filesystems don't properly support a change attribute and are
subject to the same problems with timestamp granularity. Other
applications have similar issues with timestamps (e.g backup
applications).

If we were to always use fine-grained timestamps, that would improve the
situation, but that becomes rather expensive, as the underlying
filesystem would have to log a lot more metadata updates.

What we need is a way to only use fine-grained timestamps when they are
being actively queried.

POSIX generally mandates that when the the mtime changes, the ctime must
also change. The kernel always stores normalized ctime values, so only
the first 30 bits of the tv_nsec field are ever used.

Use the 31st bit of the ctime tv_nsec field to indicate that something
has queried the inode for the mtime or ctime. When this flag is set,
on the next mtime or ctime update, the kernel will fetch a fine-grained
timestamp instead of the usual coarse-grained one.

Filesytems can opt into this behavior by setting the FS_MGTIME flag in
the fstype. Filesystems that don't set this flag will continue to use
coarse-grained timestamps.

Later patches will convert individual filesystems to use the new
infrastructure.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/inode.c         | 98 ++++++++++++++++++++++++++++++++++++++----------------
 fs/stat.c          | 41 +++++++++++++++++++++--
 include/linux/fs.h | 45 +++++++++++++++++++++++--
 3 files changed, 151 insertions(+), 33 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index d4ab92233062..369621e7faf5 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1919,6 +1919,21 @@ int inode_update_time(struct inode *inode, struct timespec64 *time, int flags)
 }
 EXPORT_SYMBOL(inode_update_time);
 
+/**
+ * current_coarse_time - Return FS time
+ * @inode: inode.
+ *
+ * Return the current coarse-grained time truncated to the time
+ * granularity supported by the fs.
+ */
+static struct timespec64 current_coarse_time(struct inode *inode)
+{
+	struct timespec64 now;
+
+	ktime_get_coarse_real_ts64(&now);
+	return timestamp_truncate(now, inode);
+}
+
 /**
  *	atime_needs_update	-	update the access time
  *	@path: the &struct path to update
@@ -1952,7 +1967,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
 	if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
 		return false;
 
-	now = current_time(inode);
+	now = current_coarse_time(inode);
 
 	if (!relatime_need_update(mnt, inode, now))
 		return false;
@@ -1986,7 +2001,7 @@ void touch_atime(const struct path *path)
 	 * We may also fail on filesystems that have the ability to make parts
 	 * of the fs read only, e.g. subvolumes in Btrfs.
 	 */
-	now = current_time(inode);
+	now = current_coarse_time(inode);
 	inode_update_time(inode, &now, S_ATIME);
 	__mnt_drop_write(mnt);
 skip_update:
@@ -2072,6 +2087,56 @@ int file_remove_privs(struct file *file)
 }
 EXPORT_SYMBOL(file_remove_privs);
 
+/**
+ * current_mgtime - Return FS time (possibly fine-grained)
+ * @inode: inode.
+ *
+ * Return the current time truncated to the time granularity supported by
+ * the fs, as suitable for a ctime/mtime change. If the ctime is flagged
+ * as having been QUERIED, get a fine-grained timestamp.
+ */
+static struct timespec64 current_mgtime(struct inode *inode)
+{
+	struct timespec64 now;
+	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
+	long nsec = atomic_long_read(pnsec);
+
+	if (nsec & I_CTIME_QUERIED) {
+		ktime_get_real_ts64(&now);
+	} else {
+		struct timespec64 ctime;
+
+		ktime_get_coarse_real_ts64(&now);
+
+		/*
+		 * If we've recently fetched a fine-grained timestamp
+		 * then the coarse-grained one may still be earlier than the
+		 * existing one. Just keep the existing ctime if so.
+		 */
+		ctime = inode_get_ctime(inode);
+		if (timespec64_compare(&ctime, &now) > 0)
+			now = ctime;
+	}
+
+	return timestamp_truncate(now, inode);
+}
+
+/**
+ * current_time - Return timestamp suitable for ctime update
+ * @inode: inode to eventually be updated
+ *
+ * Return the current time, which is usually coarse-grained but may be fine
+ * grained if the filesystem uses multigrain timestamps and the existing
+ * ctime was queried since the last update.
+ */
+struct timespec64 current_time(struct inode *inode)
+{
+	if (is_mgtime(inode))
+		return current_mgtime(inode);
+	return current_coarse_time(inode);
+}
+EXPORT_SYMBOL(current_time);
+
 static int inode_needs_update_time(struct inode *inode, struct timespec64 *now)
 {
 	int sync_it = 0;
@@ -2480,37 +2545,12 @@ struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode)
 }
 EXPORT_SYMBOL(timestamp_truncate);
 
-/**
- * current_time - Return FS time
- * @inode: inode.
- *
- * Return the current time truncated to the time granularity supported by
- * the fs.
- *
- * Note that inode and inode->sb cannot be NULL.
- * Otherwise, the function warns and returns time without truncation.
- */
-struct timespec64 current_time(struct inode *inode)
-{
-	struct timespec64 now;
-
-	ktime_get_coarse_real_ts64(&now);
-
-	if (unlikely(!inode->i_sb)) {
-		WARN(1, "current_time() called with uninitialized super_block in the inode");
-		return now;
-	}
-
-	return timestamp_truncate(now, inode);
-}
-EXPORT_SYMBOL(current_time);
-
 /**
  * inode_set_ctime_current - set the ctime to current_time
  * @inode: inode
  *
- * Set the inode->i_ctime to the current value for the inode. Returns
- * the current value that was assigned to i_ctime.
+ * Set the inode->__i_ctime to the current value for the inode. Returns
+ * the current value that was assigned to __i_ctime.
  */
 struct timespec64 inode_set_ctime_current(struct inode *inode)
 {
diff --git a/fs/stat.c b/fs/stat.c
index 062f311b5386..51effd1c2bc2 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -26,6 +26,37 @@
 #include "internal.h"
 #include "mount.h"
 
+/**
+ * fill_mg_cmtime - Fill in the mtime and ctime and flag ctime as QUERIED
+ * @request_mask: STATX_* values requested
+ * @inode: inode from which to grab the c/mtime
+ * @stat: where to store the resulting values
+ *
+ * Given @inode, grab the ctime and mtime out if it and store the result
+ * in @stat. When fetching the value, flag it as queried so the next write
+ * will use a fine-grained timestamp.
+ */
+void fill_mg_cmtime(u32 request_mask, struct inode *inode, struct kstat *stat)
+{
+	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
+
+	/* If neither time was requested, then don't report them */
+	if (!(request_mask & (STATX_CTIME|STATX_MTIME))) {
+		stat->result_mask &= ~(STATX_CTIME|STATX_MTIME);
+		return;
+	}
+
+	stat->mtime = inode->i_mtime;
+	stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
+	/*
+	 * Atomically set the QUERIED flag and fetch the new value with
+	 * the flag masked off.
+	 */
+	stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
+					~I_CTIME_QUERIED;
+}
+EXPORT_SYMBOL(fill_mg_cmtime);
+
 /**
  * generic_fillattr - Fill in the basic attributes from the inode struct
  * @idmap:	idmap of the mount the inode was found from
@@ -58,8 +89,14 @@ void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
 	stat->rdev = inode->i_rdev;
 	stat->size = i_size_read(inode);
 	stat->atime = inode->i_atime;
-	stat->mtime = inode->i_mtime;
-	stat->ctime = inode_get_ctime(inode);
+
+	if (is_mgtime(inode)) {
+		fill_mg_cmtime(request_mask, inode, stat);
+	} else {
+		stat->mtime = inode->i_mtime;
+		stat->ctime = inode_get_ctime(inode);
+	}
+
 	stat->blksize = i_blocksize(inode);
 	stat->blocks = inode->i_blocks;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 42d1434cc427..a0bdbefbf293 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1477,15 +1477,43 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
 struct timespec64 current_time(struct inode *inode);
 struct timespec64 inode_set_ctime_current(struct inode *inode);
 
+/*
+ * Multigrain timestamps
+ *
+ * Conditionally use fine-grained ctime and mtime timestamps when there
+ * are users actively observing them via getattr. The primary use-case
+ * for this is NFS clients that use the ctime to distinguish between
+ * different states of the file, and that are often fooled by multiple
+ * operations that occur in the same coarse-grained timer tick.
+ *
+ * The kernel always keeps normalized struct timespec64 values in the ctime,
+ * which means that only the first 30 bits of the value are used. Use the
+ * 31st bit of the ctime's tv_nsec field as a flag to indicate that the value
+ * has been queried since it was last updated.
+ */
+#define I_CTIME_QUERIED		(1L<<30)
+
 /**
  * inode_get_ctime - fetch the current ctime from the inode
  * @inode: inode from which to fetch ctime
  *
- * Grab the current ctime from the inode and return it.
+ * Grab the current ctime tv_nsec field from the inode, mask off the
+ * I_CTIME_QUERIED flag and return it. This is mostly intended for use by
+ * internal consumers of the ctime that aren't concerned with ensuring a
+ * fine-grained update on the next change (e.g. when preparing to store
+ * the value in the backing store for later retrieval).
+ *
+ * This is safe to call regardless of whether the underlying filesystem
+ * is using multigrain timestamps.
  */
 static inline struct timespec64 inode_get_ctime(const struct inode *inode)
 {
-	return inode->__i_ctime;
+	struct timespec64 ctime;
+
+	ctime.tv_sec = inode->__i_ctime.tv_sec;
+	ctime.tv_nsec = inode->__i_ctime.tv_nsec & ~I_CTIME_QUERIED;
+
+	return ctime;
 }
 
 /**
@@ -2261,6 +2289,7 @@ struct file_system_type {
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
 #define FS_DISALLOW_NOTIFY_PERM	16	/* Disable fanotify permission events */
 #define FS_ALLOW_IDMAP         32      /* FS has been updated to handle vfs idmappings. */
+#define FS_MGTIME		64	/* FS uses multigrain timestamps */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
 	int (*init_fs_context)(struct fs_context *);
 	const struct fs_parameter_spec *parameters;
@@ -2284,6 +2313,17 @@ struct file_system_type {
 
 #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
 
+/**
+ * is_mgtime: is this inode using multigrain timestamps
+ * @inode: inode to test for multigrain timestamps
+ *
+ * Return true if the inode uses multigrain timestamps, false otherwise.
+ */
+static inline bool is_mgtime(const struct inode *inode)
+{
+	return inode->i_sb->s_type->fs_flags & FS_MGTIME;
+}
+
 extern struct dentry *mount_bdev(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data,
 	int (*fill_super)(struct super_block *, void *, int));
@@ -2919,6 +2959,7 @@ extern void page_put_link(void *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
 extern void kfree_link(void *);
+void fill_mg_cmtime(u32 request_mask, struct inode *inode, struct kstat *stat);
 void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
 void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
 extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
  2023-07-25 14:58 ` [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-07-26  1:39   ` Hugh Dickins
  2023-07-25 14:58 ` [PATCH v6 4/7] tmpfs: add support for multigrain timestamps Jeff Layton
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

Most filesystems that use the pagecache will update the mtime, ctime,
and change attribute when a page becomes writeable. Add a page_mkwrite
operation for tmpfs and just use it to bump the mtime, ctime and change
attribute.

This fixes xfstest generic/080 on tmpfs.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 mm/shmem.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/mm/shmem.c b/mm/shmem.c
index b154af49d2df..654d9a585820 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2169,6 +2169,16 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
 	return ret;
 }
 
+static vm_fault_t shmem_page_mkwrite(struct vm_fault *vmf)
+{
+	struct vm_area_struct *vma = vmf->vma;
+	struct inode *inode = file_inode(vma->vm_file);
+
+	file_update_time(vma->vm_file);
+	inode_inc_iversion(inode);
+	return 0;
+}
+
 unsigned long shmem_get_unmapped_area(struct file *file,
 				      unsigned long uaddr, unsigned long len,
 				      unsigned long pgoff, unsigned long flags)
@@ -4210,6 +4220,7 @@ static const struct super_operations shmem_ops = {
 
 static const struct vm_operations_struct shmem_vm_ops = {
 	.fault		= shmem_fault,
+	.page_mkwrite	= shmem_page_mkwrite,
 	.map_pages	= filemap_map_pages,
 #ifdef CONFIG_NUMA
 	.set_policy     = shmem_set_policy,
@@ -4219,6 +4230,7 @@ static const struct vm_operations_struct shmem_vm_ops = {
 
 static const struct vm_operations_struct shmem_anon_vm_ops = {
 	.fault		= shmem_fault,
+	.page_mkwrite	= shmem_page_mkwrite,
 	.map_pages	= filemap_map_pages,
 #ifdef CONFIG_NUMA
 	.set_policy     = shmem_set_policy,

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 4/7] tmpfs: add support for multigrain timestamps
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
                   ` (2 preceding siblings ...)
  2023-07-25 14:58 ` [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-08-02 19:37   ` Jan Kara
  2023-07-25 14:58 ` [PATCH v6 5/7] xfs: switch to " Jeff Layton
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

Enable multigrain timestamps, which should ensure that there is an
apparent change to the timestamp whenever it has been written after
being actively observed via getattr.

tmpfs only requires the FS_MGTIME flag.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 mm/shmem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index 654d9a585820..b6019c905058 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -4264,7 +4264,7 @@ static struct file_system_type shmem_fs_type = {
 #endif
 	.kill_sb	= kill_litter_super,
 #ifdef CONFIG_SHMEM
-	.fs_flags	= FS_USERNS_MOUNT | FS_ALLOW_IDMAP,
+	.fs_flags	= FS_USERNS_MOUNT | FS_ALLOW_IDMAP | FS_MGTIME,
 #else
 	.fs_flags	= FS_USERNS_MOUNT,
 #endif

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 5/7] xfs: switch to multigrain timestamps
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
                   ` (3 preceding siblings ...)
  2023-07-25 14:58 ` [PATCH v6 4/7] tmpfs: add support for multigrain timestamps Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-08-02 17:48   ` Darrick J. Wong
  2023-07-25 14:58 ` [PATCH v6 6/7] ext4: " Jeff Layton
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

Enable multigrain timestamps, which should ensure that there is an
apparent change to the timestamp whenever it has been written after
being actively observed via getattr.

Also, anytime the mtime changes, the ctime must also change, and those
are now the only two options for xfs_trans_ichgtime. Have that function
unconditionally bump the ctime, and ASSERT that XFS_ICHGTIME_CHG is
always set.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/xfs/libxfs/xfs_trans_inode.c | 6 +++---
 fs/xfs/xfs_iops.c               | 4 ++--
 fs/xfs/xfs_super.c              | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
index 6b2296ff248a..ad22656376d3 100644
--- a/fs/xfs/libxfs/xfs_trans_inode.c
+++ b/fs/xfs/libxfs/xfs_trans_inode.c
@@ -62,12 +62,12 @@ xfs_trans_ichgtime(
 	ASSERT(tp);
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-	tv = current_time(inode);
+	/* If the mtime changes, then ctime must also change */
+	ASSERT(flags & XFS_ICHGTIME_CHG);
 
+	tv = inode_set_ctime_current(inode);
 	if (flags & XFS_ICHGTIME_MOD)
 		inode->i_mtime = tv;
-	if (flags & XFS_ICHGTIME_CHG)
-		inode_set_ctime_to_ts(inode, tv);
 	if (flags & XFS_ICHGTIME_CREATE)
 		ip->i_crtime = tv;
 }
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 3a9363953ef2..3f89ef5a2820 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -573,10 +573,10 @@ xfs_vn_getattr(
 	stat->gid = vfsgid_into_kgid(vfsgid);
 	stat->ino = ip->i_ino;
 	stat->atime = inode->i_atime;
-	stat->mtime = inode->i_mtime;
-	stat->ctime = inode_get_ctime(inode);
 	stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks);
 
+	fill_mg_cmtime(request_mask, inode, stat);
+
 	if (xfs_has_v3inodes(mp)) {
 		if (request_mask & STATX_BTIME) {
 			stat->result_mask |= STATX_BTIME;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 818510243130..4b10edb2c972 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -2009,7 +2009,7 @@ static struct file_system_type xfs_fs_type = {
 	.init_fs_context	= xfs_init_fs_context,
 	.parameters		= xfs_fs_parameters,
 	.kill_sb		= kill_block_super,
-	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
+	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME,
 };
 MODULE_ALIAS_FS("xfs");
 

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 6/7] ext4: switch to multigrain timestamps
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
                   ` (4 preceding siblings ...)
  2023-07-25 14:58 ` [PATCH v6 5/7] xfs: switch to " Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-08-02 19:38   ` Jan Kara
  2023-07-25 14:58 ` [PATCH v6 7/7] btrfs: convert " Jeff Layton
  2023-07-28 11:00 ` (subset) [PATCH v6 0/7] fs: implement " Christian Brauner
  7 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

Enable multigrain timestamps, which should ensure that there is an
apparent change to the timestamp whenever it has been written after
being actively observed via getattr.

For ext4, we only need to enable the FS_MGTIME flag.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/ext4/super.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b54c70e1a74e..cb1ff47af156 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -7279,7 +7279,7 @@ static struct file_system_type ext4_fs_type = {
 	.init_fs_context	= ext4_init_fs_context,
 	.parameters		= ext4_param_specs,
 	.kill_sb		= kill_block_super,
-	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
+	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME,
 };
 MODULE_ALIAS_FS("ext4");
 

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 7/7] btrfs: convert to multigrain timestamps
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
                   ` (5 preceding siblings ...)
  2023-07-25 14:58 ` [PATCH v6 6/7] ext4: " Jeff Layton
@ 2023-07-25 14:58 ` Jeff Layton
  2023-07-26 12:44   ` David Sterba
  2023-07-28 11:00 ` (subset) [PATCH v6 0/7] fs: implement " Christian Brauner
  7 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-07-25 14:58 UTC (permalink / raw)
  To: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

Enable multigrain timestamps, which should ensure that there is an
apparent change to the timestamp whenever it has been written after
being actively observed via getattr.

Beyond enabling the FS_MGTIME flag, this patch eliminates
update_time_for_write, which goes to great pains to avoid in-memory
stores. Just have it overwrite the timestamps unconditionally.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/btrfs/file.c  | 24 ++++--------------------
 fs/btrfs/super.c |  5 +++--
 2 files changed, 7 insertions(+), 22 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index d7a9ece7a40b..b9e75c9f95ac 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1106,25 +1106,6 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode)
 	btrfs_drew_write_unlock(&inode->root->snapshot_lock);
 }
 
-static void update_time_for_write(struct inode *inode)
-{
-	struct timespec64 now, ctime;
-
-	if (IS_NOCMTIME(inode))
-		return;
-
-	now = current_time(inode);
-	if (!timespec64_equal(&inode->i_mtime, &now))
-		inode->i_mtime = now;
-
-	ctime = inode_get_ctime(inode);
-	if (!timespec64_equal(&ctime, &now))
-		inode_set_ctime_to_ts(inode, now);
-
-	if (IS_I_VERSION(inode))
-		inode_inc_iversion(inode);
-}
-
 static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,
 			     size_t count)
 {
@@ -1156,7 +1137,10 @@ static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,
 	 * need to start yet another transaction to update the inode as we will
 	 * update the inode when we finish writing whatever data we write.
 	 */
-	update_time_for_write(inode);
+	if (!IS_NOCMTIME(inode)) {
+		inode->i_mtime = inode_set_ctime_current(inode);
+		inode_inc_iversion(inode);
+	}
 
 	start_pos = round_down(pos, fs_info->sectorsize);
 	oldsize = i_size_read(inode);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index f1dd172d8d5b..8eda51b095c9 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2144,7 +2144,7 @@ static struct file_system_type btrfs_fs_type = {
 	.name		= "btrfs",
 	.mount		= btrfs_mount,
 	.kill_sb	= btrfs_kill_super,
-	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
+	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_MGTIME,
 };
 
 static struct file_system_type btrfs_root_fs_type = {
@@ -2152,7 +2152,8 @@ static struct file_system_type btrfs_root_fs_type = {
 	.name		= "btrfs",
 	.mount		= btrfs_mount_root,
 	.kill_sb	= btrfs_kill_super,
-	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_ALLOW_IDMAP,
+	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA |
+			  FS_ALLOW_IDMAP | FS_MGTIME,
 };
 
 MODULE_ALIAS_FS("btrfs");

-- 
2.41.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable
  2023-07-25 14:58 ` [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable Jeff Layton
@ 2023-07-26  1:39   ` Hugh Dickins
  2023-07-26 10:26     ` Jeff Layton
  0 siblings, 1 reply; 30+ messages in thread
From: Hugh Dickins @ 2023-07-26  1:39 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, 25 Jul 2023, Jeff Layton wrote:

> Most filesystems that use the pagecache will update the mtime, ctime,
> and change attribute when a page becomes writeable. Add a page_mkwrite
> operation for tmpfs and just use it to bump the mtime, ctime and change
> attribute.
> 
> This fixes xfstest generic/080 on tmpfs.

Huh.  I didn't notice when this one crept into the multigrain series.

I'm inclined to NAK this patch: at the very least, it does not belong
in the series, but should be discussed separately.

Yes, tmpfs does not and never has used page_mkwrite, and gains some
performance advantage from that.  Nobody has ever asked for this
change before, or not that I recall.

Please drop it from the series: and if you feel strongly, or know
strong reasons why tmpfs suddenly needs to use page_mkwrite now,
please argue them separately.  To pass generic/080 is not enough.

Thanks,
Hugh

> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  mm/shmem.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/mm/shmem.c b/mm/shmem.c
> index b154af49d2df..654d9a585820 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -2169,6 +2169,16 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
>  	return ret;
>  }
>  
> +static vm_fault_t shmem_page_mkwrite(struct vm_fault *vmf)
> +{
> +	struct vm_area_struct *vma = vmf->vma;
> +	struct inode *inode = file_inode(vma->vm_file);
> +
> +	file_update_time(vma->vm_file);
> +	inode_inc_iversion(inode);
> +	return 0;
> +}
> +
>  unsigned long shmem_get_unmapped_area(struct file *file,
>  				      unsigned long uaddr, unsigned long len,
>  				      unsigned long pgoff, unsigned long flags)
> @@ -4210,6 +4220,7 @@ static const struct super_operations shmem_ops = {
>  
>  static const struct vm_operations_struct shmem_vm_ops = {
>  	.fault		= shmem_fault,
> +	.page_mkwrite	= shmem_page_mkwrite,
>  	.map_pages	= filemap_map_pages,
>  #ifdef CONFIG_NUMA
>  	.set_policy     = shmem_set_policy,
> @@ -4219,6 +4230,7 @@ static const struct vm_operations_struct shmem_vm_ops = {
>  
>  static const struct vm_operations_struct shmem_anon_vm_ops = {
>  	.fault		= shmem_fault,
> +	.page_mkwrite	= shmem_page_mkwrite,
>  	.map_pages	= filemap_map_pages,
>  #ifdef CONFIG_NUMA
>  	.set_policy     = shmem_set_policy,
> 
> -- 
> 2.41.0

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
@ 2023-07-26  2:46   ` Xiubo Li
  2023-07-26  9:40   ` Joseph Qi
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 30+ messages in thread
From: Xiubo Li @ 2023-07-26  2:46 UTC (permalink / raw)
  To: Jeff Layton, Eric Van Hensbergen, Latchesar Ionkov,
	Dominique Martinet, Christian Schoenebeck, David Howells,
	Marc Dionne, Chris Mason, Josef Bacik, David Sterba,
	Ilya Dryomov, Jan Harkes, coda, Tyler Hicks, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Namjae Jeon, Sungjong Seo, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi,
	Miklos Szeredi, Bob Peterson, Andreas Gruenbacher,
	Greg Kroah-Hartman, Tejun Heo, Alexander Viro, Christian Brauner,
	Trond Myklebust, Anna Schumaker, Konstantin Komarov, Mark Fasheh,
	Joel Becker, Joseph Qi, Mike Marshall, Martin Brandenburg,
	Luis Chamberlain, Kees Cook, Iurii Zaikin, Steve French,
	Paulo Alcantara, Ronnie Sahlberg, Shyam Prasad N, Tom Talpey,
	Sergey Senozhatsky, Richard Weinberger, Hans de Goede,
	Hugh Dickins, Andrew Morton, Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs


On 7/25/23 22:58, Jeff Layton wrote:
> generic_fillattr just fills in the entire stat struct indiscriminately
> today, copying data from the inode. There is at least one attribute
> (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> and we're looking at adding more with the addition of multigrain
> timestamps.
>
> Add a request_mask argument to generic_fillattr and have most callers
> just pass in the value that is passed to getattr. Have other callers
> (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> STATX_CHANGE_COOKIE into generic_fillattr.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>   fs/9p/vfs_inode.c       |  4 ++--
>   fs/9p/vfs_inode_dotl.c  |  4 ++--
>   fs/afs/inode.c          |  2 +-
>   fs/btrfs/inode.c        |  2 +-
>   fs/ceph/inode.c         |  2 +-

The ceph change looks good to me.

Reviewed-by: Xiubo Li <xiubli@redhat.com>


>   fs/coda/inode.c         |  3 ++-
>   fs/ecryptfs/inode.c     |  5 +++--
>   fs/erofs/inode.c        |  2 +-
>   fs/exfat/file.c         |  2 +-
>   fs/ext2/inode.c         |  2 +-
>   fs/ext4/inode.c         |  2 +-
>   fs/f2fs/file.c          |  2 +-
>   fs/fat/file.c           |  2 +-
>   fs/fuse/dir.c           |  2 +-
>   fs/gfs2/inode.c         |  2 +-
>   fs/hfsplus/inode.c      |  2 +-
>   fs/kernfs/inode.c       |  2 +-
>   fs/libfs.c              |  4 ++--
>   fs/minix/inode.c        |  2 +-
>   fs/nfs/inode.c          |  2 +-
>   fs/nfs/namespace.c      |  3 ++-
>   fs/ntfs3/file.c         |  2 +-
>   fs/ocfs2/file.c         |  2 +-
>   fs/orangefs/inode.c     |  2 +-
>   fs/proc/base.c          |  4 ++--
>   fs/proc/fd.c            |  2 +-
>   fs/proc/generic.c       |  2 +-
>   fs/proc/proc_net.c      |  2 +-
>   fs/proc/proc_sysctl.c   |  2 +-
>   fs/proc/root.c          |  3 ++-
>   fs/smb/client/inode.c   |  2 +-
>   fs/smb/server/smb2pdu.c | 22 +++++++++++-----------
>   fs/smb/server/vfs.c     |  3 ++-
>   fs/stat.c               | 18 ++++++++++--------
>   fs/sysv/itree.c         |  3 ++-
>   fs/ubifs/dir.c          |  2 +-
>   fs/udf/symlink.c        |  2 +-
>   fs/vboxsf/utils.c       |  2 +-
>   include/linux/fs.h      |  2 +-
>   mm/shmem.c              |  2 +-
>   40 files changed, 70 insertions(+), 62 deletions(-)
>
> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
> index 16d85e6033a3..d24d1f20e922 100644
> --- a/fs/9p/vfs_inode.c
> +++ b/fs/9p/vfs_inode.c
> @@ -1016,7 +1016,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
>   	v9ses = v9fs_dentry2v9ses(dentry);
>   	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   		return 0;
>   	} else if (v9ses->cache & CACHE_WRITEBACK) {
>   		if (S_ISREG(inode->i_mode)) {
> @@ -1037,7 +1037,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   		return PTR_ERR(st);
>   
>   	v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb, 0);
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
>   
>   	p9stat_free(st);
>   	kfree(st);
> diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
> index 464ea73d1bf8..8e8d5d2a13d8 100644
> --- a/fs/9p/vfs_inode_dotl.c
> +++ b/fs/9p/vfs_inode_dotl.c
> @@ -451,7 +451,7 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
>   	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
>   	v9ses = v9fs_dentry2v9ses(dentry);
>   	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   		return 0;
>   	} else if (v9ses->cache) {
>   		if (S_ISREG(inode->i_mode)) {
> @@ -476,7 +476,7 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
>   		return PTR_ERR(st);
>   
>   	v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
>   	/* Change block size to what the server returned */
>   	stat->blksize = st->st_blksize;
>   
> diff --git a/fs/afs/inode.c b/fs/afs/inode.c
> index 6b636f43f548..1c794a1896aa 100644
> --- a/fs/afs/inode.c
> +++ b/fs/afs/inode.c
> @@ -773,7 +773,7 @@ int afs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   
>   	do {
>   		read_seqbegin_or_lock(&vnode->cb_lock, &seq);
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   		if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
>   		    stat->nlink > 0)
>   			stat->nlink -= 1;
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index bcccd551f547..7346059209aa 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -8773,7 +8773,7 @@ static int btrfs_getattr(struct mnt_idmap *idmap,
>   				  STATX_ATTR_IMMUTABLE |
>   				  STATX_ATTR_NODUMP);
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   	stat->dev = BTRFS_I(inode)->root->anon_dev;
>   
>   	spin_lock(&BTRFS_I(inode)->lock);
> diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
> index 5f6e93714f5a..fd05d68e2990 100644
> --- a/fs/ceph/inode.c
> +++ b/fs/ceph/inode.c
> @@ -2467,7 +2467,7 @@ int ceph_getattr(struct mnt_idmap *idmap, const struct path *path,
>   			return err;
>   	}
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	stat->ino = ceph_present_inode(inode);
>   
>   	/*
> diff --git a/fs/coda/inode.c b/fs/coda/inode.c
> index 3e64679c1620..0c7c2528791e 100644
> --- a/fs/coda/inode.c
> +++ b/fs/coda/inode.c
> @@ -256,7 +256,8 @@ int coda_getattr(struct mnt_idmap *idmap, const struct path *path,
>   {
>   	int err = coda_revalidate_inode(d_inode(path->dentry));
>   	if (!err)
> -		generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask,
> +				 d_inode(path->dentry), stat);
>   	return err;
>   }
>   
> diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
> index b491bb239c8f..992d9c7e64ae 100644
> --- a/fs/ecryptfs/inode.c
> +++ b/fs/ecryptfs/inode.c
> @@ -982,7 +982,7 @@ static int ecryptfs_getattr_link(struct mnt_idmap *idmap,
>   
>   	mount_crypt_stat = &ecryptfs_superblock_to_private(
>   						dentry->d_sb)->mount_crypt_stat;
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
>   	if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
>   		char *target;
>   		size_t targetsiz;
> @@ -1011,7 +1011,8 @@ static int ecryptfs_getattr(struct mnt_idmap *idmap,
>   	if (!rc) {
>   		fsstack_copy_attr_all(d_inode(dentry),
>   				      ecryptfs_inode_to_lower(d_inode(dentry)));
> -		generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask,
> +				 d_inode(dentry), stat);
>   		stat->blocks = lower_stat.blocks;
>   	}
>   	return rc;
> diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
> index c9bbdf7c34db..edc8ec7581b8 100644
> --- a/fs/erofs/inode.c
> +++ b/fs/erofs/inode.c
> @@ -369,7 +369,7 @@ int erofs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
>   				  STATX_ATTR_IMMUTABLE);
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   
> diff --git a/fs/exfat/file.c b/fs/exfat/file.c
> index f40ecfeee3a4..32395ef686a2 100644
> --- a/fs/exfat/file.c
> +++ b/fs/exfat/file.c
> @@ -232,7 +232,7 @@ int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	struct inode *inode = d_backing_inode(path->dentry);
>   	struct exfat_inode_info *ei = EXFAT_I(inode);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	exfat_truncate_atime(&stat->atime);
>   	stat->result_mask |= STATX_BTIME;
>   	stat->btime.tv_sec = ei->i_crtime.tv_sec;
> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
> index 1259995977d2..acbab27fe957 100644
> --- a/fs/ext2/inode.c
> +++ b/fs/ext2/inode.c
> @@ -1628,7 +1628,7 @@ int ext2_getattr(struct mnt_idmap *idmap, const struct path *path,
>   			STATX_ATTR_IMMUTABLE |
>   			STATX_ATTR_NODUMP);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 86696b40c58f..6683076ecb2f 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -5535,7 +5535,7 @@ int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
>   				  STATX_ATTR_NODUMP |
>   				  STATX_ATTR_VERITY);
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index b018800223c4..35886a52edfb 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -882,7 +882,7 @@ int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   				  STATX_ATTR_NODUMP |
>   				  STATX_ATTR_VERITY);
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   
>   	/* we need to show initial sectors used for inline_data/dentries */
>   	if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
> diff --git a/fs/fat/file.c b/fs/fat/file.c
> index 456477946dd9..e887e9ab7472 100644
> --- a/fs/fat/file.c
> +++ b/fs/fat/file.c
> @@ -401,7 +401,7 @@ int fat_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	struct inode *inode = d_inode(path->dentry);
>   	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   	stat->blksize = sbi->cluster_size;
>   
>   	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) {
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 672245ee0394..881524b9a55a 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -1222,7 +1222,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
>   		forget_all_cached_acls(inode);
>   		err = fuse_do_getattr(inode, stat, file);
>   	} else if (stat) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   		stat->mode = fi->orig_i_mode;
>   		stat->ino = fi->orig_ino;
>   	}
> diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
> index 2ded6c813f20..200cabf3b393 100644
> --- a/fs/gfs2/inode.c
> +++ b/fs/gfs2/inode.c
> @@ -2071,7 +2071,7 @@ static int gfs2_getattr(struct mnt_idmap *idmap,
>   				  STATX_ATTR_IMMUTABLE |
>   				  STATX_ATTR_NODUMP);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   
>   	if (gfs2_holder_initialized(&gh))
>   		gfs2_glock_dq_uninit(&gh);
> diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
> index 40c61ab4a918..c65c8c4b03dd 100644
> --- a/fs/hfsplus/inode.c
> +++ b/fs/hfsplus/inode.c
> @@ -298,7 +298,7 @@ int hfsplus_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	stat->attributes_mask |= STATX_ATTR_APPEND | STATX_ATTR_IMMUTABLE |
>   				 STATX_ATTR_NODUMP;
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   
> diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
> index 89a9b4dcf109..af37be68bf06 100644
> --- a/fs/kernfs/inode.c
> +++ b/fs/kernfs/inode.c
> @@ -190,7 +190,7 @@ int kernfs_iop_getattr(struct mnt_idmap *idmap,
>   
>   	down_read(&root->kernfs_iattr_rwsem);
>   	kernfs_refresh_inode(kn, inode);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	up_read(&root->kernfs_iattr_rwsem);
>   
>   	return 0;
> diff --git a/fs/libfs.c b/fs/libfs.c
> index b27260e0c14a..0a9f3c426548 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -33,7 +33,7 @@ int simple_getattr(struct mnt_idmap *idmap, const struct path *path,
>   		   unsigned int query_flags)
>   {
>   	struct inode *inode = d_inode(path->dentry);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	stat->blocks = inode->i_mapping->nrpages << (PAGE_SHIFT - 9);
>   	return 0;
>   }
> @@ -1585,7 +1585,7 @@ static int empty_dir_getattr(struct mnt_idmap *idmap,
>   			     u32 request_mask, unsigned int query_flags)
>   {
>   	struct inode *inode = d_inode(path->dentry);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   
> diff --git a/fs/minix/inode.c b/fs/minix/inode.c
> index 8a4fc9420b36..df575473c1cc 100644
> --- a/fs/minix/inode.c
> +++ b/fs/minix/inode.c
> @@ -656,7 +656,7 @@ int minix_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	struct super_block *sb = path->dentry->d_sb;
>   	struct inode *inode = d_inode(path->dentry);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	if (INODE_VERSION(inode) == MINIX_V1)
>   		stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb);
>   	else
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 1283fdfa4b0a..e21c073158e5 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -912,7 +912,7 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	/* Only return attributes that were revalidated. */
>   	stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask;
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
>   	stat->change_cookie = inode_peek_iversion_raw(inode);
>   	stat->attributes_mask |= STATX_ATTR_CHANGE_MONOTONIC;
> diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
> index 19d51ebf842c..e7494cdd957e 100644
> --- a/fs/nfs/namespace.c
> +++ b/fs/nfs/namespace.c
> @@ -215,7 +215,8 @@ nfs_namespace_getattr(struct mnt_idmap *idmap,
>   	if (NFS_FH(d_inode(path->dentry))->size != 0)
>   		return nfs_getattr(idmap, path, stat, request_mask,
>   				   query_flags);
> -	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
> +			 stat);
>   	return 0;
>   }
>   
> diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
> index 12788601dc84..962f12ce6c0a 100644
> --- a/fs/ntfs3/file.c
> +++ b/fs/ntfs3/file.c
> @@ -85,7 +85,7 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   
>   	stat->attributes_mask |= STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED;
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   
>   	stat->result_mask |= STATX_BTIME;
>   	stat->btime = ni->i_crtime;
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 1b337ebce4df..8184499ae7a5 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1319,7 +1319,7 @@ int ocfs2_getattr(struct mnt_idmap *idmap, const struct path *path,
>   		goto bail;
>   	}
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	/*
>   	 * If there is inline data in the inode, the inode will normally not
>   	 * have data blocks allocated (it may have an external xattr block).
> diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
> index 9014bbcc8031..a52c30e80f45 100644
> --- a/fs/orangefs/inode.c
> +++ b/fs/orangefs/inode.c
> @@ -871,7 +871,7 @@ int orangefs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	ret = orangefs_inode_getattr(inode,
>   	    request_mask & STATX_SIZE ? ORANGEFS_GETATTR_SIZE : 0);
>   	if (ret == 0) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   
>   		/* override block size reported to stat */
>   		if (!(request_mask & STATX_SIZE))
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index d8388fc0a362..2bf67a0e0bcc 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -1966,7 +1966,7 @@ int pid_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
>   	struct task_struct *task;
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   
>   	stat->uid = GLOBAL_ROOT_UID;
>   	stat->gid = GLOBAL_ROOT_GID;
> @@ -3900,7 +3900,7 @@ static int proc_task_getattr(struct mnt_idmap *idmap,
>   {
>   	struct inode *inode = d_inode(path->dentry);
>   	struct task_struct *p = get_proc_task(inode);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   
>   	if (p) {
>   		stat->nlink += get_nr_threads(p);
> diff --git a/fs/proc/fd.c b/fs/proc/fd.c
> index b3140deebbbf..6276b3938842 100644
> --- a/fs/proc/fd.c
> +++ b/fs/proc/fd.c
> @@ -352,7 +352,7 @@ static int proc_fd_getattr(struct mnt_idmap *idmap,
>   	struct inode *inode = d_inode(path->dentry);
>   	int rv = 0;
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   
>   	/* If it's a directory, put the number of open fds there */
>   	if (S_ISDIR(inode->i_mode)) {
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index 42ae38ff6e7e..775ce0bcf08c 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -146,7 +146,7 @@ static int proc_getattr(struct mnt_idmap *idmap,
>   		}
>   	}
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   
> diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
> index 78f9e6b469c0..2ba31b6d68c0 100644
> --- a/fs/proc/proc_net.c
> +++ b/fs/proc/proc_net.c
> @@ -308,7 +308,7 @@ static int proc_tgid_net_getattr(struct mnt_idmap *idmap,
>   
>   	net = get_proc_task_net(inode);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   
>   	if (net != NULL) {
>   		stat->nlink = net->proc_net->nlink;
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index 6bc10e7e0ff7..bf06344a42cc 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -849,7 +849,7 @@ static int proc_sys_getattr(struct mnt_idmap *idmap,
>   	if (IS_ERR(head))
>   		return PTR_ERR(head);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	if (table)
>   		stat->mode = (stat->mode & S_IFMT) | table->mode;
>   
> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index a86e65a608da..9191248f2dac 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -314,7 +314,8 @@ static int proc_root_getattr(struct mnt_idmap *idmap,
>   			     const struct path *path, struct kstat *stat,
>   			     u32 request_mask, unsigned int query_flags)
>   {
> -	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
> +			 stat);
>   	stat->nlink = proc_root.nlink + nr_processes();
>   	return 0;
>   }
> diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
> index 218f03dd3f52..93fe43789d7a 100644
> --- a/fs/smb/client/inode.c
> +++ b/fs/smb/client/inode.c
> @@ -2540,7 +2540,7 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   			return rc;
>   	}
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	stat->blksize = cifs_sb->ctx->bsize;
>   	stat->ino = CIFS_I(inode)->uniqueid;
>   
> diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> index f9099831c8ff..2a084d35233a 100644
> --- a/fs/smb/server/smb2pdu.c
> +++ b/fs/smb/server/smb2pdu.c
> @@ -4391,8 +4391,8 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
>   	}
>   
>   	basic_info = (struct smb2_file_basic_info *)rsp->Buffer;
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>   	basic_info->CreationTime = cpu_to_le64(fp->create_time);
>   	time = ksmbd_UnixTimeToNT(stat.atime);
>   	basic_info->LastAccessTime = cpu_to_le64(time);
> @@ -4417,7 +4417,7 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
>   	struct kstat stat;
>   
>   	inode = file_inode(fp->filp);
> -	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
>   
>   	sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
>   	delete_pending = ksmbd_inode_pending_delete(fp);
> @@ -4471,7 +4471,7 @@ static int get_file_all_info(struct ksmbd_work *work,
>   		return PTR_ERR(filename);
>   
>   	inode = file_inode(fp->filp);
> -	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
>   
>   	ksmbd_debug(SMB, "filename = %s\n", filename);
>   	delete_pending = ksmbd_inode_pending_delete(fp);
> @@ -4548,8 +4548,8 @@ static void get_file_stream_info(struct ksmbd_work *work,
>   	int buf_free_len;
>   	struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
>   
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>   	file_info = (struct smb2_file_stream_info *)rsp->Buffer;
>   
>   	buf_free_len =
> @@ -4639,8 +4639,8 @@ static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
>   	struct smb2_file_internal_info *file_info;
>   	struct kstat stat;
>   
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>   	file_info = (struct smb2_file_internal_info *)rsp->Buffer;
>   	file_info->IndexNumber = cpu_to_le64(stat.ino);
>   	rsp->OutputBufferLength =
> @@ -4665,7 +4665,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
>   	file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
>   
>   	inode = file_inode(fp->filp);
> -	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
>   
>   	file_info->CreationTime = cpu_to_le64(fp->create_time);
>   	time = ksmbd_UnixTimeToNT(stat.atime);
> @@ -4726,8 +4726,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
>   	struct smb2_file_comp_info *file_info;
>   	struct kstat stat;
>   
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>   
>   	file_info = (struct smb2_file_comp_info *)rsp->Buffer;
>   	file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);
> diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
> index e35914457350..d0e94b73931a 100644
> --- a/fs/smb/server/vfs.c
> +++ b/fs/smb/server/vfs.c
> @@ -1650,7 +1650,8 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
>   	u64 time;
>   	int rc;
>   
> -	generic_fillattr(idmap, d_inode(dentry), ksmbd_kstat->kstat);
> +	generic_fillattr(idmap, STATX_BASIC_STATS, d_inode(dentry),
> +			 ksmbd_kstat->kstat);
>   
>   	time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);
>   	ksmbd_kstat->create_time = time;
> diff --git a/fs/stat.c b/fs/stat.c
> index 8c2b30af19f5..062f311b5386 100644
> --- a/fs/stat.c
> +++ b/fs/stat.c
> @@ -29,6 +29,7 @@
>   /**
>    * generic_fillattr - Fill in the basic attributes from the inode struct
>    * @idmap:	idmap of the mount the inode was found from
> + * @req_mask	statx request_mask
>    * @inode:	Inode to use as the source
>    * @stat:	Where to fill in the attributes
>    *
> @@ -42,8 +43,8 @@
>    * uid and gid filds. On non-idmapped mounts or if permission checking is to be
>    * performed on the raw inode simply passs @nop_mnt_idmap.
>    */
> -void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
> -		      struct kstat *stat)
> +void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
> +		      struct inode *inode, struct kstat *stat)
>   {
>   	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
>   	vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
> @@ -61,6 +62,12 @@ void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
>   	stat->ctime = inode_get_ctime(inode);
>   	stat->blksize = i_blocksize(inode);
>   	stat->blocks = inode->i_blocks;
> +
> +	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> +		stat->result_mask |= STATX_CHANGE_COOKIE;
> +		stat->change_cookie = inode_query_iversion(inode);
> +	}
> +
>   }
>   EXPORT_SYMBOL(generic_fillattr);
>   
> @@ -123,17 +130,12 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
>   	stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT |
>   				  STATX_ATTR_DAX);
>   
> -	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> -		stat->result_mask |= STATX_CHANGE_COOKIE;
> -		stat->change_cookie = inode_query_iversion(inode);
> -	}
> -
>   	idmap = mnt_idmap(path->mnt);
>   	if (inode->i_op->getattr)
>   		return inode->i_op->getattr(idmap, path, stat,
>   					    request_mask, query_flags);
>   
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   	return 0;
>   }
>   EXPORT_SYMBOL(vfs_getattr_nosec);
> diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
> index dba6a2ef26f1..edb94e55de8e 100644
> --- a/fs/sysv/itree.c
> +++ b/fs/sysv/itree.c
> @@ -449,7 +449,8 @@ int sysv_getattr(struct mnt_idmap *idmap, const struct path *path,
>   		 struct kstat *stat, u32 request_mask, unsigned int flags)
>   {
>   	struct super_block *s = path->dentry->d_sb;
> -	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
> +			 stat);
>   	stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size);
>   	stat->blksize = s->s_blocksize;
>   	return 0;
> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> index 3a1ba8ba308a..2f48c58d47cd 100644
> --- a/fs/ubifs/dir.c
> +++ b/fs/ubifs/dir.c
> @@ -1654,7 +1654,7 @@ int ubifs_getattr(struct mnt_idmap *idmap, const struct path *path,
>   				STATX_ATTR_ENCRYPTED |
>   				STATX_ATTR_IMMUTABLE);
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	stat->blksize = UBIFS_BLOCK_SIZE;
>   	stat->size = ui->ui_size;
>   
> diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
> index 779b5c2c75f6..f7eaf7b14594 100644
> --- a/fs/udf/symlink.c
> +++ b/fs/udf/symlink.c
> @@ -149,7 +149,7 @@ static int udf_symlink_getattr(struct mnt_idmap *idmap,
>   	struct inode *inode = d_backing_inode(dentry);
>   	struct page *page;
>   
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>   	page = read_mapping_page(inode->i_mapping, 0, NULL);
>   	if (IS_ERR(page))
>   		return PTR_ERR(page);
> diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c
> index 576b91d571c5..83f20dd15522 100644
> --- a/fs/vboxsf/utils.c
> +++ b/fs/vboxsf/utils.c
> @@ -252,7 +252,7 @@ int vboxsf_getattr(struct mnt_idmap *idmap, const struct path *path,
>   	if (err)
>   		return err;
>   
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), kstat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), kstat);
>   	return 0;
>   }
>   
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 39076ea6a360..42d1434cc427 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2919,7 +2919,7 @@ extern void page_put_link(void *);
>   extern int page_symlink(struct inode *inode, const char *symname, int len);
>   extern const struct inode_operations page_symlink_inode_operations;
>   extern void kfree_link(void *);
> -void generic_fillattr(struct mnt_idmap *, struct inode *, struct kstat *);
> +void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
>   void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
>   extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
>   extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 310b0544eae3..b154af49d2df 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1073,7 +1073,7 @@ static int shmem_getattr(struct mnt_idmap *idmap,
>   	stat->attributes_mask |= (STATX_ATTR_APPEND |
>   			STATX_ATTR_IMMUTABLE |
>   			STATX_ATTR_NODUMP);
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>   
>   	if (shmem_is_huge(inode, 0, false, NULL, 0))
>   		stat->blksize = HPAGE_PMD_SIZE;
>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
  2023-07-26  2:46   ` Xiubo Li
@ 2023-07-26  9:40   ` Joseph Qi
  2023-07-26 10:49     ` Jeff Layton
  2023-08-02 17:43   ` Jan Kara
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 30+ messages in thread
From: Joseph Qi @ 2023-07-26  9:40 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs



On 7/25/23 10:58 PM, Jeff Layton wrote:
> generic_fillattr just fills in the entire stat struct indiscriminately
> today, copying data from the inode. There is at least one attribute
> (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> and we're looking at adding more with the addition of multigrain
> timestamps.
> 
> Add a request_mask argument to generic_fillattr and have most callers
> just pass in the value that is passed to getattr. Have other callers
> (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> STATX_CHANGE_COOKIE into generic_fillattr.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/9p/vfs_inode.c       |  4 ++--
>  fs/9p/vfs_inode_dotl.c  |  4 ++--
>  fs/afs/inode.c          |  2 +-
>  fs/btrfs/inode.c        |  2 +-
>  fs/ceph/inode.c         |  2 +-
>  fs/coda/inode.c         |  3 ++-
>  fs/ecryptfs/inode.c     |  5 +++--
>  fs/erofs/inode.c        |  2 +-
>  fs/exfat/file.c         |  2 +-
>  fs/ext2/inode.c         |  2 +-
>  fs/ext4/inode.c         |  2 +-
>  fs/f2fs/file.c          |  2 +-
>  fs/fat/file.c           |  2 +-
>  fs/fuse/dir.c           |  2 +-
>  fs/gfs2/inode.c         |  2 +-
>  fs/hfsplus/inode.c      |  2 +-
>  fs/kernfs/inode.c       |  2 +-
>  fs/libfs.c              |  4 ++--
>  fs/minix/inode.c        |  2 +-
>  fs/nfs/inode.c          |  2 +-
>  fs/nfs/namespace.c      |  3 ++-
>  fs/ntfs3/file.c         |  2 +-
>  fs/ocfs2/file.c         |  2 +-
>  fs/orangefs/inode.c     |  2 +-
>  fs/proc/base.c          |  4 ++--
>  fs/proc/fd.c            |  2 +-
>  fs/proc/generic.c       |  2 +-
>  fs/proc/proc_net.c      |  2 +-
>  fs/proc/proc_sysctl.c   |  2 +-
>  fs/proc/root.c          |  3 ++-
>  fs/smb/client/inode.c   |  2 +-
>  fs/smb/server/smb2pdu.c | 22 +++++++++++-----------
>  fs/smb/server/vfs.c     |  3 ++-
>  fs/stat.c               | 18 ++++++++++--------
>  fs/sysv/itree.c         |  3 ++-
>  fs/ubifs/dir.c          |  2 +-
>  fs/udf/symlink.c        |  2 +-
>  fs/vboxsf/utils.c       |  2 +-
>  include/linux/fs.h      |  2 +-
>  mm/shmem.c              |  2 +-
>  40 files changed, 70 insertions(+), 62 deletions(-)
> 

...

> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 1b337ebce4df..8184499ae7a5 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1319,7 +1319,7 @@ int ocfs2_getattr(struct mnt_idmap *idmap, const struct path *path,
>  		goto bail;
>  	}
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);

For ocfs2 part, looks fine to me.

Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com>

>  	/*
>  	 * If there is inline data in the inode, the inode will normally not
>  	 * have data blocks allocated (it may have an external xattr block).

...

> diff --git a/fs/stat.c b/fs/stat.c
> index 8c2b30af19f5..062f311b5386 100644
> --- a/fs/stat.c
> +++ b/fs/stat.c
> @@ -29,6 +29,7 @@
>  /**
>   * generic_fillattr - Fill in the basic attributes from the inode struct
>   * @idmap:	idmap of the mount the inode was found from
> + * @req_mask	statx request_mask

s/req_mask/request_mask

>   * @inode:	Inode to use as the source
>   * @stat:	Where to fill in the attributes
>   *
> @@ -42,8 +43,8 @@
>   * uid and gid filds. On non-idmapped mounts or if permission checking is to be
>   * performed on the raw inode simply passs @nop_mnt_idmap.
>   */
> -void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
> -		      struct kstat *stat)
> +void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
> +		      struct inode *inode, struct kstat *stat)
>  {
>  	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
>  	vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
> @@ -61,6 +62,12 @@ void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
>  	stat->ctime = inode_get_ctime(inode);
>  	stat->blksize = i_blocksize(inode);
>  	stat->blocks = inode->i_blocks;
> +
> +	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> +		stat->result_mask |= STATX_CHANGE_COOKIE;
> +		stat->change_cookie = inode_query_iversion(inode);
> +	}
> +
>  }
>  EXPORT_SYMBOL(generic_fillattr);
>  
> @@ -123,17 +130,12 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
>  	stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT |
>  				  STATX_ATTR_DAX);
>  
> -	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> -		stat->result_mask |= STATX_CHANGE_COOKIE;
> -		stat->change_cookie = inode_query_iversion(inode);
> -	}
> -
>  	idmap = mnt_idmap(path->mnt);
>  	if (inode->i_op->getattr)
>  		return inode->i_op->getattr(idmap, path, stat,
>  					    request_mask, query_flags);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  EXPORT_SYMBOL(vfs_getattr_nosec);

...


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable
  2023-07-26  1:39   ` Hugh Dickins
@ 2023-07-26 10:26     ` Jeff Layton
  0 siblings, 0 replies; 30+ messages in thread
From: Jeff Layton @ 2023-07-26 10:26 UTC (permalink / raw)
  To: Hugh Dickins
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, 2023-07-25 at 18:39 -0700, Hugh Dickins wrote:
> On Tue, 25 Jul 2023, Jeff Layton wrote:
> 
> > Most filesystems that use the pagecache will update the mtime, ctime,
> > and change attribute when a page becomes writeable. Add a page_mkwrite
> > operation for tmpfs and just use it to bump the mtime, ctime and change
> > attribute.
> > 
> > This fixes xfstest generic/080 on tmpfs.
> 
> Huh.  I didn't notice when this one crept into the multigrain series.
> 
> I'm inclined to NAK this patch: at the very least, it does not belong
> in the series, but should be discussed separately.
> 
> Yes, tmpfs does not and never has used page_mkwrite, and gains some
> performance advantage from that.  Nobody has ever asked for this
> change before, or not that I recall.
> 
> Please drop it from the series: and if you feel strongly, or know
> strong reasons why tmpfs suddenly needs to use page_mkwrite now,
> please argue them separately.  To pass generic/080 is not enough.
> 
> Thanks,
> Hugh
> 

Dropped.

This was just something I noticed while testing this series. It stood
out since I was particularly watching for timestamp-related test
failures. I don't feel terribly strongly about it.

Thanks!

> > 
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >  mm/shmem.c | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> > 
> > diff --git a/mm/shmem.c b/mm/shmem.c
> > index b154af49d2df..654d9a585820 100644
> > --- a/mm/shmem.c
> > +++ b/mm/shmem.c
> > @@ -2169,6 +2169,16 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
> >  	return ret;
> >  }
> >  
> > +static vm_fault_t shmem_page_mkwrite(struct vm_fault *vmf)
> > +{
> > +	struct vm_area_struct *vma = vmf->vma;
> > +	struct inode *inode = file_inode(vma->vm_file);
> > +
> > +	file_update_time(vma->vm_file);
> > +	inode_inc_iversion(inode);
> > +	return 0;
> > +}
> > +
> >  unsigned long shmem_get_unmapped_area(struct file *file,
> >  				      unsigned long uaddr, unsigned long len,
> >  				      unsigned long pgoff, unsigned long flags)
> > @@ -4210,6 +4220,7 @@ static const struct super_operations shmem_ops = {
> >  
> >  static const struct vm_operations_struct shmem_vm_ops = {
> >  	.fault		= shmem_fault,
> > +	.page_mkwrite	= shmem_page_mkwrite,
> >  	.map_pages	= filemap_map_pages,
> >  #ifdef CONFIG_NUMA
> >  	.set_policy     = shmem_set_policy,
> > @@ -4219,6 +4230,7 @@ static const struct vm_operations_struct shmem_vm_ops = {
> >  
> >  static const struct vm_operations_struct shmem_anon_vm_ops = {
> >  	.fault		= shmem_fault,
> > +	.page_mkwrite	= shmem_page_mkwrite,
> >  	.map_pages	= filemap_map_pages,
> >  #ifdef CONFIG_NUMA
> >  	.set_policy     = shmem_set_policy,
> > 
> > -- 
> > 2.41.0

-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-26  9:40   ` Joseph Qi
@ 2023-07-26 10:49     ` Jeff Layton
  0 siblings, 0 replies; 30+ messages in thread
From: Jeff Layton @ 2023-07-26 10:49 UTC (permalink / raw)
  To: Joseph Qi
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs

On Wed, 2023-07-26 at 17:40 +0800, Joseph Qi wrote:
> 
> On 7/25/23 10:58 PM, Jeff Layton wrote:
> > generic_fillattr just fills in the entire stat struct indiscriminately
> > today, copying data from the inode. There is at least one attribute
> > (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> > and we're looking at adding more with the addition of multigrain
> > timestamps.
> > 
> > Add a request_mask argument to generic_fillattr and have most callers
> > just pass in the value that is passed to getattr. Have other callers
> > (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> > STATX_CHANGE_COOKIE into generic_fillattr.
> > 
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >  fs/9p/vfs_inode.c       |  4 ++--
> >  fs/9p/vfs_inode_dotl.c  |  4 ++--
> >  fs/afs/inode.c          |  2 +-
> >  fs/btrfs/inode.c        |  2 +-
> >  fs/ceph/inode.c         |  2 +-
> >  fs/coda/inode.c         |  3 ++-
> >  fs/ecryptfs/inode.c     |  5 +++--
> >  fs/erofs/inode.c        |  2 +-
> >  fs/exfat/file.c         |  2 +-
> >  fs/ext2/inode.c         |  2 +-
> >  fs/ext4/inode.c         |  2 +-
> >  fs/f2fs/file.c          |  2 +-
> >  fs/fat/file.c           |  2 +-
> >  fs/fuse/dir.c           |  2 +-
> >  fs/gfs2/inode.c         |  2 +-
> >  fs/hfsplus/inode.c      |  2 +-
> >  fs/kernfs/inode.c       |  2 +-
> >  fs/libfs.c              |  4 ++--
> >  fs/minix/inode.c        |  2 +-
> >  fs/nfs/inode.c          |  2 +-
> >  fs/nfs/namespace.c      |  3 ++-
> >  fs/ntfs3/file.c         |  2 +-
> >  fs/ocfs2/file.c         |  2 +-
> >  fs/orangefs/inode.c     |  2 +-
> >  fs/proc/base.c          |  4 ++--
> >  fs/proc/fd.c            |  2 +-
> >  fs/proc/generic.c       |  2 +-
> >  fs/proc/proc_net.c      |  2 +-
> >  fs/proc/proc_sysctl.c   |  2 +-
> >  fs/proc/root.c          |  3 ++-
> >  fs/smb/client/inode.c   |  2 +-
> >  fs/smb/server/smb2pdu.c | 22 +++++++++++-----------
> >  fs/smb/server/vfs.c     |  3 ++-
> >  fs/stat.c               | 18 ++++++++++--------
> >  fs/sysv/itree.c         |  3 ++-
> >  fs/ubifs/dir.c          |  2 +-
> >  fs/udf/symlink.c        |  2 +-
> >  fs/vboxsf/utils.c       |  2 +-
> >  include/linux/fs.h      |  2 +-
> >  mm/shmem.c              |  2 +-
> >  40 files changed, 70 insertions(+), 62 deletions(-)
> > 
> 
> ...
> 
> > diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> > index 1b337ebce4df..8184499ae7a5 100644
> > --- a/fs/ocfs2/file.c
> > +++ b/fs/ocfs2/file.c
> > @@ -1319,7 +1319,7 @@ int ocfs2_getattr(struct mnt_idmap *idmap, const struct path *path,
> >  		goto bail;
> >  	}
> >  
> > -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> > +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
> 
> For ocfs2 part, looks fine to me.
> 
> Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com>
> 
> >  	/*
> >  	 * If there is inline data in the inode, the inode will normally not
> >  	 * have data blocks allocated (it may have an external xattr block).
> 
> ...
> 
> > diff --git a/fs/stat.c b/fs/stat.c
> > index 8c2b30af19f5..062f311b5386 100644
> > --- a/fs/stat.c
> > +++ b/fs/stat.c
> > @@ -29,6 +29,7 @@
> >  /**
> >   * generic_fillattr - Fill in the basic attributes from the inode struct
> >   * @idmap:	idmap of the mount the inode was found from
> > + * @req_mask	statx request_mask
> 
> s/req_mask/request_mask
> 

Thanks. Fixed in my tree.

> >   * @inode:	Inode to use as the source
> >   * @stat:	Where to fill in the attributes
> >   *
> > @@ -42,8 +43,8 @@
> >   * uid and gid filds. On non-idmapped mounts or if permission checking is to be
> >   * performed on the raw inode simply passs @nop_mnt_idmap.
> >   */
> > -void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
> > -		      struct kstat *stat)
> > +void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
> > +		      struct inode *inode, struct kstat *stat)
> >  {
> >  	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
> >  	vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
> > @@ -61,6 +62,12 @@ void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
> >  	stat->ctime = inode_get_ctime(inode);
> >  	stat->blksize = i_blocksize(inode);
> >  	stat->blocks = inode->i_blocks;
> > +
> > +	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> > +		stat->result_mask |= STATX_CHANGE_COOKIE;
> > +		stat->change_cookie = inode_query_iversion(inode);
> > +	}
> > +
> >  }
> >  EXPORT_SYMBOL(generic_fillattr);
> >  
> > @@ -123,17 +130,12 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
> >  	stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT |
> >  				  STATX_ATTR_DAX);
> >  
> > -	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> > -		stat->result_mask |= STATX_CHANGE_COOKIE;
> > -		stat->change_cookie = inode_query_iversion(inode);
> > -	}
> > -
> >  	idmap = mnt_idmap(path->mnt);
> >  	if (inode->i_op->getattr)
> >  		return inode->i_op->getattr(idmap, path, stat,
> >  					    request_mask, query_flags);
> >  
> > -	generic_fillattr(idmap, inode, stat);
> > +	generic_fillattr(idmap, request_mask, inode, stat);
> >  	return 0;
> >  }
> >  EXPORT_SYMBOL(vfs_getattr_nosec);
> 
> ...
> 

-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 7/7] btrfs: convert to multigrain timestamps
  2023-07-25 14:58 ` [PATCH v6 7/7] btrfs: convert " Jeff Layton
@ 2023-07-26 12:44   ` David Sterba
  0 siblings, 0 replies; 30+ messages in thread
From: David Sterba @ 2023-07-26 12:44 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, Jul 25, 2023 at 10:58:20AM -0400, Jeff Layton wrote:
> Enable multigrain timestamps, which should ensure that there is an
> apparent change to the timestamp whenever it has been written after
> being actively observed via getattr.
> 
> Beyond enabling the FS_MGTIME flag, this patch eliminates
> update_time_for_write, which goes to great pains to avoid in-memory
> stores. Just have it overwrite the timestamps unconditionally.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>

Acked-by: David Sterba <dsterba@suse.com>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: (subset) [PATCH v6 0/7] fs: implement multigrain timestamps
  2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
                   ` (6 preceding siblings ...)
  2023-07-25 14:58 ` [PATCH v6 7/7] btrfs: convert " Jeff Layton
@ 2023-07-28 11:00 ` Christian Brauner
  7 siblings, 0 replies; 30+ messages in thread
From: Christian Brauner @ 2023-07-28 11:00 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Christian Brauner, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs, Eric Van Hensbergen, Latchesar Ionkov,
	Dominique Martinet, Christian Schoenebeck, David Howells,
	Marc Dionne, Chris Mason, Josef Bacik, David Sterba, Xiubo Li,
	Ilya Dryomov, Jan Harkes, coda, Tyler Hicks, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Namjae Jeon, Sungjong Seo, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi,
	Miklos Szeredi, Bob Peterson, Andreas Gruenbacher,
	Greg Kroah-Hartman, Tejun Heo, Alexander Viro, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong

On Tue, 25 Jul 2023 10:58:13 -0400, Jeff Layton wrote:
> The VFS always uses coarse-grained timestamps when updating the
> ctime and mtime after a change. This has the benefit of allowing
> filesystems to optimize away a lot metadata updates, down to around 1
> per jiffy, even when a file is under heavy writes.
> 
> Unfortunately, this coarseness has always been an issue when we're
> exporting via NFSv3, which relies on timestamps to validate caches. A
> lot of changes can happen in a jiffy, so timestamps aren't sufficient to
> help the client decide to invalidate the cache.
> 
> [...]

Survives xfstests (tmpfs, ext4, overlayfs) and the fs portions of LTP.
Let's keep our eyes open for any potential issues. Past suspects has
been IMA interacting with overlayfs. We'll see. Picked everything minus
the tmpfs-writepage patch that was contentious.

---

Applied to the vfs.ctime branch of the vfs/vfs.git tree.
Patches in the vfs.ctime branch should appear in linux-next soon.

Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.

It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.

Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs.ctime

[1/7] fs: pass the request_mask to generic_fillattr
      https://git.kernel.org/vfs/vfs/c/0a6ab6dc6958
[2/7] fs: add infrastructure for multigrain timestamps
      https://git.kernel.org/vfs/vfs/c/d242b98ac3e9
[4/7] tmpfs: add support for multigrain timestamps
      https://git.kernel.org/vfs/vfs/c/1f31c58cf032
[5/7] xfs: switch to multigrain timestamps
      https://git.kernel.org/vfs/vfs/c/859dd91017dd
[6/7] ext4: switch to multigrain timestamps
      https://git.kernel.org/vfs/vfs/c/093af249eab4
[7/7] btrfs: convert to multigrain timestamps
      https://git.kernel.org/vfs/vfs/c/b90a04d1c30c

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
  2023-07-26  2:46   ` Xiubo Li
  2023-07-26  9:40   ` Joseph Qi
@ 2023-08-02 17:43   ` Jan Kara
  2023-08-02 18:47   ` Paulo Alcantara
  2023-08-29 22:44   ` Al Viro
  4 siblings, 0 replies; 30+ messages in thread
From: Jan Kara @ 2023-08-02 17:43 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue 25-07-23 10:58:14, Jeff Layton wrote:
> generic_fillattr just fills in the entire stat struct indiscriminately
> today, copying data from the inode. There is at least one attribute
> (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> and we're looking at adding more with the addition of multigrain
> timestamps.
> 
> Add a request_mask argument to generic_fillattr and have most callers
> just pass in the value that is passed to getattr. Have other callers
> (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> STATX_CHANGE_COOKIE into generic_fillattr.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/9p/vfs_inode.c       |  4 ++--
>  fs/9p/vfs_inode_dotl.c  |  4 ++--
>  fs/afs/inode.c          |  2 +-
>  fs/btrfs/inode.c        |  2 +-
>  fs/ceph/inode.c         |  2 +-
>  fs/coda/inode.c         |  3 ++-
>  fs/ecryptfs/inode.c     |  5 +++--
>  fs/erofs/inode.c        |  2 +-
>  fs/exfat/file.c         |  2 +-
>  fs/ext2/inode.c         |  2 +-
>  fs/ext4/inode.c         |  2 +-
>  fs/f2fs/file.c          |  2 +-
>  fs/fat/file.c           |  2 +-
>  fs/fuse/dir.c           |  2 +-
>  fs/gfs2/inode.c         |  2 +-
>  fs/hfsplus/inode.c      |  2 +-
>  fs/kernfs/inode.c       |  2 +-
>  fs/libfs.c              |  4 ++--
>  fs/minix/inode.c        |  2 +-
>  fs/nfs/inode.c          |  2 +-
>  fs/nfs/namespace.c      |  3 ++-
>  fs/ntfs3/file.c         |  2 +-
>  fs/ocfs2/file.c         |  2 +-
>  fs/orangefs/inode.c     |  2 +-
>  fs/proc/base.c          |  4 ++--
>  fs/proc/fd.c            |  2 +-
>  fs/proc/generic.c       |  2 +-
>  fs/proc/proc_net.c      |  2 +-
>  fs/proc/proc_sysctl.c   |  2 +-
>  fs/proc/root.c          |  3 ++-
>  fs/smb/client/inode.c   |  2 +-
>  fs/smb/server/smb2pdu.c | 22 +++++++++++-----------
>  fs/smb/server/vfs.c     |  3 ++-
>  fs/stat.c               | 18 ++++++++++--------
>  fs/sysv/itree.c         |  3 ++-
>  fs/ubifs/dir.c          |  2 +-
>  fs/udf/symlink.c        |  2 +-
>  fs/vboxsf/utils.c       |  2 +-
>  include/linux/fs.h      |  2 +-
>  mm/shmem.c              |  2 +-
>  40 files changed, 70 insertions(+), 62 deletions(-)
> 
> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
> index 16d85e6033a3..d24d1f20e922 100644
> --- a/fs/9p/vfs_inode.c
> +++ b/fs/9p/vfs_inode.c
> @@ -1016,7 +1016,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
>  	v9ses = v9fs_dentry2v9ses(dentry);
>  	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  		return 0;
>  	} else if (v9ses->cache & CACHE_WRITEBACK) {
>  		if (S_ISREG(inode->i_mode)) {
> @@ -1037,7 +1037,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  		return PTR_ERR(st);
>  
>  	v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb, 0);
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
>  
>  	p9stat_free(st);
>  	kfree(st);
> diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
> index 464ea73d1bf8..8e8d5d2a13d8 100644
> --- a/fs/9p/vfs_inode_dotl.c
> +++ b/fs/9p/vfs_inode_dotl.c
> @@ -451,7 +451,7 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
>  	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
>  	v9ses = v9fs_dentry2v9ses(dentry);
>  	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  		return 0;
>  	} else if (v9ses->cache) {
>  		if (S_ISREG(inode->i_mode)) {
> @@ -476,7 +476,7 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
>  		return PTR_ERR(st);
>  
>  	v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
>  	/* Change block size to what the server returned */
>  	stat->blksize = st->st_blksize;
>  
> diff --git a/fs/afs/inode.c b/fs/afs/inode.c
> index 6b636f43f548..1c794a1896aa 100644
> --- a/fs/afs/inode.c
> +++ b/fs/afs/inode.c
> @@ -773,7 +773,7 @@ int afs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  
>  	do {
>  		read_seqbegin_or_lock(&vnode->cb_lock, &seq);
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  		if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
>  		    stat->nlink > 0)
>  			stat->nlink -= 1;
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index bcccd551f547..7346059209aa 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -8773,7 +8773,7 @@ static int btrfs_getattr(struct mnt_idmap *idmap,
>  				  STATX_ATTR_IMMUTABLE |
>  				  STATX_ATTR_NODUMP);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  	stat->dev = BTRFS_I(inode)->root->anon_dev;
>  
>  	spin_lock(&BTRFS_I(inode)->lock);
> diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
> index 5f6e93714f5a..fd05d68e2990 100644
> --- a/fs/ceph/inode.c
> +++ b/fs/ceph/inode.c
> @@ -2467,7 +2467,7 @@ int ceph_getattr(struct mnt_idmap *idmap, const struct path *path,
>  			return err;
>  	}
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	stat->ino = ceph_present_inode(inode);
>  
>  	/*
> diff --git a/fs/coda/inode.c b/fs/coda/inode.c
> index 3e64679c1620..0c7c2528791e 100644
> --- a/fs/coda/inode.c
> +++ b/fs/coda/inode.c
> @@ -256,7 +256,8 @@ int coda_getattr(struct mnt_idmap *idmap, const struct path *path,
>  {
>  	int err = coda_revalidate_inode(d_inode(path->dentry));
>  	if (!err)
> -		generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask,
> +				 d_inode(path->dentry), stat);
>  	return err;
>  }
>  
> diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
> index b491bb239c8f..992d9c7e64ae 100644
> --- a/fs/ecryptfs/inode.c
> +++ b/fs/ecryptfs/inode.c
> @@ -982,7 +982,7 @@ static int ecryptfs_getattr_link(struct mnt_idmap *idmap,
>  
>  	mount_crypt_stat = &ecryptfs_superblock_to_private(
>  						dentry->d_sb)->mount_crypt_stat;
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);
>  	if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
>  		char *target;
>  		size_t targetsiz;
> @@ -1011,7 +1011,8 @@ static int ecryptfs_getattr(struct mnt_idmap *idmap,
>  	if (!rc) {
>  		fsstack_copy_attr_all(d_inode(dentry),
>  				      ecryptfs_inode_to_lower(d_inode(dentry)));
> -		generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask,
> +				 d_inode(dentry), stat);
>  		stat->blocks = lower_stat.blocks;
>  	}
>  	return rc;
> diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
> index c9bbdf7c34db..edc8ec7581b8 100644
> --- a/fs/erofs/inode.c
> +++ b/fs/erofs/inode.c
> @@ -369,7 +369,7 @@ int erofs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
>  				  STATX_ATTR_IMMUTABLE);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  
> diff --git a/fs/exfat/file.c b/fs/exfat/file.c
> index f40ecfeee3a4..32395ef686a2 100644
> --- a/fs/exfat/file.c
> +++ b/fs/exfat/file.c
> @@ -232,7 +232,7 @@ int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	struct inode *inode = d_backing_inode(path->dentry);
>  	struct exfat_inode_info *ei = EXFAT_I(inode);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	exfat_truncate_atime(&stat->atime);
>  	stat->result_mask |= STATX_BTIME;
>  	stat->btime.tv_sec = ei->i_crtime.tv_sec;
> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
> index 1259995977d2..acbab27fe957 100644
> --- a/fs/ext2/inode.c
> +++ b/fs/ext2/inode.c
> @@ -1628,7 +1628,7 @@ int ext2_getattr(struct mnt_idmap *idmap, const struct path *path,
>  			STATX_ATTR_IMMUTABLE |
>  			STATX_ATTR_NODUMP);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 86696b40c58f..6683076ecb2f 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -5535,7 +5535,7 @@ int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
>  				  STATX_ATTR_NODUMP |
>  				  STATX_ATTR_VERITY);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index b018800223c4..35886a52edfb 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -882,7 +882,7 @@ int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  				  STATX_ATTR_NODUMP |
>  				  STATX_ATTR_VERITY);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  
>  	/* we need to show initial sectors used for inline_data/dentries */
>  	if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
> diff --git a/fs/fat/file.c b/fs/fat/file.c
> index 456477946dd9..e887e9ab7472 100644
> --- a/fs/fat/file.c
> +++ b/fs/fat/file.c
> @@ -401,7 +401,7 @@ int fat_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	struct inode *inode = d_inode(path->dentry);
>  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  	stat->blksize = sbi->cluster_size;
>  
>  	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) {
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 672245ee0394..881524b9a55a 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -1222,7 +1222,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
>  		forget_all_cached_acls(inode);
>  		err = fuse_do_getattr(inode, stat, file);
>  	} else if (stat) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  		stat->mode = fi->orig_i_mode;
>  		stat->ino = fi->orig_ino;
>  	}
> diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
> index 2ded6c813f20..200cabf3b393 100644
> --- a/fs/gfs2/inode.c
> +++ b/fs/gfs2/inode.c
> @@ -2071,7 +2071,7 @@ static int gfs2_getattr(struct mnt_idmap *idmap,
>  				  STATX_ATTR_IMMUTABLE |
>  				  STATX_ATTR_NODUMP);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  
>  	if (gfs2_holder_initialized(&gh))
>  		gfs2_glock_dq_uninit(&gh);
> diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
> index 40c61ab4a918..c65c8c4b03dd 100644
> --- a/fs/hfsplus/inode.c
> +++ b/fs/hfsplus/inode.c
> @@ -298,7 +298,7 @@ int hfsplus_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	stat->attributes_mask |= STATX_ATTR_APPEND | STATX_ATTR_IMMUTABLE |
>  				 STATX_ATTR_NODUMP;
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  
> diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
> index 89a9b4dcf109..af37be68bf06 100644
> --- a/fs/kernfs/inode.c
> +++ b/fs/kernfs/inode.c
> @@ -190,7 +190,7 @@ int kernfs_iop_getattr(struct mnt_idmap *idmap,
>  
>  	down_read(&root->kernfs_iattr_rwsem);
>  	kernfs_refresh_inode(kn, inode);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	up_read(&root->kernfs_iattr_rwsem);
>  
>  	return 0;
> diff --git a/fs/libfs.c b/fs/libfs.c
> index b27260e0c14a..0a9f3c426548 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -33,7 +33,7 @@ int simple_getattr(struct mnt_idmap *idmap, const struct path *path,
>  		   unsigned int query_flags)
>  {
>  	struct inode *inode = d_inode(path->dentry);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	stat->blocks = inode->i_mapping->nrpages << (PAGE_SHIFT - 9);
>  	return 0;
>  }
> @@ -1585,7 +1585,7 @@ static int empty_dir_getattr(struct mnt_idmap *idmap,
>  			     u32 request_mask, unsigned int query_flags)
>  {
>  	struct inode *inode = d_inode(path->dentry);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  
> diff --git a/fs/minix/inode.c b/fs/minix/inode.c
> index 8a4fc9420b36..df575473c1cc 100644
> --- a/fs/minix/inode.c
> +++ b/fs/minix/inode.c
> @@ -656,7 +656,7 @@ int minix_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	struct super_block *sb = path->dentry->d_sb;
>  	struct inode *inode = d_inode(path->dentry);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	if (INODE_VERSION(inode) == MINIX_V1)
>  		stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb);
>  	else
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 1283fdfa4b0a..e21c073158e5 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -912,7 +912,7 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	/* Only return attributes that were revalidated. */
>  	stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask;
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
>  	stat->change_cookie = inode_peek_iversion_raw(inode);
>  	stat->attributes_mask |= STATX_ATTR_CHANGE_MONOTONIC;
> diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
> index 19d51ebf842c..e7494cdd957e 100644
> --- a/fs/nfs/namespace.c
> +++ b/fs/nfs/namespace.c
> @@ -215,7 +215,8 @@ nfs_namespace_getattr(struct mnt_idmap *idmap,
>  	if (NFS_FH(d_inode(path->dentry))->size != 0)
>  		return nfs_getattr(idmap, path, stat, request_mask,
>  				   query_flags);
> -	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
> +			 stat);
>  	return 0;
>  }
>  
> diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
> index 12788601dc84..962f12ce6c0a 100644
> --- a/fs/ntfs3/file.c
> +++ b/fs/ntfs3/file.c
> @@ -85,7 +85,7 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  
>  	stat->attributes_mask |= STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED;
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  
>  	stat->result_mask |= STATX_BTIME;
>  	stat->btime = ni->i_crtime;
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 1b337ebce4df..8184499ae7a5 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1319,7 +1319,7 @@ int ocfs2_getattr(struct mnt_idmap *idmap, const struct path *path,
>  		goto bail;
>  	}
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	/*
>  	 * If there is inline data in the inode, the inode will normally not
>  	 * have data blocks allocated (it may have an external xattr block).
> diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
> index 9014bbcc8031..a52c30e80f45 100644
> --- a/fs/orangefs/inode.c
> +++ b/fs/orangefs/inode.c
> @@ -871,7 +871,7 @@ int orangefs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	ret = orangefs_inode_getattr(inode,
>  	    request_mask & STATX_SIZE ? ORANGEFS_GETATTR_SIZE : 0);
>  	if (ret == 0) {
> -		generic_fillattr(&nop_mnt_idmap, inode, stat);
> +		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  
>  		/* override block size reported to stat */
>  		if (!(request_mask & STATX_SIZE))
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index d8388fc0a362..2bf67a0e0bcc 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -1966,7 +1966,7 @@ int pid_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
>  	struct task_struct *task;
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  
>  	stat->uid = GLOBAL_ROOT_UID;
>  	stat->gid = GLOBAL_ROOT_GID;
> @@ -3900,7 +3900,7 @@ static int proc_task_getattr(struct mnt_idmap *idmap,
>  {
>  	struct inode *inode = d_inode(path->dentry);
>  	struct task_struct *p = get_proc_task(inode);
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  
>  	if (p) {
>  		stat->nlink += get_nr_threads(p);
> diff --git a/fs/proc/fd.c b/fs/proc/fd.c
> index b3140deebbbf..6276b3938842 100644
> --- a/fs/proc/fd.c
> +++ b/fs/proc/fd.c
> @@ -352,7 +352,7 @@ static int proc_fd_getattr(struct mnt_idmap *idmap,
>  	struct inode *inode = d_inode(path->dentry);
>  	int rv = 0;
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  
>  	/* If it's a directory, put the number of open fds there */
>  	if (S_ISDIR(inode->i_mode)) {
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index 42ae38ff6e7e..775ce0bcf08c 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -146,7 +146,7 @@ static int proc_getattr(struct mnt_idmap *idmap,
>  		}
>  	}
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  
> diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
> index 78f9e6b469c0..2ba31b6d68c0 100644
> --- a/fs/proc/proc_net.c
> +++ b/fs/proc/proc_net.c
> @@ -308,7 +308,7 @@ static int proc_tgid_net_getattr(struct mnt_idmap *idmap,
>  
>  	net = get_proc_task_net(inode);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  
>  	if (net != NULL) {
>  		stat->nlink = net->proc_net->nlink;
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index 6bc10e7e0ff7..bf06344a42cc 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -849,7 +849,7 @@ static int proc_sys_getattr(struct mnt_idmap *idmap,
>  	if (IS_ERR(head))
>  		return PTR_ERR(head);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	if (table)
>  		stat->mode = (stat->mode & S_IFMT) | table->mode;
>  
> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index a86e65a608da..9191248f2dac 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -314,7 +314,8 @@ static int proc_root_getattr(struct mnt_idmap *idmap,
>  			     const struct path *path, struct kstat *stat,
>  			     u32 request_mask, unsigned int query_flags)
>  {
> -	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
> +			 stat);
>  	stat->nlink = proc_root.nlink + nr_processes();
>  	return 0;
>  }
> diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
> index 218f03dd3f52..93fe43789d7a 100644
> --- a/fs/smb/client/inode.c
> +++ b/fs/smb/client/inode.c
> @@ -2540,7 +2540,7 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  			return rc;
>  	}
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	stat->blksize = cifs_sb->ctx->bsize;
>  	stat->ino = CIFS_I(inode)->uniqueid;
>  
> diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> index f9099831c8ff..2a084d35233a 100644
> --- a/fs/smb/server/smb2pdu.c
> +++ b/fs/smb/server/smb2pdu.c
> @@ -4391,8 +4391,8 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
>  	}
>  
>  	basic_info = (struct smb2_file_basic_info *)rsp->Buffer;
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>  	basic_info->CreationTime = cpu_to_le64(fp->create_time);
>  	time = ksmbd_UnixTimeToNT(stat.atime);
>  	basic_info->LastAccessTime = cpu_to_le64(time);
> @@ -4417,7 +4417,7 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
>  	struct kstat stat;
>  
>  	inode = file_inode(fp->filp);
> -	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
>  
>  	sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
>  	delete_pending = ksmbd_inode_pending_delete(fp);
> @@ -4471,7 +4471,7 @@ static int get_file_all_info(struct ksmbd_work *work,
>  		return PTR_ERR(filename);
>  
>  	inode = file_inode(fp->filp);
> -	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
>  
>  	ksmbd_debug(SMB, "filename = %s\n", filename);
>  	delete_pending = ksmbd_inode_pending_delete(fp);
> @@ -4548,8 +4548,8 @@ static void get_file_stream_info(struct ksmbd_work *work,
>  	int buf_free_len;
>  	struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
>  
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>  	file_info = (struct smb2_file_stream_info *)rsp->Buffer;
>  
>  	buf_free_len =
> @@ -4639,8 +4639,8 @@ static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
>  	struct smb2_file_internal_info *file_info;
>  	struct kstat stat;
>  
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>  	file_info = (struct smb2_file_internal_info *)rsp->Buffer;
>  	file_info->IndexNumber = cpu_to_le64(stat.ino);
>  	rsp->OutputBufferLength =
> @@ -4665,7 +4665,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
>  	file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
>  
>  	inode = file_inode(fp->filp);
> -	generic_fillattr(file_mnt_idmap(fp->filp), inode, &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
>  
>  	file_info->CreationTime = cpu_to_le64(fp->create_time);
>  	time = ksmbd_UnixTimeToNT(stat.atime);
> @@ -4726,8 +4726,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
>  	struct smb2_file_comp_info *file_info;
>  	struct kstat stat;
>  
> -	generic_fillattr(file_mnt_idmap(fp->filp), file_inode(fp->filp),
> -			 &stat);
> +	generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
> +			 file_inode(fp->filp), &stat);
>  
>  	file_info = (struct smb2_file_comp_info *)rsp->Buffer;
>  	file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);
> diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
> index e35914457350..d0e94b73931a 100644
> --- a/fs/smb/server/vfs.c
> +++ b/fs/smb/server/vfs.c
> @@ -1650,7 +1650,8 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
>  	u64 time;
>  	int rc;
>  
> -	generic_fillattr(idmap, d_inode(dentry), ksmbd_kstat->kstat);
> +	generic_fillattr(idmap, STATX_BASIC_STATS, d_inode(dentry),
> +			 ksmbd_kstat->kstat);
>  
>  	time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);
>  	ksmbd_kstat->create_time = time;
> diff --git a/fs/stat.c b/fs/stat.c
> index 8c2b30af19f5..062f311b5386 100644
> --- a/fs/stat.c
> +++ b/fs/stat.c
> @@ -29,6 +29,7 @@
>  /**
>   * generic_fillattr - Fill in the basic attributes from the inode struct
>   * @idmap:	idmap of the mount the inode was found from
> + * @req_mask	statx request_mask
>   * @inode:	Inode to use as the source
>   * @stat:	Where to fill in the attributes
>   *
> @@ -42,8 +43,8 @@
>   * uid and gid filds. On non-idmapped mounts or if permission checking is to be
>   * performed on the raw inode simply passs @nop_mnt_idmap.
>   */
> -void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
> -		      struct kstat *stat)
> +void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
> +		      struct inode *inode, struct kstat *stat)
>  {
>  	vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
>  	vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
> @@ -61,6 +62,12 @@ void generic_fillattr(struct mnt_idmap *idmap, struct inode *inode,
>  	stat->ctime = inode_get_ctime(inode);
>  	stat->blksize = i_blocksize(inode);
>  	stat->blocks = inode->i_blocks;
> +
> +	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> +		stat->result_mask |= STATX_CHANGE_COOKIE;
> +		stat->change_cookie = inode_query_iversion(inode);
> +	}
> +
>  }
>  EXPORT_SYMBOL(generic_fillattr);
>  
> @@ -123,17 +130,12 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
>  	stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT |
>  				  STATX_ATTR_DAX);
>  
> -	if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) {
> -		stat->result_mask |= STATX_CHANGE_COOKIE;
> -		stat->change_cookie = inode_query_iversion(inode);
> -	}
> -
>  	idmap = mnt_idmap(path->mnt);
>  	if (inode->i_op->getattr)
>  		return inode->i_op->getattr(idmap, path, stat,
>  					    request_mask, query_flags);
>  
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  	return 0;
>  }
>  EXPORT_SYMBOL(vfs_getattr_nosec);
> diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
> index dba6a2ef26f1..edb94e55de8e 100644
> --- a/fs/sysv/itree.c
> +++ b/fs/sysv/itree.c
> @@ -449,7 +449,8 @@ int sysv_getattr(struct mnt_idmap *idmap, const struct path *path,
>  		 struct kstat *stat, u32 request_mask, unsigned int flags)
>  {
>  	struct super_block *s = path->dentry->d_sb;
> -	generic_fillattr(&nop_mnt_idmap, d_inode(path->dentry), stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(path->dentry),
> +			 stat);
>  	stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size);
>  	stat->blksize = s->s_blocksize;
>  	return 0;
> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> index 3a1ba8ba308a..2f48c58d47cd 100644
> --- a/fs/ubifs/dir.c
> +++ b/fs/ubifs/dir.c
> @@ -1654,7 +1654,7 @@ int ubifs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  				STATX_ATTR_ENCRYPTED |
>  				STATX_ATTR_IMMUTABLE);
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	stat->blksize = UBIFS_BLOCK_SIZE;
>  	stat->size = ui->ui_size;
>  
> diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
> index 779b5c2c75f6..f7eaf7b14594 100644
> --- a/fs/udf/symlink.c
> +++ b/fs/udf/symlink.c
> @@ -149,7 +149,7 @@ static int udf_symlink_getattr(struct mnt_idmap *idmap,
>  	struct inode *inode = d_backing_inode(dentry);
>  	struct page *page;
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	page = read_mapping_page(inode->i_mapping, 0, NULL);
>  	if (IS_ERR(page))
>  		return PTR_ERR(page);
> diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c
> index 576b91d571c5..83f20dd15522 100644
> --- a/fs/vboxsf/utils.c
> +++ b/fs/vboxsf/utils.c
> @@ -252,7 +252,7 @@ int vboxsf_getattr(struct mnt_idmap *idmap, const struct path *path,
>  	if (err)
>  		return err;
>  
> -	generic_fillattr(&nop_mnt_idmap, d_inode(dentry), kstat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), kstat);
>  	return 0;
>  }
>  
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 39076ea6a360..42d1434cc427 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2919,7 +2919,7 @@ extern void page_put_link(void *);
>  extern int page_symlink(struct inode *inode, const char *symname, int len);
>  extern const struct inode_operations page_symlink_inode_operations;
>  extern void kfree_link(void *);
> -void generic_fillattr(struct mnt_idmap *, struct inode *, struct kstat *);
> +void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
>  void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
>  extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
>  extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 310b0544eae3..b154af49d2df 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1073,7 +1073,7 @@ static int shmem_getattr(struct mnt_idmap *idmap,
>  	stat->attributes_mask |= (STATX_ATTR_APPEND |
>  			STATX_ATTR_IMMUTABLE |
>  			STATX_ATTR_NODUMP);
> -	generic_fillattr(idmap, inode, stat);
> +	generic_fillattr(idmap, request_mask, inode, stat);
>  
>  	if (shmem_is_huge(inode, 0, false, NULL, 0))
>  		stat->blksize = HPAGE_PMD_SIZE;
> 
> -- 
> 2.41.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 5/7] xfs: switch to multigrain timestamps
  2023-07-25 14:58 ` [PATCH v6 5/7] xfs: switch to " Jeff Layton
@ 2023-08-02 17:48   ` Darrick J. Wong
  2023-08-02 18:21     ` Jeff Layton
  0 siblings, 1 reply; 30+ messages in thread
From: Darrick J. Wong @ 2023-08-02 17:48 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs

On Tue, Jul 25, 2023 at 10:58:18AM -0400, Jeff Layton wrote:
> Enable multigrain timestamps, which should ensure that there is an
> apparent change to the timestamp whenever it has been written after
> being actively observed via getattr.
> 
> Also, anytime the mtime changes, the ctime must also change, and those
> are now the only two options for xfs_trans_ichgtime. Have that function
> unconditionally bump the ctime, and ASSERT that XFS_ICHGTIME_CHG is
> always set.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/xfs/libxfs/xfs_trans_inode.c | 6 +++---
>  fs/xfs/xfs_iops.c               | 4 ++--
>  fs/xfs/xfs_super.c              | 2 +-
>  3 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
> index 6b2296ff248a..ad22656376d3 100644
> --- a/fs/xfs/libxfs/xfs_trans_inode.c
> +++ b/fs/xfs/libxfs/xfs_trans_inode.c
> @@ -62,12 +62,12 @@ xfs_trans_ichgtime(
>  	ASSERT(tp);
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>  
> -	tv = current_time(inode);
> +	/* If the mtime changes, then ctime must also change */
> +	ASSERT(flags & XFS_ICHGTIME_CHG);
>  
> +	tv = inode_set_ctime_current(inode);
>  	if (flags & XFS_ICHGTIME_MOD)
>  		inode->i_mtime = tv;
> -	if (flags & XFS_ICHGTIME_CHG)
> -		inode_set_ctime_to_ts(inode, tv);
>  	if (flags & XFS_ICHGTIME_CREATE)
>  		ip->i_crtime = tv;
>  }
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 3a9363953ef2..3f89ef5a2820 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -573,10 +573,10 @@ xfs_vn_getattr(
>  	stat->gid = vfsgid_into_kgid(vfsgid);
>  	stat->ino = ip->i_ino;
>  	stat->atime = inode->i_atime;
> -	stat->mtime = inode->i_mtime;
> -	stat->ctime = inode_get_ctime(inode);
>  	stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks);
>  
> +	fill_mg_cmtime(request_mask, inode, stat);

Huh.  I would've thought @stat would come first since that's what we're
acting upon, but ... eh. :)

If everyone else is ok with the fill_mg_cmtime signature,
Acked-by: Darrick J. Wong <djwong@kernel.org>

--D

> +
>  	if (xfs_has_v3inodes(mp)) {
>  		if (request_mask & STATX_BTIME) {
>  			stat->result_mask |= STATX_BTIME;
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index 818510243130..4b10edb2c972 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -2009,7 +2009,7 @@ static struct file_system_type xfs_fs_type = {
>  	.init_fs_context	= xfs_init_fs_context,
>  	.parameters		= xfs_fs_parameters,
>  	.kill_sb		= kill_block_super,
> -	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
> +	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME,
>  };
>  MODULE_ALIAS_FS("xfs");
>  
> 
> -- 
> 2.41.0
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 5/7] xfs: switch to multigrain timestamps
  2023-08-02 17:48   ` Darrick J. Wong
@ 2023-08-02 18:21     ` Jeff Layton
  2023-08-03  7:05       ` Christian Brauner
  0 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-08-02 18:21 UTC (permalink / raw)
  To: Darrick J. Wong, Christian Brauner
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs

On Wed, 2023-08-02 at 10:48 -0700, Darrick J. Wong wrote:
> On Tue, Jul 25, 2023 at 10:58:18AM -0400, Jeff Layton wrote:
> > Enable multigrain timestamps, which should ensure that there is an
> > apparent change to the timestamp whenever it has been written after
> > being actively observed via getattr.
> > 
> > Also, anytime the mtime changes, the ctime must also change, and those
> > are now the only two options for xfs_trans_ichgtime. Have that function
> > unconditionally bump the ctime, and ASSERT that XFS_ICHGTIME_CHG is
> > always set.
> > 
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >  fs/xfs/libxfs/xfs_trans_inode.c | 6 +++---
> >  fs/xfs/xfs_iops.c               | 4 ++--
> >  fs/xfs/xfs_super.c              | 2 +-
> >  3 files changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
> > index 6b2296ff248a..ad22656376d3 100644
> > --- a/fs/xfs/libxfs/xfs_trans_inode.c
> > +++ b/fs/xfs/libxfs/xfs_trans_inode.c
> > @@ -62,12 +62,12 @@ xfs_trans_ichgtime(
> >  	ASSERT(tp);
> >  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> >  
> > -	tv = current_time(inode);
> > +	/* If the mtime changes, then ctime must also change */
> > +	ASSERT(flags & XFS_ICHGTIME_CHG);
> >  
> > +	tv = inode_set_ctime_current(inode);
> >  	if (flags & XFS_ICHGTIME_MOD)
> >  		inode->i_mtime = tv;
> > -	if (flags & XFS_ICHGTIME_CHG)
> > -		inode_set_ctime_to_ts(inode, tv);
> >  	if (flags & XFS_ICHGTIME_CREATE)
> >  		ip->i_crtime = tv;
> >  }
> > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > index 3a9363953ef2..3f89ef5a2820 100644
> > --- a/fs/xfs/xfs_iops.c
> > +++ b/fs/xfs/xfs_iops.c
> > @@ -573,10 +573,10 @@ xfs_vn_getattr(
> >  	stat->gid = vfsgid_into_kgid(vfsgid);
> >  	stat->ino = ip->i_ino;
> >  	stat->atime = inode->i_atime;
> > -	stat->mtime = inode->i_mtime;
> > -	stat->ctime = inode_get_ctime(inode);
> >  	stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks);
> >  
> > +	fill_mg_cmtime(request_mask, inode, stat);
> 
> Huh.  I would've thought @stat would come first since that's what we're
> acting upon, but ... eh. :)
> 
> If everyone else is ok with the fill_mg_cmtime signature,
> Acked-by: Darrick J. Wong <djwong@kernel.org>
> 
> 

Good point. We can change the signature. I think xfs is the only caller
outside of the generic vfs right now, and it'd be best to do it now.

Christian, would you prefer that I send an updated series, or patches on
top of vfs.ctime that can be folded in?
 
-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
                     ` (2 preceding siblings ...)
  2023-08-02 17:43   ` Jan Kara
@ 2023-08-02 18:47   ` Paulo Alcantara
  2023-08-29 22:44   ` Al Viro
  4 siblings, 0 replies; 30+ messages in thread
From: Paulo Alcantara @ 2023-08-02 18:47 UTC (permalink / raw)
  To: Jeff Layton, Eric Van Hensbergen, Latchesar Ionkov,
	Dominique Martinet, Christian Schoenebeck, David Howells,
	Marc Dionne, Chris Mason, Josef Bacik, David Sterba, Xiubo Li,
	Ilya Dryomov, Jan Harkes, coda, Tyler Hicks, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Namjae Jeon, Sungjong Seo, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi,
	Miklos Szeredi, Bob Peterson, Andreas Gruenbacher,
	Greg Kroah-Hartman, Tejun Heo, Alexander Viro, Christian Brauner,
	Trond Myklebust, Anna Schumaker, Konstantin Komarov, Mark Fasheh,
	Joel Becker, Joseph Qi, Mike Marshall, Martin Brandenburg,
	Luis Chamberlain, Kees Cook, Iurii Zaikin, Steve French,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong
  Cc: Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs, Jeff Layton

Jeff Layton <jlayton@kernel.org> writes:

> generic_fillattr just fills in the entire stat struct indiscriminately
> today, copying data from the inode. There is at least one attribute
> (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> and we're looking at adding more with the addition of multigrain
> timestamps.
>
> Add a request_mask argument to generic_fillattr and have most callers
> just pass in the value that is passed to getattr. Have other callers
> (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> STATX_CHANGE_COOKIE into generic_fillattr.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/9p/vfs_inode.c       |  4 ++--
>  fs/9p/vfs_inode_dotl.c  |  4 ++--
>  fs/afs/inode.c          |  2 +-
>  fs/btrfs/inode.c        |  2 +-
>  fs/ceph/inode.c         |  2 +-
>  fs/coda/inode.c         |  3 ++-
>  fs/ecryptfs/inode.c     |  5 +++--
>  fs/erofs/inode.c        |  2 +-
>  fs/exfat/file.c         |  2 +-
>  fs/ext2/inode.c         |  2 +-
>  fs/ext4/inode.c         |  2 +-
>  fs/f2fs/file.c          |  2 +-
>  fs/fat/file.c           |  2 +-
>  fs/fuse/dir.c           |  2 +-
>  fs/gfs2/inode.c         |  2 +-
>  fs/hfsplus/inode.c      |  2 +-
>  fs/kernfs/inode.c       |  2 +-
>  fs/libfs.c              |  4 ++--
>  fs/minix/inode.c        |  2 +-
>  fs/nfs/inode.c          |  2 +-
>  fs/nfs/namespace.c      |  3 ++-
>  fs/ntfs3/file.c         |  2 +-
>  fs/ocfs2/file.c         |  2 +-
>  fs/orangefs/inode.c     |  2 +-
>  fs/proc/base.c          |  4 ++--
>  fs/proc/fd.c            |  2 +-
>  fs/proc/generic.c       |  2 +-
>  fs/proc/proc_net.c      |  2 +-
>  fs/proc/proc_sysctl.c   |  2 +-
>  fs/proc/root.c          |  3 ++-
>  fs/smb/client/inode.c   |  2 +-
>  fs/smb/server/smb2pdu.c | 22 +++++++++++-----------
>  fs/smb/server/vfs.c     |  3 ++-
>  fs/stat.c               | 18 ++++++++++--------
>  fs/sysv/itree.c         |  3 ++-
>  fs/ubifs/dir.c          |  2 +-
>  fs/udf/symlink.c        |  2 +-
>  fs/vboxsf/utils.c       |  2 +-
>  include/linux/fs.h      |  2 +-
>  mm/shmem.c              |  2 +-
>  40 files changed, 70 insertions(+), 62 deletions(-)
>
> [...]
>
> diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
> index 218f03dd3f52..93fe43789d7a 100644
> --- a/fs/smb/client/inode.c
> +++ b/fs/smb/client/inode.c
> @@ -2540,7 +2540,7 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
>  			return rc;
>  	}
>  
> -	generic_fillattr(&nop_mnt_idmap, inode, stat);
> +	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
>  	stat->blksize = cifs_sb->ctx->bsize;
>  	stat->ino = CIFS_I(inode)->uniqueid;

Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps
  2023-07-25 14:58 ` [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps Jeff Layton
@ 2023-08-02 19:35   ` Jan Kara
  2023-08-02 20:54     ` Jeff Layton
  0 siblings, 1 reply; 30+ messages in thread
From: Jan Kara @ 2023-08-02 19:35 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue 25-07-23 10:58:15, Jeff Layton wrote:
> The VFS always uses coarse-grained timestamps when updating the ctime
> and mtime after a change. This has the benefit of allowing filesystems
> to optimize away a lot metadata updates, down to around 1 per jiffy,
> even when a file is under heavy writes.
> 
> Unfortunately, this has always been an issue when we're exporting via
> NFSv3, which relies on timestamps to validate caches. A lot of changes
> can happen in a jiffy, so timestamps aren't sufficient to help the
> client decide to invalidate the cache. Even with NFSv4, a lot of
> exported filesystems don't properly support a change attribute and are
> subject to the same problems with timestamp granularity. Other
> applications have similar issues with timestamps (e.g backup
> applications).
> 
> If we were to always use fine-grained timestamps, that would improve the
> situation, but that becomes rather expensive, as the underlying
> filesystem would have to log a lot more metadata updates.
> 
> What we need is a way to only use fine-grained timestamps when they are
> being actively queried.
> 
> POSIX generally mandates that when the the mtime changes, the ctime must
> also change. The kernel always stores normalized ctime values, so only
> the first 30 bits of the tv_nsec field are ever used.
> 
> Use the 31st bit of the ctime tv_nsec field to indicate that something
> has queried the inode for the mtime or ctime. When this flag is set,
> on the next mtime or ctime update, the kernel will fetch a fine-grained
> timestamp instead of the usual coarse-grained one.
> 
> Filesytems can opt into this behavior by setting the FS_MGTIME flag in
> the fstype. Filesystems that don't set this flag will continue to use
> coarse-grained timestamps.
> 
> Later patches will convert individual filesystems to use the new
> infrastructure.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/inode.c         | 98 ++++++++++++++++++++++++++++++++++++++----------------
>  fs/stat.c          | 41 +++++++++++++++++++++--
>  include/linux/fs.h | 45 +++++++++++++++++++++++--
>  3 files changed, 151 insertions(+), 33 deletions(-)
> 
> diff --git a/fs/inode.c b/fs/inode.c
> index d4ab92233062..369621e7faf5 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -1919,6 +1919,21 @@ int inode_update_time(struct inode *inode, struct timespec64 *time, int flags)
>  }
>  EXPORT_SYMBOL(inode_update_time);
>  
> +/**
> + * current_coarse_time - Return FS time
> + * @inode: inode.
> + *
> + * Return the current coarse-grained time truncated to the time
> + * granularity supported by the fs.
> + */
> +static struct timespec64 current_coarse_time(struct inode *inode)
> +{
> +	struct timespec64 now;
> +
> +	ktime_get_coarse_real_ts64(&now);
> +	return timestamp_truncate(now, inode);
> +}
> +
>  /**
>   *	atime_needs_update	-	update the access time
>   *	@path: the &struct path to update
> @@ -1952,7 +1967,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
>  	if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
>  		return false;
>  
> -	now = current_time(inode);
> +	now = current_coarse_time(inode);
>  
>  	if (!relatime_need_update(mnt, inode, now))
>  		return false;
> @@ -1986,7 +2001,7 @@ void touch_atime(const struct path *path)
>  	 * We may also fail on filesystems that have the ability to make parts
>  	 * of the fs read only, e.g. subvolumes in Btrfs.
>  	 */
> -	now = current_time(inode);
> +	now = current_coarse_time(inode);
>  	inode_update_time(inode, &now, S_ATIME);
>  	__mnt_drop_write(mnt);
>  skip_update:

There are also calls in fs/smb/client/file.c:cifs_readpage_worker() and in
fs/ocfs2/file.c:ocfs2_update_inode_atime() that should probably use
current_coarse_time() to avoid needless querying of fine grained
timestamps. But see below...

> @@ -2072,6 +2087,56 @@ int file_remove_privs(struct file *file)
>  }
>  EXPORT_SYMBOL(file_remove_privs);
>  
> +/**
> + * current_mgtime - Return FS time (possibly fine-grained)
> + * @inode: inode.
> + *
> + * Return the current time truncated to the time granularity supported by
> + * the fs, as suitable for a ctime/mtime change. If the ctime is flagged
> + * as having been QUERIED, get a fine-grained timestamp.
> + */
> +static struct timespec64 current_mgtime(struct inode *inode)
> +{
> +	struct timespec64 now;
> +	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
> +	long nsec = atomic_long_read(pnsec);
> +
> +	if (nsec & I_CTIME_QUERIED) {
> +		ktime_get_real_ts64(&now);
> +	} else {
> +		struct timespec64 ctime;
> +
> +		ktime_get_coarse_real_ts64(&now);
> +
> +		/*
> +		 * If we've recently fetched a fine-grained timestamp
> +		 * then the coarse-grained one may still be earlier than the
> +		 * existing one. Just keep the existing ctime if so.
> +		 */
> +		ctime = inode_get_ctime(inode);
> +		if (timespec64_compare(&ctime, &now) > 0)
> +			now = ctime;
> +	}
> +
> +	return timestamp_truncate(now, inode);
> +}
> +
> +/**
> + * current_time - Return timestamp suitable for ctime update
> + * @inode: inode to eventually be updated
> + *
> + * Return the current time, which is usually coarse-grained but may be fine
> + * grained if the filesystem uses multigrain timestamps and the existing
> + * ctime was queried since the last update.
> + */
> +struct timespec64 current_time(struct inode *inode)
> +{
> +	if (is_mgtime(inode))
> +		return current_mgtime(inode);
> +	return current_coarse_time(inode);
> +}
> +EXPORT_SYMBOL(current_time);
> +

So if you modify current_time() to handle multigrain timestamps the code
will be still racy. In particular fill_mg_cmtime() can race with
inode_set_ctime_current() like:

fill_mg_cmtime()				inode_set_ctime_current()
  stat->mtime = inode->i_mtime;
  stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
						  now = current_time();
							/* fetches coarse
							 * grained timestamp */
  stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
				~I_CTIME_QUERIED;
						  inode_set_ctime(inode, now.tv_sec, now.tv_nsec);

and the information about a need for finegrained timestamp update gets
lost. So what I'd propose is to leave current_time() alone (just always
reporting coarse grained timestamps) and put all the magic into
inode_set_ctime_current() only. There we need something like:

struct timespec64 inode_set_ctime_current(struct inode *inode)
{
	... variables ...

	nsec = READ_ONCE(inode->__i_ctime.tv_nsec);
 	if (!(nsec & I_CTIME_QUERIED)) {
		now = current_time(inode);

		if (!is_gmtime(inode)) {
			inode_set_ctime_to_ts(inode, now);
		} else {
			/*
			 * If we've recently fetched a fine-grained
			 * timestamp then the coarse-grained one may still
			 * be earlier than the existing one. Just keep the
			 * existing ctime if so.
			 */
			ctime = inode_get_ctime(inode);
			if (timespec64_compare(&ctime, &now) > 0)
				now = ctime;

			/*
			 * Ctime updates are generally protected by inode
			 * lock but we could have raced with setting of
			 * I_CTIME_QUERIED flag.
			 */
			if (cmpxchg(&inode->__i_ctime.tv_nsec, nsec,
				    now.tv_nsec) != nsec)
				goto fine_grained;
			inode->__i_ctime.tv_sec = now.tv_sec;
		}
		return now;
	}
fine_grained:
	ktime_get_real_ts64(&now);
	inode_set_ctime_to_ts(inode, now);

	return now;
}

								Honza

>  static int inode_needs_update_time(struct inode *inode, struct timespec64 *now)
>  {
>  	int sync_it = 0;
> @@ -2480,37 +2545,12 @@ struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode)
>  }
>  EXPORT_SYMBOL(timestamp_truncate);
>  
> -/**
> - * current_time - Return FS time
> - * @inode: inode.
> - *
> - * Return the current time truncated to the time granularity supported by
> - * the fs.
> - *
> - * Note that inode and inode->sb cannot be NULL.
> - * Otherwise, the function warns and returns time without truncation.
> - */
> -struct timespec64 current_time(struct inode *inode)
> -{
> -	struct timespec64 now;
> -
> -	ktime_get_coarse_real_ts64(&now);
> -
> -	if (unlikely(!inode->i_sb)) {
> -		WARN(1, "current_time() called with uninitialized super_block in the inode");
> -		return now;
> -	}
> -
> -	return timestamp_truncate(now, inode);
> -}
> -EXPORT_SYMBOL(current_time);
> -
>  /**
>   * inode_set_ctime_current - set the ctime to current_time
>   * @inode: inode
>   *
> - * Set the inode->i_ctime to the current value for the inode. Returns
> - * the current value that was assigned to i_ctime.
> + * Set the inode->__i_ctime to the current value for the inode. Returns
> + * the current value that was assigned to __i_ctime.
>   */
>  struct timespec64 inode_set_ctime_current(struct inode *inode)
>  {
> diff --git a/fs/stat.c b/fs/stat.c
> index 062f311b5386..51effd1c2bc2 100644
> --- a/fs/stat.c
> +++ b/fs/stat.c
> @@ -26,6 +26,37 @@
>  #include "internal.h"
>  #include "mount.h"
>  
> +/**
> + * fill_mg_cmtime - Fill in the mtime and ctime and flag ctime as QUERIED
> + * @request_mask: STATX_* values requested
> + * @inode: inode from which to grab the c/mtime
> + * @stat: where to store the resulting values
> + *
> + * Given @inode, grab the ctime and mtime out if it and store the result
> + * in @stat. When fetching the value, flag it as queried so the next write
> + * will use a fine-grained timestamp.
> + */
> +void fill_mg_cmtime(u32 request_mask, struct inode *inode, struct kstat *stat)
> +{
> +	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
> +
> +	/* If neither time was requested, then don't report them */
> +	if (!(request_mask & (STATX_CTIME|STATX_MTIME))) {
> +		stat->result_mask &= ~(STATX_CTIME|STATX_MTIME);
> +		return;
> +	}
> +
> +	stat->mtime = inode->i_mtime;
> +	stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
> +	/*
> +	 * Atomically set the QUERIED flag and fetch the new value with
> +	 * the flag masked off.
> +	 */
> +	stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
> +					~I_CTIME_QUERIED;
> +}
> +EXPORT_SYMBOL(fill_mg_cmtime);
> +
>  /**
>   * generic_fillattr - Fill in the basic attributes from the inode struct
>   * @idmap:	idmap of the mount the inode was found from
> @@ -58,8 +89,14 @@ void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
>  	stat->rdev = inode->i_rdev;
>  	stat->size = i_size_read(inode);
>  	stat->atime = inode->i_atime;
> -	stat->mtime = inode->i_mtime;
> -	stat->ctime = inode_get_ctime(inode);
> +
> +	if (is_mgtime(inode)) {
> +		fill_mg_cmtime(request_mask, inode, stat);
> +	} else {
> +		stat->mtime = inode->i_mtime;
> +		stat->ctime = inode_get_ctime(inode);
> +	}
> +
>  	stat->blksize = i_blocksize(inode);
>  	stat->blocks = inode->i_blocks;
>  
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 42d1434cc427..a0bdbefbf293 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1477,15 +1477,43 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
>  struct timespec64 current_time(struct inode *inode);
>  struct timespec64 inode_set_ctime_current(struct inode *inode);
>  
> +/*
> + * Multigrain timestamps
> + *
> + * Conditionally use fine-grained ctime and mtime timestamps when there
> + * are users actively observing them via getattr. The primary use-case
> + * for this is NFS clients that use the ctime to distinguish between
> + * different states of the file, and that are often fooled by multiple
> + * operations that occur in the same coarse-grained timer tick.
> + *
> + * The kernel always keeps normalized struct timespec64 values in the ctime,
> + * which means that only the first 30 bits of the value are used. Use the
> + * 31st bit of the ctime's tv_nsec field as a flag to indicate that the value
> + * has been queried since it was last updated.
> + */
> +#define I_CTIME_QUERIED		(1L<<30)
> +
>  /**
>   * inode_get_ctime - fetch the current ctime from the inode
>   * @inode: inode from which to fetch ctime
>   *
> - * Grab the current ctime from the inode and return it.
> + * Grab the current ctime tv_nsec field from the inode, mask off the
> + * I_CTIME_QUERIED flag and return it. This is mostly intended for use by
> + * internal consumers of the ctime that aren't concerned with ensuring a
> + * fine-grained update on the next change (e.g. when preparing to store
> + * the value in the backing store for later retrieval).
> + *
> + * This is safe to call regardless of whether the underlying filesystem
> + * is using multigrain timestamps.
>   */
>  static inline struct timespec64 inode_get_ctime(const struct inode *inode)
>  {
> -	return inode->__i_ctime;
> +	struct timespec64 ctime;
> +
> +	ctime.tv_sec = inode->__i_ctime.tv_sec;
> +	ctime.tv_nsec = inode->__i_ctime.tv_nsec & ~I_CTIME_QUERIED;
> +
> +	return ctime;
>  }
>  
>  /**
> @@ -2261,6 +2289,7 @@ struct file_system_type {
>  #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
>  #define FS_DISALLOW_NOTIFY_PERM	16	/* Disable fanotify permission events */
>  #define FS_ALLOW_IDMAP         32      /* FS has been updated to handle vfs idmappings. */
> +#define FS_MGTIME		64	/* FS uses multigrain timestamps */
>  #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
>  	int (*init_fs_context)(struct fs_context *);
>  	const struct fs_parameter_spec *parameters;
> @@ -2284,6 +2313,17 @@ struct file_system_type {
>  
>  #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
>  
> +/**
> + * is_mgtime: is this inode using multigrain timestamps
> + * @inode: inode to test for multigrain timestamps
> + *
> + * Return true if the inode uses multigrain timestamps, false otherwise.
> + */
> +static inline bool is_mgtime(const struct inode *inode)
> +{
> +	return inode->i_sb->s_type->fs_flags & FS_MGTIME;
> +}
> +
>  extern struct dentry *mount_bdev(struct file_system_type *fs_type,
>  	int flags, const char *dev_name, void *data,
>  	int (*fill_super)(struct super_block *, void *, int));
> @@ -2919,6 +2959,7 @@ extern void page_put_link(void *);
>  extern int page_symlink(struct inode *inode, const char *symname, int len);
>  extern const struct inode_operations page_symlink_inode_operations;
>  extern void kfree_link(void *);
> +void fill_mg_cmtime(u32 request_mask, struct inode *inode, struct kstat *stat);
>  void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
>  void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
>  extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
> 
> -- 
> 2.41.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 4/7] tmpfs: add support for multigrain timestamps
  2023-07-25 14:58 ` [PATCH v6 4/7] tmpfs: add support for multigrain timestamps Jeff Layton
@ 2023-08-02 19:37   ` Jan Kara
  0 siblings, 0 replies; 30+ messages in thread
From: Jan Kara @ 2023-08-02 19:37 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue 25-07-23 10:58:17, Jeff Layton wrote:
> Enable multigrain timestamps, which should ensure that there is an
> apparent change to the timestamp whenever it has been written after
> being actively observed via getattr.
> 
> tmpfs only requires the FS_MGTIME flag.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  mm/shmem.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 654d9a585820..b6019c905058 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -4264,7 +4264,7 @@ static struct file_system_type shmem_fs_type = {
>  #endif
>  	.kill_sb	= kill_litter_super,
>  #ifdef CONFIG_SHMEM
> -	.fs_flags	= FS_USERNS_MOUNT | FS_ALLOW_IDMAP,
> +	.fs_flags	= FS_USERNS_MOUNT | FS_ALLOW_IDMAP | FS_MGTIME,
>  #else
>  	.fs_flags	= FS_USERNS_MOUNT,
>  #endif
> 
> -- 
> 2.41.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 6/7] ext4: switch to multigrain timestamps
  2023-07-25 14:58 ` [PATCH v6 6/7] ext4: " Jeff Layton
@ 2023-08-02 19:38   ` Jan Kara
  0 siblings, 0 replies; 30+ messages in thread
From: Jan Kara @ 2023-08-02 19:38 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue 25-07-23 10:58:19, Jeff Layton wrote:
> Enable multigrain timestamps, which should ensure that there is an
> apparent change to the timestamp whenever it has been written after
> being actively observed via getattr.
> 
> For ext4, we only need to enable the FS_MGTIME flag.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/ext4/super.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index b54c70e1a74e..cb1ff47af156 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -7279,7 +7279,7 @@ static struct file_system_type ext4_fs_type = {
>  	.init_fs_context	= ext4_init_fs_context,
>  	.parameters		= ext4_param_specs,
>  	.kill_sb		= kill_block_super,
> -	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
> +	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME,
>  };
>  MODULE_ALIAS_FS("ext4");
>  
> 
> -- 
> 2.41.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps
  2023-08-02 19:35   ` Jan Kara
@ 2023-08-02 20:54     ` Jeff Layton
  2023-08-03  7:07       ` Christian Brauner
  0 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-08-02 20:54 UTC (permalink / raw)
  To: Jan Kara
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Alexander Viro, Christian Brauner, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Wed, 2023-08-02 at 21:35 +0200, Jan Kara wrote:
> On Tue 25-07-23 10:58:15, Jeff Layton wrote:
> > The VFS always uses coarse-grained timestamps when updating the ctime
> > and mtime after a change. This has the benefit of allowing filesystems
> > to optimize away a lot metadata updates, down to around 1 per jiffy,
> > even when a file is under heavy writes.
> > 
> > Unfortunately, this has always been an issue when we're exporting via
> > NFSv3, which relies on timestamps to validate caches. A lot of changes
> > can happen in a jiffy, so timestamps aren't sufficient to help the
> > client decide to invalidate the cache. Even with NFSv4, a lot of
> > exported filesystems don't properly support a change attribute and are
> > subject to the same problems with timestamp granularity. Other
> > applications have similar issues with timestamps (e.g backup
> > applications).
> > 
> > If we were to always use fine-grained timestamps, that would improve the
> > situation, but that becomes rather expensive, as the underlying
> > filesystem would have to log a lot more metadata updates.
> > 
> > What we need is a way to only use fine-grained timestamps when they are
> > being actively queried.
> > 
> > POSIX generally mandates that when the the mtime changes, the ctime must
> > also change. The kernel always stores normalized ctime values, so only
> > the first 30 bits of the tv_nsec field are ever used.
> > 
> > Use the 31st bit of the ctime tv_nsec field to indicate that something
> > has queried the inode for the mtime or ctime. When this flag is set,
> > on the next mtime or ctime update, the kernel will fetch a fine-grained
> > timestamp instead of the usual coarse-grained one.
> > 
> > Filesytems can opt into this behavior by setting the FS_MGTIME flag in
> > the fstype. Filesystems that don't set this flag will continue to use
> > coarse-grained timestamps.
> > 
> > Later patches will convert individual filesystems to use the new
> > infrastructure.
> > 
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >  fs/inode.c         | 98 ++++++++++++++++++++++++++++++++++++++----------------
> >  fs/stat.c          | 41 +++++++++++++++++++++--
> >  include/linux/fs.h | 45 +++++++++++++++++++++++--
> >  3 files changed, 151 insertions(+), 33 deletions(-)
> > 
> > diff --git a/fs/inode.c b/fs/inode.c
> > index d4ab92233062..369621e7faf5 100644
> > --- a/fs/inode.c
> > +++ b/fs/inode.c
> > @@ -1919,6 +1919,21 @@ int inode_update_time(struct inode *inode, struct timespec64 *time, int flags)
> >  }
> >  EXPORT_SYMBOL(inode_update_time);
> >  
> > +/**
> > + * current_coarse_time - Return FS time
> > + * @inode: inode.
> > + *
> > + * Return the current coarse-grained time truncated to the time
> > + * granularity supported by the fs.
> > + */
> > +static struct timespec64 current_coarse_time(struct inode *inode)
> > +{
> > +	struct timespec64 now;
> > +
> > +	ktime_get_coarse_real_ts64(&now);
> > +	return timestamp_truncate(now, inode);
> > +}
> > +
> >  /**
> >   *	atime_needs_update	-	update the access time
> >   *	@path: the &struct path to update
> > @@ -1952,7 +1967,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
> >  	if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
> >  		return false;
> >  
> > -	now = current_time(inode);
> > +	now = current_coarse_time(inode);
> >  
> >  	if (!relatime_need_update(mnt, inode, now))
> >  		return false;
> > @@ -1986,7 +2001,7 @@ void touch_atime(const struct path *path)
> >  	 * We may also fail on filesystems that have the ability to make parts
> >  	 * of the fs read only, e.g. subvolumes in Btrfs.
> >  	 */
> > -	now = current_time(inode);
> > +	now = current_coarse_time(inode);
> >  	inode_update_time(inode, &now, S_ATIME);
> >  	__mnt_drop_write(mnt);
> >  skip_update:
> 
> There are also calls in fs/smb/client/file.c:cifs_readpage_worker() and in
> fs/ocfs2/file.c:ocfs2_update_inode_atime() that should probably use
> current_coarse_time() to avoid needless querying of fine grained
> timestamps. But see below...
> 

Technically, they already devolve to current_coarse_time anyway, but
changing them would allow them to skip the fstype flag check, but I like
your idea below better anyway.

> > @@ -2072,6 +2087,56 @@ int file_remove_privs(struct file *file)
> >  }
> >  EXPORT_SYMBOL(file_remove_privs);
> >  
> > +/**
> > + * current_mgtime - Return FS time (possibly fine-grained)
> > + * @inode: inode.
> > + *
> > + * Return the current time truncated to the time granularity supported by
> > + * the fs, as suitable for a ctime/mtime change. If the ctime is flagged
> > + * as having been QUERIED, get a fine-grained timestamp.
> > + */
> > +static struct timespec64 current_mgtime(struct inode *inode)
> > +{
> > +	struct timespec64 now;
> > +	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
> > +	long nsec = atomic_long_read(pnsec);
> > +
> > +	if (nsec & I_CTIME_QUERIED) {
> > +		ktime_get_real_ts64(&now);
> > +	} else {
> > +		struct timespec64 ctime;
> > +
> > +		ktime_get_coarse_real_ts64(&now);
> > +
> > +		/*
> > +		 * If we've recently fetched a fine-grained timestamp
> > +		 * then the coarse-grained one may still be earlier than the
> > +		 * existing one. Just keep the existing ctime if so.
> > +		 */
> > +		ctime = inode_get_ctime(inode);
> > +		if (timespec64_compare(&ctime, &now) > 0)
> > +			now = ctime;
> > +	}
> > +
> > +	return timestamp_truncate(now, inode);
> > +}
> > +
> > +/**
> > + * current_time - Return timestamp suitable for ctime update
> > + * @inode: inode to eventually be updated
> > + *
> > + * Return the current time, which is usually coarse-grained but may be fine
> > + * grained if the filesystem uses multigrain timestamps and the existing
> > + * ctime was queried since the last update.
> > + */
> > +struct timespec64 current_time(struct inode *inode)
> > +{
> > +	if (is_mgtime(inode))
> > +		return current_mgtime(inode);
> > +	return current_coarse_time(inode);
> > +}
> > +EXPORT_SYMBOL(current_time);
> > +
> 
> So if you modify current_time() to handle multigrain timestamps the code
> will be still racy. In particular fill_mg_cmtime() can race with
> inode_set_ctime_current() like:
> 
> fill_mg_cmtime()				inode_set_ctime_current()
>   stat->mtime = inode->i_mtime;
>   stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
> 						  now = current_time();
> 							/* fetches coarse
> 							 * grained timestamp */
>   stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
> 				~I_CTIME_QUERIED;
> 						  inode_set_ctime(inode, now.tv_sec, now.tv_nsec);
> 
> and the information about a need for finegrained timestamp update gets
> lost. So what I'd propose is to leave current_time() alone (just always
> reporting coarse grained timestamps) and put all the magic into
> inode_set_ctime_current() only. There we need something like:
> 
> struct timespec64 inode_set_ctime_current(struct inode *inode)
> {
> 	... variables ...
> 
> 	nsec = READ_ONCE(inode->__i_ctime.tv_nsec);
>  	if (!(nsec & I_CTIME_QUERIED)) {
> 		now = current_time(inode);
> 
> 		if (!is_gmtime(inode)) {
> 			inode_set_ctime_to_ts(inode, now);
> 		} else {
> 			/*
> 			 * If we've recently fetched a fine-grained
> 			 * timestamp then the coarse-grained one may still
> 			 * be earlier than the existing one. Just keep the
> 			 * existing ctime if so.
> 			 */
> 			ctime = inode_get_ctime(inode);
> 			if (timespec64_compare(&ctime, &now) > 0)
> 				now = ctime;
> 
> 			/*
> 			 * Ctime updates are generally protected by inode
> 			 * lock but we could have raced with setting of
> 			 * I_CTIME_QUERIED flag.
> 			 */
> 			if (cmpxchg(&inode->__i_ctime.tv_nsec, nsec,
> 				    now.tv_nsec) != nsec)
> 				goto fine_grained;
> 			inode->__i_ctime.tv_sec = now.tv_sec;
> 		}
> 		return now;
> 	}
> fine_grained:
> 	ktime_get_real_ts64(&now);
> 	inode_set_ctime_to_ts(inode, now);
> 
> 	return now;
> }
> 
> 								Honza
> 

This is a great idea. I'll rework the series along the lines you
suggest. That also answers my earlier question to Christian:

I'll just resend the whole series (it's not very big anyway), and I'll
include the fill_mg_cmtime prototype change.

Cheers,

> >  static int inode_needs_update_time(struct inode *inode, struct timespec64 *now)
> >  {
> >  	int sync_it = 0;
> > @@ -2480,37 +2545,12 @@ struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode)
> >  }
> >  EXPORT_SYMBOL(timestamp_truncate);
> >  
> > -/**
> > - * current_time - Return FS time
> > - * @inode: inode.
> > - *
> > - * Return the current time truncated to the time granularity supported by
> > - * the fs.
> > - *
> > - * Note that inode and inode->sb cannot be NULL.
> > - * Otherwise, the function warns and returns time without truncation.
> > - */
> > -struct timespec64 current_time(struct inode *inode)
> > -{
> > -	struct timespec64 now;
> > -
> > -	ktime_get_coarse_real_ts64(&now);
> > -
> > -	if (unlikely(!inode->i_sb)) {
> > -		WARN(1, "current_time() called with uninitialized super_block in the inode");
> > -		return now;
> > -	}
> > -
> > -	return timestamp_truncate(now, inode);
> > -}
> > -EXPORT_SYMBOL(current_time);
> > -
> >  /**
> >   * inode_set_ctime_current - set the ctime to current_time
> >   * @inode: inode
> >   *
> > - * Set the inode->i_ctime to the current value for the inode. Returns
> > - * the current value that was assigned to i_ctime.
> > + * Set the inode->__i_ctime to the current value for the inode. Returns
> > + * the current value that was assigned to __i_ctime.
> >   */
> >  struct timespec64 inode_set_ctime_current(struct inode *inode)
> >  {
> > diff --git a/fs/stat.c b/fs/stat.c
> > index 062f311b5386..51effd1c2bc2 100644
> > --- a/fs/stat.c
> > +++ b/fs/stat.c
> > @@ -26,6 +26,37 @@
> >  #include "internal.h"
> >  #include "mount.h"
> >  
> > +/**
> > + * fill_mg_cmtime - Fill in the mtime and ctime and flag ctime as QUERIED
> > + * @request_mask: STATX_* values requested
> > + * @inode: inode from which to grab the c/mtime
> > + * @stat: where to store the resulting values
> > + *
> > + * Given @inode, grab the ctime and mtime out if it and store the result
> > + * in @stat. When fetching the value, flag it as queried so the next write
> > + * will use a fine-grained timestamp.
> > + */
> > +void fill_mg_cmtime(u32 request_mask, struct inode *inode, struct kstat *stat)
> > +{
> > +	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
> > +
> > +	/* If neither time was requested, then don't report them */
> > +	if (!(request_mask & (STATX_CTIME|STATX_MTIME))) {
> > +		stat->result_mask &= ~(STATX_CTIME|STATX_MTIME);
> > +		return;
> > +	}
> > +
> > +	stat->mtime = inode->i_mtime;
> > +	stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
> > +	/*
> > +	 * Atomically set the QUERIED flag and fetch the new value with
> > +	 * the flag masked off.
> > +	 */
> > +	stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
> > +					~I_CTIME_QUERIED;
> > +}
> > +EXPORT_SYMBOL(fill_mg_cmtime);
> > +
> >  /**
> >   * generic_fillattr - Fill in the basic attributes from the inode struct
> >   * @idmap:	idmap of the mount the inode was found from
> > @@ -58,8 +89,14 @@ void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask,
> >  	stat->rdev = inode->i_rdev;
> >  	stat->size = i_size_read(inode);
> >  	stat->atime = inode->i_atime;
> > -	stat->mtime = inode->i_mtime;
> > -	stat->ctime = inode_get_ctime(inode);
> > +
> > +	if (is_mgtime(inode)) {
> > +		fill_mg_cmtime(request_mask, inode, stat);
> > +	} else {
> > +		stat->mtime = inode->i_mtime;
> > +		stat->ctime = inode_get_ctime(inode);
> > +	}
> > +
> >  	stat->blksize = i_blocksize(inode);
> >  	stat->blocks = inode->i_blocks;
> >  
> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > index 42d1434cc427..a0bdbefbf293 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -1477,15 +1477,43 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
> >  struct timespec64 current_time(struct inode *inode);
> >  struct timespec64 inode_set_ctime_current(struct inode *inode);
> >  
> > +/*
> > + * Multigrain timestamps
> > + *
> > + * Conditionally use fine-grained ctime and mtime timestamps when there
> > + * are users actively observing them via getattr. The primary use-case
> > + * for this is NFS clients that use the ctime to distinguish between
> > + * different states of the file, and that are often fooled by multiple
> > + * operations that occur in the same coarse-grained timer tick.
> > + *
> > + * The kernel always keeps normalized struct timespec64 values in the ctime,
> > + * which means that only the first 30 bits of the value are used. Use the
> > + * 31st bit of the ctime's tv_nsec field as a flag to indicate that the value
> > + * has been queried since it was last updated.
> > + */
> > +#define I_CTIME_QUERIED		(1L<<30)
> > +
> >  /**
> >   * inode_get_ctime - fetch the current ctime from the inode
> >   * @inode: inode from which to fetch ctime
> >   *
> > - * Grab the current ctime from the inode and return it.
> > + * Grab the current ctime tv_nsec field from the inode, mask off the
> > + * I_CTIME_QUERIED flag and return it. This is mostly intended for use by
> > + * internal consumers of the ctime that aren't concerned with ensuring a
> > + * fine-grained update on the next change (e.g. when preparing to store
> > + * the value in the backing store for later retrieval).
> > + *
> > + * This is safe to call regardless of whether the underlying filesystem
> > + * is using multigrain timestamps.
> >   */
> >  static inline struct timespec64 inode_get_ctime(const struct inode *inode)
> >  {
> > -	return inode->__i_ctime;
> > +	struct timespec64 ctime;
> > +
> > +	ctime.tv_sec = inode->__i_ctime.tv_sec;
> > +	ctime.tv_nsec = inode->__i_ctime.tv_nsec & ~I_CTIME_QUERIED;
> > +
> > +	return ctime;
> >  }
> >  
> >  /**
> > @@ -2261,6 +2289,7 @@ struct file_system_type {
> >  #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
> >  #define FS_DISALLOW_NOTIFY_PERM	16	/* Disable fanotify permission events */
> >  #define FS_ALLOW_IDMAP         32      /* FS has been updated to handle vfs idmappings. */
> > +#define FS_MGTIME		64	/* FS uses multigrain timestamps */
> >  #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
> >  	int (*init_fs_context)(struct fs_context *);
> >  	const struct fs_parameter_spec *parameters;
> > @@ -2284,6 +2313,17 @@ struct file_system_type {
> >  
> >  #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
> >  
> > +/**
> > + * is_mgtime: is this inode using multigrain timestamps
> > + * @inode: inode to test for multigrain timestamps
> > + *
> > + * Return true if the inode uses multigrain timestamps, false otherwise.
> > + */
> > +static inline bool is_mgtime(const struct inode *inode)
> > +{
> > +	return inode->i_sb->s_type->fs_flags & FS_MGTIME;
> > +}
> > +
> >  extern struct dentry *mount_bdev(struct file_system_type *fs_type,
> >  	int flags, const char *dev_name, void *data,
> >  	int (*fill_super)(struct super_block *, void *, int));
> > @@ -2919,6 +2959,7 @@ extern void page_put_link(void *);
> >  extern int page_symlink(struct inode *inode, const char *symname, int len);
> >  extern const struct inode_operations page_symlink_inode_operations;
> >  extern void kfree_link(void *);
> > +void fill_mg_cmtime(u32 request_mask, struct inode *inode, struct kstat *stat);
> >  void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
> >  void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
> >  extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
> > 
> > -- 
> > 2.41.0
> > 

-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 5/7] xfs: switch to multigrain timestamps
  2023-08-02 18:21     ` Jeff Layton
@ 2023-08-03  7:05       ` Christian Brauner
  0 siblings, 0 replies; 30+ messages in thread
From: Christian Brauner @ 2023-08-03  7:05 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Darrick J. Wong, Eric Van Hensbergen, Latchesar Ionkov,
	Dominique Martinet, Christian Schoenebeck, David Howells,
	Marc Dionne, Chris Mason, Josef Bacik, David Sterba, Xiubo Li,
	Ilya Dryomov, Jan Harkes, coda, Tyler Hicks, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Namjae Jeon, Sungjong Seo, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi,
	Miklos Szeredi, Bob Peterson, Andreas Gruenbacher,
	Greg Kroah-Hartman, Tejun Heo, Alexander Viro, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Dave Chinner, Anthony Iliopoulos, v9fs, linux-kernel, linux-afs,
	linux-btrfs, ceph-devel, codalist, ecryptfs, linux-erofs,
	linux-fsdevel, linux-ext4, linux-f2fs-devel, cluster-devel,
	linux-nfs, ntfs3, ocfs2-devel, devel, linux-cifs,
	samba-technical, linux-mtd, linux-mm, linux-xfs

On Wed, Aug 02, 2023 at 02:21:49PM -0400, Jeff Layton wrote:
> On Wed, 2023-08-02 at 10:48 -0700, Darrick J. Wong wrote:
> > On Tue, Jul 25, 2023 at 10:58:18AM -0400, Jeff Layton wrote:
> > > Enable multigrain timestamps, which should ensure that there is an
> > > apparent change to the timestamp whenever it has been written after
> > > being actively observed via getattr.
> > > 
> > > Also, anytime the mtime changes, the ctime must also change, and those
> > > are now the only two options for xfs_trans_ichgtime. Have that function
> > > unconditionally bump the ctime, and ASSERT that XFS_ICHGTIME_CHG is
> > > always set.
> > > 
> > > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > > ---
> > >  fs/xfs/libxfs/xfs_trans_inode.c | 6 +++---
> > >  fs/xfs/xfs_iops.c               | 4 ++--
> > >  fs/xfs/xfs_super.c              | 2 +-
> > >  3 files changed, 6 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
> > > index 6b2296ff248a..ad22656376d3 100644
> > > --- a/fs/xfs/libxfs/xfs_trans_inode.c
> > > +++ b/fs/xfs/libxfs/xfs_trans_inode.c
> > > @@ -62,12 +62,12 @@ xfs_trans_ichgtime(
> > >  	ASSERT(tp);
> > >  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> > >  
> > > -	tv = current_time(inode);
> > > +	/* If the mtime changes, then ctime must also change */
> > > +	ASSERT(flags & XFS_ICHGTIME_CHG);
> > >  
> > > +	tv = inode_set_ctime_current(inode);
> > >  	if (flags & XFS_ICHGTIME_MOD)
> > >  		inode->i_mtime = tv;
> > > -	if (flags & XFS_ICHGTIME_CHG)
> > > -		inode_set_ctime_to_ts(inode, tv);
> > >  	if (flags & XFS_ICHGTIME_CREATE)
> > >  		ip->i_crtime = tv;
> > >  }
> > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > > index 3a9363953ef2..3f89ef5a2820 100644
> > > --- a/fs/xfs/xfs_iops.c
> > > +++ b/fs/xfs/xfs_iops.c
> > > @@ -573,10 +573,10 @@ xfs_vn_getattr(
> > >  	stat->gid = vfsgid_into_kgid(vfsgid);
> > >  	stat->ino = ip->i_ino;
> > >  	stat->atime = inode->i_atime;
> > > -	stat->mtime = inode->i_mtime;
> > > -	stat->ctime = inode_get_ctime(inode);
> > >  	stat->blocks = XFS_FSB_TO_BB(mp, ip->i_nblocks + ip->i_delayed_blks);
> > >  
> > > +	fill_mg_cmtime(request_mask, inode, stat);
> > 
> > Huh.  I would've thought @stat would come first since that's what we're
> > acting upon, but ... eh. :)
> > 
> > If everyone else is ok with the fill_mg_cmtime signature,
> > Acked-by: Darrick J. Wong <djwong@kernel.org>
> > 
> > 
> 
> Good point. We can change the signature. I think xfs is the only caller
> outside of the generic vfs right now, and it'd be best to do it now.
> 
> Christian, would you prefer that I send an updated series, or patches on
> top of vfs.ctime that can be folded in?

Let's fold instead of inundate everyone with almost 100 patches.
When I'll apply I'll remind everyone where the series can be pulled
from anyway.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps
  2023-08-02 20:54     ` Jeff Layton
@ 2023-08-03  7:07       ` Christian Brauner
  0 siblings, 0 replies; 30+ messages in thread
From: Christian Brauner @ 2023-08-03  7:07 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Jan Kara, Eric Van Hensbergen, Latchesar Ionkov,
	Dominique Martinet, Christian Schoenebeck, David Howells,
	Marc Dionne, Chris Mason, Josef Bacik, David Sterba, Xiubo Li,
	Ilya Dryomov, Jan Harkes, coda, Tyler Hicks, Gao Xiang, Chao Yu,
	Yue Hu, Jeffle Xu, Namjae Jeon, Sungjong Seo, Jan Kara,
	Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi,
	Miklos Szeredi, Bob Peterson, Andreas Gruenbacher,
	Greg Kroah-Hartman, Tejun Heo, Alexander Viro, Trond Myklebust,
	Anna Schumaker, Konstantin Komarov, Mark Fasheh, Joel Becker,
	Joseph Qi, Mike Marshall, Martin Brandenburg, Luis Chamberlain,
	Kees Cook, Iurii Zaikin, Steve French, Paulo Alcantara,
	Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Wed, Aug 02, 2023 at 04:54:09PM -0400, Jeff Layton wrote:
> On Wed, 2023-08-02 at 21:35 +0200, Jan Kara wrote:
> > On Tue 25-07-23 10:58:15, Jeff Layton wrote:
> > > The VFS always uses coarse-grained timestamps when updating the ctime
> > > and mtime after a change. This has the benefit of allowing filesystems
> > > to optimize away a lot metadata updates, down to around 1 per jiffy,
> > > even when a file is under heavy writes.
> > > 
> > > Unfortunately, this has always been an issue when we're exporting via
> > > NFSv3, which relies on timestamps to validate caches. A lot of changes
> > > can happen in a jiffy, so timestamps aren't sufficient to help the
> > > client decide to invalidate the cache. Even with NFSv4, a lot of
> > > exported filesystems don't properly support a change attribute and are
> > > subject to the same problems with timestamp granularity. Other
> > > applications have similar issues with timestamps (e.g backup
> > > applications).
> > > 
> > > If we were to always use fine-grained timestamps, that would improve the
> > > situation, but that becomes rather expensive, as the underlying
> > > filesystem would have to log a lot more metadata updates.
> > > 
> > > What we need is a way to only use fine-grained timestamps when they are
> > > being actively queried.
> > > 
> > > POSIX generally mandates that when the the mtime changes, the ctime must
> > > also change. The kernel always stores normalized ctime values, so only
> > > the first 30 bits of the tv_nsec field are ever used.
> > > 
> > > Use the 31st bit of the ctime tv_nsec field to indicate that something
> > > has queried the inode for the mtime or ctime. When this flag is set,
> > > on the next mtime or ctime update, the kernel will fetch a fine-grained
> > > timestamp instead of the usual coarse-grained one.
> > > 
> > > Filesytems can opt into this behavior by setting the FS_MGTIME flag in
> > > the fstype. Filesystems that don't set this flag will continue to use
> > > coarse-grained timestamps.
> > > 
> > > Later patches will convert individual filesystems to use the new
> > > infrastructure.
> > > 
> > > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > > ---
> > >  fs/inode.c         | 98 ++++++++++++++++++++++++++++++++++++++----------------
> > >  fs/stat.c          | 41 +++++++++++++++++++++--
> > >  include/linux/fs.h | 45 +++++++++++++++++++++++--
> > >  3 files changed, 151 insertions(+), 33 deletions(-)
> > > 
> > > diff --git a/fs/inode.c b/fs/inode.c
> > > index d4ab92233062..369621e7faf5 100644
> > > --- a/fs/inode.c
> > > +++ b/fs/inode.c
> > > @@ -1919,6 +1919,21 @@ int inode_update_time(struct inode *inode, struct timespec64 *time, int flags)
> > >  }
> > >  EXPORT_SYMBOL(inode_update_time);
> > >  
> > > +/**
> > > + * current_coarse_time - Return FS time
> > > + * @inode: inode.
> > > + *
> > > + * Return the current coarse-grained time truncated to the time
> > > + * granularity supported by the fs.
> > > + */
> > > +static struct timespec64 current_coarse_time(struct inode *inode)
> > > +{
> > > +	struct timespec64 now;
> > > +
> > > +	ktime_get_coarse_real_ts64(&now);
> > > +	return timestamp_truncate(now, inode);
> > > +}
> > > +
> > >  /**
> > >   *	atime_needs_update	-	update the access time
> > >   *	@path: the &struct path to update
> > > @@ -1952,7 +1967,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
> > >  	if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
> > >  		return false;
> > >  
> > > -	now = current_time(inode);
> > > +	now = current_coarse_time(inode);
> > >  
> > >  	if (!relatime_need_update(mnt, inode, now))
> > >  		return false;
> > > @@ -1986,7 +2001,7 @@ void touch_atime(const struct path *path)
> > >  	 * We may also fail on filesystems that have the ability to make parts
> > >  	 * of the fs read only, e.g. subvolumes in Btrfs.
> > >  	 */
> > > -	now = current_time(inode);
> > > +	now = current_coarse_time(inode);
> > >  	inode_update_time(inode, &now, S_ATIME);
> > >  	__mnt_drop_write(mnt);
> > >  skip_update:
> > 
> > There are also calls in fs/smb/client/file.c:cifs_readpage_worker() and in
> > fs/ocfs2/file.c:ocfs2_update_inode_atime() that should probably use
> > current_coarse_time() to avoid needless querying of fine grained
> > timestamps. But see below...
> > 
> 
> Technically, they already devolve to current_coarse_time anyway, but
> changing them would allow them to skip the fstype flag check, but I like
> your idea below better anyway.
> 
> > > @@ -2072,6 +2087,56 @@ int file_remove_privs(struct file *file)
> > >  }
> > >  EXPORT_SYMBOL(file_remove_privs);
> > >  
> > > +/**
> > > + * current_mgtime - Return FS time (possibly fine-grained)
> > > + * @inode: inode.
> > > + *
> > > + * Return the current time truncated to the time granularity supported by
> > > + * the fs, as suitable for a ctime/mtime change. If the ctime is flagged
> > > + * as having been QUERIED, get a fine-grained timestamp.
> > > + */
> > > +static struct timespec64 current_mgtime(struct inode *inode)
> > > +{
> > > +	struct timespec64 now;
> > > +	atomic_long_t *pnsec = (atomic_long_t *)&inode->__i_ctime.tv_nsec;
> > > +	long nsec = atomic_long_read(pnsec);
> > > +
> > > +	if (nsec & I_CTIME_QUERIED) {
> > > +		ktime_get_real_ts64(&now);
> > > +	} else {
> > > +		struct timespec64 ctime;
> > > +
> > > +		ktime_get_coarse_real_ts64(&now);
> > > +
> > > +		/*
> > > +		 * If we've recently fetched a fine-grained timestamp
> > > +		 * then the coarse-grained one may still be earlier than the
> > > +		 * existing one. Just keep the existing ctime if so.
> > > +		 */
> > > +		ctime = inode_get_ctime(inode);
> > > +		if (timespec64_compare(&ctime, &now) > 0)
> > > +			now = ctime;
> > > +	}
> > > +
> > > +	return timestamp_truncate(now, inode);
> > > +}
> > > +
> > > +/**
> > > + * current_time - Return timestamp suitable for ctime update
> > > + * @inode: inode to eventually be updated
> > > + *
> > > + * Return the current time, which is usually coarse-grained but may be fine
> > > + * grained if the filesystem uses multigrain timestamps and the existing
> > > + * ctime was queried since the last update.
> > > + */
> > > +struct timespec64 current_time(struct inode *inode)
> > > +{
> > > +	if (is_mgtime(inode))
> > > +		return current_mgtime(inode);
> > > +	return current_coarse_time(inode);
> > > +}
> > > +EXPORT_SYMBOL(current_time);
> > > +
> > 
> > So if you modify current_time() to handle multigrain timestamps the code
> > will be still racy. In particular fill_mg_cmtime() can race with
> > inode_set_ctime_current() like:
> > 
> > fill_mg_cmtime()				inode_set_ctime_current()
> >   stat->mtime = inode->i_mtime;
> >   stat->ctime.tv_sec = inode->__i_ctime.tv_sec;
> > 						  now = current_time();
> > 							/* fetches coarse
> > 							 * grained timestamp */
> >   stat->ctime.tv_nsec = atomic_long_fetch_or(I_CTIME_QUERIED, pnsec) &
> > 				~I_CTIME_QUERIED;
> > 						  inode_set_ctime(inode, now.tv_sec, now.tv_nsec);
> > 
> > and the information about a need for finegrained timestamp update gets
> > lost. So what I'd propose is to leave current_time() alone (just always
> > reporting coarse grained timestamps) and put all the magic into
> > inode_set_ctime_current() only. There we need something like:
> > 
> > struct timespec64 inode_set_ctime_current(struct inode *inode)
> > {
> > 	... variables ...
> > 
> > 	nsec = READ_ONCE(inode->__i_ctime.tv_nsec);
> >  	if (!(nsec & I_CTIME_QUERIED)) {
> > 		now = current_time(inode);
> > 
> > 		if (!is_gmtime(inode)) {
> > 			inode_set_ctime_to_ts(inode, now);
> > 		} else {
> > 			/*
> > 			 * If we've recently fetched a fine-grained
> > 			 * timestamp then the coarse-grained one may still
> > 			 * be earlier than the existing one. Just keep the
> > 			 * existing ctime if so.
> > 			 */
> > 			ctime = inode_get_ctime(inode);
> > 			if (timespec64_compare(&ctime, &now) > 0)
> > 				now = ctime;
> > 
> > 			/*
> > 			 * Ctime updates are generally protected by inode
> > 			 * lock but we could have raced with setting of
> > 			 * I_CTIME_QUERIED flag.
> > 			 */
> > 			if (cmpxchg(&inode->__i_ctime.tv_nsec, nsec,
> > 				    now.tv_nsec) != nsec)
> > 				goto fine_grained;
> > 			inode->__i_ctime.tv_sec = now.tv_sec;
> > 		}
> > 		return now;
> > 	}
> > fine_grained:
> > 	ktime_get_real_ts64(&now);
> > 	inode_set_ctime_to_ts(inode, now);
> > 
> > 	return now;
> > }
> > 
> > 								Honza
> > 
> 
> This is a great idea. I'll rework the series along the lines you
> suggest. That also answers my earlier question to Christian:
> 
> I'll just resend the whole series (it's not very big anyway), and I'll
> include the fill_mg_cmtime prototype change.

Ok, sound good!

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
                     ` (3 preceding siblings ...)
  2023-08-02 18:47   ` Paulo Alcantara
@ 2023-08-29 22:44   ` Al Viro
  2023-08-29 22:58     ` Jeff Layton
  4 siblings, 1 reply; 30+ messages in thread
From: Al Viro @ 2023-08-29 22:44 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Christian Brauner, Trond Myklebust, Anna Schumaker,
	Konstantin Komarov, Mark Fasheh, Joel Becker, Joseph Qi,
	Mike Marshall, Martin Brandenburg, Luis Chamberlain, Kees Cook,
	Iurii Zaikin, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, Jul 25, 2023 at 10:58:14AM -0400, Jeff Layton wrote:
> generic_fillattr just fills in the entire stat struct indiscriminately
> today, copying data from the inode. There is at least one attribute
> (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> and we're looking at adding more with the addition of multigrain
> timestamps.
> 
> Add a request_mask argument to generic_fillattr and have most callers
> just pass in the value that is passed to getattr. Have other callers
> (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> STATX_CHANGE_COOKIE into generic_fillattr.

Out of curiosity - how much PITA would it be to put request_mask into
kstat?  Set it in vfs_getattr_nosec() (and those get_file_..._info()
on smbd side) and don't bother with that kind of propagation boilerplate
- just have generic_fillattr() pick it there...

Reduces the patchset size quite a bit...

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-08-29 22:44   ` Al Viro
@ 2023-08-29 22:58     ` Jeff Layton
  2023-08-30  0:02       ` Al Viro
  0 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-08-29 22:58 UTC (permalink / raw)
  To: Al Viro
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Christian Brauner, Trond Myklebust, Anna Schumaker,
	Konstantin Komarov, Mark Fasheh, Joel Becker, Joseph Qi,
	Mike Marshall, Martin Brandenburg, Luis Chamberlain, Kees Cook,
	Iurii Zaikin, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, 2023-08-29 at 23:44 +0100, Al Viro wrote:
> On Tue, Jul 25, 2023 at 10:58:14AM -0400, Jeff Layton wrote:
> > generic_fillattr just fills in the entire stat struct indiscriminately
> > today, copying data from the inode. There is at least one attribute
> > (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> > and we're looking at adding more with the addition of multigrain
> > timestamps.
> > 
> > Add a request_mask argument to generic_fillattr and have most callers
> > just pass in the value that is passed to getattr. Have other callers
> > (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> > STATX_CHANGE_COOKIE into generic_fillattr.
> 
> Out of curiosity - how much PITA would it be to put request_mask into
> kstat?  Set it in vfs_getattr_nosec() (and those get_file_..._info()
> on smbd side) and don't bother with that kind of propagation boilerplate
> - just have generic_fillattr() pick it there...
> 
> Reduces the patchset size quite a bit...

It could be done. To do that right, I think we'd want to drop
request_mask from the ->getattr prototype as well and just have
everything use the mask in the kstat.

I don't think it'd reduce the size of the patchset in any meaningful
way, but it might make for a more sensible API over the long haul.
-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-08-29 22:58     ` Jeff Layton
@ 2023-08-30  0:02       ` Al Viro
  2023-08-30  0:43         ` Jeff Layton
  0 siblings, 1 reply; 30+ messages in thread
From: Al Viro @ 2023-08-30  0:02 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Christian Brauner, Trond Myklebust, Anna Schumaker,
	Konstantin Komarov, Mark Fasheh, Joel Becker, Joseph Qi,
	Mike Marshall, Martin Brandenburg, Luis Chamberlain, Kees Cook,
	Iurii Zaikin, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, Aug 29, 2023 at 06:58:47PM -0400, Jeff Layton wrote:
> On Tue, 2023-08-29 at 23:44 +0100, Al Viro wrote:
> > On Tue, Jul 25, 2023 at 10:58:14AM -0400, Jeff Layton wrote:
> > > generic_fillattr just fills in the entire stat struct indiscriminately
> > > today, copying data from the inode. There is at least one attribute
> > > (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> > > and we're looking at adding more with the addition of multigrain
> > > timestamps.
> > > 
> > > Add a request_mask argument to generic_fillattr and have most callers
> > > just pass in the value that is passed to getattr. Have other callers
> > > (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> > > STATX_CHANGE_COOKIE into generic_fillattr.
> > 
> > Out of curiosity - how much PITA would it be to put request_mask into
> > kstat?  Set it in vfs_getattr_nosec() (and those get_file_..._info()
> > on smbd side) and don't bother with that kind of propagation boilerplate
> > - just have generic_fillattr() pick it there...
> > 
> > Reduces the patchset size quite a bit...
> 
> It could be done. To do that right, I think we'd want to drop
> request_mask from the ->getattr prototype as well and just have
> everything use the mask in the kstat.
> 
> I don't think it'd reduce the size of the patchset in any meaningful
> way, but it might make for a more sensible API over the long haul.

->getattr() prototype change would be decoupled from that - for your
patchset you'd only need the field addition + setting in vfs_getattr_nosec()
(and possibly in ksmbd), with the remainders of both series being
independent from each other.

What I suggest is

branchpoint -> field addition (trivial commit) -> argument removal
		|
		V
your series, starting with "use stat->request_mask in generic_fillattr()"

Total size would be about the same, but it would be easier to follow
the less trivial part of that.  Nothing in your branch downstream of
that touches any ->getattr() instances, so it should have no
conflicts with the argument removal side of things.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-08-30  0:02       ` Al Viro
@ 2023-08-30  0:43         ` Jeff Layton
  2023-08-30  1:22           ` Al Viro
  0 siblings, 1 reply; 30+ messages in thread
From: Jeff Layton @ 2023-08-30  0:43 UTC (permalink / raw)
  To: Al Viro
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Christian Brauner, Trond Myklebust, Anna Schumaker,
	Konstantin Komarov, Mark Fasheh, Joel Becker, Joseph Qi,
	Mike Marshall, Martin Brandenburg, Luis Chamberlain, Kees Cook,
	Iurii Zaikin, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Wed, 2023-08-30 at 01:02 +0100, Al Viro wrote:
> On Tue, Aug 29, 2023 at 06:58:47PM -0400, Jeff Layton wrote:
> > On Tue, 2023-08-29 at 23:44 +0100, Al Viro wrote:
> > > On Tue, Jul 25, 2023 at 10:58:14AM -0400, Jeff Layton wrote:
> > > > generic_fillattr just fills in the entire stat struct indiscriminately
> > > > today, copying data from the inode. There is at least one attribute
> > > > (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> > > > and we're looking at adding more with the addition of multigrain
> > > > timestamps.
> > > > 
> > > > Add a request_mask argument to generic_fillattr and have most callers
> > > > just pass in the value that is passed to getattr. Have other callers
> > > > (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> > > > STATX_CHANGE_COOKIE into generic_fillattr.
> > > 
> > > Out of curiosity - how much PITA would it be to put request_mask into
> > > kstat?  Set it in vfs_getattr_nosec() (and those get_file_..._info()
> > > on smbd side) and don't bother with that kind of propagation boilerplate
> > > - just have generic_fillattr() pick it there...
> > > 
> > > Reduces the patchset size quite a bit...
> > 
> > It could be done. To do that right, I think we'd want to drop
> > request_mask from the ->getattr prototype as well and just have
> > everything use the mask in the kstat.
> > 
> > I don't think it'd reduce the size of the patchset in any meaningful
> > way, but it might make for a more sensible API over the long haul.
> 
> ->getattr() prototype change would be decoupled from that - for your
> patchset you'd only need the field addition + setting in vfs_getattr_nosec()
> (and possibly in ksmbd), with the remainders of both series being
> independent from each other.
> 
> What I suggest is
> 
> branchpoint -> field addition (trivial commit) -> argument removal
> 		|
> 		V
> your series, starting with "use stat->request_mask in generic_fillattr()"
> 
> Total size would be about the same, but it would be easier to follow
> the less trivial part of that.  Nothing in your branch downstream of
> that touches any ->getattr() instances, so it should have no
> conflicts with the argument removal side of things.

The only problem with this plan is that Linus has already merged this.
I've no issue with adding the request_mask to the kstat and removing it
as a separate parameter elsewhere, but I think we'll need to do it on
top of what's already been merged.
-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr
  2023-08-30  0:43         ` Jeff Layton
@ 2023-08-30  1:22           ` Al Viro
  0 siblings, 0 replies; 30+ messages in thread
From: Al Viro @ 2023-08-30  1:22 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Eric Van Hensbergen, Latchesar Ionkov, Dominique Martinet,
	Christian Schoenebeck, David Howells, Marc Dionne, Chris Mason,
	Josef Bacik, David Sterba, Xiubo Li, Ilya Dryomov, Jan Harkes,
	coda, Tyler Hicks, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
	Namjae Jeon, Sungjong Seo, Jan Kara, Theodore Ts'o,
	Andreas Dilger, Jaegeuk Kim, OGAWA Hirofumi, Miklos Szeredi,
	Bob Peterson, Andreas Gruenbacher, Greg Kroah-Hartman, Tejun Heo,
	Christian Brauner, Trond Myklebust, Anna Schumaker,
	Konstantin Komarov, Mark Fasheh, Joel Becker, Joseph Qi,
	Mike Marshall, Martin Brandenburg, Luis Chamberlain, Kees Cook,
	Iurii Zaikin, Steve French, Paulo Alcantara, Ronnie Sahlberg,
	Shyam Prasad N, Tom Talpey, Sergey Senozhatsky,
	Richard Weinberger, Hans de Goede, Hugh Dickins, Andrew Morton,
	Darrick J. Wong, Dave Chinner, Anthony Iliopoulos, v9fs,
	linux-kernel, linux-afs, linux-btrfs, ceph-devel, codalist,
	ecryptfs, linux-erofs, linux-fsdevel, linux-ext4,
	linux-f2fs-devel, cluster-devel, linux-nfs, ntfs3, ocfs2-devel,
	devel, linux-cifs, samba-technical, linux-mtd, linux-mm,
	linux-xfs

On Tue, Aug 29, 2023 at 08:43:31PM -0400, Jeff Layton wrote:
> On Wed, 2023-08-30 at 01:02 +0100, Al Viro wrote:
> > On Tue, Aug 29, 2023 at 06:58:47PM -0400, Jeff Layton wrote:
> > > On Tue, 2023-08-29 at 23:44 +0100, Al Viro wrote:
> > > > On Tue, Jul 25, 2023 at 10:58:14AM -0400, Jeff Layton wrote:
> > > > > generic_fillattr just fills in the entire stat struct indiscriminately
> > > > > today, copying data from the inode. There is at least one attribute
> > > > > (STATX_CHANGE_COOKIE) that can have side effects when it is reported,
> > > > > and we're looking at adding more with the addition of multigrain
> > > > > timestamps.
> > > > > 
> > > > > Add a request_mask argument to generic_fillattr and have most callers
> > > > > just pass in the value that is passed to getattr. Have other callers
> > > > > (e.g. ksmbd) just pass in STATX_BASIC_STATS. Also move the setting of
> > > > > STATX_CHANGE_COOKIE into generic_fillattr.
> > > > 
> > > > Out of curiosity - how much PITA would it be to put request_mask into
> > > > kstat?  Set it in vfs_getattr_nosec() (and those get_file_..._info()
> > > > on smbd side) and don't bother with that kind of propagation boilerplate
> > > > - just have generic_fillattr() pick it there...
> > > > 
> > > > Reduces the patchset size quite a bit...
> > > 
> > > It could be done. To do that right, I think we'd want to drop
> > > request_mask from the ->getattr prototype as well and just have
> > > everything use the mask in the kstat.
> > > 
> > > I don't think it'd reduce the size of the patchset in any meaningful
> > > way, but it might make for a more sensible API over the long haul.
> > 
> > ->getattr() prototype change would be decoupled from that - for your
> > patchset you'd only need the field addition + setting in vfs_getattr_nosec()
> > (and possibly in ksmbd), with the remainders of both series being
> > independent from each other.
> > 
> > What I suggest is
> > 
> > branchpoint -> field addition (trivial commit) -> argument removal
> > 		|
> > 		V
> > your series, starting with "use stat->request_mask in generic_fillattr()"
> > 
> > Total size would be about the same, but it would be easier to follow
> > the less trivial part of that.  Nothing in your branch downstream of
> > that touches any ->getattr() instances, so it should have no
> > conflicts with the argument removal side of things.
> 
> The only problem with this plan is that Linus has already merged this.
> I've no issue with adding the request_mask to the kstat and removing it
> as a separate parameter elsewhere, but I think we'll need to do it on
> top of what's already been merged.

D'oh...  My apologies; I'll do a branch on top of that (and rebase on
top of -rc1 once the window closes).

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2023-08-30  1:25 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-25 14:58 [PATCH v6 0/7] fs: implement multigrain timestamps Jeff Layton
2023-07-25 14:58 ` [PATCH v6 1/7] fs: pass the request_mask to generic_fillattr Jeff Layton
2023-07-26  2:46   ` Xiubo Li
2023-07-26  9:40   ` Joseph Qi
2023-07-26 10:49     ` Jeff Layton
2023-08-02 17:43   ` Jan Kara
2023-08-02 18:47   ` Paulo Alcantara
2023-08-29 22:44   ` Al Viro
2023-08-29 22:58     ` Jeff Layton
2023-08-30  0:02       ` Al Viro
2023-08-30  0:43         ` Jeff Layton
2023-08-30  1:22           ` Al Viro
2023-07-25 14:58 ` [PATCH v6 2/7] fs: add infrastructure for multigrain timestamps Jeff Layton
2023-08-02 19:35   ` Jan Kara
2023-08-02 20:54     ` Jeff Layton
2023-08-03  7:07       ` Christian Brauner
2023-07-25 14:58 ` [PATCH v6 3/7] tmpfs: bump the mtime/ctime/iversion when page becomes writeable Jeff Layton
2023-07-26  1:39   ` Hugh Dickins
2023-07-26 10:26     ` Jeff Layton
2023-07-25 14:58 ` [PATCH v6 4/7] tmpfs: add support for multigrain timestamps Jeff Layton
2023-08-02 19:37   ` Jan Kara
2023-07-25 14:58 ` [PATCH v6 5/7] xfs: switch to " Jeff Layton
2023-08-02 17:48   ` Darrick J. Wong
2023-08-02 18:21     ` Jeff Layton
2023-08-03  7:05       ` Christian Brauner
2023-07-25 14:58 ` [PATCH v6 6/7] ext4: " Jeff Layton
2023-08-02 19:38   ` Jan Kara
2023-07-25 14:58 ` [PATCH v6 7/7] btrfs: convert " Jeff Layton
2023-07-26 12:44   ` David Sterba
2023-07-28 11:00 ` (subset) [PATCH v6 0/7] fs: implement " Christian Brauner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).