xref: /openbsd-src/sys/nfs/nfs_aiod.c (revision 0d297f47564f5557a3fdcfd88ebb29bb4878476d)
1*0d297f47Sjsg /*	$OpenBSD: nfs_aiod.c,v 1.9 2022/01/11 03:13:59 jsg Exp $	*/
203240483Sthib /*
303240483Sthib  * Copyright (c) 1989, 1993
403240483Sthib  *	The Regents of the University of California.  All rights reserved.
503240483Sthib  *
603240483Sthib  * This code is derived from software contributed to Berkeley by
703240483Sthib  * Rick Macklem at The University of Guelph.
803240483Sthib  *
903240483Sthib  * Redistribution and use in source and binary forms, with or without
1003240483Sthib  * modification, are permitted provided that the following conditions
1103240483Sthib  * are met:
1203240483Sthib  * 1. Redistributions of source code must retain the above copyright
1303240483Sthib  *    notice, this list of conditions and the following disclaimer.
1403240483Sthib  * 2. Redistributions in binary form must reproduce the above copyright
1503240483Sthib  *    notice, this list of conditions and the following disclaimer in the
1603240483Sthib  *    documentation and/or other materials provided with the distribution.
1703240483Sthib  * 3. Neither the name of the University nor the names of its contributors
1803240483Sthib  *    may be used to endorse or promote products derived from this software
1903240483Sthib  *    without specific prior written permission.
2003240483Sthib  *
2103240483Sthib  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2203240483Sthib  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2303240483Sthib  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2403240483Sthib  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2503240483Sthib  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2603240483Sthib  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2703240483Sthib  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2803240483Sthib  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2903240483Sthib  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3003240483Sthib  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3103240483Sthib  * SUCH DAMAGE.
3203240483Sthib  */
3303240483Sthib 
3403240483Sthib #include <sys/param.h>
3503240483Sthib #include <sys/systm.h>
3603240483Sthib #include <sys/kernel.h>
3703240483Sthib #include <sys/proc.h>
3803240483Sthib #include <sys/malloc.h>
3903240483Sthib #include <sys/mount.h>
4003240483Sthib #include <sys/vnode.h>
4103240483Sthib #include <sys/kthread.h>
4203240483Sthib #include <sys/rwlock.h>
4303240483Sthib #include <sys/signalvar.h>
4403240483Sthib #include <sys/queue.h>
4503240483Sthib #include <sys/mutex.h>
4603240483Sthib 
4703240483Sthib #include <nfs/rpcv2.h>
4803240483Sthib #include <nfs/nfsproto.h>
4903240483Sthib #include <nfs/nfs.h>
5003240483Sthib #include <nfs/nfsnode.h>
5103240483Sthib #include <nfs/nfs_var.h>
5203240483Sthib #include <nfs/nfsmount.h>
5303240483Sthib 
5403240483Sthib /* The nfs_aiodl_mtx mutex protects the two lists. */
5503240483Sthib struct mutex		nfs_aiodl_mtx;
5603240483Sthib struct nfs_aiodhead	nfs_aiods_all;
5703240483Sthib struct nfs_aiodhead	nfs_aiods_idle;
5803240483Sthib 
5903240483Sthib /* Current number of "running" aiods. Defaults to NFS_DEFASYNCDAEMON (4). */
6003240483Sthib int			nfs_numaiods = -1;
6103240483Sthib 
6203240483Sthib /* Maximum # of buf to queue on an aiod. */
6303240483Sthib int			nfs_aiodbufqmax;
6403240483Sthib 
6503240483Sthib /*
6603240483Sthib  * Asynchronous I/O threads for client nfs.
6703240483Sthib  * They do read-ahead and write-behind operations on the block I/O cache.
6803240483Sthib  * Never returns unless it fails or gets killed.
6903240483Sthib  */
7003240483Sthib void
nfs_aiod(void * arg)7103240483Sthib nfs_aiod(void *arg)
7203240483Sthib {
7303240483Sthib 	struct nfs_aiod	*aiod;
7403240483Sthib 	struct nfsmount	*nmp;
7503240483Sthib 	struct buf	*bp;
7603240483Sthib 
7703240483Sthib 	aiod = malloc(sizeof(*aiod), M_TEMP, M_WAITOK|M_ZERO);
7803240483Sthib 	mtx_enter(&nfs_aiodl_mtx);
7903240483Sthib 	LIST_INSERT_HEAD(&nfs_aiods_all, aiod, nad_all);
807ae83476Sthib 	LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
8103240483Sthib 	mtx_leave(&nfs_aiodl_mtx);
8203240483Sthib 	nfs_numaiods++;
8303240483Sthib 
8403240483Sthib 	/*
8503240483Sthib 	 * Enforce an upper limit on how many bufs we'll queue up for
8603240483Sthib 	 * a given aiod. This is arbitrarily chosen to be a quarter of
8703240483Sthib 	 * the number of bufs in the system, divided evenly between
8803240483Sthib 	 * the running aiods.
8903240483Sthib 	 *
9003240483Sthib 	 * Since the number of bufs in the system is dynamic, and the
9103240483Sthib 	 * aiods are usually started up very early (during boot), the
9203240483Sthib 	 * number of buffers available is pretty low, so the limit we
9303240483Sthib 	 * enforce is way to low: So, always allow a minimum of 64 bufs.
9403240483Sthib 	 * XXX: Footshooting.
9503240483Sthib 	 */
9603240483Sthib 	nfs_aiodbufqmax = max((bcstats.numbufs / 4) / nfs_numaiods, 64);
9703240483Sthib 
9803240483Sthib 
9903240483Sthib loop:	/* Loop around until SIGKILL */
10000cb4738Sthib 	if (aiod->nad_flags & NFSAIOD_WAKEUP) {
10103240483Sthib 		mtx_enter(&nfs_aiodl_mtx);
10203240483Sthib 		LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
10303240483Sthib 		mtx_leave(&nfs_aiodl_mtx);
10400cb4738Sthib 		aiod->nad_flags &= ~NFSAIOD_WAKEUP;
10500cb4738Sthib 	}
10603240483Sthib 
10703240483Sthib 	while (1) {
10803240483Sthib 		nmp = aiod->nad_mnt;
10903240483Sthib 		if (nmp) {
11003240483Sthib 			aiod->nad_mnt = NULL;
11103240483Sthib 			break;
11203240483Sthib 		}
11303240483Sthib 
11400cb4738Sthib 		while (!(aiod->nad_flags & NFSAIOD_WAKEUP))
115ae991a59Smpi 			tsleep_nsec(aiod, PWAIT, "aiodidle", INFSLP);
11603240483Sthib 
11703240483Sthib 		/*
11803240483Sthib 		 * Wakeup for this aiod happens in one of the following
11903240483Sthib 		 * situations:
12003240483Sthib 		 * - The thread is being asked to exit by nfs_set_naiod(), or
12103240483Sthib 		 * - nfs_asyncio() has found work for this thread on a mount.
12203240483Sthib 		 *
12303240483Sthib 		 * In the former case, check to see if nfs_asyncio() has just
12403240483Sthib 		 * found some work for this thread, and if so, ignore it until
12503240483Sthib 		 * later.
12603240483Sthib 		 */
12700cb4738Sthib 		if (aiod->nad_flags & NFSAIOD_EXIT) {
12803240483Sthib 			if (aiod->nad_mnt == NULL)
12903240483Sthib 				goto out1;
13003240483Sthib 			else
13103240483Sthib 				break;
13203240483Sthib 		}
13303240483Sthib 	}
13403240483Sthib 
13503240483Sthib 	while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
13603240483Sthib 		/* Take one off the front of the list */
13703240483Sthib 		TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
13803240483Sthib 		nmp->nm_bufqlen--;
13903240483Sthib 		nfs_doio(bp, NULL);
14003240483Sthib 	}
14103240483Sthib 
14203240483Sthib 	KASSERT(nmp->nm_naiods > 0);
14303240483Sthib 	nmp->nm_naiods--;
14400cb4738Sthib 	if (aiod->nad_flags & NFSAIOD_EXIT)
14503240483Sthib 		goto out1;
14603240483Sthib 
14703240483Sthib 	goto loop;
14803240483Sthib 
14903240483Sthib out1:
150bae2bd50Sderaadt 	free(aiod, M_TEMP, sizeof(*aiod));
15103240483Sthib 	nfs_numaiods--;
15200cb4738Sthib 	KASSERT(nfs_numaiods >= 0);
153*0d297f47Sjsg 	/* Readjust the limit of bufs to queue. See comment above. */
15400cb4738Sthib 	if (nfs_numaiods > 0)
15503240483Sthib 		nfs_aiodbufqmax = max((bcstats.numbufs / 4) / nfs_numaiods, 64);
15600cb4738Sthib 	else
15700cb4738Sthib 		nfs_aiodbufqmax = 0;
158469c0eb2Sthib 	kthread_exit(0);
15903240483Sthib }
16003240483Sthib 
16103240483Sthib int
nfs_set_naiod(int howmany)16203240483Sthib nfs_set_naiod(int howmany)
16303240483Sthib {
16403240483Sthib 	struct nfs_aiod	*aiod;
165469c0eb2Sthib 	int		 want, error;
16603240483Sthib 
16703240483Sthib 	KASSERT(howmany >= 0);
16803240483Sthib 
16903240483Sthib 	error = 0;
17003240483Sthib 
17103240483Sthib 	if (nfs_numaiods == -1)
17203240483Sthib 		nfs_numaiods = 0;
17303240483Sthib 
17403240483Sthib 	want = howmany - nfs_numaiods;
17503240483Sthib 
17603240483Sthib 	if (want > 0) {
17703240483Sthib 		/* Add more. */
17803240483Sthib 		want = min(want, NFS_MAXASYNCDAEMON);
17903240483Sthib 		while (want > 0) {
18096a748bbSmiod 			error = kthread_create(nfs_aiod, NULL, NULL, "nfsaio");
18103240483Sthib 			if (error)
18203240483Sthib 				return (error);
18303240483Sthib 			want--;
18403240483Sthib 		}
18503240483Sthib 	} else if (want < 0) {
18603240483Sthib 		/* Get rid of some. */
18703240483Sthib 		want = -want;
18803240483Sthib 		want = min(want, nfs_numaiods);
18903240483Sthib 
19003240483Sthib 		/* Favour idle aiod's. */
19103240483Sthib 		mtx_enter(&nfs_aiodl_mtx);
19203240483Sthib 		while (!LIST_EMPTY(&nfs_aiods_idle) && want > 0) {
19303240483Sthib 			aiod = LIST_FIRST(&nfs_aiods_idle);
19403240483Sthib 			LIST_REMOVE(aiod, nad_idle);
19503240483Sthib 			LIST_REMOVE(aiod, nad_all);	/* Yuck. */
19600cb4738Sthib 			aiod->nad_flags |= NFSAIOD_QUIT;
19700cb4738Sthib 			wakeup_one(aiod);
19803240483Sthib 			want--;
19903240483Sthib 		}
20003240483Sthib 
20103240483Sthib 		while (!LIST_EMPTY(&nfs_aiods_all) && want > 0) {
20203240483Sthib 			aiod = LIST_FIRST(&nfs_aiods_all);
20303240483Sthib 			LIST_REMOVE(aiod, nad_all);
20400cb4738Sthib 			aiod->nad_flags |= NFSAIOD_QUIT;
20500cb4738Sthib 			wakeup_one(aiod);
20603240483Sthib 			want--;
20703240483Sthib 		}
20803240483Sthib 		mtx_leave(&nfs_aiodl_mtx);
20903240483Sthib 	}
21003240483Sthib 	/* ignore the want == nfs_numaiods case, since it means no work */
21103240483Sthib 
21203240483Sthib 	return (error);
21303240483Sthib }
214