summaryrefslogtreecommitdiff
path: root/sys/nfsclient
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2002-01-14 02:13:46 +0000
committerPeter Wemm <peter@FreeBSD.org>2002-01-14 02:13:46 +0000
commit117f61374cac9ab861ceebb51d0588bfe2a176d2 (patch)
tree077cb662afe0f3570e4fd98b2cbdc9d58d25867c /sys/nfsclient
parent971730fc67968ec59db33ec6e3a13e2e09c8d224 (diff)
Notes
Diffstat (limited to 'sys/nfsclient')
-rw-r--r--sys/nfsclient/nfs.h1
-rw-r--r--sys/nfsclient/nfs_bio.c48
-rw-r--r--sys/nfsclient/nfs_nfsiod.c103
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);
}