summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfsclient/nfs_clbio.c12
-rw-r--r--sys/nfsclient/nfs_bio.c12
2 files changed, 20 insertions, 4 deletions
diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
index 32c88fa..a0ec8ee 100644
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -1404,10 +1404,18 @@ ncl_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(&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);
}
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index b7fe832..630a7ff 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);
}
OpenPOWER on IntegriCloud