]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfsserver/nfs_syscalls.c
This commit was generated by cvs2svn to compensate for changes in r169765,
[FreeBSD/FreeBSD.git] / sys / nfsserver / nfs_syscalls.c
1 /*-
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *      @(#)nfs_syscalls.c      8.5 (Berkeley) 3/30/95
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include "opt_inet6.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/sysproto.h>
43 #include <sys/kernel.h>
44 #include <sys/sysctl.h>
45 #include <sys/file.h>
46 #include <sys/filedesc.h>
47 #include <sys/vnode.h>
48 #include <sys/malloc.h>
49 #include <sys/mount.h>
50 #include <sys/priv.h>
51 #include <sys/proc.h>
52 #include <sys/bio.h>
53 #include <sys/buf.h>
54 #include <sys/mbuf.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/domain.h>
58 #include <sys/protosw.h>
59 #include <sys/namei.h>
60 #include <sys/fcntl.h>
61 #include <sys/lockf.h>
62
63 #include <netinet/in.h>
64 #include <netinet/tcp.h>
65 #ifdef INET6
66 #include <net/if.h>
67 #include <netinet6/in6_var.h>
68 #endif
69 #include <nfs/xdr_subs.h>
70 #include <nfs/rpcv2.h>
71 #include <nfs/nfsproto.h>
72 #include <nfsserver/nfs.h>
73 #include <nfsserver/nfsm_subs.h>
74 #include <nfsserver/nfsrvcache.h>
75
76 static MALLOC_DEFINE(M_NFSSVC, "nfss_srvsock", "Nfs server structure");
77
78 MALLOC_DEFINE(M_NFSRVDESC, "nfss_srvdesc", "NFS server socket descriptor");
79 MALLOC_DEFINE(M_NFSD, "nfss_daemon", "Nfs server daemon structure");
80
81 #define TRUE    1
82 #define FALSE   0
83
84 SYSCTL_DECL(_vfs_nfsrv);
85
86 int             nfsd_waiting = 0;
87 int             nfsrv_numnfsd = 0;
88 static int      notstarted = 1;
89
90 static int      nfs_privport = 0;
91 SYSCTL_INT(_vfs_nfsrv, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW,
92             &nfs_privport, 0, "");
93 SYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay, CTLFLAG_RW,
94             &nfsrvw_procrastinate, 0, "");
95 SYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay_v3, CTLFLAG_RW,
96             &nfsrvw_procrastinate_v3, 0, "");
97
98 static int      nfssvc_addsock(struct file *, struct sockaddr *,
99                     struct thread *);
100 static void     nfsrv_zapsock(struct nfssvc_sock *slp);
101 static int      nfssvc_nfsd(struct thread *);
102
103 /*
104  * NFS server system calls
105  */
106
107 /*
108  * Nfs server psuedo system call for the nfsd's
109  * Based on the flag value it either:
110  * - adds a socket to the selection list
111  * - remains in the kernel as an nfsd
112  * - remains in the kernel as an nfsiod
113  * For INET6 we suppose that nfsd provides only IN6P_IPV6_V6ONLY sockets
114  * and that mountd provides
115  *  - sockaddr with no IPv4-mapped addresses
116  *  - mask for both INET and INET6 families if there is IPv4-mapped overlap
117  */
118 #ifndef _SYS_SYSPROTO_H_
119 struct nfssvc_args {
120         int flag;
121         caddr_t argp;
122 };
123 #endif
124 int
125 nfssvc(struct thread *td, struct nfssvc_args *uap)
126 {
127         struct file *fp;
128         struct sockaddr *nam;
129         struct nfsd_args nfsdarg;
130         int error;
131
132         KASSERT(!mtx_owned(&Giant), ("nfssvc(): called with Giant"));
133
134         error = priv_check(td, PRIV_NFS_DAEMON);
135         if (error)
136                 return (error);
137         NET_LOCK_GIANT();
138         NFSD_LOCK();
139         while (nfssvc_sockhead_flag & SLP_INIT) {
140                  nfssvc_sockhead_flag |= SLP_WANTINIT;
141                 (void) msleep(&nfssvc_sockhead, &nfsd_mtx, PSOCK,
142                     "nfsd init", 0);
143         }
144         NFSD_UNLOCK();
145         if (uap->flag & NFSSVC_ADDSOCK) {
146                 error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
147                 if (error)
148                         goto done2;
149                 if ((error = fget(td, nfsdarg.sock, &fp)) != 0)
150                         goto done2;
151                 if (fp->f_type != DTYPE_SOCKET) {
152                         fdrop(fp, td);
153                         goto done2;
154                 }
155                 /*
156                  * Get the client address for connected sockets.
157                  */
158                 if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
159                         nam = NULL;
160                 else {
161                         error = getsockaddr(&nam, nfsdarg.name,
162                                             nfsdarg.namelen);
163                         if (error) {
164                                 fdrop(fp, td);
165                                 goto done2;
166                         }
167                 }
168                 error = nfssvc_addsock(fp, nam, td);
169                 fdrop(fp, td);
170         } else if (uap->flag & NFSSVC_NFSD) {
171                 error = nfssvc_nfsd(td);
172         } else {
173                 error = ENXIO;
174         }
175         if (error == EINTR || error == ERESTART)
176                 error = 0;
177 done2:
178         NET_UNLOCK_GIANT();
179         return (error);
180 }
181
182 /*
183  * Adds a socket to the list for servicing by nfsds.
184  */
185 static int
186 nfssvc_addsock(struct file *fp, struct sockaddr *mynam, struct thread *td)
187 {
188         int siz;
189         struct nfssvc_sock *slp;
190         struct socket *so;
191         int error, s;
192
193         NET_ASSERT_GIANT();
194
195         so = fp->f_data;
196 #if 0
197         /*
198          * XXXRW: If this code is ever enabled, there's a race when running
199          * MPSAFE.
200          */
201         tslp = NULL;
202         /*
203          * Add it to the list, as required.
204          */
205         if (so->so_proto->pr_protocol == IPPROTO_UDP) {
206                 tslp = nfs_udpsock;
207                 if (tslp->ns_flag & SLP_VALID) {
208                         if (mynam != NULL)
209                                 FREE(mynam, M_SONAME);
210                         return (EPERM);
211                 }
212         }
213 #endif
214         if (so->so_type == SOCK_STREAM)
215                 siz = NFS_MAXPACKET + sizeof (u_long);
216         else
217                 siz = NFS_MAXPACKET;
218         error = soreserve(so, siz, siz);
219         if (error) {
220                 if (mynam != NULL)
221                         FREE(mynam, M_SONAME);
222                 return (error);
223         }
224
225         /*
226          * Set protocol specific options { for now TCP only } and
227          * reserve some space. For datagram sockets, this can get called
228          * repeatedly for the same socket, but that isn't harmful.
229          */
230         if (so->so_type == SOCK_STREAM) {
231                 struct sockopt sopt;
232                 int val;
233
234                 bzero(&sopt, sizeof sopt);
235                 sopt.sopt_dir = SOPT_SET;
236                 sopt.sopt_level = SOL_SOCKET;
237                 sopt.sopt_name = SO_KEEPALIVE;
238                 sopt.sopt_val = &val;
239                 sopt.sopt_valsize = sizeof val;
240                 val = 1;
241                 sosetopt(so, &sopt);
242         }
243         if (so->so_proto->pr_protocol == IPPROTO_TCP) {
244                 struct sockopt sopt;
245                 int val;
246
247                 bzero(&sopt, sizeof sopt);
248                 sopt.sopt_dir = SOPT_SET;
249                 sopt.sopt_level = IPPROTO_TCP;
250                 sopt.sopt_name = TCP_NODELAY;
251                 sopt.sopt_val = &val;
252                 sopt.sopt_valsize = sizeof val;
253                 val = 1;
254                 sosetopt(so, &sopt);
255         }
256         SOCKBUF_LOCK(&so->so_rcv);
257         so->so_rcv.sb_flags &= ~SB_NOINTR;
258         so->so_rcv.sb_timeo = 0;
259         SOCKBUF_UNLOCK(&so->so_rcv);
260         SOCKBUF_LOCK(&so->so_snd);
261         so->so_snd.sb_flags &= ~SB_NOINTR;
262         so->so_snd.sb_timeo = 0;
263         SOCKBUF_UNLOCK(&so->so_snd);
264
265         slp = (struct nfssvc_sock *)
266                 malloc(sizeof (struct nfssvc_sock), M_NFSSVC,
267                 M_WAITOK | M_ZERO);
268         STAILQ_INIT(&slp->ns_rec);
269         NFSD_LOCK();
270         TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
271
272         slp->ns_so = so;
273         slp->ns_nam = mynam;
274         fhold(fp);
275         slp->ns_fp = fp;
276         /*
277          * XXXRW: Socket locking here?
278          */
279         s = splnet();
280         so->so_upcallarg = (caddr_t)slp;
281         so->so_upcall = nfsrv_rcv;
282         SOCKBUF_LOCK(&so->so_rcv);
283         so->so_rcv.sb_flags |= SB_UPCALL;
284         SOCKBUF_UNLOCK(&so->so_rcv);
285         slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
286         nfsrv_wakenfsd(slp);
287         splx(s);
288         NFSD_UNLOCK();
289         return (0);
290 }
291
292 /*
293  * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
294  * until it is killed by a signal.
295  */
296 static int
297 nfssvc_nfsd(struct thread *td)
298 {
299         int siz;
300         struct nfssvc_sock *slp;
301         struct nfsd *nfsd;
302         struct nfsrv_descript *nd = NULL;
303         struct mbuf *m, *mreq;
304         int error = 0, cacherep, s, sotype, writes_todo;
305         int procrastinate;
306         u_quad_t cur_usec;
307
308         NET_ASSERT_GIANT();
309
310 #ifndef nolint
311         cacherep = RC_DOIT;
312         writes_todo = 0;
313 #endif
314         nfsd = (struct nfsd *)
315                 malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK | M_ZERO);
316         s = splnet();
317         NFSD_LOCK();
318
319         nfsd->nfsd_td = td;
320         TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
321         nfsrv_numnfsd++;
322
323         /*
324          * Loop getting rpc requests until SIGKILL.
325          */
326         for (;;) {
327                 if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
328                         while (nfsd->nfsd_slp == NULL &&
329                             (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
330                                 nfsd->nfsd_flag |= NFSD_WAITING;
331                                 nfsd_waiting++;
332                                 error = msleep(nfsd, &nfsd_mtx,
333                                     PSOCK | PCATCH, "-", 0);
334                                 nfsd_waiting--;
335                                 if (error)
336                                         goto done;
337                         }
338                         if (nfsd->nfsd_slp == NULL &&
339                             (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
340                                 TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) {
341                                     if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
342                                         == (SLP_VALID | SLP_DOREC)) {
343                                             slp->ns_flag &= ~SLP_DOREC;
344                                             slp->ns_sref++;
345                                             nfsd->nfsd_slp = slp;
346                                             break;
347                                     }
348                                 }
349                                 if (slp == NULL)
350                                         nfsd_head_flag &= ~NFSD_CHECKSLP;
351                         }
352                         if ((slp = nfsd->nfsd_slp) == NULL)
353                                 continue;
354                         if (slp->ns_flag & SLP_VALID) {
355                                 if (slp->ns_flag & SLP_DISCONN)
356                                         nfsrv_zapsock(slp);
357                                 else if (slp->ns_flag & SLP_NEEDQ) {
358                                         slp->ns_flag &= ~SLP_NEEDQ;
359                                         (void) nfs_slplock(slp, 1);
360                                         NFSD_UNLOCK();
361                                         nfsrv_rcv(slp->ns_so, (caddr_t)slp,
362                                                 M_TRYWAIT);
363                                         NFSD_LOCK();
364                                         nfs_slpunlock(slp);
365                                 }
366                                 error = nfsrv_dorec(slp, nfsd, &nd);
367                                 cur_usec = nfs_curusec();
368                                 if (error && LIST_FIRST(&slp->ns_tq) &&
369                                     LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) {
370                                         error = 0;
371                                         cacherep = RC_DOIT;
372                                         writes_todo = 1;
373                                 } else
374                                         writes_todo = 0;
375                                 nfsd->nfsd_flag |= NFSD_REQINPROG;
376                         }
377                 } else {
378                         error = 0;
379                         slp = nfsd->nfsd_slp;
380                 }
381                 if (error || (slp->ns_flag & SLP_VALID) == 0) {
382                         if (nd) {
383                                 if (nd->nd_cr != NULL)
384                                         crfree(nd->nd_cr);
385                                 free((caddr_t)nd, M_NFSRVDESC);
386                                 nd = NULL;
387                         }
388                         nfsd->nfsd_slp = NULL;
389                         nfsd->nfsd_flag &= ~NFSD_REQINPROG;
390                         nfsrv_slpderef(slp);
391                         continue;
392                 }
393                 splx(s);
394                 sotype = slp->ns_so->so_type;
395                 if (nd) {
396                     getmicrotime(&nd->nd_starttime);
397                     if (nd->nd_nam2)
398                         nd->nd_nam = nd->nd_nam2;
399                     else
400                         nd->nd_nam = slp->ns_nam;
401
402                     /*
403                      * Check to see if authorization is needed.
404                      */
405                     cacherep = nfsrv_getcache(nd, &mreq);
406
407                     if (nfs_privport) {
408                         /* Check if source port is privileged */
409                         u_short port;
410                         struct sockaddr *nam = nd->nd_nam;
411                         struct sockaddr_in *sin;
412
413                         sin = (struct sockaddr_in *)nam;
414                         /*
415                          * INET/INET6 - same code:
416                          *    sin_port and sin6_port are at same offset
417                          */
418                         port = ntohs(sin->sin_port);
419                         if (port >= IPPORT_RESERVED &&
420                             nd->nd_procnum != NFSPROC_NULL) {
421 #ifdef INET6
422                             char b6[INET6_ADDRSTRLEN];
423 #if defined(KLD_MODULE)
424         /* Do not use ip6_sprintf: the nfs module should work without INET6. */
425 #define ip6_sprintf(buf, a) \
426          (sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x", \
427                   (a)->s6_addr16[0], (a)->s6_addr16[1], \
428                   (a)->s6_addr16[2], (a)->s6_addr16[3], \
429                   (a)->s6_addr16[4], (a)->s6_addr16[5], \
430                   (a)->s6_addr16[6], (a)->s6_addr16[7]), \
431          (buf))
432 #endif
433 #endif
434                             nd->nd_procnum = NFSPROC_NOOP;
435                             nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
436                             cacherep = RC_DOIT;
437                             printf("NFS request from unprivileged port (%s:%d)\n",
438 #ifdef INET6
439                                 sin->sin_family == AF_INET6 ?
440                                     ip6_sprintf(b6, &satosin6(sin)->sin6_addr) :
441 #if defined(KLD_MODULE)
442 #undef ip6_sprintf
443 #endif
444 #endif
445                                     inet_ntoa(sin->sin_addr), port);
446                         }
447                     }
448
449                 }
450
451                 /*
452                  * Loop to get all the write rpc relies that have been
453                  * gathered together.
454                  */
455                 do {
456                     switch (cacherep) {
457                     case RC_DOIT:
458                         if (nd && (nd->nd_flag & ND_NFSV3))
459                             procrastinate = nfsrvw_procrastinate_v3;
460                         else
461                             procrastinate = nfsrvw_procrastinate;
462                         NFSD_UNLOCK();
463                         if (writes_todo || (!(nd->nd_flag & ND_NFSV3) &&
464                             nd->nd_procnum == NFSPROC_WRITE &&
465                             procrastinate > 0 && !notstarted))
466                             error = nfsrv_writegather(&nd, slp,
467                                 nfsd->nfsd_td, &mreq);
468                         else
469                             error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
470                                 slp, nfsd->nfsd_td, &mreq);
471                         NFSD_LOCK();
472                         if (mreq == NULL)
473                                 break;
474                         if (error != 0 && error != NFSERR_RETVOID) {
475                                 nfsrvstats.srv_errs++;
476                                 nfsrv_updatecache(nd, FALSE, mreq);
477                                 if (nd->nd_nam2)
478                                         FREE(nd->nd_nam2, M_SONAME);
479                                 break;
480                         }
481                         nfsrvstats.srvrpccnt[nd->nd_procnum]++;
482                         nfsrv_updatecache(nd, TRUE, mreq);
483                         nd->nd_mrep = NULL;
484                         /* FALLTHROUGH */
485                     case RC_REPLY:
486                         NFSD_UNLOCK();
487                         siz = m_length(mreq, NULL);
488                         if (siz <= 0 || siz > NFS_MAXPACKET) {
489                                 printf("mbuf siz=%d\n",siz);
490                                 panic("Bad nfs svc reply");
491                         }
492                         m = mreq;
493                         m->m_pkthdr.len = siz;
494                         m->m_pkthdr.rcvif = NULL;
495                         /*
496                          * For stream protocols, prepend a Sun RPC
497                          * Record Mark.
498                          */
499                         if (sotype == SOCK_STREAM) {
500                                 M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT);
501                                 *mtod(m, u_int32_t *) = htonl(0x80000000 | siz);
502                         }
503                         NFSD_LOCK();
504                         if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED)
505                                 (void) nfs_slplock(slp, 1);
506                         if (slp->ns_flag & SLP_VALID) {
507                             NFSD_UNLOCK();
508                             error = nfsrv_send(slp->ns_so, nd->nd_nam2, m);
509                             NFSD_LOCK();
510                         } else {
511                             error = EPIPE;
512                             m_freem(m);
513                         }
514                         if (nd->nd_nam2)
515                                 FREE(nd->nd_nam2, M_SONAME);
516                         if (nd->nd_mrep)
517                                 m_freem(nd->nd_mrep);
518                         if (error == EPIPE)
519                                 nfsrv_zapsock(slp);
520                         if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED)
521                                 nfs_slpunlock(slp);
522                         if (error == EINTR || error == ERESTART) {
523                                 if (nd->nd_cr != NULL)
524                                         crfree(nd->nd_cr);
525                                 free((caddr_t)nd, M_NFSRVDESC);
526                                 nfsrv_slpderef(slp);
527                                 s = splnet();
528                                 goto done;
529                         }
530                         break;
531                     case RC_DROPIT:
532                         m_freem(nd->nd_mrep);
533                         if (nd->nd_nam2)
534                                 FREE(nd->nd_nam2, M_SONAME);
535                         break;
536                     };
537                     if (nd) {
538                         if (nd->nd_cr != NULL)
539                                 crfree(nd->nd_cr);
540                         FREE((caddr_t)nd, M_NFSRVDESC);
541                         nd = NULL;
542                     }
543
544                     /*
545                      * Check to see if there are outstanding writes that
546                      * need to be serviced.
547                      */
548                     cur_usec = nfs_curusec();
549                     s = splsoftclock();
550                     if (LIST_FIRST(&slp->ns_tq) &&
551                         LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec) {
552                         cacherep = RC_DOIT;
553                         writes_todo = 1;
554                     } else
555                         writes_todo = 0;
556                     splx(s);
557                 } while (writes_todo);
558                 s = splnet();
559                 if (nfsrv_dorec(slp, nfsd, &nd)) {
560                         nfsd->nfsd_flag &= ~NFSD_REQINPROG;
561                         nfsd->nfsd_slp = NULL;
562                         nfsrv_slpderef(slp);
563                 }
564                 KASSERT(!(debug_mpsafenet == 0 && !mtx_owned(&Giant)),
565                     ("nfssvc_nfsd(): debug.mpsafenet=0 && !Giant"));
566                 KASSERT(!(debug_mpsafenet == 1 && mtx_owned(&Giant)),
567                     ("nfssvc_nfsd(): debug.mpsafenet=1 && Giant"));
568         }
569 done:
570         KASSERT(!(debug_mpsafenet == 0 && !mtx_owned(&Giant)),
571             ("nfssvc_nfsd(): debug.mpsafenet=0 && !Giant"));
572         KASSERT(!(debug_mpsafenet == 1 && mtx_owned(&Giant)),
573             ("nfssvc_nfsd(): debug.mpsafenet=1 && Giant"));
574         TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
575         splx(s);
576         free((caddr_t)nfsd, M_NFSD);
577         if (--nfsrv_numnfsd == 0)
578                 nfsrv_init(TRUE);       /* Reinitialize everything */
579         NFSD_UNLOCK();
580         return (error);
581 }
582
583 /*
584  * Shut down a socket associated with an nfssvc_sock structure.
585  * Should be called with the send lock set, if required.
586  * The trick here is to increment the sref at the start, so that the nfsds
587  * will stop using it and clear ns_flag at the end so that it will not be
588  * reassigned during cleanup.
589  */
590 static void
591 nfsrv_zapsock(struct nfssvc_sock *slp)
592 {
593         struct nfsrv_descript *nwp, *nnwp;
594         struct socket *so;
595         struct file *fp;
596         struct nfsrv_rec *rec;
597         int s;
598
599         NET_ASSERT_GIANT();
600         NFSD_LOCK_ASSERT();
601
602         /*
603          * XXXRW: By clearing all flags, other threads/etc should ignore
604          * this slp and we can safely release nfsd_mtx so we can clean
605          * up the slp safely.
606          */
607         slp->ns_flag &= ~SLP_ALLFLAGS;
608         fp = slp->ns_fp;
609         if (fp) {
610                 NFSD_UNLOCK();
611                 slp->ns_fp = NULL;
612                 so = slp->ns_so;
613                 SOCKBUF_LOCK(&so->so_rcv);
614                 so->so_rcv.sb_flags &= ~SB_UPCALL;
615                 SOCKBUF_UNLOCK(&so->so_rcv);
616                 so->so_upcall = NULL;
617                 so->so_upcallarg = NULL;
618                 soshutdown(so, SHUT_RDWR);
619                 closef(fp, NULL);
620                 NFSD_LOCK();
621                 if (slp->ns_nam)
622                         FREE(slp->ns_nam, M_SONAME);
623                 m_freem(slp->ns_raw);
624                 while ((rec = STAILQ_FIRST(&slp->ns_rec)) != NULL) {
625                         STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link);
626                         if (rec->nr_address)
627                                 FREE(rec->nr_address, M_SONAME);
628                         m_freem(rec->nr_packet);
629                         free(rec, M_NFSRVDESC);
630                 }
631                 s = splsoftclock();
632                 for (nwp = LIST_FIRST(&slp->ns_tq); nwp; nwp = nnwp) {
633                         nnwp = LIST_NEXT(nwp, nd_tq);
634                         LIST_REMOVE(nwp, nd_tq);
635                         if (nwp->nd_cr != NULL)
636                                 crfree(nwp->nd_cr);
637                         free((caddr_t)nwp, M_NFSRVDESC);
638                 }
639                 LIST_INIT(&slp->ns_tq);
640                 splx(s);
641         }
642 }
643
644 /*
645  * Derefence a server socket structure. If it has no more references and
646  * is no longer valid, you can throw it away.
647  */
648 void
649 nfsrv_slpderef(struct nfssvc_sock *slp)
650 {
651
652         NFSD_LOCK_ASSERT();
653
654         if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
655                 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
656                 free((caddr_t)slp, M_NFSSVC);
657         }
658 }
659
660 /*
661  * Lock a socket against others.
662  *
663  * XXXRW: Wait argument is always 1 in the caller.  Replace with a real
664  * sleep lock?
665  */
666 int
667 nfs_slplock(struct nfssvc_sock *slp, int wait)
668 {
669         int *statep = &slp->ns_solock;
670
671         NFSD_LOCK_ASSERT();
672
673         if (!wait && (*statep & NFSRV_SNDLOCK))
674                 return(0);      /* already locked, fail */
675         while (*statep & NFSRV_SNDLOCK) {
676                 *statep |= NFSRV_WANTSND;
677                 (void) msleep(statep, &nfsd_mtx, PZERO - 1, "nfsslplck", 0);
678         }
679         *statep |= NFSRV_SNDLOCK;
680         return (1);
681 }
682
683 /*
684  * Unlock the stream socket for others.
685  */
686 void
687 nfs_slpunlock(struct nfssvc_sock *slp)
688 {
689         int *statep = &slp->ns_solock;
690
691         NFSD_LOCK_ASSERT();
692
693         if ((*statep & NFSRV_SNDLOCK) == 0)
694                 panic("nfs slpunlock");
695         *statep &= ~NFSRV_SNDLOCK;
696         if (*statep & NFSRV_WANTSND) {
697                 *statep &= ~NFSRV_WANTSND;
698                 wakeup(statep);
699         }
700 }
701
702 /*
703  * Initialize the data structures for the server.
704  * Handshake with any new nfsds starting up to avoid any chance of
705  * corruption.
706  */
707 void
708 nfsrv_init(int terminating)
709 {
710         struct nfssvc_sock *slp, *nslp;
711
712         NET_ASSERT_GIANT();
713         NFSD_LOCK_ASSERT();
714
715         if (nfssvc_sockhead_flag & SLP_INIT)
716                 panic("nfsd init");
717         nfssvc_sockhead_flag |= SLP_INIT;
718         if (terminating) {
719                 TAILQ_FOREACH_SAFE(slp, &nfssvc_sockhead, ns_chain, nslp) {
720                         if (slp->ns_flag & SLP_VALID)
721                                 nfsrv_zapsock(slp);
722                         TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
723                         free((caddr_t)slp, M_NFSSVC);
724                 }
725                 nfsrv_cleancache();     /* And clear out server cache */
726         } else
727                 nfs_pub.np_valid = 0;
728
729         TAILQ_INIT(&nfssvc_sockhead);
730         nfssvc_sockhead_flag &= ~SLP_INIT;
731         if (nfssvc_sockhead_flag & SLP_WANTINIT) {
732                 nfssvc_sockhead_flag &= ~SLP_WANTINIT;
733                 wakeup(&nfssvc_sockhead);
734         }
735
736         TAILQ_INIT(&nfsd_head);
737         nfsd_head_flag &= ~NFSD_CHECKSLP;
738
739 #if 0
740         nfs_udpsock = (struct nfssvc_sock *)
741             malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO);
742         STAILQ_INIT(&nfs_udpsock->ns_rec);
743         TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
744
745         nfs_cltpsock = (struct nfssvc_sock *)
746             malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO);
747         STAILQ_INIT(&nfs_cltpsock->ns_rec);
748         TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
749 #endif
750 }