LCOV - code coverage report
Current view: top level - nfs - nfs_syscalls.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 336 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: nfs_syscalls.c,v 1.114 2018/06/06 06:55:22 mpi Exp $  */
       2             : /*      $NetBSD: nfs_syscalls.c,v 1.19 1996/02/18 11:53:52 fvdl Exp $   */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1989, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  *
       8             :  * This code is derived from software contributed to Berkeley by
       9             :  * Rick Macklem at The University of Guelph.
      10             :  *
      11             :  * Redistribution and use in source and binary forms, with or without
      12             :  * modification, are permitted provided that the following conditions
      13             :  * are met:
      14             :  * 1. Redistributions of source code must retain the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  * 3. Neither the name of the University nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  *
      35             :  *      @(#)nfs_syscalls.c      8.5 (Berkeley) 3/30/95
      36             :  */
      37             : 
      38             : #include <sys/param.h>
      39             : #include <sys/systm.h>
      40             : #include <sys/kernel.h>
      41             : #include <sys/file.h>
      42             : #include <sys/stat.h>
      43             : #include <sys/vnode.h>
      44             : #include <sys/mount.h>
      45             : #include <sys/pool.h>
      46             : #include <sys/proc.h>
      47             : #include <sys/uio.h>
      48             : #include <sys/malloc.h>
      49             : #include <sys/buf.h>
      50             : #include <sys/mbuf.h>
      51             : #include <sys/socket.h>
      52             : #include <sys/socketvar.h>
      53             : #include <sys/domain.h>
      54             : #include <sys/protosw.h>
      55             : #include <sys/namei.h>
      56             : #include <sys/syslog.h>
      57             : #include <sys/filedesc.h>
      58             : #include <sys/signalvar.h>
      59             : #include <sys/kthread.h>
      60             : #include <sys/queue.h>
      61             : 
      62             : #include <sys/syscallargs.h>
      63             : 
      64             : #include <netinet/in.h>
      65             : #include <netinet/tcp.h>
      66             : #include <nfs/xdr_subs.h>
      67             : #include <nfs/rpcv2.h>
      68             : #include <nfs/nfsproto.h>
      69             : #include <nfs/nfs.h>
      70             : #include <nfs/nfsrvcache.h>
      71             : #include <nfs/nfsmount.h>
      72             : #include <nfs/nfsnode.h>
      73             : #include <nfs/nfs_var.h>
      74             : 
      75             : /* Global defs. */
      76             : extern int nfs_numasync;
      77             : extern struct nfsstats nfsstats;
      78             : struct nfssvc_sock *nfs_udpsock;
      79             : int nfsd_waiting = 0;
      80             : 
      81             : #ifdef NFSSERVER
      82             : struct pool nfsrv_descript_pl;
      83             : 
      84             : int nfsrv_getslp(struct nfsd *nfsd);
      85             : 
      86             : static int nfs_numnfsd = 0;
      87             : int (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *,
      88             :     struct nfssvc_sock *, struct proc *, struct mbuf **) = {
      89             :         nfsrv_null,
      90             :         nfsrv_getattr,
      91             :         nfsrv_setattr,
      92             :         nfsrv_lookup,
      93             :         nfsrv3_access,
      94             :         nfsrv_readlink,
      95             :         nfsrv_read,
      96             :         nfsrv_write,
      97             :         nfsrv_create,
      98             :         nfsrv_mkdir,
      99             :         nfsrv_symlink,
     100             :         nfsrv_mknod,
     101             :         nfsrv_remove,
     102             :         nfsrv_rmdir,
     103             :         nfsrv_rename,
     104             :         nfsrv_link,
     105             :         nfsrv_readdir,
     106             :         nfsrv_readdirplus,
     107             :         nfsrv_statfs,
     108             :         nfsrv_fsinfo,
     109             :         nfsrv_pathconf,
     110             :         nfsrv_commit,
     111             :         nfsrv_noop
     112             : };
     113             : #endif
     114             : 
     115             : TAILQ_HEAD(, nfssvc_sock) nfssvc_sockhead;
     116             : struct nfsdhead nfsd_head;
     117             : 
     118             : int nfssvc_sockhead_flag;
     119             : #define SLP_INIT        0x01    /* NFS data undergoing initialization */
     120             : #define SLP_WANTINIT    0x02    /* thread waiting on NFS initialization */
     121             : int nfsd_head_flag;
     122             : 
     123             : #ifdef NFSCLIENT
     124             : struct proc *nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
     125             : int nfs_niothreads = -1;
     126             : #endif
     127             : 
     128             : int nfssvc_addsock(struct file *, struct mbuf *);
     129             : int nfssvc_nfsd(struct nfsd *);
     130             : void nfsrv_slpderef(struct nfssvc_sock *);
     131             : void nfsrv_zapsock(struct nfssvc_sock *);
     132             : void nfssvc_iod(void *);
     133             : 
     134             : /*
     135             :  * NFS server pseudo system call for the nfsd's
     136             :  * Based on the flag value it either:
     137             :  * - adds a socket to the selection list
     138             :  * - remains in the kernel as an nfsd
     139             :  */
     140             : int
     141           0 : sys_nfssvc(struct proc *p, void *v, register_t *retval)
     142             : {
     143             :         int error = 0;
     144             : #ifdef NFSSERVER
     145             :         struct sys_nfssvc_args /* {
     146             :                 syscallarg(int) flag;
     147             :                 syscallarg(caddr_t) argp;
     148           0 :         } */ *uap = v;
     149           0 :         int flags = SCARG(uap, flag);
     150           0 :         struct file *fp;
     151           0 :         struct mbuf *nam;
     152           0 :         struct nfsd_args nfsdarg;
     153           0 :         struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
     154             :         struct nfsd *nfsd;
     155             : #endif
     156             : 
     157             :         /* Must be super user */
     158           0 :         error = suser(p);
     159           0 :         if (error)
     160           0 :                 return (error);
     161             : 
     162             : #ifndef NFSSERVER
     163             :         error = ENOSYS;
     164             : #else
     165             : 
     166           0 :         while (nfssvc_sockhead_flag & SLP_INIT) {
     167           0 :                 nfssvc_sockhead_flag |= SLP_WANTINIT;
     168           0 :                 tsleep(&nfssvc_sockhead, PSOCK, "nfsd init", 0);
     169             :         }
     170             : 
     171           0 :         switch (flags) {
     172             :         case NFSSVC_ADDSOCK:
     173           0 :                 error = copyin(SCARG(uap, argp), &nfsdarg, sizeof(nfsdarg));
     174           0 :                 if (error)
     175           0 :                         return (error);
     176             : 
     177           0 :                 error = getsock(p, nfsdarg.sock, &fp);
     178           0 :                 if (error)
     179           0 :                         return (error);
     180             : 
     181             :                 /*
     182             :                  * Get the client address for connected sockets.
     183             :                  */
     184           0 :                 if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
     185           0 :                         nam = NULL;
     186             :                 else {
     187           0 :                         error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
     188             :                                 MT_SONAME);
     189           0 :                         if (error) {
     190           0 :                                 FRELE(fp, p);
     191           0 :                                 return (error);
     192             :                         }
     193             :                 }
     194           0 :                 error = nfssvc_addsock(fp, nam);
     195           0 :                 FRELE(fp, p);
     196             :                 break;
     197             :         case NFSSVC_NFSD:
     198           0 :                 error = copyin(SCARG(uap, argp), nsd, sizeof(*nsd));
     199           0 :                 if (error)
     200           0 :                         return (error);
     201             : 
     202           0 :                 nfsd = malloc(sizeof(*nfsd), M_NFSD, M_WAITOK|M_ZERO);
     203           0 :                 nfsd->nfsd_procp = p;
     204           0 :                 nfsd->nfsd_slp = NULL;
     205             : 
     206           0 :                 error = nfssvc_nfsd(nfsd);
     207           0 :                 break;
     208             :         default:
     209             :                 error = EINVAL;
     210           0 :                 break;
     211             :         }
     212             : 
     213           0 :         if (error == EINTR || error == ERESTART)
     214           0 :                 error = 0;
     215             : #endif  /* !NFSSERVER */
     216             : 
     217           0 :         return (error);
     218           0 : }
     219             : 
     220             : #ifdef NFSSERVER
     221             : /*
     222             :  * Adds a socket to the list for servicing by nfsds.
     223             :  */
     224             : int
     225           0 : nfssvc_addsock(struct file *fp, struct mbuf *mynam)
     226             : {
     227             :         struct mbuf *m;
     228             :         int siz;
     229             :         struct nfssvc_sock *slp;
     230             :         struct socket *so;
     231             :         struct nfssvc_sock *tslp;
     232             :         int s, error;
     233             : 
     234           0 :         so = (struct socket *)fp->f_data;
     235             :         tslp = NULL;
     236             :         /*
     237             :          * Add it to the list, as required.
     238             :          */
     239           0 :         if (so->so_proto->pr_protocol == IPPROTO_UDP) {
     240           0 :                 tslp = nfs_udpsock;
     241           0 :                 if (tslp->ns_flag & SLP_VALID) {
     242           0 :                         m_freem(mynam);
     243           0 :                         return (EPERM);
     244             :                 }
     245             :         }
     246           0 :         if (so->so_type == SOCK_STREAM)
     247           0 :                 siz = NFS_MAXPACKET + sizeof (u_long);
     248             :         else
     249             :                 siz = NFS_MAXPACKET;
     250           0 :         s = solock(so);
     251           0 :         error = soreserve(so, siz, siz); 
     252           0 :         if (error) {
     253           0 :                 sounlock(so, s);
     254           0 :                 m_freem(mynam);
     255           0 :                 return (error);
     256             :         }
     257             : 
     258             :         /*
     259             :          * Set protocol specific options { for now TCP only } and
     260             :          * reserve some space. For datagram sockets, this can get called
     261             :          * repeatedly for the same socket, but that isn't harmful.
     262             :          */
     263           0 :         if (so->so_type == SOCK_STREAM) {
     264           0 :                 MGET(m, M_WAIT, MT_SOOPTS);
     265           0 :                 *mtod(m, int32_t *) = 1;
     266           0 :                 m->m_len = sizeof(int32_t);
     267           0 :                 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
     268           0 :                 m_freem(m);
     269           0 :         }
     270           0 :         if (so->so_proto->pr_domain->dom_family == AF_INET &&
     271           0 :             so->so_proto->pr_protocol == IPPROTO_TCP) {
     272           0 :                 MGET(m, M_WAIT, MT_SOOPTS);
     273           0 :                 *mtod(m, int32_t *) = 1;
     274           0 :                 m->m_len = sizeof(int32_t);
     275           0 :                 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
     276           0 :                 m_freem(m);
     277           0 :         }
     278           0 :         so->so_rcv.sb_flags &= ~SB_NOINTR;
     279           0 :         so->so_rcv.sb_timeo = 0;
     280           0 :         so->so_snd.sb_flags &= ~SB_NOINTR;
     281           0 :         so->so_snd.sb_timeo = 0;
     282           0 :         sounlock(so, s);
     283           0 :         if (tslp)
     284           0 :                 slp = tslp;
     285             :         else {
     286           0 :                 slp = malloc(sizeof(*slp), M_NFSSVC, M_WAITOK|M_ZERO);
     287           0 :                 TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
     288             :         }
     289           0 :         slp->ns_so = so;
     290           0 :         slp->ns_nam = mynam;
     291           0 :         FREF(fp);
     292           0 :         slp->ns_fp = fp;
     293           0 :         so->so_upcallarg = (caddr_t)slp;
     294           0 :         so->so_upcall = nfsrv_rcv;
     295           0 :         slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
     296           0 :         nfsrv_wakenfsd(slp);
     297           0 :         return (0);
     298           0 : }
     299             : 
     300             : /*
     301             :  * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
     302             :  * until it is killed by a signal.
     303             :  */
     304             : int
     305           0 : nfssvc_nfsd(struct nfsd *nfsd)
     306             : {
     307             :         struct mbuf *m;
     308             :         int siz;
     309             :         struct nfssvc_sock *slp;
     310             :         struct socket *so;
     311             :         int *solockp;
     312           0 :         struct nfsrv_descript *nd = NULL;
     313           0 :         struct mbuf *mreq;
     314             :         int error = 0, cacherep, sotype;
     315             : 
     316             :         cacherep = RC_DOIT;
     317             : 
     318           0 :         TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
     319           0 :         nfs_numnfsd++;
     320             : 
     321             :         /* Loop getting rpc requests until SIGKILL. */
     322             : loop:
     323           0 :         if (!ISSET(nfsd->nfsd_flag, NFSD_REQINPROG)) {
     324             : 
     325             :                 /* attach an nfssvc_sock to nfsd */
     326           0 :                 error = nfsrv_getslp(nfsd);
     327           0 :                 if (error)
     328             :                         goto done;
     329             : 
     330           0 :                 slp = nfsd->nfsd_slp;
     331             : 
     332           0 :                 if (ISSET(slp->ns_flag, SLP_VALID)) {
     333           0 :                         if (ISSET(slp->ns_flag, SLP_DISCONN)) {
     334           0 :                                 nfsrv_zapsock(slp);
     335           0 :                         } else if (ISSET(slp->ns_flag, SLP_NEEDQ)) {
     336           0 :                                 CLR(slp->ns_flag, SLP_NEEDQ);
     337           0 :                                 nfs_sndlock(&slp->ns_solock, NULL);
     338           0 :                                 nfsrv_rcv(slp->ns_so, (caddr_t)slp, M_WAIT);
     339           0 :                                 nfs_sndunlock(&slp->ns_solock);
     340           0 :                         }
     341             : 
     342           0 :                         error = nfsrv_dorec(slp, nfsd, &nd);
     343           0 :                         SET(nfsd->nfsd_flag, NFSD_REQINPROG);
     344           0 :                 }
     345             :         } else {
     346             :                 error = 0;
     347           0 :                 slp = nfsd->nfsd_slp;
     348             :         }
     349             : 
     350           0 :         if (error || !ISSET(slp->ns_flag, SLP_VALID)) {
     351           0 :                 if (nd != NULL) {
     352           0 :                         pool_put(&nfsrv_descript_pl, nd);
     353           0 :                         nd = NULL;
     354           0 :                 }
     355           0 :                 nfsd->nfsd_slp = NULL;
     356           0 :                 CLR(nfsd->nfsd_flag, NFSD_REQINPROG);
     357           0 :                 nfsrv_slpderef(slp);
     358           0 :                 goto loop;
     359             :         }
     360             : 
     361           0 :         so = slp->ns_so;
     362           0 :         sotype = so->so_type;
     363           0 :         if (ISSET(so->so_proto->pr_flags, PR_CONNREQUIRED))
     364           0 :                 solockp = &slp->ns_solock;
     365             :         else
     366             :                 solockp = NULL;
     367             : 
     368           0 :         if (nd) {
     369           0 :                 if (nd->nd_nam2)
     370           0 :                         nd->nd_nam = nd->nd_nam2;
     371             :                 else
     372           0 :                         nd->nd_nam = slp->ns_nam;
     373             :         }
     374             : 
     375           0 :         cacherep = nfsrv_getcache(nd, slp, &mreq);
     376           0 :         switch (cacherep) {
     377             :         case RC_DOIT:
     378           0 :                 error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, slp, nfsd->nfsd_procp, &mreq);
     379           0 :                 if (mreq == NULL) {
     380           0 :                         if (nd != NULL) {
     381           0 :                                 m_freem(nd->nd_nam2);
     382           0 :                                 m_freem(nd->nd_mrep);
     383           0 :                         }
     384             :                         break;
     385             :                 }
     386           0 :                 if (error) {
     387           0 :                         nfsstats.srv_errs++;
     388           0 :                         nfsrv_updatecache(nd, 0, mreq);
     389           0 :                         m_freem(nd->nd_nam2);
     390           0 :                         break;
     391             :                 }
     392           0 :                 nfsstats.srvrpccnt[nd->nd_procnum]++;
     393           0 :                 nfsrv_updatecache(nd, 1, mreq);
     394           0 :                 nd->nd_mrep = NULL;
     395             : 
     396             :                 /* FALLTHROUGH */
     397             :         case RC_REPLY:
     398           0 :                 m = mreq;
     399             :                 siz = 0;
     400           0 :                 while (m) {
     401           0 :                         siz += m->m_len;
     402           0 :                         m = m->m_next;
     403             :                 }
     404             : 
     405           0 :                 if (siz <= 0 || siz > NFS_MAXPACKET)
     406           0 :                         panic("bad nfs svc reply, siz = %i", siz);
     407             : 
     408           0 :                 m = mreq;
     409           0 :                 m->m_pkthdr.len = siz;
     410           0 :                 m->m_pkthdr.ph_ifidx = 0;
     411             : 
     412             :                 /* For stream protocols, prepend a Sun RPC Record Mark. */
     413           0 :                 if (sotype == SOCK_STREAM) {
     414           0 :                         M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
     415           0 :                         *mtod(m, u_int32_t *) = htonl(0x80000000 | siz);
     416           0 :                 }
     417             : 
     418           0 :                 if (solockp)
     419           0 :                         nfs_sndlock(solockp, NULL);
     420             : 
     421           0 :                 if (ISSET(slp->ns_flag, SLP_VALID))
     422           0 :                     error = nfs_send(so, nd->nd_nam2, m, NULL);
     423             :                 else {
     424             :                     error = EPIPE;
     425           0 :                     m_freem(m);
     426             :                 }
     427           0 :                 m_freem(nd->nd_nam2);
     428           0 :                 m_freem(nd->nd_mrep);
     429           0 :                 if (error == EPIPE)
     430           0 :                         nfsrv_zapsock(slp);
     431           0 :                 if (solockp)
     432           0 :                         nfs_sndunlock(solockp);
     433           0 :                 if (error == EINTR || error == ERESTART) {
     434           0 :                         pool_put(&nfsrv_descript_pl, nd);
     435           0 :                         nfsrv_slpderef(slp);
     436           0 :                         goto done;
     437             :                 }
     438             :                 break;
     439             :         case RC_DROPIT:
     440           0 :                 m_freem(nd->nd_mrep);
     441           0 :                 m_freem(nd->nd_nam2);
     442           0 :                 break;
     443             :         };
     444             : 
     445           0 :         if (nd) {
     446           0 :                 pool_put(&nfsrv_descript_pl, nd);
     447           0 :                 nd = NULL;
     448           0 :         }
     449             : 
     450           0 :         if (nfsrv_dorec(slp, nfsd, &nd)) {
     451           0 :                 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
     452           0 :                 nfsd->nfsd_slp = NULL;
     453           0 :                 nfsrv_slpderef(slp);
     454           0 :         }
     455           0 :         goto loop;
     456             : 
     457             : done:
     458           0 :         TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
     459           0 :         free(nfsd, M_NFSD, sizeof(*nfsd));
     460           0 :         if (--nfs_numnfsd == 0)
     461           0 :                 nfsrv_init(1);  /* Reinitialize everything */
     462           0 :         return (error);
     463           0 : }
     464             : 
     465             : /*
     466             :  * Shut down a socket associated with an nfssvc_sock structure.
     467             :  * Should be called with the send lock set, if required.
     468             :  * The trick here is to increment the sref at the start, so that the nfsds
     469             :  * will stop using it and clear ns_flag at the end so that it will not be
     470             :  * reassigned during cleanup.
     471             :  */
     472             : void
     473           0 : nfsrv_zapsock(struct nfssvc_sock *slp)
     474             : {
     475             :         struct socket *so;
     476             :         struct file *fp;
     477             :         struct mbuf *m, *n;
     478             : 
     479           0 :         slp->ns_flag &= ~SLP_ALLFLAGS;
     480           0 :         fp = slp->ns_fp;
     481           0 :         if (fp) {
     482           0 :                 FREF(fp);
     483           0 :                 slp->ns_fp = NULL;
     484           0 :                 so = slp->ns_so;
     485           0 :                 so->so_upcall = NULL;
     486           0 :                 soshutdown(so, SHUT_RDWR);
     487           0 :                 closef(fp, NULL);
     488           0 :                 if (slp->ns_nam)
     489           0 :                         m = m_free(slp->ns_nam);
     490           0 :                 m_freem(slp->ns_raw);
     491           0 :                 m = slp->ns_rec;
     492           0 :                 while (m) {
     493           0 :                         n = m->m_nextpkt;
     494           0 :                         m_freem(m);
     495             :                         m = n;
     496             :                 }
     497             :         }
     498           0 : }
     499             : 
     500             : /*
     501             :  * Derefence a server socket structure. If it has no more references and
     502             :  * is no longer valid, you can throw it away.
     503             :  */
     504             : void
     505           0 : nfsrv_slpderef(struct nfssvc_sock *slp)
     506             : {
     507           0 :         if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
     508           0 :                 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
     509           0 :                 free(slp, M_NFSSVC, sizeof(*slp));
     510           0 :         }
     511           0 : }
     512             : 
     513             : /*
     514             :  * Initialize the data structures for the server.
     515             :  * Handshake with any new nfsds starting up to avoid any chance of
     516             :  * corruption.
     517             :  */
     518             : void
     519           0 : nfsrv_init(int terminating)
     520             : {
     521             :         struct nfssvc_sock *slp, *nslp;
     522             : 
     523           0 :         if (nfssvc_sockhead_flag & SLP_INIT)
     524           0 :                 panic("nfsd init");
     525           0 :         nfssvc_sockhead_flag |= SLP_INIT;
     526           0 :         if (terminating) {
     527           0 :                 for (slp = TAILQ_FIRST(&nfssvc_sockhead); slp != NULL;
     528             :                     slp = nslp) {
     529           0 :                         nslp = TAILQ_NEXT(slp, ns_chain);
     530           0 :                         if (slp->ns_flag & SLP_VALID)
     531           0 :                                 nfsrv_zapsock(slp);
     532           0 :                         TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
     533           0 :                         free(slp, M_NFSSVC, sizeof(*slp));
     534             :                 }
     535           0 :                 nfsrv_cleancache();     /* And clear out server cache */
     536           0 :         }
     537             : 
     538           0 :         TAILQ_INIT(&nfssvc_sockhead);
     539           0 :         nfssvc_sockhead_flag &= ~SLP_INIT;
     540           0 :         if (nfssvc_sockhead_flag & SLP_WANTINIT) {
     541           0 :                 nfssvc_sockhead_flag &= ~SLP_WANTINIT;
     542           0 :                 wakeup((caddr_t)&nfssvc_sockhead);
     543           0 :         }
     544             : 
     545           0 :         TAILQ_INIT(&nfsd_head);
     546           0 :         nfsd_head_flag &= ~NFSD_CHECKSLP;
     547             : 
     548           0 :         nfs_udpsock =  malloc(sizeof(*nfs_udpsock), M_NFSSVC,
     549             :             M_WAITOK|M_ZERO);
     550           0 :         TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
     551             : 
     552           0 :         if (!terminating) {
     553           0 :                 pool_init(&nfsrv_descript_pl, sizeof(struct nfsrv_descript),
     554             :                     0, IPL_NONE, PR_WAITOK, "ndscpl", NULL);
     555           0 :         }
     556           0 : }
     557             : #endif /* NFSSERVER */
     558             : 
     559             : #ifdef NFSCLIENT
     560             : /*
     561             :  * Asynchronous I/O threads for client nfs.
     562             :  * They do read-ahead and write-behind operations on the block I/O cache.
     563             :  * Never returns unless it fails or gets killed.
     564             :  */
     565             : void
     566           0 : nfssvc_iod(void *arg)
     567             : {
     568           0 :         struct proc *p = curproc;
     569             :         struct buf *bp, *nbp;
     570             :         int i, myiod;
     571             :         struct vnode *vp;
     572             :         int error = 0, s, bufcount;
     573             : 
     574           0 :         bufcount = MIN(256, bcstats.kvaslots / 8);
     575           0 :         bufcount = MIN(bufcount, bcstats.numbufs / 8);
     576             : 
     577             :         /* Assign my position or return error if too many already running. */
     578             :         myiod = -1;
     579           0 :         for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
     580           0 :                 if (nfs_asyncdaemon[i] == NULL) {
     581             :                         myiod = i;
     582           0 :                         break;
     583             :                 }
     584             :         }
     585           0 :         if (myiod == -1)
     586           0 :                 kthread_exit(EBUSY);
     587             : 
     588           0 :         nfs_asyncdaemon[myiod] = p;
     589           0 :         nfs_numasync++;
     590             : 
     591             :         /* Upper limit on how many bufs we'll queue up for this iod. */
     592           0 :         if (nfs_bufqmax > bcstats.kvaslots / 4) {
     593           0 :                 nfs_bufqmax = bcstats.kvaslots / 4;
     594             :                 bufcount = 0;
     595           0 :         } 
     596           0 :         if (nfs_bufqmax > bcstats.numbufs / 4) {
     597           0 :                 nfs_bufqmax = bcstats.numbufs / 4;
     598             :                 bufcount = 0;
     599           0 :         }
     600             : 
     601           0 :         nfs_bufqmax += bufcount;
     602           0 :         wakeup(&nfs_bufqlen); /* wake up anyone waiting for room to enqueue IO */
     603             : 
     604             :         /* Just loop around doin our stuff until SIGKILL. */
     605           0 :         for (;;) {
     606           0 :             while (TAILQ_FIRST(&nfs_bufq) == NULL && error == 0) {
     607           0 :                     error = tsleep(&nfs_bufq,
     608             :                         PWAIT | PCATCH, "nfsidl", 0);
     609             :             }
     610           0 :             while ((bp = TAILQ_FIRST(&nfs_bufq)) != NULL) {
     611             :                 /* Take one off the front of the list */
     612           0 :                 TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
     613           0 :                 nfs_bufqlen--;
     614           0 :                 wakeup_one(&nfs_bufqlen);
     615           0 :                 if (bp->b_flags & B_READ)
     616           0 :                     (void) nfs_doio(bp, NULL);
     617           0 :                 else do {
     618             :                     /*
     619             :                      * Look for a delayed write for the same vnode, so I can do 
     620             :                      * it now. We must grab it before calling nfs_doio() to
     621             :                      * avoid any risk of the vnode getting vclean()'d while
     622             :                      * we are doing the write rpc.
     623             :                      */
     624           0 :                     vp = bp->b_vp;
     625           0 :                     s = splbio();
     626           0 :                     LIST_FOREACH(nbp, &vp->v_dirtyblkhd, b_vnbufs) {
     627           0 :                         if ((nbp->b_flags &
     628           0 :                             (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI)
     629             :                             continue;
     630           0 :                         nbp->b_flags |= B_ASYNC;
     631           0 :                         bremfree(nbp);
     632           0 :                         buf_acquire(nbp);
     633           0 :                         break;
     634             :                     }
     635             :                     /*
     636             :                      * For the delayed write, do the first part of nfs_bwrite()
     637             :                      * up to, but not including nfs_strategy().
     638             :                      */
     639           0 :                     if (nbp) {
     640           0 :                         nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR);
     641           0 :                         buf_undirty(nbp);
     642           0 :                         nbp->b_vp->v_numoutput++;
     643           0 :                     }
     644           0 :                     splx(s);
     645             : 
     646           0 :                     (void) nfs_doio(bp, NULL);
     647           0 :                 } while ((bp = nbp) != NULL);
     648             :             }
     649           0 :             if (error) {
     650           0 :                 nfs_asyncdaemon[myiod] = NULL;
     651           0 :                 nfs_numasync--;
     652           0 :                 nfs_bufqmax -= bufcount;
     653           0 :                 kthread_exit(error);
     654             :             }
     655             :         }
     656             : }
     657             : 
     658             : void
     659           0 : nfs_getset_niothreads(int set)
     660             : {
     661             :         int i, have, start;
     662             :         
     663           0 :         for (have = 0, i = 0; i < NFS_MAXASYNCDAEMON; i++)
     664           0 :                 if (nfs_asyncdaemon[i] != NULL)
     665           0 :                         have++;
     666             : 
     667           0 :         if (set) {
     668             :                 /* clamp to sane range */
     669           0 :                 nfs_niothreads = max(0, min(nfs_niothreads, NFS_MAXASYNCDAEMON));
     670             : 
     671           0 :                 start = nfs_niothreads - have;
     672             : 
     673           0 :                 while (start > 0) {
     674           0 :                         kthread_create(nfssvc_iod, NULL, NULL, "nfsio");
     675           0 :                         start--;
     676             :                 }
     677             : 
     678           0 :                 for (i = 0; (start < 0) && (i < NFS_MAXASYNCDAEMON); i++)
     679           0 :                         if (nfs_asyncdaemon[i] != NULL) {
     680           0 :                                 psignal(nfs_asyncdaemon[i], SIGKILL);
     681           0 :                                 start++;
     682           0 :                         }
     683             :         } else {
     684           0 :                 if (nfs_niothreads >= 0)
     685           0 :                         nfs_niothreads = have;
     686             :         }
     687           0 : }
     688             : #endif /* NFSCLIENT */
     689             : 
     690             : #ifdef NFSSERVER
     691             : /*
     692             :  * Find an nfssrv_sock for nfsd, sleeping if needed.
     693             :  */
     694             : int
     695           0 : nfsrv_getslp(struct nfsd *nfsd)
     696             : {
     697             :         struct nfssvc_sock *slp;
     698           0 :         int error;
     699             : 
     700             : again:
     701           0 :         while (nfsd->nfsd_slp == NULL &&
     702           0 :             (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
     703           0 :                 nfsd->nfsd_flag |= NFSD_WAITING;
     704           0 :                 nfsd_waiting++;
     705           0 :                 error = tsleep(nfsd, PSOCK | PCATCH, "nfsd", 0);
     706           0 :                 nfsd_waiting--;
     707           0 :                 if (error)
     708           0 :                         return (error);
     709             :         }
     710             : 
     711           0 :         if (nfsd->nfsd_slp == NULL &&
     712           0 :             (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
     713           0 :                 TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) {
     714           0 :                         if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) ==
     715             :                             (SLP_VALID | SLP_DOREC)) {
     716           0 :                                 slp->ns_flag &= ~SLP_DOREC;
     717           0 :                                 slp->ns_sref++;
     718           0 :                                 nfsd->nfsd_slp = slp;
     719           0 :                                 break;
     720             :                         }
     721             :                 }
     722           0 :                 if (slp == NULL)
     723           0 :                         nfsd_head_flag &= ~NFSD_CHECKSLP;
     724             :         }
     725             : 
     726           0 :         if (nfsd->nfsd_slp == NULL)
     727           0 :                 goto again;
     728             : 
     729           0 :         return (0);
     730           0 : }
     731             : #endif /* NFSSERVER */

Generated by: LCOV version 1.13