summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormohans <mohans@FreeBSD.org>2007-09-25 21:08:49 +0000
committermohans <mohans@FreeBSD.org>2007-09-25 21:08:49 +0000
commit422753af04dbb4b35f1007b2d48aa571f767f32f (patch)
treea5621c03f3af624f4e5d427d6fac2b59d127d713 /sys
parent0d59ddbedf9205bb2600383d7600e7ea4c683ee3 (diff)
downloadFreeBSD-src-422753af04dbb4b35f1007b2d48aa571f767f32f.zip
FreeBSD-src-422753af04dbb4b35f1007b2d48aa571f767f32f.tar.gz
Fix for a very rare race, caused by the nfsiod wakeup and nfsiod idle
timeout occurring at exactly the same time. If this happens, the nfsiod exits although there may be a queued async IO request for it. Found by : Kris Kennaway Approved by: re
Diffstat (limited to 'sys')
-rw-r--r--sys/nfsclient/nfs_bio.c7
-rw-r--r--sys/nfsclient/nfs_nfsiod.c16
2 files changed, 20 insertions, 3 deletions
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index e1a7453..8066ac2 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -1453,6 +1453,13 @@ again:
}
}
+ /* We might have lost our nfsiod */
+ if (nmp->nm_bufqiods == 0) {
+ NFS_DPF(ASYNCIO,
+ ("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp));
+ goto again;
+ }
+
if (bp->b_iocmd == BIO_READ) {
if (bp->b_rcred == NOCRED && cred != NOCRED)
bp->b_rcred = crhold(cred);
diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c
index e219c71..ac98732 100644
--- a/sys/nfsclient/nfs_nfsiod.c
+++ b/sys/nfsclient/nfs_nfsiod.c
@@ -229,9 +229,8 @@ nfssvc_iod(void *instance)
* Main loop
*/
for (;;) {
- while (((nmp = nfs_iodmount[myiod]) == NULL
- || !TAILQ_FIRST(&nmp->nm_bufq))
- && error == 0) {
+ while (((nmp = nfs_iodmount[myiod]) == NULL)
+ || !TAILQ_FIRST(&nmp->nm_bufq)) {
if (myiod >= nfs_iodmax)
goto finish;
if (nmp)
@@ -244,6 +243,17 @@ nfssvc_iod(void *instance)
timo = (myiod < nfs_iodmin) ? 0 : nfs_iodmaxidle * hz;
error = msleep(&nfs_iodwant[myiod], &nfs_iod_mtx, PWAIT | PCATCH,
"-", timo);
+ if (error) {
+ nmp = nfs_iodmount[myiod];
+ /*
+ * Rechecking the nm_bufq closes a rare race where the
+ * nfsiod is woken up at the exact time the idle timeout
+ * fires
+ */
+ if (nmp && TAILQ_FIRST(&nmp->nm_bufq))
+ error = 0;
+ break;
+ }
}
if (error)
break;
OpenPOWER on IntegriCloud