The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_aiod.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: nfs_aiod.c,v 1.9 2022/01/11 03:13:59 jsg Exp $        */
    2 /*
    3  * Copyright (c) 1989, 1993
    4  *      The Regents of the University of California.  All rights reserved.
    5  *
    6  * This code is derived from software contributed to Berkeley by
    7  * Rick Macklem at The University of Guelph.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/proc.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mount.h>
   40 #include <sys/vnode.h>
   41 #include <sys/kthread.h>
   42 #include <sys/rwlock.h>
   43 #include <sys/signalvar.h>
   44 #include <sys/queue.h>
   45 #include <sys/mutex.h>
   46 
   47 #include <nfs/rpcv2.h>
   48 #include <nfs/nfsproto.h>
   49 #include <nfs/nfs.h>
   50 #include <nfs/nfsnode.h>
   51 #include <nfs/nfs_var.h>
   52 #include <nfs/nfsmount.h>
   53 
   54 /* The nfs_aiodl_mtx mutex protects the two lists. */
   55 struct mutex            nfs_aiodl_mtx;
   56 struct nfs_aiodhead     nfs_aiods_all;
   57 struct nfs_aiodhead     nfs_aiods_idle;
   58 
   59 /* Current number of "running" aiods. Defaults to NFS_DEFASYNCDAEMON (4). */
   60 int                     nfs_numaiods = -1;
   61 
   62 /* Maximum # of buf to queue on an aiod. */
   63 int                     nfs_aiodbufqmax;
   64 
   65 /*
   66  * Asynchronous I/O threads for client nfs.
   67  * They do read-ahead and write-behind operations on the block I/O cache.
   68  * Never returns unless it fails or gets killed.
   69  */
   70 void
   71 nfs_aiod(void *arg)
   72 {
   73         struct nfs_aiod *aiod;
   74         struct nfsmount *nmp;
   75         struct buf      *bp;
   76 
   77         aiod = malloc(sizeof(*aiod), M_TEMP, M_WAITOK|M_ZERO);
   78         mtx_enter(&nfs_aiodl_mtx);
   79         LIST_INSERT_HEAD(&nfs_aiods_all, aiod, nad_all);
   80         LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
   81         mtx_leave(&nfs_aiodl_mtx);
   82         nfs_numaiods++;
   83 
   84         /*
   85          * Enforce an upper limit on how many bufs we'll queue up for
   86          * a given aiod. This is arbitrarily chosen to be a quarter of
   87          * the number of bufs in the system, divided evenly between
   88          * the running aiods.
   89          *
   90          * Since the number of bufs in the system is dynamic, and the
   91          * aiods are usually started up very early (during boot), the
   92          * number of buffers available is pretty low, so the limit we
   93          * enforce is way to low: So, always allow a minimum of 64 bufs.
   94          * XXX: Footshooting.
   95          */
   96         nfs_aiodbufqmax = max((bcstats.numbufs / 4) / nfs_numaiods, 64);
   97 
   98 
   99 loop:   /* Loop around until SIGKILL */
  100         if (aiod->nad_flags & NFSAIOD_WAKEUP) {
  101                 mtx_enter(&nfs_aiodl_mtx);
  102                 LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
  103                 mtx_leave(&nfs_aiodl_mtx);
  104                 aiod->nad_flags &= ~NFSAIOD_WAKEUP;
  105         }
  106 
  107         while (1) {
  108                 nmp = aiod->nad_mnt;
  109                 if (nmp) {
  110                         aiod->nad_mnt = NULL;
  111                         break;
  112                 }
  113 
  114                 while (!(aiod->nad_flags & NFSAIOD_WAKEUP))
  115                         tsleep_nsec(aiod, PWAIT, "aiodidle", INFSLP);
  116 
  117                 /*
  118                  * Wakeup for this aiod happens in one of the following
  119                  * situations:
  120                  * - The thread is being asked to exit by nfs_set_naiod(), or
  121                  * - nfs_asyncio() has found work for this thread on a mount.
  122                  *
  123                  * In the former case, check to see if nfs_asyncio() has just
  124                  * found some work for this thread, and if so, ignore it until
  125                  * later.
  126                  */
  127                 if (aiod->nad_flags & NFSAIOD_EXIT) {
  128                         if (aiod->nad_mnt == NULL)
  129                                 goto out1;
  130                         else
  131                                 break;
  132                 }
  133         }
  134 
  135         while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) {
  136                 /* Take one off the front of the list */
  137                 TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
  138                 nmp->nm_bufqlen--;
  139                 nfs_doio(bp, NULL);
  140         }
  141 
  142         KASSERT(nmp->nm_naiods > 0);
  143         nmp->nm_naiods--;
  144         if (aiod->nad_flags & NFSAIOD_EXIT)
  145                 goto out1;
  146 
  147         goto loop;
  148 
  149 out1:
  150         free(aiod, M_TEMP, sizeof(*aiod));
  151         nfs_numaiods--;
  152         KASSERT(nfs_numaiods >= 0);
  153         /* Readjust the limit of bufs to queue. See comment above. */
  154         if (nfs_numaiods > 0)
  155                 nfs_aiodbufqmax = max((bcstats.numbufs / 4) / nfs_numaiods, 64);
  156         else
  157                 nfs_aiodbufqmax = 0;
  158         kthread_exit(0);
  159 }
  160 
  161 int
  162 nfs_set_naiod(int howmany)
  163 {
  164         struct nfs_aiod *aiod;
  165         int              want, error;
  166 
  167         KASSERT(howmany >= 0);
  168 
  169         error = 0;
  170 
  171         if (nfs_numaiods == -1)
  172                 nfs_numaiods = 0;
  173 
  174         want = howmany - nfs_numaiods;
  175 
  176         if (want > 0) {
  177                 /* Add more. */ 
  178                 want = min(want, NFS_MAXASYNCDAEMON);
  179                 while (want > 0) {
  180                         error = kthread_create(nfs_aiod, NULL, NULL, "nfsaio");
  181                         if (error)
  182                                 return (error);
  183                         want--;
  184                 }
  185         } else if (want < 0) {
  186                 /* Get rid of some. */
  187                 want = -want;
  188                 want = min(want, nfs_numaiods);
  189 
  190                 /* Favour idle aiod's. */
  191                 mtx_enter(&nfs_aiodl_mtx);
  192                 while (!LIST_EMPTY(&nfs_aiods_idle) && want > 0) {
  193                         aiod = LIST_FIRST(&nfs_aiods_idle);
  194                         LIST_REMOVE(aiod, nad_idle);
  195                         LIST_REMOVE(aiod, nad_all);     /* Yuck. */
  196                         aiod->nad_flags |= NFSAIOD_QUIT;
  197                         wakeup_one(aiod);
  198                         want--;
  199                 }
  200 
  201                 while (!LIST_EMPTY(&nfs_aiods_all) && want > 0) {
  202                         aiod = LIST_FIRST(&nfs_aiods_all);
  203                         LIST_REMOVE(aiod, nad_all);
  204                         aiod->nad_flags |= NFSAIOD_QUIT;
  205                         wakeup_one(aiod);
  206                         want--;
  207                 }
  208                 mtx_leave(&nfs_aiodl_mtx);
  209         }
  210         /* ignore the want == nfs_numaiods case, since it means no work */
  211 
  212         return (error);
  213 }

Cache object: d038d4cf1614c506438bba3957e295d2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.