summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient/nfs_nfsiod.c
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2010-01-27 15:22:20 +0000
committerrmacklem <rmacklem@FreeBSD.org>2010-01-27 15:22:20 +0000
commit3c42ac5cd551fe829f4d35317c16a44d287b0cb8 (patch)
treed60068d127fdd1a020342ef14d2b90110e566716 /sys/nfsclient/nfs_nfsiod.c
parentc75f72dd7c93d46f29e0e0a7b6fce9f5104ae43c (diff)
downloadFreeBSD-src-3c42ac5cd551fe829f4d35317c16a44d287b0cb8.zip
FreeBSD-src-3c42ac5cd551fe829f4d35317c16a44d287b0cb8.tar.gz
Fix a race that can occur when nfs nfsiod threads are being created.
Without this patch it was possible for a different thread that calls nfs_asyncio() to snitch a newly created nfsiod thread that was intended for another caller of nfs_asyncio(), because the nfs_iod_mtx mutex was unlocked while the new nfsiod thread was created. This patch labels the newly created nfsiod, so that it is not taken by another caller of nfs_asyncio(). This is believed to fix the problem reported on the freebsd-stable email list under the subject: FreeBSD NFS client/Linux NFS server issue. Tested by: to DOT my DOT trociny AT gmail DOT com Reviewed by: jhb MFC after: 2 weeks
Diffstat (limited to 'sys/nfsclient/nfs_nfsiod.c')
-rw-r--r--sys/nfsclient/nfs_nfsiod.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c
index 3fafa1e..5302c56 100644
--- a/sys/nfsclient/nfs_nfsiod.c
+++ b/sys/nfsclient/nfs_nfsiod.c
@@ -113,7 +113,7 @@ sysctl_iodmin(SYSCTL_HANDLER_ARGS)
* than the new minimum, create some more.
*/
for (i = nfs_iodmin - nfs_numasync; i > 0; i--)
- nfs_nfsiodnew();
+ nfs_nfsiodnew(0);
out:
mtx_unlock(&nfs_iod_mtx);
return (0);
@@ -147,7 +147,7 @@ sysctl_iodmax(SYSCTL_HANDLER_ARGS)
*/
iod = nfs_numasync - 1;
for (i = 0; i < nfs_numasync - nfs_iodmax; i++) {
- if (nfs_iodwant[iod])
+ if (nfs_iodwant[iod] == NFSIOD_AVAILABLE)
wakeup(&nfs_iodwant[iod]);
iod--;
}
@@ -160,7 +160,7 @@ SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0,
"Max number of nfsiod kthreads");
int
-nfs_nfsiodnew(void)
+nfs_nfsiodnew(int set_iodwant)
{
int error, i;
int newiod;
@@ -176,12 +176,17 @@ nfs_nfsiodnew(void)
}
if (newiod == -1)
return (-1);
+ if (set_iodwant > 0)
+ nfs_iodwant[i] = NFSIOD_CREATED_FOR_NFS_ASYNCIO;
mtx_unlock(&nfs_iod_mtx);
error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID,
0, "nfsiod %d", newiod);
mtx_lock(&nfs_iod_mtx);
- if (error)
+ if (error) {
+ if (set_iodwant > 0)
+ nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE;
return (-1);
+ }
nfs_numasync++;
return (newiod);
}
@@ -199,7 +204,7 @@ nfsiod_setup(void *dummy)
nfs_iodmin = NFS_MAXASYNCDAEMON;
for (i = 0; i < nfs_iodmin; i++) {
- error = nfs_nfsiodnew();
+ error = nfs_nfsiodnew(0);
if (error == -1)
panic("nfsiod_setup: nfs_nfsiodnew failed");
}
@@ -236,7 +241,8 @@ nfssvc_iod(void *instance)
goto finish;
if (nmp)
nmp->nm_bufqiods--;
- nfs_iodwant[myiod] = curthread->td_proc;
+ if (nfs_iodwant[myiod] == NFSIOD_NOT_AVAILABLE)
+ nfs_iodwant[myiod] = NFSIOD_AVAILABLE;
nfs_iodmount[myiod] = NULL;
/*
* Always keep at least nfs_iodmin kthreads.
@@ -303,7 +309,7 @@ finish:
nfs_asyncdaemon[myiod] = 0;
if (nmp)
nmp->nm_bufqiods--;
- nfs_iodwant[myiod] = NULL;
+ nfs_iodwant[myiod] = NFSIOD_NOT_AVAILABLE;
nfs_iodmount[myiod] = NULL;
/* Someone may be waiting for the last nfsiod to terminate. */
if (--nfs_numasync == 0)
OpenPOWER on IntegriCloud