Home | History | Annotate | Line # | Download | only in nfs
nfs_socket.c revision 1.112
      1  1.112     perry /*	$NetBSD: nfs_socket.c,v 1.112 2005/02/26 22:39:50 perry Exp $	*/
      2   1.15       cgd 
      3    1.1       cgd /*
      4   1.24      fvdl  * Copyright (c) 1989, 1991, 1993, 1995
      5   1.14   mycroft  *	The Regents of the University of California.  All rights reserved.
      6    1.1       cgd  *
      7    1.1       cgd  * This code is derived from software contributed to Berkeley by
      8    1.1       cgd  * Rick Macklem at The University of Guelph.
      9    1.1       cgd  *
     10    1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11    1.1       cgd  * modification, are permitted provided that the following conditions
     12    1.1       cgd  * are met:
     13    1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14    1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15    1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16    1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17    1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18   1.96       agc  * 3. Neither the name of the University nor the names of its contributors
     19    1.1       cgd  *    may be used to endorse or promote products derived from this software
     20    1.1       cgd  *    without specific prior written permission.
     21    1.1       cgd  *
     22    1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23    1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24    1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25    1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26    1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27    1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28    1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29    1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30    1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31    1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32    1.1       cgd  * SUCH DAMAGE.
     33    1.1       cgd  *
     34   1.24      fvdl  *	@(#)nfs_socket.c	8.5 (Berkeley) 3/30/95
     35    1.1       cgd  */
     36    1.1       cgd 
     37    1.1       cgd /*
     38    1.1       cgd  * Socket operations for use by nfs
     39    1.1       cgd  */
     40   1.69     lukem 
     41   1.69     lukem #include <sys/cdefs.h>
     42  1.112     perry __KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.112 2005/02/26 22:39:50 perry Exp $");
     43   1.42   thorpej 
     44   1.42   thorpej #include "fs_nfs.h"
     45   1.59     bjh21 #include "opt_nfs.h"
     46   1.44   thorpej #include "opt_nfsserver.h"
     47   1.89    martin #include "opt_mbuftrace.h"
     48   1.57      fvdl #include "opt_inet.h"
     49    1.1       cgd 
     50    1.9   mycroft #include <sys/param.h>
     51    1.9   mycroft #include <sys/systm.h>
     52   1.54   thorpej #include <sys/callout.h>
     53    1.9   mycroft #include <sys/proc.h>
     54    1.9   mycroft #include <sys/mount.h>
     55    1.9   mycroft #include <sys/kernel.h>
     56    1.9   mycroft #include <sys/mbuf.h>
     57    1.9   mycroft #include <sys/vnode.h>
     58    1.9   mycroft #include <sys/domain.h>
     59    1.9   mycroft #include <sys/protosw.h>
     60    1.9   mycroft #include <sys/socket.h>
     61    1.9   mycroft #include <sys/socketvar.h>
     62    1.9   mycroft #include <sys/syslog.h>
     63    1.9   mycroft #include <sys/tprintf.h>
     64   1.23  christos #include <sys/namei.h>
     65   1.47   mycroft #include <sys/signal.h>
     66   1.47   mycroft #include <sys/signalvar.h>
     67    1.1       cgd 
     68    1.9   mycroft #include <netinet/in.h>
     69    1.9   mycroft #include <netinet/tcp.h>
     70   1.24      fvdl 
     71    1.9   mycroft #include <nfs/rpcv2.h>
     72   1.24      fvdl #include <nfs/nfsproto.h>
     73    1.9   mycroft #include <nfs/nfs.h>
     74    1.9   mycroft #include <nfs/xdr_subs.h>
     75    1.9   mycroft #include <nfs/nfsm_subs.h>
     76    1.9   mycroft #include <nfs/nfsmount.h>
     77   1.14   mycroft #include <nfs/nfsnode.h>
     78   1.14   mycroft #include <nfs/nfsrtt.h>
     79   1.14   mycroft #include <nfs/nqnfs.h>
     80   1.23  christos #include <nfs/nfs_var.h>
     81   1.78   thorpej 
     82   1.78   thorpej MALLOC_DEFINE(M_NFSREQ, "NFS req", "NFS request header");
     83   1.79      matt #ifdef MBUFTRACE
     84   1.79      matt struct mowner nfs_mowner = { "nfs" };
     85   1.79      matt #endif
     86    1.1       cgd 
     87    1.1       cgd /*
     88   1.14   mycroft  * Estimate rto for an nfs rpc sent via. an unreliable datagram.
     89   1.14   mycroft  * Use the mean and mean deviation of rtt for the appropriate type of rpc
     90   1.14   mycroft  * for the frequent rpcs and a default for the others.
     91   1.14   mycroft  * The justification for doing "other" this way is that these rpcs
     92   1.14   mycroft  * happen so infrequently that timer est. would probably be stale.
     93   1.14   mycroft  * Also, since many of these rpcs are
     94   1.14   mycroft  * non-idempotent, a conservative timeout is desired.
     95   1.14   mycroft  * getattr, lookup - A+2D
     96   1.14   mycroft  * read, write     - A+4D
     97   1.14   mycroft  * other           - nm_timeo
     98   1.14   mycroft  */
     99   1.14   mycroft #define	NFS_RTO(n, t) \
    100   1.14   mycroft 	((t) == 0 ? (n)->nm_timeo : \
    101   1.14   mycroft 	 ((t) < 3 ? \
    102   1.14   mycroft 	  (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \
    103   1.14   mycroft 	  ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1)))
    104   1.14   mycroft #define	NFS_SRTT(r)	(r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1]
    105   1.14   mycroft #define	NFS_SDRTT(r)	(r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1]
    106   1.14   mycroft /*
    107    1.1       cgd  * External data, mostly RPC constants in XDR form
    108    1.1       cgd  */
    109   1.22       cgd extern u_int32_t rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers,
    110   1.24      fvdl 	rpc_auth_unix, rpc_msgaccepted, rpc_call, rpc_autherr,
    111   1.14   mycroft 	rpc_auth_kerb;
    112   1.24      fvdl extern u_int32_t nfs_prog, nqnfs_prog;
    113   1.14   mycroft extern time_t nqnfsstarttime;
    114   1.77      matt extern const int nfsv3_procid[NFS_NPROCS];
    115   1.24      fvdl extern int nfs_ticks;
    116   1.14   mycroft 
    117   1.14   mycroft /*
    118   1.14   mycroft  * Defines which timer to use for the procnum.
    119   1.14   mycroft  * 0 - default
    120   1.14   mycroft  * 1 - getattr
    121   1.14   mycroft  * 2 - lookup
    122   1.14   mycroft  * 3 - read
    123   1.14   mycroft  * 4 - write
    124   1.14   mycroft  */
    125   1.66  jdolecek static const int proct[NFS_NPROCS] = {
    126   1.24      fvdl 	0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0,
    127   1.24      fvdl 	0, 0, 0,
    128    1.1       cgd };
    129   1.14   mycroft 
    130   1.14   mycroft /*
    131   1.14   mycroft  * There is a congestion window for outstanding rpcs maintained per mount
    132   1.14   mycroft  * point. The cwnd size is adjusted in roughly the way that:
    133   1.14   mycroft  * Van Jacobson, Congestion avoidance and Control, In "Proceedings of
    134   1.14   mycroft  * SIGCOMM '88". ACM, August 1988.
    135   1.14   mycroft  * describes for TCP. The cwnd size is chopped in half on a retransmit timeout
    136   1.14   mycroft  * and incremented by 1/cwnd when each rpc reply is received and a full cwnd
    137   1.14   mycroft  * of rpcs is in progress.
    138   1.14   mycroft  * (The sent count and cwnd are scaled for integer arith.)
    139   1.14   mycroft  * Variants of "slow start" were tried and were found to be too much of a
    140   1.14   mycroft  * performance hit (ave. rtt 3 times larger),
    141   1.14   mycroft  * I suspect due to the large rtt that nfs rpcs have.
    142   1.14   mycroft  */
    143   1.14   mycroft #define	NFS_CWNDSCALE	256
    144   1.14   mycroft #define	NFS_MAXCWND	(NFS_CWNDSCALE * 32)
    145   1.66  jdolecek static const int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };
    146   1.14   mycroft int nfsrtton = 0;
    147   1.14   mycroft struct nfsrtt nfsrtt;
    148   1.74      matt struct nfsreqhead nfs_reqq;
    149    1.1       cgd 
    150   1.99      yamt struct callout nfs_timer_ch = CALLOUT_INITIALIZER_SETFUNC(nfs_timer, NULL);
    151   1.54   thorpej 
    152    1.1       cgd /*
    153    1.1       cgd  * Initialize sockets and congestion for a new NFS connection.
    154    1.1       cgd  * We do not free the sockaddr if error.
    155    1.1       cgd  */
    156   1.23  christos int
    157  1.105  jonathan nfs_connect(nmp, rep, p)
    158   1.55  augustss 	struct nfsmount *nmp;
    159   1.14   mycroft 	struct nfsreq *rep;
    160  1.105  jonathan 	struct proc *p;
    161    1.1       cgd {
    162   1.55  augustss 	struct socket *so;
    163   1.14   mycroft 	int s, error, rcvreserve, sndreserve;
    164   1.11       cgd 	struct sockaddr *saddr;
    165   1.14   mycroft 	struct sockaddr_in *sin;
    166   1.57      fvdl #ifdef INET6
    167   1.57      fvdl 	struct sockaddr_in6 *sin6;
    168   1.57      fvdl #endif
    169    1.1       cgd 	struct mbuf *m;
    170    1.1       cgd 
    171    1.1       cgd 	nmp->nm_so = (struct socket *)0;
    172   1.11       cgd 	saddr = mtod(nmp->nm_nam, struct sockaddr *);
    173  1.105  jonathan 	error = socreate(saddr->sa_family, &nmp->nm_so,
    174  1.105  jonathan 		nmp->nm_sotype, nmp->nm_soproto, p);
    175   1.23  christos 	if (error)
    176    1.1       cgd 		goto bad;
    177    1.1       cgd 	so = nmp->nm_so;
    178   1.79      matt #ifdef MBUFTRACE
    179   1.79      matt 	so->so_mowner = &nfs_mowner;
    180   1.79      matt 	so->so_rcv.sb_mowner = &nfs_mowner;
    181   1.79      matt 	so->so_snd.sb_mowner = &nfs_mowner;
    182   1.79      matt #endif
    183    1.1       cgd 	nmp->nm_soflags = so->so_proto->pr_flags;
    184    1.1       cgd 
    185    1.2       cgd 	/*
    186    1.2       cgd 	 * Some servers require that the client port be a reserved port number.
    187    1.2       cgd 	 */
    188   1.14   mycroft 	if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
    189   1.79      matt 		m = m_get(M_WAIT, MT_SOOPTS);
    190   1.79      matt 		MCLAIM(m, so->so_mowner);
    191   1.72     lukem 		*mtod(m, int32_t *) = IP_PORTRANGE_LOW;
    192   1.72     lukem 		m->m_len = sizeof(int32_t);
    193   1.72     lukem 		if ((error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, m)))
    194   1.72     lukem 			goto bad;
    195   1.79      matt 		m = m_get(M_WAIT, MT_SONAME);
    196   1.79      matt 		MCLAIM(m, so->so_mowner);
    197    1.2       cgd 		sin = mtod(m, struct sockaddr_in *);
    198    1.2       cgd 		sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
    199    1.2       cgd 		sin->sin_family = AF_INET;
    200    1.2       cgd 		sin->sin_addr.s_addr = INADDR_ANY;
    201   1.72     lukem 		sin->sin_port = 0;
    202   1.92      fvdl 		error = sobind(so, m, &proc0);
    203    1.2       cgd 		m_freem(m);
    204   1.14   mycroft 		if (error)
    205   1.14   mycroft 			goto bad;
    206    1.2       cgd 	}
    207   1.57      fvdl #ifdef INET6
    208   1.57      fvdl 	if (saddr->sa_family == AF_INET6 && (nmp->nm_flag & NFSMNT_RESVPORT)) {
    209   1.79      matt 		m = m_get(M_WAIT, MT_SOOPTS);
    210   1.79      matt 		MCLAIM(m, so->so_mowner);
    211   1.72     lukem 		*mtod(m, int32_t *) = IPV6_PORTRANGE_LOW;
    212   1.72     lukem 		m->m_len = sizeof(int32_t);
    213   1.72     lukem 		if ((error = sosetopt(so, IPPROTO_IPV6, IPV6_PORTRANGE, m)))
    214   1.72     lukem 			goto bad;
    215   1.79      matt 		m = m_get(M_WAIT, MT_SONAME);
    216   1.79      matt 		MCLAIM(m, so->so_mowner);
    217   1.57      fvdl 		sin6 = mtod(m, struct sockaddr_in6 *);
    218   1.57      fvdl 		sin6->sin6_len = m->m_len = sizeof (struct sockaddr_in6);
    219   1.57      fvdl 		sin6->sin6_family = AF_INET6;
    220   1.57      fvdl 		sin6->sin6_addr = in6addr_any;
    221   1.72     lukem 		sin6->sin6_port = 0;
    222   1.92      fvdl 		error = sobind(so, m, &proc0);
    223   1.57      fvdl 		m_freem(m);
    224   1.57      fvdl 		if (error)
    225   1.57      fvdl 			goto bad;
    226   1.57      fvdl 	}
    227   1.57      fvdl #endif
    228    1.2       cgd 
    229    1.1       cgd 	/*
    230    1.1       cgd 	 * Protocols that do not require connections may be optionally left
    231    1.1       cgd 	 * unconnected for servers that reply from a port other than NFS_PORT.
    232    1.1       cgd 	 */
    233    1.1       cgd 	if (nmp->nm_flag & NFSMNT_NOCONN) {
    234    1.1       cgd 		if (nmp->nm_soflags & PR_CONNREQUIRED) {
    235    1.1       cgd 			error = ENOTCONN;
    236    1.1       cgd 			goto bad;
    237    1.1       cgd 		}
    238    1.1       cgd 	} else {
    239  1.105  jonathan 		error = soconnect(so, nmp->nm_nam, p);
    240   1.24      fvdl 		if (error)
    241    1.1       cgd 			goto bad;
    242    1.1       cgd 
    243    1.1       cgd 		/*
    244    1.1       cgd 		 * Wait for the connection to complete. Cribbed from the
    245   1.14   mycroft 		 * connect system call but with the wait timing out so
    246   1.14   mycroft 		 * that interruptible mounts don't hang here for a long time.
    247    1.1       cgd 		 */
    248   1.21   mycroft 		s = splsoftnet();
    249   1.14   mycroft 		while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
    250   1.14   mycroft 			(void) tsleep((caddr_t)&so->so_timeo, PSOCK,
    251   1.48      fvdl 				"nfscn1", 2 * hz);
    252   1.14   mycroft 			if ((so->so_state & SS_ISCONNECTING) &&
    253   1.14   mycroft 			    so->so_error == 0 && rep &&
    254   1.92      fvdl 			    (error = nfs_sigintr(nmp, rep, rep->r_procp)) != 0){
    255   1.14   mycroft 				so->so_state &= ~SS_ISCONNECTING;
    256   1.14   mycroft 				splx(s);
    257   1.14   mycroft 				goto bad;
    258   1.14   mycroft 			}
    259   1.14   mycroft 		}
    260    1.1       cgd 		if (so->so_error) {
    261    1.1       cgd 			error = so->so_error;
    262   1.14   mycroft 			so->so_error = 0;
    263   1.14   mycroft 			splx(s);
    264    1.1       cgd 			goto bad;
    265    1.1       cgd 		}
    266   1.14   mycroft 		splx(s);
    267   1.14   mycroft 	}
    268   1.14   mycroft 	if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
    269   1.14   mycroft 		so->so_rcv.sb_timeo = (5 * hz);
    270   1.14   mycroft 		so->so_snd.sb_timeo = (5 * hz);
    271   1.14   mycroft 	} else {
    272  1.106      yamt 		/*
    273  1.106      yamt 		 * enable receive timeout to detect server crash and reconnect.
    274  1.106      yamt 		 * otherwise, we can be stuck in soreceive forever.
    275  1.106      yamt 		 */
    276  1.106      yamt 		so->so_rcv.sb_timeo = (5 * hz);
    277   1.14   mycroft 		so->so_snd.sb_timeo = 0;
    278    1.1       cgd 	}
    279    1.1       cgd 	if (nmp->nm_sotype == SOCK_DGRAM) {
    280   1.37      fvdl 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2;
    281   1.37      fvdl 		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
    282   1.37      fvdl 		    NFS_MAXPKTHDR) * 2;
    283   1.14   mycroft 	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
    284   1.26      fvdl 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2;
    285   1.26      fvdl 		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
    286   1.25      fvdl 		    NFS_MAXPKTHDR) * 2;
    287    1.1       cgd 	} else {
    288   1.14   mycroft 		if (nmp->nm_sotype != SOCK_STREAM)
    289   1.14   mycroft 			panic("nfscon sotype");
    290    1.1       cgd 		if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
    291   1.79      matt 			m = m_get(M_WAIT, MT_SOOPTS);
    292   1.79      matt 			MCLAIM(m, so->so_mowner);
    293   1.22       cgd 			*mtod(m, int32_t *) = 1;
    294   1.22       cgd 			m->m_len = sizeof(int32_t);
    295    1.1       cgd 			sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
    296    1.1       cgd 		}
    297   1.14   mycroft 		if (so->so_proto->pr_protocol == IPPROTO_TCP) {
    298   1.79      matt 			m = m_get(M_WAIT, MT_SOOPTS);
    299   1.79      matt 			MCLAIM(m, so->so_mowner);
    300   1.22       cgd 			*mtod(m, int32_t *) = 1;
    301   1.22       cgd 			m->m_len = sizeof(int32_t);
    302    1.1       cgd 			sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
    303    1.1       cgd 		}
    304   1.22       cgd 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
    305   1.22       cgd 		    sizeof (u_int32_t)) * 2;
    306   1.22       cgd 		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
    307   1.22       cgd 		    sizeof (u_int32_t)) * 2;
    308    1.1       cgd 	}
    309   1.24      fvdl 	error = soreserve(so, sndreserve, rcvreserve);
    310   1.24      fvdl 	if (error)
    311   1.14   mycroft 		goto bad;
    312    1.1       cgd 	so->so_rcv.sb_flags |= SB_NOINTR;
    313    1.1       cgd 	so->so_snd.sb_flags |= SB_NOINTR;
    314    1.1       cgd 
    315    1.1       cgd 	/* Initialize other non-zero congestion variables */
    316   1.14   mycroft 	nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] =
    317   1.68    simonb 		NFS_TIMEO << 3;
    318   1.14   mycroft 	nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] =
    319   1.68    simonb 		nmp->nm_sdrtt[3] = 0;
    320   1.14   mycroft 	nmp->nm_cwnd = NFS_MAXCWND / 2;	    /* Initial send window */
    321    1.1       cgd 	nmp->nm_sent = 0;
    322   1.14   mycroft 	nmp->nm_timeouts = 0;
    323    1.1       cgd 	return (0);
    324    1.1       cgd 
    325    1.1       cgd bad:
    326    1.1       cgd 	nfs_disconnect(nmp);
    327    1.1       cgd 	return (error);
    328    1.1       cgd }
    329    1.1       cgd 
    330    1.1       cgd /*
    331    1.1       cgd  * Reconnect routine:
    332    1.1       cgd  * Called when a connection is broken on a reliable protocol.
    333    1.1       cgd  * - clean up the old socket
    334    1.1       cgd  * - nfs_connect() again
    335    1.1       cgd  * - set R_MUSTRESEND for all outstanding requests on mount point
    336    1.1       cgd  * If this fails the mount point is DEAD!
    337   1.14   mycroft  * nb: Must be called with the nfs_sndlock() set on the mount point.
    338    1.1       cgd  */
    339   1.23  christos int
    340  1.105  jonathan nfs_reconnect(rep, p)
    341   1.55  augustss 	struct nfsreq *rep;
    342  1.105  jonathan 	struct proc *p;
    343    1.1       cgd {
    344   1.55  augustss 	struct nfsreq *rp;
    345   1.55  augustss 	struct nfsmount *nmp = rep->r_nmp;
    346    1.1       cgd 	int error;
    347    1.1       cgd 
    348   1.14   mycroft 	nfs_disconnect(nmp);
    349  1.105  jonathan 	while ((error = nfs_connect(nmp, rep, p)) != 0) {
    350   1.14   mycroft 		if (error == EINTR || error == ERESTART)
    351    1.1       cgd 			return (EINTR);
    352   1.48      fvdl 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfscn2", 0);
    353    1.1       cgd 	}
    354    1.1       cgd 
    355    1.1       cgd 	/*
    356    1.1       cgd 	 * Loop through outstanding request list and fix up all requests
    357    1.1       cgd 	 * on old socket.
    358    1.1       cgd 	 */
    359   1.73  christos 	TAILQ_FOREACH(rp, &nfs_reqq, r_chain) {
    360  1.106      yamt 		if (rp->r_nmp == nmp) {
    361  1.106      yamt 			if ((rp->r_flags & R_MUSTRESEND) == 0)
    362  1.106      yamt 				rp->r_flags |= R_MUSTRESEND | R_REXMITTED;
    363  1.106      yamt 			rp->r_rexmit = 0;
    364  1.106      yamt 		}
    365    1.1       cgd 	}
    366    1.1       cgd 	return (0);
    367    1.1       cgd }
    368    1.1       cgd 
    369    1.1       cgd /*
    370    1.1       cgd  * NFS disconnect. Clean up and unlink.
    371    1.1       cgd  */
    372    1.1       cgd void
    373    1.1       cgd nfs_disconnect(nmp)
    374   1.55  augustss 	struct nfsmount *nmp;
    375    1.1       cgd {
    376   1.55  augustss 	struct socket *so;
    377   1.53  sommerfe 	int drain = 0;
    378  1.112     perry 
    379    1.1       cgd 	if (nmp->nm_so) {
    380    1.1       cgd 		so = nmp->nm_so;
    381    1.1       cgd 		nmp->nm_so = (struct socket *)0;
    382    1.1       cgd 		soshutdown(so, 2);
    383   1.53  sommerfe 		drain = (nmp->nm_iflag & NFSMNT_DISMNT) != 0;
    384   1.53  sommerfe 		if (drain) {
    385   1.51  sommerfe 			/*
    386   1.51  sommerfe 			 * soshutdown() above should wake up the current
    387   1.51  sommerfe 			 * listener.
    388   1.71   minoura 			 * Now wake up those waiting for the receive lock, and
    389   1.51  sommerfe 			 * wait for them to go away unhappy, to prevent *nmp
    390   1.51  sommerfe 			 * from evaporating while they're sleeping.
    391   1.51  sommerfe 			 */
    392   1.51  sommerfe 			while (nmp->nm_waiters > 0) {
    393   1.51  sommerfe 				wakeup (&nmp->nm_iflag);
    394   1.56   thorpej 				(void) tsleep(&nmp->nm_waiters, PVFS,
    395   1.56   thorpej 				    "nfsdis", 0);
    396   1.51  sommerfe 			}
    397   1.51  sommerfe 		}
    398    1.1       cgd 		soclose(so);
    399   1.41      fvdl 	}
    400   1.51  sommerfe #ifdef DIAGNOSTIC
    401   1.53  sommerfe 	if (drain && (nmp->nm_waiters > 0))
    402   1.76    provos 		panic("nfs_disconnect: waiters left after drain?");
    403   1.51  sommerfe #endif
    404   1.41      fvdl }
    405   1.40      fvdl 
    406   1.41      fvdl void
    407   1.41      fvdl nfs_safedisconnect(nmp)
    408   1.41      fvdl 	struct nfsmount *nmp;
    409   1.41      fvdl {
    410   1.41      fvdl 	struct nfsreq dummyreq;
    411   1.41      fvdl 
    412   1.46     perry 	memset(&dummyreq, 0, sizeof(dummyreq));
    413   1.41      fvdl 	dummyreq.r_nmp = nmp;
    414   1.51  sommerfe 	nfs_rcvlock(&dummyreq); /* XXX ignored error return */
    415   1.41      fvdl 	nfs_disconnect(nmp);
    416   1.87      yamt 	nfs_rcvunlock(nmp);
    417    1.1       cgd }
    418    1.1       cgd 
    419    1.1       cgd /*
    420    1.1       cgd  * This is the nfs send routine. For connection based socket types, it
    421   1.14   mycroft  * must be called with an nfs_sndlock() on the socket.
    422    1.1       cgd  * "rep == NULL" indicates that it has been called from a server.
    423   1.14   mycroft  * For the client side:
    424   1.14   mycroft  * - return EINTR if the RPC is terminated, 0 otherwise
    425   1.14   mycroft  * - set R_MUSTRESEND if the send fails for any reason
    426   1.58       mrg  * - do any cleanup required by recoverable socket errors (? ? ?)
    427   1.14   mycroft  * For the server side:
    428   1.14   mycroft  * - return EINTR or ERESTART if interrupted by a signal
    429   1.14   mycroft  * - return EPIPE if a connection is lost for connection based sockets (TCP...)
    430   1.58       mrg  * - do any cleanup required by recoverable socket errors (? ? ?)
    431    1.1       cgd  */
    432   1.23  christos int
    433  1.105  jonathan nfs_send(so, nam, top, rep, p)
    434   1.55  augustss 	struct socket *so;
    435    1.1       cgd 	struct mbuf *nam;
    436   1.55  augustss 	struct mbuf *top;
    437    1.1       cgd 	struct nfsreq *rep;
    438  1.105  jonathan 	struct proc *p;
    439    1.1       cgd {
    440    1.1       cgd 	struct mbuf *sendnam;
    441   1.14   mycroft 	int error, soflags, flags;
    442    1.1       cgd 
    443  1.105  jonathan 	/* XXX nfs_doio()/nfs_request() calls with  rep->r_procp == NULL */
    444  1.109      yamt 	if (p == NULL && rep->r_procp == NULL)
    445  1.105  jonathan 		p = curproc;
    446  1.105  jonathan 
    447    1.1       cgd 	if (rep) {
    448    1.1       cgd 		if (rep->r_flags & R_SOFTTERM) {
    449    1.1       cgd 			m_freem(top);
    450    1.1       cgd 			return (EINTR);
    451    1.1       cgd 		}
    452   1.14   mycroft 		if ((so = rep->r_nmp->nm_so) == NULL) {
    453   1.14   mycroft 			rep->r_flags |= R_MUSTRESEND;
    454   1.14   mycroft 			m_freem(top);
    455   1.14   mycroft 			return (0);
    456   1.14   mycroft 		}
    457    1.1       cgd 		rep->r_flags &= ~R_MUSTRESEND;
    458    1.1       cgd 		soflags = rep->r_nmp->nm_soflags;
    459    1.1       cgd 	} else
    460    1.1       cgd 		soflags = so->so_proto->pr_flags;
    461    1.1       cgd 	if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
    462    1.1       cgd 		sendnam = (struct mbuf *)0;
    463    1.1       cgd 	else
    464    1.1       cgd 		sendnam = nam;
    465   1.14   mycroft 	if (so->so_type == SOCK_SEQPACKET)
    466   1.14   mycroft 		flags = MSG_EOR;
    467   1.14   mycroft 	else
    468   1.14   mycroft 		flags = 0;
    469    1.1       cgd 
    470   1.43      matt 	error = (*so->so_send)(so, sendnam, (struct uio *)0, top,
    471  1.105  jonathan 		    (struct mbuf *)0, flags,  p);
    472   1.14   mycroft 	if (error) {
    473   1.14   mycroft 		if (rep) {
    474   1.60      fvdl 			if (error == ENOBUFS && so->so_type == SOCK_DGRAM) {
    475   1.60      fvdl 				/*
    476   1.60      fvdl 				 * We're too fast for the network/driver,
    477   1.60      fvdl 				 * and UDP isn't flowcontrolled.
    478   1.60      fvdl 				 * We need to resend. This is not fatal,
    479   1.60      fvdl 				 * just try again.
    480   1.60      fvdl 				 *
    481   1.60      fvdl 				 * Could be smarter here by doing some sort
    482   1.60      fvdl 				 * of a backoff, but this is rare.
    483   1.60      fvdl 				 */
    484   1.14   mycroft 				rep->r_flags |= R_MUSTRESEND;
    485   1.60      fvdl 			} else {
    486  1.101      matt 				if (error != EPIPE)
    487  1.101      matt 					log(LOG_INFO,
    488  1.101      matt 					    "nfs send error %d for %s\n",
    489  1.101      matt 					    error,
    490  1.101      matt 					    rep->r_nmp->nm_mountp->
    491  1.101      matt 						    mnt_stat.f_mntfromname);
    492   1.60      fvdl 				/*
    493   1.60      fvdl 				 * Deal with errors for the client side.
    494   1.60      fvdl 				 */
    495   1.60      fvdl 				if (rep->r_flags & R_SOFTTERM)
    496   1.60      fvdl 					error = EINTR;
    497   1.60      fvdl 				else
    498   1.60      fvdl 					rep->r_flags |= R_MUSTRESEND;
    499   1.60      fvdl 			}
    500   1.67      fvdl 		} else {
    501   1.67      fvdl 			/*
    502   1.67      fvdl 			 * See above. This error can happen under normal
    503   1.67      fvdl 			 * circumstances and the log is too noisy.
    504   1.67      fvdl 			 * The error will still show up in nfsstat.
    505   1.67      fvdl 			 */
    506   1.67      fvdl 			if (error != ENOBUFS || so->so_type != SOCK_DGRAM)
    507   1.67      fvdl 				log(LOG_INFO, "nfsd send error %d\n", error);
    508   1.67      fvdl 		}
    509   1.14   mycroft 
    510   1.14   mycroft 		/*
    511   1.58       mrg 		 * Handle any recoverable (soft) socket errors here. (? ? ?)
    512   1.14   mycroft 		 */
    513   1.14   mycroft 		if (error != EINTR && error != ERESTART &&
    514   1.14   mycroft 			error != EWOULDBLOCK && error != EPIPE)
    515    1.1       cgd 			error = 0;
    516    1.1       cgd 	}
    517    1.1       cgd 	return (error);
    518    1.1       cgd }
    519    1.1       cgd 
    520   1.32   thorpej #ifdef NFS
    521    1.1       cgd /*
    522    1.1       cgd  * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
    523    1.1       cgd  * done by soreceive(), but for SOCK_STREAM we must deal with the Record
    524    1.1       cgd  * Mark and consolidate the data into a new mbuf list.
    525    1.1       cgd  * nb: Sometimes TCP passes the data up to soreceive() in long lists of
    526    1.1       cgd  *     small mbufs.
    527    1.1       cgd  * For SOCK_STREAM we must be very careful to read an entire record once
    528    1.1       cgd  * we have read any of it, even if the system call has been interrupted.
    529    1.1       cgd  */
    530   1.23  christos int
    531  1.105  jonathan nfs_receive(rep, aname, mp, p)
    532   1.55  augustss 	struct nfsreq *rep;
    533    1.1       cgd 	struct mbuf **aname;
    534    1.1       cgd 	struct mbuf **mp;
    535  1.105  jonathan 	struct proc *p;
    536    1.1       cgd {
    537   1.55  augustss 	struct socket *so;
    538    1.1       cgd 	struct uio auio;
    539    1.1       cgd 	struct iovec aio;
    540   1.55  augustss 	struct mbuf *m;
    541   1.14   mycroft 	struct mbuf *control;
    542   1.22       cgd 	u_int32_t len;
    543    1.1       cgd 	struct mbuf **getnam;
    544   1.14   mycroft 	int error, sotype, rcvflg;
    545    1.1       cgd 
    546    1.1       cgd 	/*
    547    1.1       cgd 	 * Set up arguments for soreceive()
    548    1.1       cgd 	 */
    549    1.1       cgd 	*mp = (struct mbuf *)0;
    550    1.1       cgd 	*aname = (struct mbuf *)0;
    551   1.14   mycroft 	sotype = rep->r_nmp->nm_sotype;
    552    1.1       cgd 
    553    1.1       cgd 	/*
    554    1.1       cgd 	 * For reliable protocols, lock against other senders/receivers
    555    1.1       cgd 	 * in case a reconnect is necessary.
    556    1.1       cgd 	 * For SOCK_STREAM, first get the Record Mark to find out how much
    557    1.1       cgd 	 * more there is to get.
    558    1.1       cgd 	 * We must lock the socket against other receivers
    559    1.1       cgd 	 * until we have an entire rpc request/reply.
    560    1.1       cgd 	 */
    561   1.14   mycroft 	if (sotype != SOCK_DGRAM) {
    562   1.39      fvdl 		error = nfs_sndlock(&rep->r_nmp->nm_iflag, rep);
    563   1.24      fvdl 		if (error)
    564   1.14   mycroft 			return (error);
    565    1.1       cgd tryagain:
    566    1.1       cgd 		/*
    567    1.1       cgd 		 * Check for fatal errors and resending request.
    568    1.1       cgd 		 */
    569   1.14   mycroft 		/*
    570   1.14   mycroft 		 * Ugh: If a reconnect attempt just happened, nm_so
    571   1.14   mycroft 		 * would have changed. NULL indicates a failed
    572   1.14   mycroft 		 * attempt that has essentially shut down this
    573   1.14   mycroft 		 * mount point.
    574   1.14   mycroft 		 */
    575   1.14   mycroft 		if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {
    576   1.39      fvdl 			nfs_sndunlock(&rep->r_nmp->nm_iflag);
    577   1.14   mycroft 			return (EINTR);
    578   1.14   mycroft 		}
    579   1.24      fvdl 		so = rep->r_nmp->nm_so;
    580   1.24      fvdl 		if (!so) {
    581  1.112     perry 			error = nfs_reconnect(rep, p);
    582   1.24      fvdl 			if (error) {
    583   1.39      fvdl 				nfs_sndunlock(&rep->r_nmp->nm_iflag);
    584   1.14   mycroft 				return (error);
    585   1.14   mycroft 			}
    586   1.14   mycroft 			goto tryagain;
    587   1.14   mycroft 		}
    588   1.14   mycroft 		while (rep->r_flags & R_MUSTRESEND) {
    589   1.14   mycroft 			m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
    590   1.14   mycroft 			nfsstats.rpcretries++;
    591  1.106      yamt 			rep->r_rtt = 0;
    592  1.106      yamt 			rep->r_flags &= ~R_TIMING;
    593  1.105  jonathan 			error = nfs_send(so, rep->r_nmp->nm_nam, m, rep, p);
    594   1.23  christos 			if (error) {
    595   1.14   mycroft 				if (error == EINTR || error == ERESTART ||
    596  1.105  jonathan 				    (error = nfs_reconnect(rep, p)) != 0) {
    597   1.39      fvdl 					nfs_sndunlock(&rep->r_nmp->nm_iflag);
    598   1.14   mycroft 					return (error);
    599   1.14   mycroft 				}
    600   1.14   mycroft 				goto tryagain;
    601    1.1       cgd 			}
    602    1.1       cgd 		}
    603   1.39      fvdl 		nfs_sndunlock(&rep->r_nmp->nm_iflag);
    604   1.14   mycroft 		if (sotype == SOCK_STREAM) {
    605    1.1       cgd 			aio.iov_base = (caddr_t) &len;
    606   1.22       cgd 			aio.iov_len = sizeof(u_int32_t);
    607    1.1       cgd 			auio.uio_iov = &aio;
    608    1.1       cgd 			auio.uio_iovcnt = 1;
    609    1.1       cgd 			auio.uio_segflg = UIO_SYSSPACE;
    610    1.1       cgd 			auio.uio_rw = UIO_READ;
    611    1.1       cgd 			auio.uio_offset = 0;
    612   1.22       cgd 			auio.uio_resid = sizeof(u_int32_t);
    613  1.111     skrll 			auio.uio_procp = NULL;
    614    1.1       cgd 			do {
    615   1.14   mycroft 			   rcvflg = MSG_WAITALL;
    616   1.43      matt 			   error = (*so->so_receive)(so, (struct mbuf **)0, &auio,
    617    1.1       cgd 				(struct mbuf **)0, (struct mbuf **)0, &rcvflg);
    618   1.14   mycroft 			   if (error == EWOULDBLOCK && rep) {
    619    1.1       cgd 				if (rep->r_flags & R_SOFTTERM)
    620    1.1       cgd 					return (EINTR);
    621  1.106      yamt 				/*
    622  1.106      yamt 				 * if it seems that the server died after it
    623  1.106      yamt 				 * received our request, set EPIPE so that
    624  1.106      yamt 				 * we'll reconnect and retransmit requests.
    625  1.106      yamt 				 */
    626  1.106      yamt 				if (rep->r_rexmit >= rep->r_nmp->nm_retry) {
    627  1.106      yamt 					nfsstats.rpctimeouts++;
    628  1.106      yamt 					error = EPIPE;
    629  1.106      yamt 				}
    630   1.14   mycroft 			   }
    631    1.1       cgd 			} while (error == EWOULDBLOCK);
    632    1.1       cgd 			if (!error && auio.uio_resid > 0) {
    633   1.41      fvdl 			    /*
    634   1.41      fvdl 			     * Don't log a 0 byte receive; it means
    635   1.41      fvdl 			     * that the socket has been closed, and
    636   1.41      fvdl 			     * can happen during normal operation
    637   1.41      fvdl 			     * (forcible unmount or Solaris server).
    638   1.41      fvdl 			     */
    639   1.41      fvdl 			    if (auio.uio_resid != sizeof (u_int32_t))
    640   1.41      fvdl 			      log(LOG_INFO,
    641   1.49   thorpej 				 "short receive (%lu/%lu) from nfs server %s\n",
    642   1.49   thorpej 				 (u_long)sizeof(u_int32_t) - auio.uio_resid,
    643   1.49   thorpej 				 (u_long)sizeof(u_int32_t),
    644    1.1       cgd 				 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    645    1.1       cgd 			    error = EPIPE;
    646    1.1       cgd 			}
    647    1.1       cgd 			if (error)
    648    1.1       cgd 				goto errout;
    649    1.1       cgd 			len = ntohl(len) & ~0x80000000;
    650    1.1       cgd 			/*
    651    1.1       cgd 			 * This is SERIOUS! We are out of sync with the sender
    652    1.1       cgd 			 * and forcing a disconnect/reconnect is all I can do.
    653    1.1       cgd 			 */
    654    1.1       cgd 			if (len > NFS_MAXPACKET) {
    655   1.14   mycroft 			    log(LOG_ERR, "%s (%d) from nfs server %s\n",
    656   1.14   mycroft 				"impossible packet length",
    657   1.14   mycroft 				len,
    658   1.14   mycroft 				rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    659    1.1       cgd 			    error = EFBIG;
    660    1.1       cgd 			    goto errout;
    661    1.1       cgd 			}
    662    1.1       cgd 			auio.uio_resid = len;
    663    1.1       cgd 			do {
    664    1.1       cgd 			    rcvflg = MSG_WAITALL;
    665   1.43      matt 			    error =  (*so->so_receive)(so, (struct mbuf **)0,
    666    1.1       cgd 				&auio, mp, (struct mbuf **)0, &rcvflg);
    667    1.1       cgd 			} while (error == EWOULDBLOCK || error == EINTR ||
    668    1.1       cgd 				 error == ERESTART);
    669    1.1       cgd 			if (!error && auio.uio_resid > 0) {
    670   1.41      fvdl 			    if (len != auio.uio_resid)
    671   1.41      fvdl 			      log(LOG_INFO,
    672   1.49   thorpej 				"short receive (%lu/%d) from nfs server %s\n",
    673   1.49   thorpej 				(u_long)len - auio.uio_resid, len,
    674   1.14   mycroft 				rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    675    1.1       cgd 			    error = EPIPE;
    676    1.1       cgd 			}
    677    1.1       cgd 		} else {
    678   1.14   mycroft 			/*
    679   1.14   mycroft 			 * NB: Since uio_resid is big, MSG_WAITALL is ignored
    680   1.14   mycroft 			 * and soreceive() will return when it has either a
    681   1.14   mycroft 			 * control msg or a data msg.
    682   1.14   mycroft 			 * We have no use for control msg., but must grab them
    683   1.14   mycroft 			 * and then throw them away so we know what is going
    684   1.14   mycroft 			 * on.
    685   1.14   mycroft 			 */
    686   1.14   mycroft 			auio.uio_resid = len = 100000000; /* Anything Big */
    687   1.92      fvdl 			auio.uio_procp = p;
    688    1.1       cgd 			do {
    689    1.1       cgd 			    rcvflg = 0;
    690   1.43      matt 			    error =  (*so->so_receive)(so, (struct mbuf **)0,
    691   1.14   mycroft 				&auio, mp, &control, &rcvflg);
    692   1.14   mycroft 			    if (control)
    693   1.14   mycroft 				m_freem(control);
    694    1.1       cgd 			    if (error == EWOULDBLOCK && rep) {
    695    1.1       cgd 				if (rep->r_flags & R_SOFTTERM)
    696    1.1       cgd 					return (EINTR);
    697    1.1       cgd 			    }
    698   1.14   mycroft 			} while (error == EWOULDBLOCK ||
    699   1.14   mycroft 				 (!error && *mp == NULL && control));
    700   1.14   mycroft 			if ((rcvflg & MSG_EOR) == 0)
    701   1.31  christos 				printf("Egad!!\n");
    702    1.1       cgd 			if (!error && *mp == NULL)
    703    1.1       cgd 				error = EPIPE;
    704    1.1       cgd 			len -= auio.uio_resid;
    705    1.1       cgd 		}
    706    1.1       cgd errout:
    707   1.14   mycroft 		if (error && error != EINTR && error != ERESTART) {
    708    1.1       cgd 			m_freem(*mp);
    709    1.1       cgd 			*mp = (struct mbuf *)0;
    710   1.14   mycroft 			if (error != EPIPE)
    711    1.1       cgd 				log(LOG_INFO,
    712    1.1       cgd 				    "receive error %d from nfs server %s\n",
    713    1.1       cgd 				    error,
    714    1.1       cgd 				 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
    715   1.39      fvdl 			error = nfs_sndlock(&rep->r_nmp->nm_iflag, rep);
    716   1.14   mycroft 			if (!error)
    717  1.105  jonathan 				error = nfs_reconnect(rep, p);
    718    1.1       cgd 			if (!error)
    719    1.1       cgd 				goto tryagain;
    720   1.37      fvdl 			else
    721   1.39      fvdl 				nfs_sndunlock(&rep->r_nmp->nm_iflag);
    722    1.1       cgd 		}
    723    1.1       cgd 	} else {
    724   1.14   mycroft 		if ((so = rep->r_nmp->nm_so) == NULL)
    725   1.14   mycroft 			return (EACCES);
    726    1.1       cgd 		if (so->so_state & SS_ISCONNECTED)
    727    1.1       cgd 			getnam = (struct mbuf **)0;
    728    1.1       cgd 		else
    729    1.1       cgd 			getnam = aname;
    730    1.1       cgd 		auio.uio_resid = len = 1000000;
    731   1.92      fvdl 		auio.uio_procp = p;
    732    1.1       cgd 		do {
    733    1.1       cgd 			rcvflg = 0;
    734   1.43      matt 			error =  (*so->so_receive)(so, getnam, &auio, mp,
    735    1.1       cgd 				(struct mbuf **)0, &rcvflg);
    736   1.14   mycroft 			if (error == EWOULDBLOCK &&
    737    1.1       cgd 			    (rep->r_flags & R_SOFTTERM))
    738    1.1       cgd 				return (EINTR);
    739    1.1       cgd 		} while (error == EWOULDBLOCK);
    740    1.1       cgd 		len -= auio.uio_resid;
    741   1.51  sommerfe 		if (!error && *mp == NULL)
    742   1.51  sommerfe 			error = EPIPE;
    743    1.1       cgd 	}
    744    1.1       cgd 	if (error) {
    745    1.1       cgd 		m_freem(*mp);
    746    1.1       cgd 		*mp = (struct mbuf *)0;
    747    1.1       cgd 	}
    748    1.1       cgd 	return (error);
    749    1.1       cgd }
    750    1.1       cgd 
    751    1.1       cgd /*
    752    1.1       cgd  * Implement receipt of reply on a socket.
    753    1.1       cgd  * We must search through the list of received datagrams matching them
    754    1.1       cgd  * with outstanding requests using the xid, until ours is found.
    755    1.1       cgd  */
    756    1.1       cgd /* ARGSUSED */
    757   1.23  christos int
    758  1.105  jonathan nfs_reply(myrep, procp)
    759    1.1       cgd 	struct nfsreq *myrep;
    760  1.105  jonathan 	struct proc *procp;
    761    1.1       cgd {
    762   1.55  augustss 	struct nfsreq *rep;
    763   1.55  augustss 	struct nfsmount *nmp = myrep->r_nmp;
    764   1.55  augustss 	int32_t t1;
    765   1.14   mycroft 	struct mbuf *mrep, *nam, *md;
    766   1.22       cgd 	u_int32_t rxid, *tl;
    767   1.14   mycroft 	caddr_t dpos, cp2;
    768   1.14   mycroft 	int error;
    769    1.1       cgd 
    770    1.1       cgd 	/*
    771    1.1       cgd 	 * Loop around until we get our own reply
    772    1.1       cgd 	 */
    773    1.1       cgd 	for (;;) {
    774    1.1       cgd 		/*
    775    1.1       cgd 		 * Lock against other receivers so that I don't get stuck in
    776    1.1       cgd 		 * sbwait() after someone else has received my reply for me.
    777    1.1       cgd 		 * Also necessary for connection based protocols to avoid
    778    1.1       cgd 		 * race conditions during a reconnect.
    779    1.1       cgd 		 */
    780   1.24      fvdl 		error = nfs_rcvlock(myrep);
    781   1.36      fvdl 		if (error == EALREADY)
    782   1.36      fvdl 			return (0);
    783   1.24      fvdl 		if (error)
    784   1.14   mycroft 			return (error);
    785    1.1       cgd 		/*
    786    1.1       cgd 		 * Get the next Rpc reply off the socket
    787    1.1       cgd 		 */
    788   1.51  sommerfe 		nmp->nm_waiters++;
    789  1.105  jonathan 		error = nfs_receive(myrep, &nam, &mrep, procp);
    790   1.87      yamt 		nfs_rcvunlock(nmp);
    791   1.14   mycroft 		if (error) {
    792    1.1       cgd 
    793   1.51  sommerfe 			if (nmp->nm_iflag & NFSMNT_DISMNT) {
    794   1.51  sommerfe 				/*
    795   1.51  sommerfe 				 * Oops, we're going away now..
    796   1.51  sommerfe 				 */
    797   1.51  sommerfe 				nmp->nm_waiters--;
    798   1.51  sommerfe 				wakeup (&nmp->nm_waiters);
    799   1.51  sommerfe 				return error;
    800   1.51  sommerfe 			}
    801   1.51  sommerfe 			nmp->nm_waiters--;
    802    1.1       cgd 			/*
    803   1.58       mrg 			 * Ignore routing errors on connectionless protocols? ?
    804    1.1       cgd 			 */
    805    1.1       cgd 			if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
    806    1.1       cgd 				nmp->nm_so->so_error = 0;
    807   1.37      fvdl #ifdef DEBUG
    808   1.33      fvdl 				printf("nfs_reply: ignoring error %d\n", error);
    809   1.37      fvdl #endif
    810   1.14   mycroft 				if (myrep->r_flags & R_GETONEREP)
    811   1.14   mycroft 					return (0);
    812    1.1       cgd 				continue;
    813    1.1       cgd 			}
    814    1.1       cgd 			return (error);
    815    1.1       cgd 		}
    816  1.112     perry 		nmp->nm_waiters--;
    817   1.14   mycroft 		if (nam)
    818   1.14   mycroft 			m_freem(nam);
    819  1.112     perry 
    820    1.1       cgd 		/*
    821    1.1       cgd 		 * Get the xid and check that it is an rpc reply
    822    1.1       cgd 		 */
    823   1.14   mycroft 		md = mrep;
    824   1.14   mycroft 		dpos = mtod(md, caddr_t);
    825   1.22       cgd 		nfsm_dissect(tl, u_int32_t *, 2*NFSX_UNSIGNED);
    826   1.14   mycroft 		rxid = *tl++;
    827   1.14   mycroft 		if (*tl != rpc_reply) {
    828   1.61     bjh21 #ifndef NFS_V2_ONLY
    829   1.14   mycroft 			if (nmp->nm_flag & NFSMNT_NQNFS) {
    830   1.92      fvdl 				if (nqnfs_callback(nmp, mrep, md, dpos))
    831   1.14   mycroft 					nfsstats.rpcinvalid++;
    832   1.61     bjh21 			} else
    833   1.61     bjh21 #endif
    834   1.61     bjh21 			{
    835   1.14   mycroft 				nfsstats.rpcinvalid++;
    836   1.14   mycroft 				m_freem(mrep);
    837   1.14   mycroft 			}
    838   1.14   mycroft nfsmout:
    839   1.14   mycroft 			if (myrep->r_flags & R_GETONEREP)
    840   1.14   mycroft 				return (0);
    841    1.1       cgd 			continue;
    842    1.1       cgd 		}
    843   1.14   mycroft 
    844    1.1       cgd 		/*
    845    1.1       cgd 		 * Loop through the request list to match up the reply
    846    1.1       cgd 		 * Iff no match, just drop the datagram
    847    1.1       cgd 		 */
    848   1.73  christos 		TAILQ_FOREACH(rep, &nfs_reqq, r_chain) {
    849    1.1       cgd 			if (rep->r_mrep == NULL && rxid == rep->r_xid) {
    850    1.1       cgd 				/* Found it.. */
    851   1.14   mycroft 				rep->r_mrep = mrep;
    852   1.14   mycroft 				rep->r_md = md;
    853   1.14   mycroft 				rep->r_dpos = dpos;
    854   1.14   mycroft 				if (nfsrtton) {
    855   1.14   mycroft 					struct rttl *rt;
    856   1.14   mycroft 
    857   1.14   mycroft 					rt = &nfsrtt.rttl[nfsrtt.pos];
    858   1.14   mycroft 					rt->proc = rep->r_procnum;
    859   1.14   mycroft 					rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]);
    860   1.14   mycroft 					rt->sent = nmp->nm_sent;
    861   1.14   mycroft 					rt->cwnd = nmp->nm_cwnd;
    862   1.14   mycroft 					rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1];
    863   1.14   mycroft 					rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1];
    864  1.103  christos 					rt->fsid = nmp->nm_mountp->mnt_stat.f_fsidx;
    865   1.14   mycroft 					rt->tstamp = time;
    866   1.14   mycroft 					if (rep->r_flags & R_TIMING)
    867   1.14   mycroft 						rt->rtt = rep->r_rtt;
    868   1.14   mycroft 					else
    869   1.14   mycroft 						rt->rtt = 1000000;
    870   1.14   mycroft 					nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ;
    871   1.14   mycroft 				}
    872    1.1       cgd 				/*
    873   1.14   mycroft 				 * Update congestion window.
    874   1.14   mycroft 				 * Do the additive increase of
    875   1.14   mycroft 				 * one rpc/rtt.
    876   1.14   mycroft 				 */
    877   1.14   mycroft 				if (nmp->nm_cwnd <= nmp->nm_sent) {
    878   1.14   mycroft 					nmp->nm_cwnd +=
    879   1.14   mycroft 					   (NFS_CWNDSCALE * NFS_CWNDSCALE +
    880   1.14   mycroft 					   (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd;
    881   1.14   mycroft 					if (nmp->nm_cwnd > NFS_MAXCWND)
    882   1.14   mycroft 						nmp->nm_cwnd = NFS_MAXCWND;
    883   1.14   mycroft 				}
    884   1.14   mycroft 				rep->r_flags &= ~R_SENT;
    885   1.14   mycroft 				nmp->nm_sent -= NFS_CWNDSCALE;
    886   1.14   mycroft 				/*
    887   1.14   mycroft 				 * Update rtt using a gain of 0.125 on the mean
    888   1.14   mycroft 				 * and a gain of 0.25 on the deviation.
    889    1.1       cgd 				 */
    890    1.1       cgd 				if (rep->r_flags & R_TIMING) {
    891   1.14   mycroft 					/*
    892   1.14   mycroft 					 * Since the timer resolution of
    893   1.14   mycroft 					 * NFS_HZ is so course, it can often
    894   1.14   mycroft 					 * result in r_rtt == 0. Since
    895   1.14   mycroft 					 * r_rtt == N means that the actual
    896   1.14   mycroft 					 * rtt is between N+dt and N+2-dt ticks,
    897   1.14   mycroft 					 * add 1.
    898   1.14   mycroft 					 */
    899   1.14   mycroft 					t1 = rep->r_rtt + 1;
    900   1.14   mycroft 					t1 -= (NFS_SRTT(rep) >> 3);
    901   1.14   mycroft 					NFS_SRTT(rep) += t1;
    902   1.14   mycroft 					if (t1 < 0)
    903   1.14   mycroft 						t1 = -t1;
    904   1.14   mycroft 					t1 -= (NFS_SDRTT(rep) >> 2);
    905   1.14   mycroft 					NFS_SDRTT(rep) += t1;
    906    1.1       cgd 				}
    907   1.14   mycroft 				nmp->nm_timeouts = 0;
    908    1.1       cgd 				break;
    909    1.1       cgd 			}
    910    1.1       cgd 		}
    911    1.1       cgd 		/*
    912    1.1       cgd 		 * If not matched to a request, drop it.
    913    1.1       cgd 		 * If it's mine, get out.
    914    1.1       cgd 		 */
    915   1.16   mycroft 		if (rep == 0) {
    916    1.1       cgd 			nfsstats.rpcunexpected++;
    917   1.14   mycroft 			m_freem(mrep);
    918   1.14   mycroft 		} else if (rep == myrep) {
    919   1.14   mycroft 			if (rep->r_mrep == NULL)
    920   1.14   mycroft 				panic("nfsreply nil");
    921   1.14   mycroft 			return (0);
    922   1.14   mycroft 		}
    923   1.14   mycroft 		if (myrep->r_flags & R_GETONEREP)
    924    1.1       cgd 			return (0);
    925    1.1       cgd 	}
    926    1.1       cgd }
    927    1.1       cgd 
    928    1.1       cgd /*
    929    1.1       cgd  * nfs_request - goes something like this
    930    1.1       cgd  *	- fill in request struct
    931    1.1       cgd  *	- links it into list
    932    1.1       cgd  *	- calls nfs_send() for first transmit
    933    1.1       cgd  *	- calls nfs_receive() to get reply
    934    1.1       cgd  *	- break down rpc header and return with nfs reply pointed to
    935    1.1       cgd  *	  by mrep or error
    936    1.1       cgd  * nb: always frees up mreq mbuf list
    937    1.1       cgd  */
    938   1.23  christos int
    939  1.104      yamt nfs_request(np, mrest, procnum, procp, cred, mrp, mdp, dposp, rexmitp)
    940   1.83  drochner 	struct nfsnode *np;
    941   1.14   mycroft 	struct mbuf *mrest;
    942    1.1       cgd 	int procnum;
    943   1.92      fvdl 	struct proc *procp;
    944   1.14   mycroft 	struct ucred *cred;
    945    1.1       cgd 	struct mbuf **mrp;
    946    1.1       cgd 	struct mbuf **mdp;
    947    1.1       cgd 	caddr_t *dposp;
    948  1.104      yamt 	int *rexmitp;
    949    1.1       cgd {
    950   1.55  augustss 	struct mbuf *m, *mrep;
    951   1.55  augustss 	struct nfsreq *rep;
    952   1.55  augustss 	u_int32_t *tl;
    953   1.55  augustss 	int i;
    954  1.110      yamt 	struct nfsmount *nmp = VFSTONFS(np->n_vnode->v_mount);
    955   1.14   mycroft 	struct mbuf *md, *mheadend;
    956   1.24      fvdl 	char nickv[RPCX_NICKVERF];
    957   1.14   mycroft 	time_t reqtime, waituntil;
    958   1.14   mycroft 	caddr_t dpos, cp2;
    959   1.62      fvdl 	int t1, s, error = 0, mrest_len, auth_len, auth_type;
    960   1.97      yamt 	int trylater_delay = NFS_TRYLATERDEL, failed_auth = 0;
    961   1.24      fvdl 	int verf_len, verf_type;
    962   1.22       cgd 	u_int32_t xid;
    963   1.24      fvdl 	char *auth_str, *verf_str;
    964   1.24      fvdl 	NFSKERBKEY_T key;		/* save session key */
    965  1.100      fvdl 	struct ucred acred;
    966   1.62      fvdl #ifndef NFS_V2_ONLY
    967   1.62      fvdl 	int nqlflag, cachable;
    968   1.62      fvdl 	u_quad_t frev;
    969   1.62      fvdl #endif
    970  1.110      yamt 	struct mbuf *mrest_backup = NULL;
    971  1.110      yamt 	struct ucred *origcred = NULL; /* XXX: gcc */
    972  1.110      yamt 	boolean_t retry_cred = TRUE;
    973  1.110      yamt 	boolean_t use_opencred = (np->n_flag & NUSEOPENCRED) != 0;
    974    1.1       cgd 
    975  1.104      yamt 	if (rexmitp != NULL)
    976  1.104      yamt 		*rexmitp = 0;
    977  1.104      yamt 
    978  1.110      yamt tryagain_cred:
    979   1.64     bjh21 	KASSERT(cred != NULL);
    980    1.1       cgd 	MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
    981    1.1       cgd 	rep->r_nmp = nmp;
    982   1.92      fvdl 	rep->r_procp = procp;
    983   1.14   mycroft 	rep->r_procnum = procnum;
    984   1.14   mycroft 	i = 0;
    985   1.14   mycroft 	m = mrest;
    986    1.1       cgd 	while (m) {
    987   1.14   mycroft 		i += m->m_len;
    988    1.1       cgd 		m = m->m_next;
    989    1.1       cgd 	}
    990   1.14   mycroft 	mrest_len = i;
    991   1.14   mycroft 
    992   1.14   mycroft 	/*
    993   1.14   mycroft 	 * Get the RPC header with authorization.
    994   1.14   mycroft 	 */
    995   1.14   mycroft kerbauth:
    996   1.24      fvdl 	verf_str = auth_str = (char *)0;
    997   1.14   mycroft 	if (nmp->nm_flag & NFSMNT_KERB) {
    998   1.24      fvdl 		verf_str = nickv;
    999   1.24      fvdl 		verf_len = sizeof (nickv);
   1000   1.24      fvdl 		auth_type = RPCAUTH_KERB4;
   1001   1.46     perry 		memset((caddr_t)key, 0, sizeof (key));
   1002   1.24      fvdl 		if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str,
   1003   1.24      fvdl 			&auth_len, verf_str, verf_len)) {
   1004   1.24      fvdl 			error = nfs_getauth(nmp, rep, cred, &auth_str,
   1005   1.24      fvdl 				&auth_len, verf_str, &verf_len, key);
   1006   1.14   mycroft 			if (error) {
   1007   1.14   mycroft 				free((caddr_t)rep, M_NFSREQ);
   1008   1.14   mycroft 				m_freem(mrest);
   1009   1.14   mycroft 				return (error);
   1010   1.14   mycroft 			}
   1011    1.1       cgd 		}
   1012  1.110      yamt 		retry_cred = FALSE;
   1013   1.14   mycroft 	} else {
   1014  1.110      yamt 		/* AUTH_UNIX */
   1015  1.110      yamt 		uid_t uid;
   1016  1.110      yamt 		gid_t gid;
   1017  1.110      yamt 
   1018  1.110      yamt 		/*
   1019  1.110      yamt 		 * on the most unix filesystems, permission checks are
   1020  1.110      yamt 		 * done when the file is open(2)'ed.
   1021  1.110      yamt 		 * ie. once a file is successfully open'ed,
   1022  1.110      yamt 		 * following i/o operations never fail with EACCES.
   1023  1.110      yamt 		 * we try to follow the semantics as far as possible.
   1024  1.110      yamt 		 *
   1025  1.110      yamt 		 * note that we expect that the nfs server always grant
   1026  1.110      yamt 		 * accesses by the file's owner.
   1027  1.110      yamt 		 */
   1028  1.110      yamt 		origcred = cred;
   1029  1.100      fvdl 		switch (procnum) {
   1030  1.100      fvdl 		case NFSPROC_READ:
   1031  1.100      fvdl 		case NFSPROC_WRITE:
   1032  1.100      fvdl 		case NFSPROC_COMMIT:
   1033  1.110      yamt 			uid = np->n_vattr->va_uid;
   1034  1.110      yamt 			gid = np->n_vattr->va_gid;
   1035  1.110      yamt 			if (cred->cr_uid == uid && cred->cr_gid == gid) {
   1036  1.110      yamt 				retry_cred = FALSE;
   1037  1.110      yamt 				break;
   1038  1.110      yamt 			}
   1039  1.110      yamt 			if (use_opencred)
   1040  1.110      yamt 				break;
   1041  1.110      yamt 			acred.cr_uid = uid;
   1042  1.110      yamt 			acred.cr_gid = gid;
   1043  1.100      fvdl 			acred.cr_ngroups = 0;
   1044  1.100      fvdl 			acred.cr_ref = 2;	/* Just to be safe.. */
   1045  1.100      fvdl 			cred = &acred;
   1046  1.100      fvdl 			break;
   1047  1.110      yamt 		default:
   1048  1.110      yamt 			retry_cred = FALSE;
   1049  1.110      yamt 			break;
   1050  1.100      fvdl 		}
   1051  1.110      yamt 		/*
   1052  1.110      yamt 		 * backup mbuf chain if we can need it later to retry.
   1053  1.110      yamt 		 *
   1054  1.110      yamt 		 * XXX maybe we can keep a direct reference to
   1055  1.110      yamt 		 * mrest without doing m_copym, but it's ...ugly.
   1056  1.110      yamt 		 */
   1057  1.110      yamt 		if (retry_cred)
   1058  1.110      yamt 			mrest_backup = m_copym(mrest, 0, M_COPYALL, M_WAIT);
   1059   1.14   mycroft 		auth_type = RPCAUTH_UNIX;
   1060   1.20   mycroft 		auth_len = (((cred->cr_ngroups > nmp->nm_numgrps) ?
   1061   1.20   mycroft 			nmp->nm_numgrps : cred->cr_ngroups) << 2) +
   1062   1.14   mycroft 			5 * NFSX_UNSIGNED;
   1063   1.14   mycroft 	}
   1064   1.24      fvdl 	m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len,
   1065   1.24      fvdl 	     auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid);
   1066   1.14   mycroft 	if (auth_str)
   1067   1.14   mycroft 		free(auth_str, M_TEMP);
   1068   1.14   mycroft 
   1069    1.1       cgd 	/*
   1070   1.14   mycroft 	 * For stream protocols, insert a Sun RPC Record Mark.
   1071    1.1       cgd 	 */
   1072   1.14   mycroft 	if (nmp->nm_sotype == SOCK_STREAM) {
   1073   1.14   mycroft 		M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
   1074   1.22       cgd 		*mtod(m, u_int32_t *) = htonl(0x80000000 |
   1075   1.14   mycroft 			 (m->m_pkthdr.len - NFSX_UNSIGNED));
   1076    1.1       cgd 	}
   1077   1.14   mycroft 	rep->r_mreq = m;
   1078   1.14   mycroft 	rep->r_xid = xid;
   1079   1.14   mycroft tryagain:
   1080   1.14   mycroft 	if (nmp->nm_flag & NFSMNT_SOFT)
   1081   1.14   mycroft 		rep->r_retry = nmp->nm_retry;
   1082   1.14   mycroft 	else
   1083   1.14   mycroft 		rep->r_retry = NFS_MAXREXMIT + 1;	/* past clip limit */
   1084   1.14   mycroft 	rep->r_rtt = rep->r_rexmit = 0;
   1085   1.14   mycroft 	if (proct[procnum] > 0)
   1086   1.14   mycroft 		rep->r_flags = R_TIMING;
   1087   1.14   mycroft 	else
   1088   1.14   mycroft 		rep->r_flags = 0;
   1089   1.14   mycroft 	rep->r_mrep = NULL;
   1090    1.1       cgd 
   1091    1.1       cgd 	/*
   1092    1.1       cgd 	 * Do the client side RPC.
   1093    1.1       cgd 	 */
   1094    1.1       cgd 	nfsstats.rpcrequests++;
   1095    1.1       cgd 	/*
   1096    1.1       cgd 	 * Chain request into list of outstanding requests. Be sure
   1097    1.1       cgd 	 * to put it LAST so timer finds oldest requests first.
   1098    1.1       cgd 	 */
   1099   1.35      fvdl 	s = splsoftnet();
   1100   1.16   mycroft 	TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain);
   1101   1.14   mycroft 
   1102   1.14   mycroft 	/* Get send time for nqnfs */
   1103   1.14   mycroft 	reqtime = time.tv_sec;
   1104   1.14   mycroft 
   1105    1.1       cgd 	/*
   1106    1.1       cgd 	 * If backing off another request or avoiding congestion, don't
   1107    1.1       cgd 	 * send this one now but let timer do it. If not timing a request,
   1108    1.1       cgd 	 * do it now.
   1109    1.1       cgd 	 */
   1110   1.14   mycroft 	if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM ||
   1111   1.14   mycroft 		(nmp->nm_flag & NFSMNT_DUMBTIMR) ||
   1112   1.14   mycroft 		nmp->nm_sent < nmp->nm_cwnd)) {
   1113    1.1       cgd 		splx(s);
   1114    1.1       cgd 		if (nmp->nm_soflags & PR_CONNREQUIRED)
   1115   1.39      fvdl 			error = nfs_sndlock(&nmp->nm_iflag, rep);
   1116   1.14   mycroft 		if (!error) {
   1117   1.52      fvdl 			m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
   1118  1.105  jonathan 			error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep, procp);
   1119   1.14   mycroft 			if (nmp->nm_soflags & PR_CONNREQUIRED)
   1120   1.39      fvdl 				nfs_sndunlock(&nmp->nm_iflag);
   1121   1.14   mycroft 		}
   1122   1.14   mycroft 		if (!error && (rep->r_flags & R_MUSTRESEND) == 0) {
   1123   1.14   mycroft 			nmp->nm_sent += NFS_CWNDSCALE;
   1124   1.14   mycroft 			rep->r_flags |= R_SENT;
   1125   1.14   mycroft 		}
   1126   1.14   mycroft 	} else {
   1127    1.1       cgd 		splx(s);
   1128   1.14   mycroft 		rep->r_rtt = -1;
   1129   1.14   mycroft 	}
   1130    1.1       cgd 
   1131    1.1       cgd 	/*
   1132    1.1       cgd 	 * Wait for the reply from our send or the timer's.
   1133    1.1       cgd 	 */
   1134   1.14   mycroft 	if (!error || error == EPIPE)
   1135  1.105  jonathan 		error = nfs_reply(rep, procp);
   1136    1.1       cgd 
   1137    1.1       cgd 	/*
   1138    1.1       cgd 	 * RPC done, unlink the request.
   1139    1.1       cgd 	 */
   1140   1.35      fvdl 	s = splsoftnet();
   1141   1.16   mycroft 	TAILQ_REMOVE(&nfs_reqq, rep, r_chain);
   1142    1.1       cgd 	splx(s);
   1143    1.1       cgd 
   1144    1.1       cgd 	/*
   1145   1.14   mycroft 	 * Decrement the outstanding request count.
   1146   1.14   mycroft 	 */
   1147   1.14   mycroft 	if (rep->r_flags & R_SENT) {
   1148   1.14   mycroft 		rep->r_flags &= ~R_SENT;	/* paranoia */
   1149   1.14   mycroft 		nmp->nm_sent -= NFS_CWNDSCALE;
   1150   1.14   mycroft 	}
   1151   1.14   mycroft 
   1152  1.104      yamt 	if (rexmitp != NULL) {
   1153  1.104      yamt 		int rexmit;
   1154  1.104      yamt 
   1155  1.104      yamt 		if (nmp->nm_sotype != SOCK_DGRAM)
   1156  1.104      yamt 			rexmit = (rep->r_flags & R_REXMITTED) != 0;
   1157  1.104      yamt 		else
   1158  1.104      yamt 			rexmit = rep->r_rexmit;
   1159  1.104      yamt 		*rexmitp = rexmit;
   1160  1.104      yamt 	}
   1161  1.104      yamt 
   1162   1.14   mycroft 	/*
   1163    1.1       cgd 	 * If there was a successful reply and a tprintf msg.
   1164    1.1       cgd 	 * tprintf a response.
   1165    1.1       cgd 	 */
   1166    1.1       cgd 	if (!error && (rep->r_flags & R_TPRINTFMSG))
   1167   1.92      fvdl 		nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
   1168    1.1       cgd 		    "is alive again");
   1169    1.1       cgd 	mrep = rep->r_mrep;
   1170   1.14   mycroft 	md = rep->r_md;
   1171   1.14   mycroft 	dpos = rep->r_dpos;
   1172  1.110      yamt 	if (error)
   1173  1.110      yamt 		goto nfsmout;
   1174    1.1       cgd 
   1175    1.1       cgd 	/*
   1176    1.1       cgd 	 * break down the rpc header and check if ok
   1177    1.1       cgd 	 */
   1178   1.24      fvdl 	nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1179    1.1       cgd 	if (*tl++ == rpc_msgdenied) {
   1180    1.1       cgd 		if (*tl == rpc_mismatch)
   1181    1.1       cgd 			error = EOPNOTSUPP;
   1182   1.14   mycroft 		else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) {
   1183   1.24      fvdl 			if (!failed_auth) {
   1184   1.14   mycroft 				failed_auth++;
   1185   1.14   mycroft 				mheadend->m_next = (struct mbuf *)0;
   1186   1.14   mycroft 				m_freem(mrep);
   1187   1.14   mycroft 				m_freem(rep->r_mreq);
   1188   1.14   mycroft 				goto kerbauth;
   1189   1.14   mycroft 			} else
   1190   1.14   mycroft 				error = EAUTH;
   1191   1.14   mycroft 		} else
   1192    1.1       cgd 			error = EACCES;
   1193    1.1       cgd 		m_freem(mrep);
   1194  1.110      yamt 		goto nfsmout;
   1195    1.1       cgd 	}
   1196   1.14   mycroft 
   1197    1.1       cgd 	/*
   1198   1.24      fvdl 	 * Grab any Kerberos verifier, otherwise just throw it away.
   1199    1.1       cgd 	 */
   1200   1.24      fvdl 	verf_type = fxdr_unsigned(int, *tl++);
   1201   1.24      fvdl 	i = fxdr_unsigned(int32_t, *tl);
   1202   1.24      fvdl 	if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) {
   1203   1.24      fvdl 		error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep);
   1204   1.24      fvdl 		if (error)
   1205   1.24      fvdl 			goto nfsmout;
   1206   1.24      fvdl 	} else if (i > 0)
   1207   1.24      fvdl 		nfsm_adv(nfsm_rndup(i));
   1208   1.22       cgd 	nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
   1209    1.1       cgd 	/* 0 == ok */
   1210    1.1       cgd 	if (*tl == 0) {
   1211   1.22       cgd 		nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
   1212    1.1       cgd 		if (*tl != 0) {
   1213    1.1       cgd 			error = fxdr_unsigned(int, *tl);
   1214  1.110      yamt 			if (error == NFSERR_ACCES && retry_cred) {
   1215  1.110      yamt 				m_freem(mrep);
   1216  1.110      yamt 				m_freem(rep->r_mreq);
   1217  1.110      yamt 				FREE(rep, M_NFSREQ);
   1218  1.110      yamt 				use_opencred = !use_opencred;
   1219  1.110      yamt 				if (mrest_backup == NULL)
   1220  1.110      yamt 					return ENOMEM; /* m_copym failure */
   1221  1.110      yamt 				mrest = mrest_backup;
   1222  1.110      yamt 				mrest_backup = NULL;
   1223  1.110      yamt 				cred = origcred;
   1224  1.110      yamt 				error = 0;
   1225  1.110      yamt 				retry_cred = FALSE;
   1226  1.110      yamt 				goto tryagain_cred;
   1227  1.110      yamt 			}
   1228   1.24      fvdl 			if ((nmp->nm_flag & NFSMNT_NFSV3) &&
   1229   1.24      fvdl 				error == NFSERR_TRYLATER) {
   1230   1.24      fvdl 				m_freem(mrep);
   1231   1.14   mycroft 				error = 0;
   1232   1.14   mycroft 				waituntil = time.tv_sec + trylater_delay;
   1233   1.14   mycroft 				while (time.tv_sec < waituntil)
   1234   1.14   mycroft 					(void) tsleep((caddr_t)&lbolt,
   1235   1.14   mycroft 						PSOCK, "nqnfstry", 0);
   1236   1.97      yamt 				trylater_delay *= NFS_TRYLATERDELMUL;
   1237   1.97      yamt 				if (trylater_delay > NFS_TRYLATERDELMAX)
   1238   1.97      yamt 					trylater_delay = NFS_TRYLATERDELMAX;
   1239   1.95      yamt 				/*
   1240   1.95      yamt 				 * RFC1813:
   1241   1.95      yamt 				 * The client should wait and then try
   1242   1.95      yamt 				 * the request with a new RPC transaction ID.
   1243   1.95      yamt 				 */
   1244   1.95      yamt 				nfs_renewxid(rep);
   1245   1.14   mycroft 				goto tryagain;
   1246   1.14   mycroft 			}
   1247   1.14   mycroft 
   1248   1.14   mycroft 			/*
   1249   1.14   mycroft 			 * If the File Handle was stale, invalidate the
   1250   1.14   mycroft 			 * lookup cache, just in case.
   1251   1.14   mycroft 			 */
   1252   1.14   mycroft 			if (error == ESTALE)
   1253   1.83  drochner 				cache_purge(NFSTOV(np));
   1254   1.24      fvdl 			if (nmp->nm_flag & NFSMNT_NFSV3) {
   1255   1.24      fvdl 				*mrp = mrep;
   1256   1.24      fvdl 				*mdp = md;
   1257   1.24      fvdl 				*dposp = dpos;
   1258   1.24      fvdl 				error |= NFSERR_RETERR;
   1259   1.24      fvdl 			} else
   1260   1.24      fvdl 				m_freem(mrep);
   1261  1.110      yamt 			goto nfsmout;
   1262    1.1       cgd 		}
   1263   1.14   mycroft 
   1264  1.110      yamt 		/*
   1265  1.110      yamt 		 * note which credential worked to minimize number of retries.
   1266  1.110      yamt 		 */
   1267  1.110      yamt 		if (use_opencred)
   1268  1.110      yamt 			np->n_flag |= NUSEOPENCRED;
   1269  1.110      yamt 		else
   1270  1.110      yamt 			np->n_flag &= ~NUSEOPENCRED;
   1271  1.110      yamt 
   1272   1.61     bjh21 #ifndef NFS_V2_ONLY
   1273   1.14   mycroft 		/*
   1274   1.14   mycroft 		 * For nqnfs, get any lease in reply
   1275   1.14   mycroft 		 */
   1276   1.14   mycroft 		if (nmp->nm_flag & NFSMNT_NQNFS) {
   1277   1.22       cgd 			nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
   1278   1.14   mycroft 			if (*tl) {
   1279   1.14   mycroft 				nqlflag = fxdr_unsigned(int, *tl);
   1280   1.22       cgd 				nfsm_dissect(tl, u_int32_t *, 4*NFSX_UNSIGNED);
   1281   1.14   mycroft 				cachable = fxdr_unsigned(int, *tl++);
   1282   1.14   mycroft 				reqtime += fxdr_unsigned(int, *tl++);
   1283   1.14   mycroft 				if (reqtime > time.tv_sec) {
   1284   1.50      fair 				    frev = fxdr_hyper(tl);
   1285   1.14   mycroft 				    nqnfs_clientlease(nmp, np, nqlflag,
   1286   1.14   mycroft 					cachable, reqtime, frev);
   1287   1.14   mycroft 				}
   1288   1.14   mycroft 			}
   1289   1.14   mycroft 		}
   1290   1.61     bjh21 #endif
   1291    1.1       cgd 		*mrp = mrep;
   1292    1.1       cgd 		*mdp = md;
   1293    1.1       cgd 		*dposp = dpos;
   1294  1.110      yamt 
   1295  1.110      yamt 		KASSERT(error == 0);
   1296  1.110      yamt 		goto nfsmout;
   1297    1.1       cgd 	}
   1298    1.1       cgd 	m_freem(mrep);
   1299   1.24      fvdl 	error = EPROTONOSUPPORT;
   1300   1.24      fvdl nfsmout:
   1301   1.14   mycroft 	m_freem(rep->r_mreq);
   1302   1.14   mycroft 	free((caddr_t)rep, M_NFSREQ);
   1303  1.110      yamt 	m_freem(mrest_backup);
   1304    1.1       cgd 	return (error);
   1305    1.1       cgd }
   1306   1.32   thorpej #endif /* NFS */
   1307    1.1       cgd 
   1308    1.1       cgd /*
   1309    1.1       cgd  * Generate the rpc reply header
   1310    1.1       cgd  * siz arg. is used to decide if adding a cluster is worthwhile
   1311    1.1       cgd  */
   1312   1.23  christos int
   1313   1.24      fvdl nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
   1314    1.1       cgd 	int siz;
   1315   1.24      fvdl 	struct nfsrv_descript *nd;
   1316   1.24      fvdl 	struct nfssvc_sock *slp;
   1317    1.1       cgd 	int err;
   1318   1.14   mycroft 	int cache;
   1319   1.14   mycroft 	u_quad_t *frev;
   1320    1.1       cgd 	struct mbuf **mrq;
   1321    1.1       cgd 	struct mbuf **mbp;
   1322    1.1       cgd 	caddr_t *bposp;
   1323    1.1       cgd {
   1324   1.55  augustss 	u_int32_t *tl;
   1325   1.55  augustss 	struct mbuf *mreq;
   1326    1.1       cgd 	caddr_t bpos;
   1327   1.79      matt 	struct mbuf *mb;
   1328    1.1       cgd 
   1329   1.79      matt 	mreq = m_gethdr(M_WAIT, MT_DATA);
   1330   1.79      matt 	MCLAIM(mreq, &nfs_mowner);
   1331    1.1       cgd 	mb = mreq;
   1332   1.14   mycroft 	/*
   1333   1.14   mycroft 	 * If this is a big reply, use a cluster else
   1334   1.14   mycroft 	 * try and leave leading space for the lower level headers.
   1335   1.14   mycroft 	 */
   1336   1.14   mycroft 	siz += RPC_REPLYSIZ;
   1337   1.45      fvdl 	if (siz >= max_datalen) {
   1338   1.79      matt 		m_clget(mreq, M_WAIT);
   1339   1.14   mycroft 	} else
   1340   1.14   mycroft 		mreq->m_data += max_hdr;
   1341   1.22       cgd 	tl = mtod(mreq, u_int32_t *);
   1342   1.24      fvdl 	mreq->m_len = 6 * NFSX_UNSIGNED;
   1343   1.24      fvdl 	bpos = ((caddr_t)tl) + mreq->m_len;
   1344   1.14   mycroft 	*tl++ = txdr_unsigned(nd->nd_retxid);
   1345    1.1       cgd 	*tl++ = rpc_reply;
   1346   1.24      fvdl 	if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
   1347    1.1       cgd 		*tl++ = rpc_msgdenied;
   1348   1.24      fvdl 		if (err & NFSERR_AUTHERR) {
   1349   1.14   mycroft 			*tl++ = rpc_autherr;
   1350   1.24      fvdl 			*tl = txdr_unsigned(err & ~NFSERR_AUTHERR);
   1351   1.14   mycroft 			mreq->m_len -= NFSX_UNSIGNED;
   1352   1.14   mycroft 			bpos -= NFSX_UNSIGNED;
   1353   1.14   mycroft 		} else {
   1354   1.14   mycroft 			*tl++ = rpc_mismatch;
   1355   1.24      fvdl 			*tl++ = txdr_unsigned(RPC_VER2);
   1356   1.24      fvdl 			*tl = txdr_unsigned(RPC_VER2);
   1357   1.14   mycroft 		}
   1358    1.1       cgd 	} else {
   1359    1.1       cgd 		*tl++ = rpc_msgaccepted;
   1360   1.24      fvdl 
   1361   1.24      fvdl 		/*
   1362   1.24      fvdl 		 * For Kerberos authentication, we must send the nickname
   1363   1.24      fvdl 		 * verifier back, otherwise just RPCAUTH_NULL.
   1364   1.24      fvdl 		 */
   1365   1.24      fvdl 		if (nd->nd_flag & ND_KERBFULL) {
   1366   1.84      yamt 			struct nfsuid *nuidp;
   1367   1.84      yamt 			struct timeval ktvin, ktvout;
   1368   1.24      fvdl 
   1369   1.84      yamt 			LIST_FOREACH(nuidp, NUIDHASH(slp, nd->nd_cr.cr_uid),
   1370   1.84      yamt 			    nu_hash) {
   1371   1.84      yamt 				if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid &&
   1372   1.84      yamt 				    (!nd->nd_nam2 || netaddr_match(
   1373   1.84      yamt 				    NU_NETFAM(nuidp), &nuidp->nu_haddr,
   1374   1.84      yamt 				    nd->nd_nam2)))
   1375   1.84      yamt 					break;
   1376   1.84      yamt 			}
   1377   1.84      yamt 			if (nuidp) {
   1378   1.84      yamt 				ktvin.tv_sec =
   1379   1.84      yamt 				    txdr_unsigned(nuidp->nu_timestamp.tv_sec
   1380   1.84      yamt 					- 1);
   1381   1.84      yamt 				ktvin.tv_usec =
   1382   1.84      yamt 				    txdr_unsigned(nuidp->nu_timestamp.tv_usec);
   1383   1.24      fvdl 
   1384   1.84      yamt 				/*
   1385   1.84      yamt 				 * Encrypt the timestamp in ecb mode using the
   1386   1.84      yamt 				 * session key.
   1387   1.84      yamt 				 */
   1388   1.24      fvdl #ifdef NFSKERB
   1389   1.84      yamt 				XXX
   1390   1.24      fvdl #endif
   1391   1.24      fvdl 
   1392   1.84      yamt 				*tl++ = rpc_auth_kerb;
   1393   1.84      yamt 				*tl++ = txdr_unsigned(3 * NFSX_UNSIGNED);
   1394   1.84      yamt 				*tl = ktvout.tv_sec;
   1395   1.84      yamt 				nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1396   1.84      yamt 				*tl++ = ktvout.tv_usec;
   1397   1.84      yamt 				*tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid);
   1398   1.84      yamt 			} else {
   1399   1.84      yamt 				*tl++ = 0;
   1400   1.84      yamt 				*tl++ = 0;
   1401   1.84      yamt 			}
   1402   1.24      fvdl 		} else {
   1403   1.24      fvdl 			*tl++ = 0;
   1404   1.24      fvdl 			*tl++ = 0;
   1405   1.24      fvdl 		}
   1406    1.1       cgd 		switch (err) {
   1407    1.1       cgd 		case EPROGUNAVAIL:
   1408    1.1       cgd 			*tl = txdr_unsigned(RPC_PROGUNAVAIL);
   1409    1.1       cgd 			break;
   1410    1.1       cgd 		case EPROGMISMATCH:
   1411    1.1       cgd 			*tl = txdr_unsigned(RPC_PROGMISMATCH);
   1412   1.24      fvdl 			nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1413   1.24      fvdl 			if (nd->nd_flag & ND_NQNFS) {
   1414   1.24      fvdl 				*tl++ = txdr_unsigned(3);
   1415   1.24      fvdl 				*tl = txdr_unsigned(3);
   1416   1.24      fvdl 			} else {
   1417   1.24      fvdl 				*tl++ = txdr_unsigned(2);
   1418   1.24      fvdl 				*tl = txdr_unsigned(3);
   1419   1.24      fvdl 			}
   1420    1.1       cgd 			break;
   1421    1.1       cgd 		case EPROCUNAVAIL:
   1422    1.1       cgd 			*tl = txdr_unsigned(RPC_PROCUNAVAIL);
   1423    1.1       cgd 			break;
   1424   1.24      fvdl 		case EBADRPC:
   1425   1.24      fvdl 			*tl = txdr_unsigned(RPC_GARBAGE);
   1426   1.24      fvdl 			break;
   1427    1.1       cgd 		default:
   1428    1.1       cgd 			*tl = 0;
   1429   1.24      fvdl 			if (err != NFSERR_RETVOID) {
   1430   1.22       cgd 				nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
   1431   1.14   mycroft 				if (err)
   1432   1.24      fvdl 				    *tl = txdr_unsigned(nfsrv_errmap(nd, err));
   1433   1.14   mycroft 				else
   1434   1.24      fvdl 				    *tl = 0;
   1435    1.1       cgd 			}
   1436    1.1       cgd 			break;
   1437    1.1       cgd 		};
   1438    1.1       cgd 	}
   1439   1.14   mycroft 
   1440   1.14   mycroft 	/*
   1441   1.14   mycroft 	 * For nqnfs, piggyback lease as requested.
   1442   1.14   mycroft 	 */
   1443   1.24      fvdl 	if ((nd->nd_flag & ND_NQNFS) && err == 0) {
   1444   1.24      fvdl 		if (nd->nd_flag & ND_LEASE) {
   1445   1.24      fvdl 			nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1446   1.24      fvdl 			*tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE);
   1447   1.14   mycroft 			*tl++ = txdr_unsigned(cache);
   1448   1.14   mycroft 			*tl++ = txdr_unsigned(nd->nd_duration);
   1449   1.50      fair 			txdr_hyper(*frev, tl);
   1450   1.14   mycroft 		} else {
   1451   1.22       cgd 			nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
   1452   1.14   mycroft 			*tl = 0;
   1453   1.14   mycroft 		}
   1454   1.14   mycroft 	}
   1455   1.34      fvdl 	if (mrq != NULL)
   1456   1.34      fvdl 		*mrq = mreq;
   1457    1.1       cgd 	*mbp = mb;
   1458    1.1       cgd 	*bposp = bpos;
   1459   1.24      fvdl 	if (err != 0 && err != NFSERR_RETVOID)
   1460    1.1       cgd 		nfsstats.srvrpc_errs++;
   1461    1.1       cgd 	return (0);
   1462    1.1       cgd }
   1463    1.1       cgd 
   1464    1.1       cgd /*
   1465    1.1       cgd  * Nfs timer routine
   1466    1.1       cgd  * Scan the nfsreq list and retranmit any requests that have timed out
   1467    1.1       cgd  * To avoid retransmission attempts on STREAM sockets (in the future) make
   1468    1.1       cgd  * sure to set the r_retry field to 0 (implies nm_retry == 0).
   1469    1.1       cgd  */
   1470    1.7   mycroft void
   1471   1.14   mycroft nfs_timer(arg)
   1472   1.24      fvdl 	void *arg;	/* never used */
   1473    1.1       cgd {
   1474   1.55  augustss 	struct nfsreq *rep;
   1475   1.55  augustss 	struct mbuf *m;
   1476   1.55  augustss 	struct socket *so;
   1477   1.55  augustss 	struct nfsmount *nmp;
   1478   1.55  augustss 	int timeo;
   1479   1.27   thorpej 	int s, error;
   1480   1.27   thorpej #ifdef NFSSERVER
   1481   1.55  augustss 	struct nfssvc_sock *slp;
   1482   1.14   mycroft 	static long lasttime = 0;
   1483   1.27   thorpej 	u_quad_t cur_usec;
   1484   1.23  christos #endif
   1485    1.1       cgd 
   1486   1.21   mycroft 	s = splsoftnet();
   1487   1.73  christos 	TAILQ_FOREACH(rep, &nfs_reqq, r_chain) {
   1488    1.1       cgd 		nmp = rep->r_nmp;
   1489   1.14   mycroft 		if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
   1490    1.1       cgd 			continue;
   1491   1.92      fvdl 		if (nfs_sigintr(nmp, rep, rep->r_procp)) {
   1492    1.1       cgd 			rep->r_flags |= R_SOFTTERM;
   1493    1.1       cgd 			continue;
   1494    1.1       cgd 		}
   1495   1.14   mycroft 		if (rep->r_rtt >= 0) {
   1496   1.14   mycroft 			rep->r_rtt++;
   1497   1.14   mycroft 			if (nmp->nm_flag & NFSMNT_DUMBTIMR)
   1498   1.14   mycroft 				timeo = nmp->nm_timeo;
   1499   1.14   mycroft 			else
   1500   1.14   mycroft 				timeo = NFS_RTO(nmp, proct[rep->r_procnum]);
   1501   1.14   mycroft 			if (nmp->nm_timeouts > 0)
   1502   1.14   mycroft 				timeo *= nfs_backoff[nmp->nm_timeouts - 1];
   1503   1.14   mycroft 			if (rep->r_rtt <= timeo)
   1504   1.14   mycroft 				continue;
   1505   1.98      yamt 			if (nmp->nm_timeouts <
   1506   1.98      yamt 			    (sizeof(nfs_backoff) / sizeof(nfs_backoff[0])))
   1507   1.14   mycroft 				nmp->nm_timeouts++;
   1508    1.1       cgd 		}
   1509    1.1       cgd 		/*
   1510    1.1       cgd 		 * Check for server not responding
   1511    1.1       cgd 		 */
   1512    1.1       cgd 		if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
   1513   1.14   mycroft 		     rep->r_rexmit > nmp->nm_deadthresh) {
   1514   1.92      fvdl 			nfs_msg(rep->r_procp,
   1515    1.1       cgd 			    nmp->nm_mountp->mnt_stat.f_mntfromname,
   1516    1.1       cgd 			    "not responding");
   1517    1.1       cgd 			rep->r_flags |= R_TPRINTFMSG;
   1518    1.1       cgd 		}
   1519    1.1       cgd 		if (rep->r_rexmit >= rep->r_retry) {	/* too many */
   1520    1.1       cgd 			nfsstats.rpctimeouts++;
   1521    1.1       cgd 			rep->r_flags |= R_SOFTTERM;
   1522    1.1       cgd 			continue;
   1523    1.1       cgd 		}
   1524   1.14   mycroft 		if (nmp->nm_sotype != SOCK_DGRAM) {
   1525   1.14   mycroft 			if (++rep->r_rexmit > NFS_MAXREXMIT)
   1526   1.14   mycroft 				rep->r_rexmit = NFS_MAXREXMIT;
   1527   1.14   mycroft 			continue;
   1528   1.14   mycroft 		}
   1529   1.14   mycroft 		if ((so = nmp->nm_so) == NULL)
   1530    1.1       cgd 			continue;
   1531    1.1       cgd 
   1532    1.1       cgd 		/*
   1533    1.1       cgd 		 * If there is enough space and the window allows..
   1534    1.1       cgd 		 *	Resend it
   1535   1.14   mycroft 		 * Set r_rtt to -1 in case we fail to send it now.
   1536    1.1       cgd 		 */
   1537   1.14   mycroft 		rep->r_rtt = -1;
   1538    1.1       cgd 		if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
   1539   1.14   mycroft 		   ((nmp->nm_flag & NFSMNT_DUMBTIMR) ||
   1540   1.14   mycroft 		    (rep->r_flags & R_SENT) ||
   1541   1.14   mycroft 		    nmp->nm_sent < nmp->nm_cwnd) &&
   1542   1.14   mycroft 		   (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
   1543   1.40      fvdl 		        if (so->so_state & SS_ISCONNECTED)
   1544    1.1       cgd 			    error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
   1545   1.92      fvdl 			    (struct mbuf *)0, (struct mbuf *)0, (struct proc *)0);
   1546    1.1       cgd 			else
   1547    1.1       cgd 			    error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
   1548   1.92      fvdl 			    nmp->nm_nam, (struct mbuf *)0, (struct proc *)0);
   1549    1.1       cgd 			if (error) {
   1550   1.33      fvdl 				if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
   1551   1.37      fvdl #ifdef DEBUG
   1552   1.33      fvdl 					printf("nfs_timer: ignoring error %d\n",
   1553   1.33      fvdl 						error);
   1554   1.37      fvdl #endif
   1555    1.1       cgd 					so->so_error = 0;
   1556   1.33      fvdl 				}
   1557    1.1       cgd 			} else {
   1558    1.1       cgd 				/*
   1559   1.14   mycroft 				 * Iff first send, start timing
   1560   1.14   mycroft 				 * else turn timing off, backoff timer
   1561   1.14   mycroft 				 * and divide congestion window by 2.
   1562    1.1       cgd 				 */
   1563   1.14   mycroft 				if (rep->r_flags & R_SENT) {
   1564   1.14   mycroft 					rep->r_flags &= ~R_TIMING;
   1565   1.14   mycroft 					if (++rep->r_rexmit > NFS_MAXREXMIT)
   1566   1.14   mycroft 						rep->r_rexmit = NFS_MAXREXMIT;
   1567   1.14   mycroft 					nmp->nm_cwnd >>= 1;
   1568   1.14   mycroft 					if (nmp->nm_cwnd < NFS_CWNDSCALE)
   1569   1.14   mycroft 						nmp->nm_cwnd = NFS_CWNDSCALE;
   1570   1.14   mycroft 					nfsstats.rpcretries++;
   1571   1.14   mycroft 				} else {
   1572   1.14   mycroft 					rep->r_flags |= R_SENT;
   1573   1.14   mycroft 					nmp->nm_sent += NFS_CWNDSCALE;
   1574   1.14   mycroft 				}
   1575   1.14   mycroft 				rep->r_rtt = 0;
   1576    1.1       cgd 			}
   1577    1.1       cgd 		}
   1578    1.1       cgd 	}
   1579   1.14   mycroft 
   1580   1.14   mycroft #ifdef NFSSERVER
   1581   1.14   mycroft 	/*
   1582   1.14   mycroft 	 * Call the nqnfs server timer once a second to handle leases.
   1583   1.14   mycroft 	 */
   1584   1.14   mycroft 	if (lasttime != time.tv_sec) {
   1585   1.14   mycroft 		lasttime = time.tv_sec;
   1586   1.14   mycroft 		nqnfs_serverd();
   1587   1.14   mycroft 	}
   1588   1.24      fvdl 
   1589   1.24      fvdl 	/*
   1590   1.24      fvdl 	 * Scan the write gathering queues for writes that need to be
   1591   1.24      fvdl 	 * completed now.
   1592   1.24      fvdl 	 */
   1593   1.24      fvdl 	cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
   1594   1.73  christos 	TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) {
   1595   1.80      yamt 	    if (LIST_FIRST(&slp->ns_tq) &&
   1596   1.80      yamt 		LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec)
   1597   1.24      fvdl 		nfsrv_wakenfsd(slp);
   1598   1.24      fvdl 	}
   1599   1.14   mycroft #endif /* NFSSERVER */
   1600    1.1       cgd 	splx(s);
   1601   1.99      yamt 	callout_schedule(&nfs_timer_ch, nfs_ticks);
   1602    1.1       cgd }
   1603    1.1       cgd 
   1604   1.73  christos /*ARGSUSED*/
   1605   1.73  christos void
   1606   1.92      fvdl nfs_exit(p, v)
   1607   1.92      fvdl 	struct proc *p;
   1608   1.73  christos 	void *v;
   1609   1.73  christos {
   1610   1.73  christos 	struct nfsreq *rp;
   1611   1.73  christos 	int s = splsoftnet();
   1612   1.73  christos 
   1613   1.73  christos 	TAILQ_FOREACH(rp, &nfs_reqq, r_chain) {
   1614   1.92      fvdl 		if (rp->r_procp == p)
   1615   1.73  christos 			TAILQ_REMOVE(&nfs_reqq, rp, r_chain);
   1616   1.73  christos 	}
   1617   1.73  christos 	splx(s);
   1618   1.73  christos }
   1619   1.73  christos 
   1620    1.1       cgd /*
   1621   1.14   mycroft  * Test for a termination condition pending on the process.
   1622   1.14   mycroft  * This is used for NFSMNT_INT mounts.
   1623    1.1       cgd  */
   1624   1.23  christos int
   1625   1.92      fvdl nfs_sigintr(nmp, rep, p)
   1626   1.14   mycroft 	struct nfsmount *nmp;
   1627   1.14   mycroft 	struct nfsreq *rep;
   1628   1.92      fvdl 	struct proc *p;
   1629   1.14   mycroft {
   1630   1.47   mycroft 	sigset_t ss;
   1631   1.14   mycroft 
   1632   1.14   mycroft 	if (rep && (rep->r_flags & R_SOFTTERM))
   1633   1.14   mycroft 		return (EINTR);
   1634   1.14   mycroft 	if (!(nmp->nm_flag & NFSMNT_INT))
   1635   1.14   mycroft 		return (0);
   1636   1.92      fvdl 	if (p) {
   1637   1.92      fvdl 		sigpending1(p, &ss);
   1638   1.47   mycroft #if 0
   1639   1.92      fvdl 		sigminusset(&p->p_sigctx.ps_sigignore, &ss);
   1640   1.47   mycroft #endif
   1641   1.47   mycroft 		if (sigismember(&ss, SIGINT) || sigismember(&ss, SIGTERM) ||
   1642   1.47   mycroft 		    sigismember(&ss, SIGKILL) || sigismember(&ss, SIGHUP) ||
   1643   1.47   mycroft 		    sigismember(&ss, SIGQUIT))
   1644   1.47   mycroft 			return (EINTR);
   1645   1.47   mycroft 	}
   1646   1.14   mycroft 	return (0);
   1647   1.14   mycroft }
   1648    1.1       cgd 
   1649    1.1       cgd /*
   1650   1.14   mycroft  * Lock a socket against others.
   1651   1.14   mycroft  * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
   1652   1.14   mycroft  * and also to avoid race conditions between the processes with nfs requests
   1653   1.14   mycroft  * in progress when a reconnect is necessary.
   1654    1.1       cgd  */
   1655   1.23  christos int
   1656   1.14   mycroft nfs_sndlock(flagp, rep)
   1657   1.55  augustss 	int *flagp;
   1658   1.14   mycroft 	struct nfsreq *rep;
   1659   1.14   mycroft {
   1660   1.92      fvdl 	struct proc *p;
   1661   1.14   mycroft 	int slpflag = 0, slptimeo = 0;
   1662   1.14   mycroft 
   1663   1.14   mycroft 	if (rep) {
   1664   1.92      fvdl 		p = rep->r_procp;
   1665   1.14   mycroft 		if (rep->r_nmp->nm_flag & NFSMNT_INT)
   1666   1.14   mycroft 			slpflag = PCATCH;
   1667   1.14   mycroft 	} else
   1668   1.92      fvdl 		p = (struct proc *)0;
   1669   1.14   mycroft 	while (*flagp & NFSMNT_SNDLOCK) {
   1670  1.102      yamt 		if (rep && nfs_sigintr(rep->r_nmp, rep, p))
   1671   1.14   mycroft 			return (EINTR);
   1672   1.14   mycroft 		*flagp |= NFSMNT_WANTSND;
   1673   1.14   mycroft 		(void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsndlck",
   1674   1.14   mycroft 			slptimeo);
   1675   1.14   mycroft 		if (slpflag == PCATCH) {
   1676   1.14   mycroft 			slpflag = 0;
   1677   1.14   mycroft 			slptimeo = 2 * hz;
   1678   1.14   mycroft 		}
   1679   1.14   mycroft 	}
   1680   1.14   mycroft 	*flagp |= NFSMNT_SNDLOCK;
   1681   1.14   mycroft 	return (0);
   1682   1.14   mycroft }
   1683    1.1       cgd 
   1684   1.14   mycroft /*
   1685   1.14   mycroft  * Unlock the stream socket for others.
   1686   1.14   mycroft  */
   1687   1.14   mycroft void
   1688   1.14   mycroft nfs_sndunlock(flagp)
   1689   1.55  augustss 	int *flagp;
   1690    1.1       cgd {
   1691    1.1       cgd 
   1692   1.14   mycroft 	if ((*flagp & NFSMNT_SNDLOCK) == 0)
   1693   1.14   mycroft 		panic("nfs sndunlock");
   1694   1.14   mycroft 	*flagp &= ~NFSMNT_SNDLOCK;
   1695   1.14   mycroft 	if (*flagp & NFSMNT_WANTSND) {
   1696   1.14   mycroft 		*flagp &= ~NFSMNT_WANTSND;
   1697   1.14   mycroft 		wakeup((caddr_t)flagp);
   1698    1.1       cgd 	}
   1699   1.14   mycroft }
   1700   1.14   mycroft 
   1701   1.23  christos int
   1702   1.14   mycroft nfs_rcvlock(rep)
   1703   1.55  augustss 	struct nfsreq *rep;
   1704   1.14   mycroft {
   1705   1.51  sommerfe 	struct nfsmount *nmp = rep->r_nmp;
   1706   1.55  augustss 	int *flagp = &nmp->nm_iflag;
   1707   1.14   mycroft 	int slpflag, slptimeo = 0;
   1708   1.87      yamt 	int error = 0;
   1709   1.14   mycroft 
   1710   1.51  sommerfe 	if (*flagp & NFSMNT_DISMNT)
   1711   1.51  sommerfe 		return EIO;
   1712  1.112     perry 
   1713   1.14   mycroft 	if (*flagp & NFSMNT_INT)
   1714   1.14   mycroft 		slpflag = PCATCH;
   1715   1.14   mycroft 	else
   1716   1.14   mycroft 		slpflag = 0;
   1717   1.87      yamt 	simple_lock(&nmp->nm_slock);
   1718   1.14   mycroft 	while (*flagp & NFSMNT_RCVLOCK) {
   1719   1.92      fvdl 		if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp)) {
   1720   1.87      yamt 			error = EINTR;
   1721   1.87      yamt 			goto quit;
   1722   1.87      yamt 		}
   1723   1.14   mycroft 		*flagp |= NFSMNT_WANTRCV;
   1724   1.51  sommerfe 		nmp->nm_waiters++;
   1725   1.87      yamt 		(void) ltsleep(flagp, slpflag | (PZERO - 1), "nfsrcvlk",
   1726   1.87      yamt 			slptimeo, &nmp->nm_slock);
   1727   1.51  sommerfe 		nmp->nm_waiters--;
   1728   1.51  sommerfe 		if (*flagp & NFSMNT_DISMNT) {
   1729   1.51  sommerfe 			wakeup(&nmp->nm_waiters);
   1730   1.87      yamt 			error = EIO;
   1731   1.87      yamt 			goto quit;
   1732   1.51  sommerfe 		}
   1733   1.36      fvdl 		/* If our reply was received while we were sleeping,
   1734   1.36      fvdl 		 * then just return without taking the lock to avoid a
   1735   1.36      fvdl 		 * situation where a single iod could 'capture' the
   1736   1.36      fvdl 		 * receive lock.
   1737   1.36      fvdl 		 */
   1738   1.87      yamt 		if (rep->r_mrep != NULL) {
   1739   1.87      yamt 			error = EALREADY;
   1740   1.87      yamt 			goto quit;
   1741   1.87      yamt 		}
   1742   1.14   mycroft 		if (slpflag == PCATCH) {
   1743   1.14   mycroft 			slpflag = 0;
   1744   1.14   mycroft 			slptimeo = 2 * hz;
   1745    1.1       cgd 		}
   1746    1.1       cgd 	}
   1747   1.14   mycroft 	*flagp |= NFSMNT_RCVLOCK;
   1748   1.87      yamt quit:
   1749   1.87      yamt 	simple_unlock(&nmp->nm_slock);
   1750   1.87      yamt 	return error;
   1751   1.14   mycroft }
   1752   1.14   mycroft 
   1753   1.14   mycroft /*
   1754   1.14   mycroft  * Unlock the stream socket for others.
   1755   1.14   mycroft  */
   1756   1.14   mycroft void
   1757   1.87      yamt nfs_rcvunlock(nmp)
   1758   1.87      yamt 	struct nfsmount *nmp;
   1759   1.14   mycroft {
   1760   1.87      yamt 	int *flagp = &nmp->nm_iflag;
   1761   1.14   mycroft 
   1762   1.87      yamt 	simple_lock(&nmp->nm_slock);
   1763   1.14   mycroft 	if ((*flagp & NFSMNT_RCVLOCK) == 0)
   1764   1.14   mycroft 		panic("nfs rcvunlock");
   1765   1.14   mycroft 	*flagp &= ~NFSMNT_RCVLOCK;
   1766   1.14   mycroft 	if (*flagp & NFSMNT_WANTRCV) {
   1767   1.14   mycroft 		*flagp &= ~NFSMNT_WANTRCV;
   1768   1.14   mycroft 		wakeup((caddr_t)flagp);
   1769   1.14   mycroft 	}
   1770   1.87      yamt 	simple_unlock(&nmp->nm_slock);
   1771    1.1       cgd }
   1772    1.1       cgd 
   1773   1.14   mycroft /*
   1774   1.14   mycroft  * Parse an RPC request
   1775   1.14   mycroft  * - verify it
   1776   1.14   mycroft  * - fill in the cred struct.
   1777    1.1       cgd  */
   1778   1.23  christos int
   1779   1.24      fvdl nfs_getreq(nd, nfsd, has_header)
   1780   1.55  augustss 	struct nfsrv_descript *nd;
   1781   1.24      fvdl 	struct nfsd *nfsd;
   1782   1.14   mycroft 	int has_header;
   1783    1.1       cgd {
   1784   1.55  augustss 	int len, i;
   1785   1.55  augustss 	u_int32_t *tl;
   1786   1.55  augustss 	int32_t t1;
   1787   1.14   mycroft 	struct uio uio;
   1788   1.14   mycroft 	struct iovec iov;
   1789   1.24      fvdl 	caddr_t dpos, cp2, cp;
   1790   1.22       cgd 	u_int32_t nfsvers, auth_type;
   1791   1.24      fvdl 	uid_t nickuid;
   1792   1.24      fvdl 	int error = 0, nqnfs = 0, ticklen;
   1793   1.14   mycroft 	struct mbuf *mrep, *md;
   1794   1.55  augustss 	struct nfsuid *nuidp;
   1795   1.24      fvdl 	struct timeval tvin, tvout;
   1796   1.14   mycroft 
   1797   1.14   mycroft 	mrep = nd->nd_mrep;
   1798   1.14   mycroft 	md = nd->nd_md;
   1799   1.14   mycroft 	dpos = nd->nd_dpos;
   1800   1.14   mycroft 	if (has_header) {
   1801   1.24      fvdl 		nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
   1802   1.24      fvdl 		nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++);
   1803   1.14   mycroft 		if (*tl++ != rpc_call) {
   1804   1.14   mycroft 			m_freem(mrep);
   1805   1.14   mycroft 			return (EBADRPC);
   1806   1.14   mycroft 		}
   1807   1.24      fvdl 	} else
   1808   1.24      fvdl 		nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
   1809   1.14   mycroft 	nd->nd_repstat = 0;
   1810   1.24      fvdl 	nd->nd_flag = 0;
   1811   1.14   mycroft 	if (*tl++ != rpc_vers) {
   1812   1.14   mycroft 		nd->nd_repstat = ERPCMISMATCH;
   1813   1.14   mycroft 		nd->nd_procnum = NFSPROC_NOOP;
   1814   1.14   mycroft 		return (0);
   1815   1.14   mycroft 	}
   1816   1.14   mycroft 	if (*tl != nfs_prog) {
   1817   1.24      fvdl 		if (*tl == nqnfs_prog)
   1818   1.14   mycroft 			nqnfs++;
   1819   1.24      fvdl 		else {
   1820   1.14   mycroft 			nd->nd_repstat = EPROGUNAVAIL;
   1821   1.14   mycroft 			nd->nd_procnum = NFSPROC_NOOP;
   1822   1.14   mycroft 			return (0);
   1823   1.14   mycroft 		}
   1824   1.14   mycroft 	}
   1825   1.14   mycroft 	tl++;
   1826   1.24      fvdl 	nfsvers = fxdr_unsigned(u_int32_t, *tl++);
   1827   1.24      fvdl 	if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) ||
   1828   1.24      fvdl 		(nfsvers != NQNFS_VER3 && nqnfs)) {
   1829   1.14   mycroft 		nd->nd_repstat = EPROGMISMATCH;
   1830   1.14   mycroft 		nd->nd_procnum = NFSPROC_NOOP;
   1831   1.14   mycroft 		return (0);
   1832   1.14   mycroft 	}
   1833   1.24      fvdl 	if (nqnfs)
   1834   1.24      fvdl 		nd->nd_flag = (ND_NFSV3 | ND_NQNFS);
   1835   1.24      fvdl 	else if (nfsvers == NFS_VER3)
   1836   1.24      fvdl 		nd->nd_flag = ND_NFSV3;
   1837   1.24      fvdl 	nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++);
   1838   1.14   mycroft 	if (nd->nd_procnum == NFSPROC_NULL)
   1839   1.14   mycroft 		return (0);
   1840   1.14   mycroft 	if (nd->nd_procnum >= NFS_NPROCS ||
   1841   1.24      fvdl 		(!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) ||
   1842   1.24      fvdl 		(!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) {
   1843   1.14   mycroft 		nd->nd_repstat = EPROCUNAVAIL;
   1844   1.14   mycroft 		nd->nd_procnum = NFSPROC_NOOP;
   1845    1.1       cgd 		return (0);
   1846   1.14   mycroft 	}
   1847   1.24      fvdl 	if ((nd->nd_flag & ND_NFSV3) == 0)
   1848   1.24      fvdl 		nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
   1849   1.14   mycroft 	auth_type = *tl++;
   1850   1.14   mycroft 	len = fxdr_unsigned(int, *tl++);
   1851   1.14   mycroft 	if (len < 0 || len > RPCAUTH_MAXSIZ) {
   1852   1.14   mycroft 		m_freem(mrep);
   1853   1.14   mycroft 		return (EBADRPC);
   1854   1.14   mycroft 	}
   1855   1.14   mycroft 
   1856   1.24      fvdl 	nd->nd_flag &= ~ND_KERBAUTH;
   1857   1.14   mycroft 	/*
   1858   1.14   mycroft 	 * Handle auth_unix or auth_kerb.
   1859   1.14   mycroft 	 */
   1860   1.14   mycroft 	if (auth_type == rpc_auth_unix) {
   1861   1.14   mycroft 		len = fxdr_unsigned(int, *++tl);
   1862   1.14   mycroft 		if (len < 0 || len > NFS_MAXNAMLEN) {
   1863   1.14   mycroft 			m_freem(mrep);
   1864   1.14   mycroft 			return (EBADRPC);
   1865   1.14   mycroft 		}
   1866   1.14   mycroft 		nfsm_adv(nfsm_rndup(len));
   1867   1.24      fvdl 		nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1868   1.46     perry 		memset((caddr_t)&nd->nd_cr, 0, sizeof (struct ucred));
   1869   1.24      fvdl 		nd->nd_cr.cr_ref = 1;
   1870   1.14   mycroft 		nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
   1871   1.14   mycroft 		nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++);
   1872   1.14   mycroft 		len = fxdr_unsigned(int, *tl);
   1873   1.14   mycroft 		if (len < 0 || len > RPCAUTH_UNIXGIDS) {
   1874   1.14   mycroft 			m_freem(mrep);
   1875   1.14   mycroft 			return (EBADRPC);
   1876   1.14   mycroft 		}
   1877   1.24      fvdl 		nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED);
   1878   1.18   mycroft 		for (i = 0; i < len; i++)
   1879   1.24      fvdl 		    if (i < NGROUPS)
   1880   1.24      fvdl 			nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
   1881   1.24      fvdl 		    else
   1882   1.24      fvdl 			tl++;
   1883   1.19   mycroft 		nd->nd_cr.cr_ngroups = (len > NGROUPS) ? NGROUPS : len;
   1884   1.24      fvdl 		if (nd->nd_cr.cr_ngroups > 1)
   1885   1.24      fvdl 		    nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups);
   1886   1.24      fvdl 		len = fxdr_unsigned(int, *++tl);
   1887   1.24      fvdl 		if (len < 0 || len > RPCAUTH_MAXSIZ) {
   1888   1.14   mycroft 			m_freem(mrep);
   1889   1.14   mycroft 			return (EBADRPC);
   1890   1.14   mycroft 		}
   1891   1.24      fvdl 		if (len > 0)
   1892   1.24      fvdl 			nfsm_adv(nfsm_rndup(len));
   1893   1.24      fvdl 	} else if (auth_type == rpc_auth_kerb) {
   1894   1.24      fvdl 		switch (fxdr_unsigned(int, *tl++)) {
   1895   1.24      fvdl 		case RPCAKN_FULLNAME:
   1896   1.24      fvdl 			ticklen = fxdr_unsigned(int, *tl);
   1897   1.24      fvdl 			*((u_int32_t *)nfsd->nfsd_authstr) = *tl;
   1898   1.24      fvdl 			uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED;
   1899   1.24      fvdl 			nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED;
   1900   1.24      fvdl 			if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
   1901   1.24      fvdl 				m_freem(mrep);
   1902   1.24      fvdl 				return (EBADRPC);
   1903   1.24      fvdl 			}
   1904   1.24      fvdl 			uio.uio_offset = 0;
   1905   1.24      fvdl 			uio.uio_iov = &iov;
   1906   1.24      fvdl 			uio.uio_iovcnt = 1;
   1907   1.24      fvdl 			uio.uio_segflg = UIO_SYSSPACE;
   1908   1.24      fvdl 			iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4];
   1909   1.24      fvdl 			iov.iov_len = RPCAUTH_MAXSIZ - 4;
   1910   1.24      fvdl 			nfsm_mtouio(&uio, uio.uio_resid);
   1911   1.24      fvdl 			nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1912   1.24      fvdl 			if (*tl++ != rpc_auth_kerb ||
   1913   1.24      fvdl 				fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) {
   1914   1.31  christos 				printf("Bad kerb verifier\n");
   1915   1.24      fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
   1916   1.24      fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   1917   1.24      fvdl 				return (0);
   1918   1.24      fvdl 			}
   1919   1.24      fvdl 			nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED);
   1920   1.24      fvdl 			tl = (u_int32_t *)cp;
   1921   1.24      fvdl 			if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) {
   1922   1.31  christos 				printf("Not fullname kerb verifier\n");
   1923   1.24      fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
   1924   1.24      fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   1925   1.24      fvdl 				return (0);
   1926   1.24      fvdl 			}
   1927   1.24      fvdl 			cp += NFSX_UNSIGNED;
   1928   1.46     perry 			memcpy(nfsd->nfsd_verfstr, cp, 3 * NFSX_UNSIGNED);
   1929   1.24      fvdl 			nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED;
   1930   1.24      fvdl 			nd->nd_flag |= ND_KERBFULL;
   1931   1.24      fvdl 			nfsd->nfsd_flag |= NFSD_NEEDAUTH;
   1932   1.24      fvdl 			break;
   1933   1.24      fvdl 		case RPCAKN_NICKNAME:
   1934   1.24      fvdl 			if (len != 2 * NFSX_UNSIGNED) {
   1935   1.31  christos 				printf("Kerb nickname short\n");
   1936   1.24      fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED);
   1937   1.24      fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   1938   1.24      fvdl 				return (0);
   1939   1.24      fvdl 			}
   1940   1.24      fvdl 			nickuid = fxdr_unsigned(uid_t, *tl);
   1941   1.24      fvdl 			nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1942   1.24      fvdl 			if (*tl++ != rpc_auth_kerb ||
   1943   1.24      fvdl 				fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) {
   1944   1.31  christos 				printf("Kerb nick verifier bad\n");
   1945   1.24      fvdl 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
   1946   1.24      fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   1947   1.24      fvdl 				return (0);
   1948   1.24      fvdl 			}
   1949   1.24      fvdl 			nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1950   1.24      fvdl 			tvin.tv_sec = *tl++;
   1951   1.24      fvdl 			tvin.tv_usec = *tl;
   1952   1.24      fvdl 
   1953   1.80      yamt 			LIST_FOREACH(nuidp, NUIDHASH(nfsd->nfsd_slp, nickuid),
   1954   1.80      yamt 			    nu_hash) {
   1955   1.24      fvdl 				if (nuidp->nu_cr.cr_uid == nickuid &&
   1956   1.24      fvdl 				    (!nd->nd_nam2 ||
   1957   1.24      fvdl 				     netaddr_match(NU_NETFAM(nuidp),
   1958   1.24      fvdl 				      &nuidp->nu_haddr, nd->nd_nam2)))
   1959   1.24      fvdl 					break;
   1960   1.24      fvdl 			}
   1961   1.24      fvdl 			if (!nuidp) {
   1962   1.24      fvdl 				nd->nd_repstat =
   1963   1.24      fvdl 					(NFSERR_AUTHERR|AUTH_REJECTCRED);
   1964   1.24      fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   1965   1.24      fvdl 				return (0);
   1966   1.24      fvdl 			}
   1967   1.24      fvdl 
   1968   1.24      fvdl 			/*
   1969   1.24      fvdl 			 * Now, decrypt the timestamp using the session key
   1970   1.24      fvdl 			 * and validate it.
   1971   1.24      fvdl 			 */
   1972   1.24      fvdl #ifdef NFSKERB
   1973   1.24      fvdl 			XXX
   1974   1.24      fvdl #endif
   1975   1.14   mycroft 
   1976   1.24      fvdl 			tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec);
   1977   1.24      fvdl 			tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec);
   1978   1.24      fvdl 			if (nuidp->nu_expire < time.tv_sec ||
   1979   1.24      fvdl 			    nuidp->nu_timestamp.tv_sec > tvout.tv_sec ||
   1980   1.24      fvdl 			    (nuidp->nu_timestamp.tv_sec == tvout.tv_sec &&
   1981   1.24      fvdl 			     nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) {
   1982   1.24      fvdl 				nuidp->nu_expire = 0;
   1983   1.24      fvdl 				nd->nd_repstat =
   1984   1.24      fvdl 				    (NFSERR_AUTHERR|AUTH_REJECTVERF);
   1985   1.24      fvdl 				nd->nd_procnum = NFSPROC_NOOP;
   1986   1.24      fvdl 				return (0);
   1987   1.24      fvdl 			}
   1988   1.24      fvdl 			nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr);
   1989   1.24      fvdl 			nd->nd_flag |= ND_KERBNICK;
   1990   1.24      fvdl 		};
   1991   1.24      fvdl 	} else {
   1992   1.24      fvdl 		nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
   1993   1.24      fvdl 		nd->nd_procnum = NFSPROC_NOOP;
   1994   1.24      fvdl 		return (0);
   1995   1.14   mycroft 	}
   1996   1.14   mycroft 
   1997   1.14   mycroft 	/*
   1998   1.14   mycroft 	 * For nqnfs, get piggybacked lease request.
   1999   1.14   mycroft 	 */
   2000   1.14   mycroft 	if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) {
   2001   1.22       cgd 		nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
   2002   1.24      fvdl 		nd->nd_flag |= fxdr_unsigned(int, *tl);
   2003   1.24      fvdl 		if (nd->nd_flag & ND_LEASE) {
   2004   1.22       cgd 			nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
   2005   1.24      fvdl 			nd->nd_duration = fxdr_unsigned(u_int32_t, *tl);
   2006   1.14   mycroft 		} else
   2007   1.14   mycroft 			nd->nd_duration = NQ_MINLEASE;
   2008   1.24      fvdl 	} else
   2009   1.14   mycroft 		nd->nd_duration = NQ_MINLEASE;
   2010   1.14   mycroft 	nd->nd_md = md;
   2011   1.14   mycroft 	nd->nd_dpos = dpos;
   2012   1.14   mycroft 	return (0);
   2013   1.14   mycroft nfsmout:
   2014   1.14   mycroft 	return (error);
   2015    1.1       cgd }
   2016    1.1       cgd 
   2017   1.24      fvdl int
   2018   1.92      fvdl nfs_msg(p, server, msg)
   2019   1.92      fvdl 	struct proc *p;
   2020    1.1       cgd 	char *server, *msg;
   2021    1.1       cgd {
   2022    1.1       cgd 	tpr_t tpr;
   2023    1.1       cgd 
   2024   1.92      fvdl 	if (p)
   2025   1.92      fvdl 		tpr = tprintf_open(p);
   2026    1.1       cgd 	else
   2027    1.1       cgd 		tpr = NULL;
   2028    1.1       cgd 	tprintf(tpr, "nfs server %s: %s\n", server, msg);
   2029    1.1       cgd 	tprintf_close(tpr);
   2030   1.24      fvdl 	return (0);
   2031    1.1       cgd }
   2032    1.1       cgd 
   2033   1.14   mycroft #ifdef NFSSERVER
   2034   1.24      fvdl int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *,
   2035   1.92      fvdl 				    struct nfssvc_sock *, struct proc *,
   2036   1.23  christos 				    struct mbuf **)) = {
   2037   1.14   mycroft 	nfsrv_null,
   2038   1.14   mycroft 	nfsrv_getattr,
   2039   1.14   mycroft 	nfsrv_setattr,
   2040   1.14   mycroft 	nfsrv_lookup,
   2041   1.24      fvdl 	nfsrv3_access,
   2042   1.14   mycroft 	nfsrv_readlink,
   2043   1.14   mycroft 	nfsrv_read,
   2044   1.14   mycroft 	nfsrv_write,
   2045   1.14   mycroft 	nfsrv_create,
   2046   1.24      fvdl 	nfsrv_mkdir,
   2047   1.24      fvdl 	nfsrv_symlink,
   2048   1.24      fvdl 	nfsrv_mknod,
   2049   1.14   mycroft 	nfsrv_remove,
   2050   1.24      fvdl 	nfsrv_rmdir,
   2051   1.14   mycroft 	nfsrv_rename,
   2052   1.14   mycroft 	nfsrv_link,
   2053   1.14   mycroft 	nfsrv_readdir,
   2054   1.24      fvdl 	nfsrv_readdirplus,
   2055   1.14   mycroft 	nfsrv_statfs,
   2056   1.24      fvdl 	nfsrv_fsinfo,
   2057   1.24      fvdl 	nfsrv_pathconf,
   2058   1.24      fvdl 	nfsrv_commit,
   2059   1.14   mycroft 	nqnfsrv_getlease,
   2060   1.14   mycroft 	nqnfsrv_vacated,
   2061   1.14   mycroft 	nfsrv_noop,
   2062   1.24      fvdl 	nfsrv_noop
   2063   1.14   mycroft };
   2064   1.14   mycroft 
   2065    1.1       cgd /*
   2066   1.14   mycroft  * Socket upcall routine for the nfsd sockets.
   2067   1.14   mycroft  * The caddr_t arg is a pointer to the "struct nfssvc_sock".
   2068   1.14   mycroft  * Essentially do as much as possible non-blocking, else punt and it will
   2069   1.14   mycroft  * be called with M_WAIT from an nfsd.
   2070    1.1       cgd  */
   2071   1.14   mycroft void
   2072   1.14   mycroft nfsrv_rcv(so, arg, waitflag)
   2073   1.14   mycroft 	struct socket *so;
   2074   1.14   mycroft 	caddr_t arg;
   2075   1.14   mycroft 	int waitflag;
   2076    1.1       cgd {
   2077   1.55  augustss 	struct nfssvc_sock *slp = (struct nfssvc_sock *)arg;
   2078   1.55  augustss 	struct mbuf *m;
   2079   1.14   mycroft 	struct mbuf *mp, *nam;
   2080   1.14   mycroft 	struct uio auio;
   2081   1.14   mycroft 	int flags, error;
   2082    1.1       cgd 
   2083   1.14   mycroft 	if ((slp->ns_flag & SLP_VALID) == 0)
   2084   1.14   mycroft 		return;
   2085   1.14   mycroft #ifdef notdef
   2086   1.14   mycroft 	/*
   2087   1.14   mycroft 	 * Define this to test for nfsds handling this under heavy load.
   2088   1.14   mycroft 	 */
   2089   1.14   mycroft 	if (waitflag == M_DONTWAIT) {
   2090   1.14   mycroft 		slp->ns_flag |= SLP_NEEDQ; goto dorecs;
   2091    1.1       cgd 	}
   2092   1.14   mycroft #endif
   2093  1.105  jonathan 	/* XXX: was NULL, soreceive() requires non-NULL uio->uio_procp */
   2094  1.105  jonathan 	auio.uio_procp = curproc;	/* XXX curproc */
   2095   1.14   mycroft 	if (so->so_type == SOCK_STREAM) {
   2096   1.14   mycroft 		/*
   2097   1.14   mycroft 		 * If there are already records on the queue, defer soreceive()
   2098   1.14   mycroft 		 * to an nfsd so that there is feedback to the TCP layer that
   2099   1.14   mycroft 		 * the nfs servers are heavily loaded.
   2100   1.14   mycroft 		 */
   2101   1.14   mycroft 		if (slp->ns_rec && waitflag == M_DONTWAIT) {
   2102   1.14   mycroft 			slp->ns_flag |= SLP_NEEDQ;
   2103   1.14   mycroft 			goto dorecs;
   2104   1.14   mycroft 		}
   2105   1.14   mycroft 
   2106   1.14   mycroft 		/*
   2107   1.14   mycroft 		 * Do soreceive().
   2108   1.14   mycroft 		 */
   2109   1.14   mycroft 		auio.uio_resid = 1000000000;
   2110   1.14   mycroft 		flags = MSG_DONTWAIT;
   2111   1.43      matt 		error = (*so->so_receive)(so, &nam, &auio, &mp, (struct mbuf **)0, &flags);
   2112   1.14   mycroft 		if (error || mp == (struct mbuf *)0) {
   2113   1.14   mycroft 			if (error == EWOULDBLOCK)
   2114   1.14   mycroft 				slp->ns_flag |= SLP_NEEDQ;
   2115   1.14   mycroft 			else
   2116   1.14   mycroft 				slp->ns_flag |= SLP_DISCONN;
   2117   1.14   mycroft 			goto dorecs;
   2118   1.14   mycroft 		}
   2119   1.14   mycroft 		m = mp;
   2120   1.14   mycroft 		if (slp->ns_rawend) {
   2121   1.14   mycroft 			slp->ns_rawend->m_next = m;
   2122   1.14   mycroft 			slp->ns_cc += 1000000000 - auio.uio_resid;
   2123   1.14   mycroft 		} else {
   2124   1.14   mycroft 			slp->ns_raw = m;
   2125   1.14   mycroft 			slp->ns_cc = 1000000000 - auio.uio_resid;
   2126   1.14   mycroft 		}
   2127   1.14   mycroft 		while (m->m_next)
   2128   1.14   mycroft 			m = m->m_next;
   2129   1.14   mycroft 		slp->ns_rawend = m;
   2130   1.14   mycroft 
   2131   1.14   mycroft 		/*
   2132   1.14   mycroft 		 * Now try and parse record(s) out of the raw stream data.
   2133   1.14   mycroft 		 */
   2134   1.24      fvdl 		error = nfsrv_getstream(slp, waitflag);
   2135   1.24      fvdl 		if (error) {
   2136   1.14   mycroft 			if (error == EPERM)
   2137   1.14   mycroft 				slp->ns_flag |= SLP_DISCONN;
   2138   1.14   mycroft 			else
   2139   1.14   mycroft 				slp->ns_flag |= SLP_NEEDQ;
   2140   1.14   mycroft 		}
   2141   1.14   mycroft 	} else {
   2142   1.14   mycroft 		do {
   2143   1.14   mycroft 			auio.uio_resid = 1000000000;
   2144   1.14   mycroft 			flags = MSG_DONTWAIT;
   2145   1.43      matt 			error = (*so->so_receive)(so, &nam, &auio, &mp,
   2146   1.14   mycroft 						(struct mbuf **)0, &flags);
   2147   1.14   mycroft 			if (mp) {
   2148   1.14   mycroft 				if (nam) {
   2149   1.14   mycroft 					m = nam;
   2150   1.14   mycroft 					m->m_next = mp;
   2151   1.14   mycroft 				} else
   2152   1.14   mycroft 					m = mp;
   2153   1.14   mycroft 				if (slp->ns_recend)
   2154   1.14   mycroft 					slp->ns_recend->m_nextpkt = m;
   2155   1.14   mycroft 				else
   2156   1.14   mycroft 					slp->ns_rec = m;
   2157   1.14   mycroft 				slp->ns_recend = m;
   2158   1.14   mycroft 				m->m_nextpkt = (struct mbuf *)0;
   2159   1.14   mycroft 			}
   2160   1.14   mycroft 			if (error) {
   2161   1.14   mycroft 				if ((so->so_proto->pr_flags & PR_CONNREQUIRED)
   2162   1.14   mycroft 					&& error != EWOULDBLOCK) {
   2163   1.14   mycroft 					slp->ns_flag |= SLP_DISCONN;
   2164   1.14   mycroft 					goto dorecs;
   2165   1.14   mycroft 				}
   2166   1.14   mycroft 			}
   2167   1.14   mycroft 		} while (mp);
   2168   1.14   mycroft 	}
   2169   1.14   mycroft 
   2170   1.14   mycroft 	/*
   2171   1.14   mycroft 	 * Now try and process the request records, non-blocking.
   2172   1.14   mycroft 	 */
   2173   1.14   mycroft dorecs:
   2174   1.14   mycroft 	if (waitflag == M_DONTWAIT &&
   2175   1.14   mycroft 		(slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN))))
   2176   1.14   mycroft 		nfsrv_wakenfsd(slp);
   2177    1.1       cgd }
   2178    1.1       cgd 
   2179    1.1       cgd /*
   2180   1.14   mycroft  * Try and extract an RPC request from the mbuf data list received on a
   2181   1.14   mycroft  * stream socket. The "waitflag" argument indicates whether or not it
   2182   1.14   mycroft  * can sleep.
   2183   1.14   mycroft  */
   2184   1.23  christos int
   2185   1.14   mycroft nfsrv_getstream(slp, waitflag)
   2186   1.55  augustss 	struct nfssvc_sock *slp;
   2187   1.14   mycroft 	int waitflag;
   2188    1.1       cgd {
   2189   1.55  augustss 	struct mbuf *m, **mpp;
   2190   1.81      yamt 	struct mbuf *recm;
   2191   1.24      fvdl 	u_int32_t recmark;
   2192    1.1       cgd 
   2193   1.14   mycroft 	if (slp->ns_flag & SLP_GETSTREAM)
   2194   1.14   mycroft 		panic("nfs getstream");
   2195   1.14   mycroft 	slp->ns_flag |= SLP_GETSTREAM;
   2196   1.14   mycroft 	for (;;) {
   2197   1.82      yamt 		if (slp->ns_reclen == 0) {
   2198   1.82      yamt 			if (slp->ns_cc < NFSX_UNSIGNED) {
   2199   1.82      yamt 				slp->ns_flag &= ~SLP_GETSTREAM;
   2200   1.82      yamt 				return (0);
   2201   1.82      yamt 			}
   2202   1.82      yamt 			m = slp->ns_raw;
   2203   1.82      yamt 			m_copydata(m, 0, NFSX_UNSIGNED, (caddr_t)&recmark);
   2204   1.82      yamt 			m_adj(m, NFSX_UNSIGNED);
   2205   1.82      yamt 			slp->ns_cc -= NFSX_UNSIGNED;
   2206   1.82      yamt 			recmark = ntohl(recmark);
   2207   1.82      yamt 			slp->ns_reclen = recmark & ~0x80000000;
   2208   1.82      yamt 			if (recmark & 0x80000000)
   2209   1.82      yamt 				slp->ns_flag |= SLP_LASTFRAG;
   2210   1.82      yamt 			else
   2211   1.82      yamt 				slp->ns_flag &= ~SLP_LASTFRAG;
   2212   1.82      yamt 			if (slp->ns_reclen > NFS_MAXPACKET) {
   2213   1.82      yamt 				slp->ns_flag &= ~SLP_GETSTREAM;
   2214   1.82      yamt 				return (EPERM);
   2215   1.82      yamt 			}
   2216   1.82      yamt 		}
   2217   1.82      yamt 
   2218   1.82      yamt 		/*
   2219   1.82      yamt 		 * Now get the record part.
   2220   1.82      yamt 		 *
   2221   1.82      yamt 		 * Note that slp->ns_reclen may be 0.  Linux sometimes
   2222   1.82      yamt 		 * generates 0-length records.
   2223   1.82      yamt 		 */
   2224   1.82      yamt 		if (slp->ns_cc == slp->ns_reclen) {
   2225   1.82      yamt 			recm = slp->ns_raw;
   2226   1.82      yamt 			slp->ns_raw = slp->ns_rawend = (struct mbuf *)0;
   2227   1.82      yamt 			slp->ns_cc = slp->ns_reclen = 0;
   2228   1.82      yamt 		} else if (slp->ns_cc > slp->ns_reclen) {
   2229   1.82      yamt 			recm = slp->ns_raw;
   2230   1.82      yamt 			m = m_split(recm, slp->ns_reclen, waitflag);
   2231   1.82      yamt 			if (m == NULL) {
   2232   1.82      yamt 				slp->ns_flag &= ~SLP_GETSTREAM;
   2233   1.82      yamt 				return (EWOULDBLOCK);
   2234   1.82      yamt 			}
   2235  1.108  jonathan 			m_claimm(recm, &nfs_mowner);
   2236   1.82      yamt 			slp->ns_raw = m;
   2237   1.82      yamt 			if (m->m_next == NULL)
   2238   1.82      yamt 				slp->ns_rawend = m;
   2239   1.82      yamt 			slp->ns_cc -= slp->ns_reclen;
   2240   1.82      yamt 			slp->ns_reclen = 0;
   2241   1.82      yamt 		} else {
   2242   1.14   mycroft 			slp->ns_flag &= ~SLP_GETSTREAM;
   2243   1.14   mycroft 			return (0);
   2244   1.14   mycroft 		}
   2245   1.14   mycroft 
   2246   1.82      yamt 		/*
   2247   1.82      yamt 		 * Accumulate the fragments into a record.
   2248   1.82      yamt 		 */
   2249   1.82      yamt 		mpp = &slp->ns_frag;
   2250   1.82      yamt 		while (*mpp)
   2251   1.82      yamt 			mpp = &((*mpp)->m_next);
   2252   1.82      yamt 		*mpp = recm;
   2253   1.82      yamt 		if (slp->ns_flag & SLP_LASTFRAG) {
   2254   1.82      yamt 			if (slp->ns_recend)
   2255   1.82      yamt 				slp->ns_recend->m_nextpkt = slp->ns_frag;
   2256   1.82      yamt 			else
   2257   1.82      yamt 				slp->ns_rec = slp->ns_frag;
   2258   1.82      yamt 			slp->ns_recend = slp->ns_frag;
   2259   1.82      yamt 			slp->ns_frag = (struct mbuf *)0;
   2260   1.14   mycroft 		}
   2261    1.1       cgd 	}
   2262    1.1       cgd }
   2263    1.1       cgd 
   2264    1.1       cgd /*
   2265   1.14   mycroft  * Parse an RPC header.
   2266   1.14   mycroft  */
   2267   1.23  christos int
   2268   1.24      fvdl nfsrv_dorec(slp, nfsd, ndp)
   2269   1.55  augustss 	struct nfssvc_sock *slp;
   2270   1.24      fvdl 	struct nfsd *nfsd;
   2271   1.24      fvdl 	struct nfsrv_descript **ndp;
   2272   1.14   mycroft {
   2273   1.55  augustss 	struct mbuf *m, *nam;
   2274   1.55  augustss 	struct nfsrv_descript *nd;
   2275   1.14   mycroft 	int error;
   2276    1.1       cgd 
   2277   1.24      fvdl 	*ndp = NULL;
   2278   1.14   mycroft 	if ((slp->ns_flag & SLP_VALID) == 0 ||
   2279   1.14   mycroft 	    (m = slp->ns_rec) == (struct mbuf *)0)
   2280   1.14   mycroft 		return (ENOBUFS);
   2281   1.24      fvdl 	slp->ns_rec = m->m_nextpkt;
   2282   1.24      fvdl 	if (slp->ns_rec)
   2283   1.14   mycroft 		m->m_nextpkt = (struct mbuf *)0;
   2284   1.14   mycroft 	else
   2285   1.14   mycroft 		slp->ns_recend = (struct mbuf *)0;
   2286   1.14   mycroft 	if (m->m_type == MT_SONAME) {
   2287   1.24      fvdl 		nam = m;
   2288   1.24      fvdl 		m = m->m_next;
   2289   1.24      fvdl 		nam->m_next = NULL;
   2290   1.24      fvdl 	} else
   2291   1.24      fvdl 		nam = NULL;
   2292   1.88      yamt 	nd = pool_get(&nfs_srvdesc_pool, PR_WAITOK);
   2293   1.24      fvdl 	nd->nd_md = nd->nd_mrep = m;
   2294   1.24      fvdl 	nd->nd_nam2 = nam;
   2295   1.24      fvdl 	nd->nd_dpos = mtod(m, caddr_t);
   2296   1.24      fvdl 	error = nfs_getreq(nd, nfsd, TRUE);
   2297   1.24      fvdl 	if (error) {
   2298   1.24      fvdl 		m_freem(nam);
   2299   1.88      yamt 		pool_put(&nfs_srvdesc_pool, nd);
   2300   1.14   mycroft 		return (error);
   2301   1.14   mycroft 	}
   2302   1.24      fvdl 	*ndp = nd;
   2303   1.24      fvdl 	nfsd->nfsd_nd = nd;
   2304    1.1       cgd 	return (0);
   2305    1.1       cgd }
   2306    1.1       cgd 
   2307   1.24      fvdl 
   2308    1.1       cgd /*
   2309   1.14   mycroft  * Search for a sleeping nfsd and wake it up.
   2310   1.14   mycroft  * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the
   2311   1.14   mycroft  * running nfsds will go look for the work in the nfssvc_sock list.
   2312   1.14   mycroft  */
   2313   1.14   mycroft void
   2314   1.14   mycroft nfsrv_wakenfsd(slp)
   2315   1.14   mycroft 	struct nfssvc_sock *slp;
   2316   1.14   mycroft {
   2317   1.55  augustss 	struct nfsd *nd;
   2318   1.14   mycroft 
   2319   1.14   mycroft 	if ((slp->ns_flag & SLP_VALID) == 0)
   2320   1.14   mycroft 		return;
   2321   1.90      yamt 	simple_lock(&nfsd_slock);
   2322   1.90      yamt 	if (slp->ns_flag & SLP_DOREC) {
   2323   1.90      yamt 		simple_unlock(&nfsd_slock);
   2324   1.90      yamt 		return;
   2325   1.90      yamt 	}
   2326   1.90      yamt 	nd = SLIST_FIRST(&nfsd_idle_head);
   2327   1.90      yamt 	if (nd) {
   2328   1.90      yamt 		SLIST_REMOVE_HEAD(&nfsd_idle_head, nfsd_idle);
   2329   1.90      yamt 		simple_unlock(&nfsd_slock);
   2330   1.90      yamt 
   2331   1.90      yamt 		KASSERT(nd->nfsd_flag & NFSD_WAITING);
   2332   1.90      yamt 		nd->nfsd_flag &= ~NFSD_WAITING;
   2333   1.90      yamt 		if (nd->nfsd_slp)
   2334   1.90      yamt 			panic("nfsd wakeup");
   2335   1.90      yamt 		slp->ns_sref++;
   2336   1.90      yamt 		nd->nfsd_slp = slp;
   2337   1.90      yamt 		wakeup(nd);
   2338   1.90      yamt 		return;
   2339   1.14   mycroft 	}
   2340   1.14   mycroft 	slp->ns_flag |= SLP_DOREC;
   2341   1.17   mycroft 	nfsd_head_flag |= NFSD_CHECKSLP;
   2342   1.90      yamt 	TAILQ_INSERT_TAIL(&nfssvc_sockpending, slp, ns_pending);
   2343   1.90      yamt 	simple_unlock(&nfsd_slock);
   2344    1.1       cgd }
   2345   1.14   mycroft #endif /* NFSSERVER */
   2346