From 1bde56868248c115a9cbeb78ed487d6e4fee6265 Mon Sep 17 00:00:00 2001 From: Peter Wemm Date: Tue, 15 Jan 2002 20:57:21 +0000 Subject: [PATCH] Revise the nfsiod auto tuning code. Now both the upper and lower limits are specifyable by sysctl and are respected. Submitted by: Maxime Henrion --- sys/nfsclient/nfs.h | 2 +- sys/nfsclient/nfs_bio.c | 26 ++++++------ sys/nfsclient/nfs_nfsiod.c | 81 +++++++++++++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 22 deletions(-) diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index 01901a4e34fa..7a0f758a9659 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -76,7 +76,7 @@ #define NFS_READDIRSIZE 8192 /* Def. readdir size */ #define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ #define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ +#define NFS_MAXASYNCDAEMON 64 /* Max. number async_daemons runnable */ #define NFS_DIRBLKSIZ 4096 /* Must be a multiple of DIRBLKSIZ */ #ifdef _KERNEL #define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index 390511859ed8..1b607dc06faa 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -1143,7 +1143,7 @@ again: /* * Find a free iod to process this request. */ - for (iod = 0; iod < NFS_MAXASYNCDAEMON; iod++) + for (iod = 0; iod < nfs_numasync; iod++) if (nfs_iodwant[iod]) { gotiod = TRUE; break; @@ -1158,6 +1158,19 @@ again: gotiod = TRUE; } + 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]); + } + /* * If none are free, we may already have an iod working on this mount * point. If so, it will process our request. @@ -1176,17 +1189,6 @@ again: * the buffer. */ 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 d09579234389..a27548ac468d 100644 --- a/sys/nfsclient/nfs_nfsiod.c +++ b/sys/nfsclient/nfs_nfsiod.c @@ -83,13 +83,74 @@ static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; SYSCTL_DECL(_vfs_nfs); +/* Maximum number of seconds a nfsiod kthread will sleep before exiting */ +static unsigned int nfs_iodmaxidle = 120; +SYSCTL_UINT(_vfs_nfs, OID_AUTO, iodmaxidle, CTLFLAG_RW, &nfs_iodmaxidle, 0, ""); + +/* Maximum number of nfsiod kthreads */ +static unsigned int nfs_iodmax = 20; + /* 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, ""); +static int +sysctl_iodmin(SYSCTL_HANDLER_ARGS) +{ + int error, i; + int newmin; + + newmin = nfs_iodmin; + error = sysctl_handle_int(oidp, &newmin, 0, req); + if (error || (req->newptr == NULL)) + return (error); + if (newmin > nfs_iodmax) + return (EINVAL); + nfs_iodmin = newmin; + if (nfs_numasync >= nfs_iodmin) + return (0); + /* + * If the current number of nfsiod is lower + * than the new minimum, create some more. + */ + for (i = nfs_iodmin - nfs_numasync; i > 0; i--) + nfs_nfsiodnew(); + return (0); +} +SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmin, CTLTYPE_UINT | CTLFLAG_RW, 0, + sizeof (nfs_iodmin), sysctl_iodmin, "IU", ""); + + +static int +sysctl_iodmax(SYSCTL_HANDLER_ARGS) +{ + int error, i; + int iod, newmax; + + newmax = nfs_iodmax; + error = sysctl_handle_int(oidp, &newmax, 0, req); + if (error || (req->newptr == NULL)) + return (error); + if (newmax > NFS_MAXASYNCDAEMON) + return (EINVAL); + nfs_iodmax = newmax; + if (nfs_numasync <= nfs_iodmax) + return (0); + /* + * If there are some asleep nfsiods that should + * exit, wakeup() them so that they check nfs_iodmax + * and exit. Those who are active will exit as + * soon as they finish I/O. + */ + iod = nfs_numasync - 1; + for (i = 0; i < nfs_numasync - nfs_iodmax; i++) { + if (nfs_iodwant[iod]) + wakeup((caddr_t)&nfs_iodwant[iod]); + iod--; + } + return (0); +} +SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0, + sizeof (nfs_iodmax), sysctl_iodmax, "IU", ""); int nfs_nfsiodnew(void) @@ -97,8 +158,10 @@ nfs_nfsiodnew(void) int error, i; int newiod; + if (nfs_numasync >= nfs_iodmax) + return (-1); newiod = -1; - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) + for (i = 0; i < nfs_iodmax; i++) if (nfs_asyncdaemon[i] == 0) { nfs_asyncdaemon[i]++; newiod = i; @@ -163,9 +226,6 @@ nfssvc_iod(void *instance) int error = 0; mtx_lock(&Giant); - /* - * Assign my position or return error if too many already running - */ myiod = (int *)instance - nfs_asyncdaemon; /* * Main loop @@ -174,6 +234,8 @@ nfssvc_iod(void *instance) while (((nmp = nfs_iodmount[myiod]) == NULL || !TAILQ_FIRST(&nmp->nm_bufq)) && error == 0) { + if (myiod >= nfs_iodmax) + goto finish; if (nmp) nmp->nm_bufqiods--; nfs_iodwant[myiod] = curthread->td_proc; @@ -213,13 +275,14 @@ nfssvc_iod(void *instance) } } } +finish: nfs_asyncdaemon[myiod] = 0; if (nmp) nmp->nm_bufqiods--; nfs_iodwant[myiod] = NULL; nfs_iodmount[myiod] = NULL; nfs_numasync--; - if (error == EWOULDBLOCK) + if ((error == 0) || (error == EWOULDBLOCK)) kthread_exit(0); /* Abnormal termination */ kthread_exit(1);