Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Jun 2013 01:35:52 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r251768 - in stable/8/sys: fs/nfsclient nfsclient
Message-ID:  <201306150135.r5F1Zqpw060659@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Sat Jun 15 01:35:52 2013
New Revision: 251768
URL: http://svnweb.freebsd.org/changeset/base/251768

Log:
  MFC: r249623
  Both NFS clients can deadlock when using the "rdirplus" mount
  option. This can occur when an nfsiod thread that already holds
  a buffer lock attempts to acquire a vnode lock on an entry in
  the directory (a LOR) when another thread holding the vnode lock
  is waiting on an nfsiod thread. This patch avoids the deadlock by disabling
  readahead for this case, so the nfsiod threads never do readdirplus.
  Since readaheads for directories need the directory offset cookie
  from the previous read, they cannot normally happen in parallel.
  As such, testing by jhb@ and myself didn't find any performance
  degredation when this patch is applied. If there is a case where
  this results in a significant performance degradation, mounting
  without the "rdirplus" option can be done to re-enable readahead
  for directories.

Modified:
  stable/8/sys/fs/nfsclient/nfs_clbio.c
  stable/8/sys/nfsclient/nfs_bio.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/fs/   (props changed)
  stable/8/sys/nfsclient/   (props changed)

Modified: stable/8/sys/fs/nfsclient/nfs_clbio.c
==============================================================================
--- stable/8/sys/fs/nfsclient/nfs_clbio.c	Fri Jun 14 23:43:44 2013	(r251767)
+++ stable/8/sys/fs/nfsclient/nfs_clbio.c	Sat Jun 15 01:35:52 2013	(r251768)
@@ -1368,10 +1368,18 @@ ncl_asyncio(struct nfsmount *nmp, struct
 	 * Commits are usually short and sweet so lets save some cpu and
 	 * leave the async daemons for more important rpc's (such as reads
 	 * and writes).
+	 *
+	 * Readdirplus RPCs do vget()s to acquire the vnodes for entries
+	 * in the directory in order to update attributes. This can deadlock
+	 * with another thread that is waiting for async I/O to be done by
+	 * an nfsiod thread while holding a lock on one of these vnodes.
+	 * To avoid this deadlock, don't allow the async nfsiod threads to
+	 * perform Readdirplus RPCs.
 	 */
 	mtx_lock(&ncl_iod_mutex);
-	if (bp->b_iocmd == BIO_WRITE && (bp->b_flags & B_NEEDCOMMIT) &&
-	    (nmp->nm_bufqiods > ncl_numasync / 2)) {
+	if ((bp->b_iocmd == BIO_WRITE && (bp->b_flags & B_NEEDCOMMIT) &&
+	     (nmp->nm_bufqiods > ncl_numasync / 2)) ||
+	    (bp->b_vp->v_type == VDIR && (nmp->nm_flag & NFSMNT_RDIRPLUS))) {
 		mtx_unlock(&ncl_iod_mutex);
 		return(EIO);
 	}

Modified: stable/8/sys/nfsclient/nfs_bio.c
==============================================================================
--- stable/8/sys/nfsclient/nfs_bio.c	Fri Jun 14 23:43:44 2013	(r251767)
+++ stable/8/sys/nfsclient/nfs_bio.c	Sat Jun 15 01:35:52 2013	(r251768)
@@ -1360,10 +1360,18 @@ nfs_asyncio(struct nfsmount *nmp, struct
 	 * Commits are usually short and sweet so lets save some cpu and
 	 * leave the async daemons for more important rpc's (such as reads
 	 * and writes).
+	 *
+	 * Readdirplus RPCs do vget()s to acquire the vnodes for entries
+	 * in the directory in order to update attributes. This can deadlock
+	 * with another thread that is waiting for async I/O to be done by
+	 * an nfsiod thread while holding a lock on one of these vnodes.
+	 * To avoid this deadlock, don't allow the async nfsiod threads to
+	 * perform Readdirplus RPCs.
 	 */
 	mtx_lock(&nfs_iod_mtx);
-	if (bp->b_iocmd == BIO_WRITE && (bp->b_flags & B_NEEDCOMMIT) &&
-	    (nmp->nm_bufqiods > nfs_numasync / 2)) {
+	if ((bp->b_iocmd == BIO_WRITE && (bp->b_flags & B_NEEDCOMMIT) &&
+	     (nmp->nm_bufqiods > nfs_numasync / 2)) ||
+	    (bp->b_vp->v_type == VDIR && (nmp->nm_flag & NFSMNT_RDIRPLUS))) {
 		mtx_unlock(&nfs_iod_mtx);
 		return(EIO);
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201306150135.r5F1Zqpw060659>