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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
 fs/nfsd/nfs4xdr.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

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))
-- 
2.37.3




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux