diff options
-rw-r--r-- | sys/fs/nfsclient/nfs_clbio.c | 12 | ||||
-rw-r--r-- | sys/nfsclient/nfs_bio.c | 12 |
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); } |