diff options
| author | Peter Wemm <peter@FreeBSD.org> | 2002-01-14 02:13:46 +0000 |
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 2002-01-14 02:13:46 +0000 |
| commit | 117f61374cac9ab861ceebb51d0588bfe2a176d2 (patch) | |
| tree | 077cb662afe0f3570e4fd98b2cbdc9d58d25867c /sys/nfsclient | |
| parent | 971730fc67968ec59db33ec6e3a13e2e09c8d224 (diff) | |
Notes
Diffstat (limited to 'sys/nfsclient')
| -rw-r--r-- | sys/nfsclient/nfs.h | 1 | ||||
| -rw-r--r-- | sys/nfsclient/nfs_bio.c | 48 | ||||
| -rw-r--r-- | sys/nfsclient/nfs_nfsiod.c | 103 |
3 files changed, 92 insertions, 60 deletions
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index ec0e6acc9be6..01901a4e34fa 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -265,6 +265,7 @@ int nfs_writerpc(struct vnode *, struct uio *, struct ucred *, int *, 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_asyncio(struct buf *, struct ucred *, struct thread *); int nfs_doio(struct buf *, struct ucred *, struct thread *); int nfs_readlinkrpc(struct vnode *, struct uio *, struct ucred *); diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index 2f3a44b59eff..390511859ed8 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -424,7 +424,7 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) /* * Start the read ahead(s), as required. */ - if (nfs_numasync > 0 && nmp->nm_readahead > 0) { + if (nmp->nm_readahead > 0) { for (nra = 0; nra < nmp->nm_readahead && nra < seqcount && (off_t)(lbn + 1 + nra) * biosize < np->n_size; nra++) { rabn = lbn + 1 + nra; @@ -609,7 +609,7 @@ again: * (You need the current block first, so that you have the * directory offset cookie of the next block.) */ - if (nfs_numasync > 0 && nmp->nm_readahead > 0 && + if (nmp->nm_readahead > 0 && (bp->b_flags & B_INVAL) == 0 && (np->n_direofoffset == 0 || (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) && @@ -1117,19 +1117,12 @@ int nfs_asyncio(struct buf *bp, struct ucred *cred, struct thread *td) { struct nfsmount *nmp; - int i; + int iod; int gotiod; int slpflag = 0; int slptimeo = 0; int error; - /* - * If no async daemons then return EIO to force caller to run the rpc - * synchronously. - */ - if (nfs_numasync == 0) - return (EIO); - nmp = VFSTONFS(bp->b_vp->v_mount); /* @@ -1150,24 +1143,22 @@ again: /* * Find a free iod to process this request. */ - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) - if (nfs_iodwant[i]) { - /* - * Found one, so wake it up and tell it which - * mount to process. - */ - NFS_DPF(ASYNCIO, - ("nfs_asyncio: waking iod %d for mount %p\n", - i, nmp)); - nfs_iodwant[i] = (struct proc *)0; - nfs_iodmount[i] = nmp; - nmp->nm_bufqiods++; - wakeup((caddr_t)&nfs_iodwant[i]); + for (iod = 0; iod < NFS_MAXASYNCDAEMON; iod++) + if (nfs_iodwant[iod]) { gotiod = TRUE; break; } /* + * Try to create one if none are free. + */ + if (!gotiod) { + iod = nfs_nfsiodnew(); + if (iod != -1) + gotiod = TRUE; + } + + /* * If none are free, we may already have an iod working on this mount * point. If so, it will process our request. */ @@ -1186,6 +1177,17 @@ again: */ if (gotiod) { /* + * Found one, so wake it up and tell it which + * mount to process. + */ + NFS_DPF(ASYNCIO, ("nfs_asyncio: waking iod %d for mount %p\n", + iod, nmp)); + nfs_iodwant[iod] = (struct proc *)0; + nfs_iodmount[iod] = nmp; + nmp->nm_bufqiods++; + wakeup((caddr_t)&nfs_iodwant[iod]); + + /* * Ensure that the queue never grows too large. We still want * to asynchronize so we block rather then return EIO. */ diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c index 6fe1a5596379..d09579234389 100644 --- a/sys/nfsclient/nfs_nfsiod.c +++ b/sys/nfsclient/nfs_nfsiod.c @@ -79,25 +79,56 @@ static MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure"); static void nfssvc_iod(void *); -#define TRUE 1 -#define FALSE 0 - static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; SYSCTL_DECL(_vfs_nfs); +/* Minimum number of nfsiod kthreads to keep as spares */ +static unsigned int nfs_iodmin = 4; +SYSCTL_INT(_vfs_nfs, OID_AUTO, iodmin, CTLFLAG_RW, &nfs_iodmin, 0, ""); + +/* Maximum number of seconds a nfsiod kthread will sleep before exiting */ +static int nfs_iodmaxidle = 120; +SYSCTL_INT(_vfs_nfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &nfs_iodmaxidle, 0, ""); + +int +nfs_nfsiodnew(void) +{ + int error, i; + int newiod; + + newiod = -1; + for (i = 0; i < NFS_MAXASYNCDAEMON; i++) + if (nfs_asyncdaemon[i] == 0) { + nfs_asyncdaemon[i]++; + newiod = i; + break; + } + if (newiod == -1) + return (-1); + error = kthread_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID, + "nfsiod %d", newiod); + if (error) + return (-1); + nfs_numasync++; + return (newiod); +} + static void nfsiod_setup(void *dummy) { int i; int error; - struct proc *p; - for (i = 0; i < 4; i++) { - error = kthread_create(nfssvc_iod, NULL, &p, RFHIGHPID, - "nfsiod %d", i); - if (error) - panic("nfsiod_setup: kthread_create error %d", error); + TUNABLE_INT_FETCH("vfs.nfs.iodmin", &nfs_iodmin); + /* Silently limit the start number of nfsiod's */ + if (nfs_iodmin > NFS_MAXASYNCDAEMON) + nfs_iodmin = NFS_MAXASYNCDAEMON; + + for (i = 0; i < nfs_iodmin; i++) { + error = nfs_nfsiodnew(); + if (error == -1) + panic("nfsiod_setup: nfs_nfsiodnew failed"); } } SYSINIT(nfsiod, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, nfsiod_setup, NULL); @@ -121,59 +152,47 @@ nfsclnt(struct thread *td, struct nfsclnt_args *uap) /* * Asynchronous I/O daemons for client nfs. * They do read-ahead and write-behind operations on the block I/O cache. - * Never returns unless it fails or gets killed. + * Returns if we hit the timeout defined by the iodmaxidle sysctl. */ static void -nfssvc_iod(void *dummy) +nfssvc_iod(void *instance) { struct buf *bp; - int i, myiod; struct nfsmount *nmp; + int myiod, timo; int error = 0; mtx_lock(&Giant); /* * Assign my position or return error if too many already running */ - myiod = -1; - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) - if (nfs_asyncdaemon[i] == 0) { - nfs_asyncdaemon[i]++; - myiod = i; - break; - } - if (myiod == -1) - return /* XXX (EBUSY) */; - nfs_numasync++; + myiod = (int *)instance - nfs_asyncdaemon; /* - * Just loop around doin our stuff until SIGKILL + * Main loop */ for (;;) { while (((nmp = nfs_iodmount[myiod]) == NULL - || !TAILQ_FIRST(&nmp->nm_bufq)) + || !TAILQ_FIRST(&nmp->nm_bufq)) && error == 0) { if (nmp) - nmp->nm_bufqiods--; + nmp->nm_bufqiods--; nfs_iodwant[myiod] = curthread->td_proc; nfs_iodmount[myiod] = NULL; - error = tsleep((caddr_t)&nfs_iodwant[myiod], - PWAIT | PCATCH, "nfsidl", 0); - } - if (error) { - nfs_asyncdaemon[myiod] = 0; - if (nmp) - nmp->nm_bufqiods--; - nfs_iodwant[myiod] = NULL; - nfs_iodmount[myiod] = NULL; - nfs_numasync--; - return /* XXX (error) */; + /* + * Always keep at least nfs_iodmin kthreads. + */ + timo = (myiod < nfs_iodmin) ? 0 : nfs_iodmaxidle * hz; + error = tsleep((caddr_t)&nfs_iodwant[myiod], PWAIT | PCATCH, + "nfsidl", timo); } + if (error) + break; while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) { /* Take one off the front of the list */ TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); nmp->nm_bufqlen--; if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) { - nmp->nm_bufqwant = FALSE; + nmp->nm_bufqwant = 0; wakeup(&nmp->nm_bufq); } if (bp->b_iocmd == BIO_READ) @@ -194,4 +213,14 @@ nfssvc_iod(void *dummy) } } } + nfs_asyncdaemon[myiod] = 0; + if (nmp) + nmp->nm_bufqiods--; + nfs_iodwant[myiod] = NULL; + nfs_iodmount[myiod] = NULL; + nfs_numasync--; + if (error == EWOULDBLOCK) + kthread_exit(0); + /* Abnormal termination */ + kthread_exit(1); } |
