diff mbox series

[RFC,v5,8/8] nfsd: take inode_lock when querying for NFSv4 GETATTR

Message ID 20220908172448.208585-9-jlayton@kernel.org
State New
Headers show
Series vfs/nfsd: clean up handling of the i_version counter | expand

Commit Message

Jeff Layton Sept. 8, 2022, 5:24 p.m. UTC
The i_version counter for regular files is updated in update_time, and
that's usually done before copying the data to the pagecache. It's
possible that a reader and writer could race like this:

	reader		writer
	------		------
			i_version++
	read
	getattr
			update page cache

If that happens then the reader may associate the i_version value with
the wrong inode state.

All of the existing filesystems that implement i_version take the
i_rwsem in their write_iter operations before incrementing it. Take the
inode_lock when issuing a getattr for NFSv4 attributes to prevent the
above race.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/nfsd/nfs4xdr.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 4eec2ce05e7e..f7951d8d55ca 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2872,9 +2872,22 @@  nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 			goto out;
 	}
 
+	/*
+	 * The inode lock is needed here to ensure that there is not a
+	 * write to the inode in progress that might change the size,
+	 * or an in-progress directory morphing operation for directory
+	 * inodes.
+	 *
+	 * READ and GETATTR are not guaranteed to be atomic, even when in
+	 * the same compound, but we do try to present attributes in the
+	 * GETATTR reply as representing a single point in time.
+	 */
+	inode_lock(d_inode(dentry));
 	err = vfs_getattr(&path, &stat,
 			  STATX_BASIC_STATS | STATX_BTIME | STATX_INO_VERSION,
 			  AT_STATX_SYNC_AS_STAT);
+	inode_unlock(d_inode(dentry));
+
 	if (err)
 		goto out_nfserr;
 	if (!(stat.result_mask & STATX_BTIME))