diff options
author | mohans <mohans@FreeBSD.org> | 2007-09-25 21:08:49 +0000 |
---|---|---|
committer | mohans <mohans@FreeBSD.org> | 2007-09-25 21:08:49 +0000 |
commit | 422753af04dbb4b35f1007b2d48aa571f767f32f (patch) | |
tree | a5621c03f3af624f4e5d427d6fac2b59d127d713 /sys/nfsclient/nfs_nfsiod.c | |
parent | 0d59ddbedf9205bb2600383d7600e7ea4c683ee3 (diff) | |
download | FreeBSD-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/nfsclient/nfs_nfsiod.c')
-rw-r--r-- | sys/nfsclient/nfs_nfsiod.c | 16 |
1 files changed, 13 insertions, 3 deletions
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; |