FreeBSD NFS client/Linux NFS server issue
Rick Macklem
rmacklem at uoguelph.ca
Fri Jan 22 22:02:36 UTC 2010
On Fri, 22 Jan 2010, Rick Macklem wrote:
>
> There should probably be some sort of 3 way handshake between
> the code in nfs_asyncio() after calling nfs_nfsnewiod() and the
> code near the beginning of nfssvc_iod(), but I think the following
> somewhat cheesy fix might do the trick:
>
[stuff deleted]
I know it's a little weird to reply to my own posting, but I think
this might be a reasonable patch (I have only tested it for a few
minutes at this point).
I basically redefined nfs_iodwant[] as a tri-state variable (although
it was a struct proc *, it was only tested NULL/non-NULL).
0 - was NULL
1 - was non-NULL
-1 - just created by nfs_asyncio() and will be used by it
I'll keep testing it, but hopefully someone else can test and/or
review it... rick
ps: Mikolaj, I'm a sysadmin so I understand the problems with
production systems, but if you do get a chance to test it somehow,
that would be great.
pss: This is against -current, but hopefully stable/7 can be patched
about the same.
--- patch for nfsiod race against -current ---
--- nfsclient/nfs.h.sav 2010-01-22 16:21:53.000000000 -0500
+++ nfsclient/nfs.h 2010-01-22 16:22:04.000000000 -0500
@@ -252,7 +252,7 @@
int nfs_commit(struct vnode *vp, u_quad_t offset, int cnt,
struct ucred *cred, struct thread *td);
int nfs_readdirrpc(struct vnode *, struct uio *, struct ucred *);
-int nfs_nfsiodnew(void);
+int nfs_nfsiodnew(int);
int nfs_asyncio(struct nfsmount *, struct buf *, struct ucred *, struct thread *);
int nfs_doio(struct vnode *, struct buf *, struct ucred *, struct thread *);
void nfs_doio_directwrite (struct buf *);
--- nfsclient/nfsnode.h.sav 2010-01-22 14:56:34.000000000 -0500
+++ nfsclient/nfsnode.h 2010-01-22 14:56:52.000000000 -0500
@@ -180,7 +180,7 @@
* Queue head for nfsiod's
*/
extern TAILQ_HEAD(nfs_bufq, buf) nfs_bufq;
-extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
+extern int nfs_iodwant[NFS_MAXASYNCDAEMON];
extern struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON];
#if defined(_KERNEL)
--- nfsclient/nfs_bio.c.sav 2010-01-22 14:57:28.000000000 -0500
+++ nfsclient/nfs_bio.c 2010-01-22 16:17:24.000000000 -0500
@@ -1377,7 +1377,7 @@
* Find a free iod to process this request.
*/
for (iod = 0; iod < nfs_numasync; iod++)
- if (nfs_iodwant[iod]) {
+ if (nfs_iodwant[iod] > 0) {
gotiod = TRUE;
break;
}
@@ -1386,7 +1386,7 @@
* Try to create one if none are free.
*/
if (!gotiod) {
- iod = nfs_nfsiodnew();
+ iod = nfs_nfsiodnew(1);
if (iod != -1)
gotiod = TRUE;
}
@@ -1398,7 +1398,7 @@
*/
NFS_DPF(ASYNCIO, ("nfs_asyncio: waking iod %d for mount %p\n",
iod, nmp));
- nfs_iodwant[iod] = NULL;
+ nfs_iodwant[iod] = 0;
nfs_iodmount[iod] = nmp;
nmp->nm_bufqiods++;
wakeup(&nfs_iodwant[iod]);
--- nfsclient/nfs_nfsiod.c.sav 2010-01-22 14:57:28.000000000 -0500
+++ nfsclient/nfs_nfsiod.c 2010-01-22 16:32:31.000000000 -0500
@@ -113,7 +113,7 @@
* 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 @@
*/
iod = nfs_numasync - 1;
for (i = 0; i < nfs_numasync - nfs_iodmax; i++) {
- if (nfs_iodwant[iod])
+ if (nfs_iodwant[iod] > 0)
wakeup(&nfs_iodwant[iod]);
iod--;
}
@@ -160,7 +160,7 @@
"Max number of nfsiod kthreads");
int
-nfs_nfsiodnew(void)
+nfs_nfsiodnew(int set_iodwant)
{
int error, i;
int newiod;
@@ -176,12 +176,17 @@
}
if (newiod == -1)
return (-1);
+ if (set_iodwant > 0)
+ nfs_iodwant[i] = -1;
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] = 0;
return (-1);
+ }
nfs_numasync++;
return (newiod);
}
@@ -199,7 +204,7 @@
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 @@
goto finish;
if (nmp)
nmp->nm_bufqiods--;
- nfs_iodwant[myiod] = curthread->td_proc;
+ if (nfs_iodwant[myiod] == 0)
+ nfs_iodwant[myiod] = 1;
nfs_iodmount[myiod] = NULL;
/*
* Always keep at least nfs_iodmin kthreads.
@@ -303,7 +309,7 @@
nfs_asyncdaemon[myiod] = 0;
if (nmp)
nmp->nm_bufqiods--;
- nfs_iodwant[myiod] = NULL;
+ nfs_iodwant[myiod] = 0;
nfs_iodmount[myiod] = NULL;
/* Someone may be waiting for the last nfsiod to terminate. */
if (--nfs_numasync == 0)
--- nfsclient/nfs_subs.c.sav 2010-01-22 14:57:28.000000000 -0500
+++ nfsclient/nfs_subs.c 2010-01-22 16:35:10.000000000 -0500
@@ -347,7 +347,7 @@
nfs_ticks = 1;
/* Ensure async daemons disabled */
for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
- nfs_iodwant[i] = NULL;
+ nfs_iodwant[i] = 0;
nfs_iodmount[i] = NULL;
}
nfs_nhinit(); /* Init the nfsnode table */
@@ -375,7 +375,7 @@
mtx_lock(&nfs_iod_mtx);
nfs_iodmax = 0;
for (i = 0; i < nfs_numasync; i++)
- if (nfs_iodwant[i])
+ if (nfs_iodwant[i] > 0)
wakeup(&nfs_iodwant[i]);
/* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */
while (nfs_numasync)
--- nfsclient/nfs_vnops.c.sav 2010-01-22 14:57:28.000000000 -0500
+++ nfsclient/nfs_vnops.c 2010-01-22 15:01:38.000000000 -0500
@@ -212,7 +212,7 @@
* Global variables
*/
struct mtx nfs_iod_mtx;
-struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
+int nfs_iodwant[NFS_MAXASYNCDAEMON];
struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON];
int nfs_numasync = 0;
vop_advlock_t *nfs_advlock_p = nfs_dolock;
More information about the freebsd-fs
mailing list