Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28c494c5 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

NFS: Prevent nfs_getattr() hang during heavy write workloads



POSIX requires that ctime and mtime, as reported by the stat(2) call,
reflect the activity of the most recent write(2).  To that end, nfs_getattr()
flushes pending dirty writes to a file before doing a GETATTR to allow the
NFS server to set the file's size, ctime, and mtime properly.

However, nfs_getattr() can be starved when a constant stream of application
writes to a file prevents nfs_wb_nocommit() from completing.  This usually
results in hangs of programs doing a stat against an NFS file that is being
written.  "ls -l" is a common victim of this behavior.

To prevent starvation, hold the file's i_mutex in nfs_getattr() to
freeze applications writes temporarily so the client can more quickly obtain
clean values for a file's size, mtime, and ctime.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 464ad6b1
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -461,9 +461,18 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
	int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
	int err;

	/* Flush out writes to the server in order to update c/mtime */
	if (S_ISREG(inode->i_mode))
	/*
	 * Flush out writes to the server in order to update c/mtime.
	 *
	 * Hold the i_mutex to suspend application writes temporarily;
	 * this prevents long-running writing applications from blocking
	 * nfs_wb_nocommit.
	 */
	if (S_ISREG(inode->i_mode)) {
		mutex_lock(&inode->i_mutex);
		nfs_wb_nocommit(inode);
		mutex_unlock(&inode->i_mutex);
	}

	/*
	 * We may force a getattr if the user cares about atime.