aboutsummaryrefslogtreecommitdiff
path: root/sys/nfsclient
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2013-04-18 13:09:04 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2013-04-18 13:09:04 +0000
commit175b3f31d328545a5bca42b0f6ac6de344e0eb4a (patch)
tree426b7722bfd3485b471929d4c1aa32849c7396ea /sys/nfsclient
parentca11419237a6458a92855e838724ef8c71225f0f (diff)
Notes
Diffstat (limited to 'sys/nfsclient')
-rw-r--r--sys/nfsclient/nfs_bio.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index b7fe832eb4c8..630a7ffe5931 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -1345,10 +1345,18 @@ nfs_asyncio(struct nfsmount *nmp, struct buf *bp, struct ucred *cred, struct thr
* 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);
}