xref: /netbsd-src/sys/nfs/nfs_socket.c (revision f17b710f3d406bee67aa39c65053114ab78297c5)
1 /*	$NetBSD: nfs_socket.c,v 1.196 2015/05/09 15:22:47 rtr Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1991, 1993, 1995
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	@(#)nfs_socket.c	8.5 (Berkeley) 3/30/95
35  */
36 
37 /*
38  * Socket operations for use by nfs
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.196 2015/05/09 15:22:47 rtr Exp $");
43 
44 #ifdef _KERNEL_OPT
45 #include "opt_nfs.h"
46 #include "opt_mbuftrace.h"
47 #endif
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/evcnt.h>
52 #include <sys/callout.h>
53 #include <sys/proc.h>
54 #include <sys/mount.h>
55 #include <sys/kernel.h>
56 #include <sys/kmem.h>
57 #include <sys/mbuf.h>
58 #include <sys/vnode.h>
59 #include <sys/domain.h>
60 #include <sys/protosw.h>
61 #include <sys/socket.h>
62 #include <sys/socketvar.h>
63 #include <sys/syslog.h>
64 #include <sys/tprintf.h>
65 #include <sys/namei.h>
66 #include <sys/signal.h>
67 #include <sys/signalvar.h>
68 #include <sys/kauth.h>
69 
70 #include <netinet/in.h>
71 #include <netinet/tcp.h>
72 
73 #include <nfs/rpcv2.h>
74 #include <nfs/nfsproto.h>
75 #include <nfs/nfs.h>
76 #include <nfs/xdr_subs.h>
77 #include <nfs/nfsm_subs.h>
78 #include <nfs/nfsmount.h>
79 #include <nfs/nfsnode.h>
80 #include <nfs/nfsrtt.h>
81 #include <nfs/nfs_var.h>
82 
83 #ifdef MBUFTRACE
84 struct mowner nfs_mowner = MOWNER_INIT("nfs","");
85 #endif
86 
87 /*
88  * Estimate rto for an nfs rpc sent via. an unreliable datagram.
89  * Use the mean and mean deviation of rtt for the appropriate type of rpc
90  * for the frequent rpcs and a default for the others.
91  * The justification for doing "other" this way is that these rpcs
92  * happen so infrequently that timer est. would probably be stale.
93  * Also, since many of these rpcs are
94  * non-idempotent, a conservative timeout is desired.
95  * getattr, lookup - A+2D
96  * read, write     - A+4D
97  * other           - nm_timeo
98  */
99 #define	NFS_RTO(n, t) \
100 	((t) == 0 ? (n)->nm_timeo : \
101 	 ((t) < 3 ? \
102 	  (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \
103 	  ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1)))
104 #define	NFS_SRTT(r)	(r)->r_nmp->nm_srtt[nfs_proct[(r)->r_procnum] - 1]
105 #define	NFS_SDRTT(r)	(r)->r_nmp->nm_sdrtt[nfs_proct[(r)->r_procnum] - 1]
106 
107 /*
108  * Defines which timer to use for the procnum.
109  * 0 - default
110  * 1 - getattr
111  * 2 - lookup
112  * 3 - read
113  * 4 - write
114  */
115 const int nfs_proct[NFS_NPROCS] = {
116 	[NFSPROC_NULL] = 0,
117 	[NFSPROC_GETATTR] = 1,
118 	[NFSPROC_SETATTR] = 0,
119 	[NFSPROC_LOOKUP] = 2,
120 	[NFSPROC_ACCESS] = 1,
121 	[NFSPROC_READLINK] = 3,
122 	[NFSPROC_READ] = 3,
123 	[NFSPROC_WRITE] = 4,
124 	[NFSPROC_CREATE] = 0,
125 	[NFSPROC_MKDIR] = 0,
126 	[NFSPROC_SYMLINK] = 0,
127 	[NFSPROC_MKNOD] = 0,
128 	[NFSPROC_REMOVE] = 0,
129 	[NFSPROC_RMDIR] = 0,
130 	[NFSPROC_RENAME] = 0,
131 	[NFSPROC_LINK] = 0,
132 	[NFSPROC_READDIR] = 3,
133 	[NFSPROC_READDIRPLUS] = 3,
134 	[NFSPROC_FSSTAT] = 0,
135 	[NFSPROC_FSINFO] = 0,
136 	[NFSPROC_PATHCONF] = 0,
137 	[NFSPROC_COMMIT] = 0,
138 	[NFSPROC_NOOP] = 0,
139 };
140 
141 #ifdef DEBUG
142 /*
143  * Avoid spamming the console with debugging messages.  We only print
144  * the nfs timer and reply error debugs every 10 seconds.
145  */
146 const struct timeval nfs_err_interval = { 10, 0 };
147 struct timeval nfs_reply_last_err_time;
148 struct timeval nfs_timer_last_err_time;
149 #endif
150 
151 /*
152  * There is a congestion window for outstanding rpcs maintained per mount
153  * point. The cwnd size is adjusted in roughly the way that:
154  * Van Jacobson, Congestion avoidance and Control, In "Proceedings of
155  * SIGCOMM '88". ACM, August 1988.
156  * describes for TCP. The cwnd size is chopped in half on a retransmit timeout
157  * and incremented by 1/cwnd when each rpc reply is received and a full cwnd
158  * of rpcs is in progress.
159  * (The sent count and cwnd are scaled for integer arith.)
160  * Variants of "slow start" were tried and were found to be too much of a
161  * performance hit (ave. rtt 3 times larger),
162  * I suspect due to the large rtt that nfs rpcs have.
163  */
164 int nfsrtton = 0;
165 struct nfsrtt nfsrtt;
166 static const int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };
167 struct nfsreqhead nfs_reqq;
168 static callout_t nfs_timer_ch;
169 static struct evcnt nfs_timer_ev;
170 static struct evcnt nfs_timer_start_ev;
171 static struct evcnt nfs_timer_stop_ev;
172 static kmutex_t nfs_timer_lock;
173 static bool (*nfs_timer_srvvec)(void);
174 
175 /*
176  * Initialize sockets and congestion for a new NFS connection.
177  * We do not free the sockaddr if error.
178  */
179 int
180 nfs_connect(struct nfsmount *nmp, struct nfsreq *rep, struct lwp *l)
181 {
182 	struct socket *so;
183 	int error, rcvreserve, sndreserve;
184 	struct sockaddr *saddr;
185 	struct sockaddr_in sin;
186 	struct sockaddr_in6 sin6;
187 	int val;
188 
189 	nmp->nm_so = NULL;
190 	saddr = mtod(nmp->nm_nam, struct sockaddr *);
191 	error = socreate(saddr->sa_family, &nmp->nm_so,
192 		nmp->nm_sotype, nmp->nm_soproto, l, NULL);
193 	if (error)
194 		goto bad;
195 	so = nmp->nm_so;
196 #ifdef MBUFTRACE
197 	so->so_mowner = &nfs_mowner;
198 	so->so_rcv.sb_mowner = &nfs_mowner;
199 	so->so_snd.sb_mowner = &nfs_mowner;
200 #endif
201 	nmp->nm_soflags = so->so_proto->pr_flags;
202 
203 	/*
204 	 * Some servers require that the client port be a reserved port number.
205 	 */
206 	if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
207 		val = IP_PORTRANGE_LOW;
208 
209 		if ((error = so_setsockopt(NULL, so, IPPROTO_IP, IP_PORTRANGE,
210 		    &val, sizeof(val))))
211 			goto bad;
212 		sin.sin_len = sizeof(struct sockaddr_in);
213 		sin.sin_family = AF_INET;
214 		sin.sin_addr.s_addr = INADDR_ANY;
215 		sin.sin_port = 0;
216 		error = sobind(so, (struct sockaddr *)&sin, &lwp0);
217 		if (error)
218 			goto bad;
219 	}
220 	if (saddr->sa_family == AF_INET6 && (nmp->nm_flag & NFSMNT_RESVPORT)) {
221 		val = IPV6_PORTRANGE_LOW;
222 
223 		if ((error = so_setsockopt(NULL, so, IPPROTO_IPV6,
224 		    IPV6_PORTRANGE, &val, sizeof(val))))
225 			goto bad;
226 		memset(&sin6, 0, sizeof(sin6));
227 		sin6.sin6_len = sizeof(struct sockaddr_in6);
228 		sin6.sin6_family = AF_INET6;
229 		error = sobind(so, (struct sockaddr *)&sin6, &lwp0);
230 		if (error)
231 			goto bad;
232 	}
233 
234 	/*
235 	 * Protocols that do not require connections may be optionally left
236 	 * unconnected for servers that reply from a port other than NFS_PORT.
237 	 */
238 	solock(so);
239 	if (nmp->nm_flag & NFSMNT_NOCONN) {
240 		if (nmp->nm_soflags & PR_CONNREQUIRED) {
241 			sounlock(so);
242 			error = ENOTCONN;
243 			goto bad;
244 		}
245 	} else {
246 		error = soconnect(so, mtod(nmp->nm_nam, struct sockaddr *), l);
247 		if (error) {
248 			sounlock(so);
249 			goto bad;
250 		}
251 
252 		/*
253 		 * Wait for the connection to complete. Cribbed from the
254 		 * connect system call but with the wait timing out so
255 		 * that interruptible mounts don't hang here for a long time.
256 		 */
257 		while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
258 			(void)sowait(so, false, 2 * hz);
259 			if ((so->so_state & SS_ISCONNECTING) &&
260 			    so->so_error == 0 && rep &&
261 			    (error = nfs_sigintr(nmp, rep, rep->r_lwp)) != 0){
262 				so->so_state &= ~SS_ISCONNECTING;
263 				sounlock(so);
264 				goto bad;
265 			}
266 		}
267 		if (so->so_error) {
268 			error = so->so_error;
269 			so->so_error = 0;
270 			sounlock(so);
271 			goto bad;
272 		}
273 	}
274 	if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
275 		so->so_rcv.sb_timeo = (5 * hz);
276 		so->so_snd.sb_timeo = (5 * hz);
277 	} else {
278 		/*
279 		 * enable receive timeout to detect server crash and reconnect.
280 		 * otherwise, we can be stuck in soreceive forever.
281 		 */
282 		so->so_rcv.sb_timeo = (5 * hz);
283 		so->so_snd.sb_timeo = 0;
284 	}
285 	if (nmp->nm_sotype == SOCK_DGRAM) {
286 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 3;
287 		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
288 		    NFS_MAXPKTHDR) * 2;
289 	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
290 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 3;
291 		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
292 		    NFS_MAXPKTHDR) * 3;
293 	} else {
294 		sounlock(so);
295 		if (nmp->nm_sotype != SOCK_STREAM)
296 			panic("nfscon sotype");
297 		if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
298 			val = 1;
299 			so_setsockopt(NULL, so, SOL_SOCKET, SO_KEEPALIVE, &val,
300 			    sizeof(val));
301 		}
302 		if (so->so_proto->pr_protocol == IPPROTO_TCP) {
303 			val = 1;
304 			so_setsockopt(NULL, so, IPPROTO_TCP, TCP_NODELAY, &val,
305 			    sizeof(val));
306 		}
307 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
308 		    sizeof (u_int32_t)) * 3;
309 		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
310 		    sizeof (u_int32_t)) * 3;
311 		solock(so);
312 	}
313 	error = soreserve(so, sndreserve, rcvreserve);
314 	if (error) {
315 		sounlock(so);
316 		goto bad;
317 	}
318 	so->so_rcv.sb_flags |= SB_NOINTR;
319 	so->so_snd.sb_flags |= SB_NOINTR;
320 	sounlock(so);
321 
322 	/* Initialize other non-zero congestion variables */
323 	nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] =
324 		NFS_TIMEO << 3;
325 	nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] =
326 		nmp->nm_sdrtt[3] = 0;
327 	nmp->nm_cwnd = NFS_MAXCWND / 2;	    /* Initial send window */
328 	nmp->nm_sent = 0;
329 	nmp->nm_timeouts = 0;
330 	return (0);
331 
332 bad:
333 	nfs_disconnect(nmp);
334 	return (error);
335 }
336 
337 /*
338  * Reconnect routine:
339  * Called when a connection is broken on a reliable protocol.
340  * - clean up the old socket
341  * - nfs_connect() again
342  * - set R_MUSTRESEND for all outstanding requests on mount point
343  * If this fails the mount point is DEAD!
344  * nb: Must be called with the nfs_sndlock() set on the mount point.
345  */
346 int
347 nfs_reconnect(struct nfsreq *rep)
348 {
349 	struct nfsreq *rp;
350 	struct nfsmount *nmp = rep->r_nmp;
351 	int error;
352 
353 	nfs_disconnect(nmp);
354 	while ((error = nfs_connect(nmp, rep, &lwp0)) != 0) {
355 		if (error == EINTR || error == ERESTART)
356 			return (EINTR);
357 		kpause("nfscn2", false, hz, NULL);
358 	}
359 
360 	/*
361 	 * Loop through outstanding request list and fix up all requests
362 	 * on old socket.
363 	 */
364 	TAILQ_FOREACH(rp, &nfs_reqq, r_chain) {
365 		if (rp->r_nmp == nmp) {
366 			if ((rp->r_flags & R_MUSTRESEND) == 0)
367 				rp->r_flags |= R_MUSTRESEND | R_REXMITTED;
368 			rp->r_rexmit = 0;
369 		}
370 	}
371 	return (0);
372 }
373 
374 /*
375  * NFS disconnect. Clean up and unlink.
376  */
377 void
378 nfs_disconnect(struct nfsmount *nmp)
379 {
380 	struct socket *so;
381 	int drain = 0;
382 
383 	if (nmp->nm_so) {
384 		so = nmp->nm_so;
385 		nmp->nm_so = NULL;
386 		solock(so);
387 		soshutdown(so, SHUT_RDWR);
388 		sounlock(so);
389 		drain = (nmp->nm_iflag & NFSMNT_DISMNT) != 0;
390 		if (drain) {
391 			/*
392 			 * soshutdown() above should wake up the current
393 			 * listener.
394 			 * Now wake up those waiting for the receive lock, and
395 			 * wait for them to go away unhappy, to prevent *nmp
396 			 * from evaporating while they're sleeping.
397 			 */
398 			mutex_enter(&nmp->nm_lock);
399 			while (nmp->nm_waiters > 0) {
400 				cv_broadcast(&nmp->nm_rcvcv);
401 				cv_broadcast(&nmp->nm_sndcv);
402 				cv_wait(&nmp->nm_disconcv, &nmp->nm_lock);
403 			}
404 			mutex_exit(&nmp->nm_lock);
405 		}
406 		soclose(so);
407 	}
408 #ifdef DIAGNOSTIC
409 	if (drain && (nmp->nm_waiters > 0))
410 		panic("nfs_disconnect: waiters left after drain?");
411 #endif
412 }
413 
414 void
415 nfs_safedisconnect(struct nfsmount *nmp)
416 {
417 	struct nfsreq dummyreq;
418 
419 	memset(&dummyreq, 0, sizeof(dummyreq));
420 	dummyreq.r_nmp = nmp;
421 	nfs_rcvlock(nmp, &dummyreq); /* XXX ignored error return */
422 	nfs_disconnect(nmp);
423 	nfs_rcvunlock(nmp);
424 }
425 
426 /*
427  * This is the nfs send routine. For connection based socket types, it
428  * must be called with an nfs_sndlock() on the socket.
429  * "rep == NULL" indicates that it has been called from a server.
430  * For the client side:
431  * - return EINTR if the RPC is terminated, 0 otherwise
432  * - set R_MUSTRESEND if the send fails for any reason
433  * - do any cleanup required by recoverable socket errors (? ? ?)
434  * For the server side:
435  * - return EINTR or ERESTART if interrupted by a signal
436  * - return EPIPE if a connection is lost for connection based sockets (TCP...)
437  * - do any cleanup required by recoverable socket errors (? ? ?)
438  */
439 int
440 nfs_send(struct socket *so, struct mbuf *nam, struct mbuf *top, struct nfsreq *rep, struct lwp *l)
441 {
442 	struct sockaddr *sendnam;
443 	int error, soflags, flags;
444 
445 	/* XXX nfs_doio()/nfs_request() calls with  rep->r_lwp == NULL */
446 	if (l == NULL && rep->r_lwp == NULL)
447 		l = curlwp;
448 
449 	if (rep) {
450 		if (rep->r_flags & R_SOFTTERM) {
451 			m_freem(top);
452 			return (EINTR);
453 		}
454 		if ((so = rep->r_nmp->nm_so) == NULL) {
455 			rep->r_flags |= R_MUSTRESEND;
456 			m_freem(top);
457 			return (0);
458 		}
459 		rep->r_flags &= ~R_MUSTRESEND;
460 		soflags = rep->r_nmp->nm_soflags;
461 	} else
462 		soflags = so->so_proto->pr_flags;
463 	if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
464 		sendnam = NULL;
465 	else
466 		sendnam = mtod(nam, struct sockaddr *);
467 	if (so->so_type == SOCK_SEQPACKET)
468 		flags = MSG_EOR;
469 	else
470 		flags = 0;
471 
472 	error = (*so->so_send)(so, sendnam, NULL, top, NULL, flags,  l);
473 	if (error) {
474 		if (rep) {
475 			if (error == ENOBUFS && so->so_type == SOCK_DGRAM) {
476 				/*
477 				 * We're too fast for the network/driver,
478 				 * and UDP isn't flowcontrolled.
479 				 * We need to resend. This is not fatal,
480 				 * just try again.
481 				 *
482 				 * Could be smarter here by doing some sort
483 				 * of a backoff, but this is rare.
484 				 */
485 				rep->r_flags |= R_MUSTRESEND;
486 			} else {
487 				if (error != EPIPE)
488 					log(LOG_INFO,
489 					    "nfs send error %d for %s\n",
490 					    error,
491 					    rep->r_nmp->nm_mountp->
492 						    mnt_stat.f_mntfromname);
493 				/*
494 				 * Deal with errors for the client side.
495 				 */
496 				if (rep->r_flags & R_SOFTTERM)
497 					error = EINTR;
498 				else if (error != EMSGSIZE)
499 					rep->r_flags |= R_MUSTRESEND;
500 			}
501 		} else {
502 			/*
503 			 * See above. This error can happen under normal
504 			 * circumstances and the log is too noisy.
505 			 * The error will still show up in nfsstat.
506 			 */
507 			if (error != ENOBUFS || so->so_type != SOCK_DGRAM)
508 				log(LOG_INFO, "nfsd send error %d\n", error);
509 		}
510 
511 		/*
512 		 * Handle any recoverable (soft) socket errors here. (? ? ?)
513 		 */
514 		if (error != EINTR && error != ERESTART &&
515 		    error != EWOULDBLOCK && error != EPIPE &&
516 		    error != EMSGSIZE)
517 			error = 0;
518 	}
519 	return (error);
520 }
521 
522 /*
523  * Generate the rpc reply header
524  * siz arg. is used to decide if adding a cluster is worthwhile
525  */
526 int
527 nfs_rephead(int siz, struct nfsrv_descript *nd, struct nfssvc_sock *slp, int err, int cache, u_quad_t *frev, struct mbuf **mrq, struct mbuf **mbp, char **bposp)
528 {
529 	u_int32_t *tl;
530 	struct mbuf *mreq;
531 	char *bpos;
532 	struct mbuf *mb;
533 
534 	mreq = m_gethdr(M_WAIT, MT_DATA);
535 	MCLAIM(mreq, &nfs_mowner);
536 	mb = mreq;
537 	/*
538 	 * If this is a big reply, use a cluster else
539 	 * try and leave leading space for the lower level headers.
540 	 */
541 	siz += RPC_REPLYSIZ;
542 	if (siz >= max_datalen) {
543 		m_clget(mreq, M_WAIT);
544 	} else
545 		mreq->m_data += max_hdr;
546 	tl = mtod(mreq, u_int32_t *);
547 	mreq->m_len = 6 * NFSX_UNSIGNED;
548 	bpos = ((char *)tl) + mreq->m_len;
549 	*tl++ = txdr_unsigned(nd->nd_retxid);
550 	*tl++ = rpc_reply;
551 	if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
552 		*tl++ = rpc_msgdenied;
553 		if (err & NFSERR_AUTHERR) {
554 			*tl++ = rpc_autherr;
555 			*tl = txdr_unsigned(err & ~NFSERR_AUTHERR);
556 			mreq->m_len -= NFSX_UNSIGNED;
557 			bpos -= NFSX_UNSIGNED;
558 		} else {
559 			*tl++ = rpc_mismatch;
560 			*tl++ = txdr_unsigned(RPC_VER2);
561 			*tl = txdr_unsigned(RPC_VER2);
562 		}
563 	} else {
564 		*tl++ = rpc_msgaccepted;
565 
566 		/*
567 		 * For Kerberos authentication, we must send the nickname
568 		 * verifier back, otherwise just RPCAUTH_NULL.
569 		 */
570 		if (nd->nd_flag & ND_KERBFULL) {
571 			struct nfsuid *nuidp;
572 			struct timeval ktvin, ktvout;
573 
574 			memset(&ktvout, 0, sizeof ktvout);	/* XXX gcc */
575 
576 			LIST_FOREACH(nuidp,
577 			    NUIDHASH(slp, kauth_cred_geteuid(nd->nd_cr)),
578 			    nu_hash) {
579 				if (kauth_cred_geteuid(nuidp->nu_cr) ==
580 				kauth_cred_geteuid(nd->nd_cr) &&
581 				    (!nd->nd_nam2 || netaddr_match(
582 				    NU_NETFAM(nuidp), &nuidp->nu_haddr,
583 				    nd->nd_nam2)))
584 					break;
585 			}
586 			if (nuidp) {
587 				ktvin.tv_sec =
588 				    txdr_unsigned(nuidp->nu_timestamp.tv_sec
589 					- 1);
590 				ktvin.tv_usec =
591 				    txdr_unsigned(nuidp->nu_timestamp.tv_usec);
592 
593 				/*
594 				 * Encrypt the timestamp in ecb mode using the
595 				 * session key.
596 				 */
597 #ifdef NFSKERB
598 				XXX
599 #else
600 				(void)ktvin.tv_sec;
601 #endif
602 
603 				*tl++ = rpc_auth_kerb;
604 				*tl++ = txdr_unsigned(3 * NFSX_UNSIGNED);
605 				*tl = ktvout.tv_sec;
606 				nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
607 				*tl++ = ktvout.tv_usec;
608 				*tl++ = txdr_unsigned(
609 				    kauth_cred_geteuid(nuidp->nu_cr));
610 			} else {
611 				*tl++ = 0;
612 				*tl++ = 0;
613 			}
614 		} else {
615 			*tl++ = 0;
616 			*tl++ = 0;
617 		}
618 		switch (err) {
619 		case EPROGUNAVAIL:
620 			*tl = txdr_unsigned(RPC_PROGUNAVAIL);
621 			break;
622 		case EPROGMISMATCH:
623 			*tl = txdr_unsigned(RPC_PROGMISMATCH);
624 			nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
625 			*tl++ = txdr_unsigned(2);
626 			*tl = txdr_unsigned(3);
627 			break;
628 		case EPROCUNAVAIL:
629 			*tl = txdr_unsigned(RPC_PROCUNAVAIL);
630 			break;
631 		case EBADRPC:
632 			*tl = txdr_unsigned(RPC_GARBAGE);
633 			break;
634 		default:
635 			*tl = 0;
636 			if (err != NFSERR_RETVOID) {
637 				nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
638 				if (err)
639 				    *tl = txdr_unsigned(nfsrv_errmap(nd, err));
640 				else
641 				    *tl = 0;
642 			}
643 			break;
644 		};
645 	}
646 
647 	if (mrq != NULL)
648 		*mrq = mreq;
649 	*mbp = mb;
650 	*bposp = bpos;
651 	if (err != 0 && err != NFSERR_RETVOID)
652 		nfsstats.srvrpc_errs++;
653 	return (0);
654 }
655 
656 static void
657 nfs_timer_schedule(void)
658 {
659 
660 	callout_schedule(&nfs_timer_ch, nfs_ticks);
661 }
662 
663 void
664 nfs_timer_start(void)
665 {
666 
667 	if (callout_pending(&nfs_timer_ch))
668 		return;
669 
670 	nfs_timer_start_ev.ev_count++;
671 	nfs_timer_schedule();
672 }
673 
674 void
675 nfs_timer_init(void)
676 {
677 
678 	mutex_init(&nfs_timer_lock, MUTEX_DEFAULT, IPL_NONE);
679 	callout_init(&nfs_timer_ch, 0);
680 	callout_setfunc(&nfs_timer_ch, nfs_timer, NULL);
681 	evcnt_attach_dynamic(&nfs_timer_ev, EVCNT_TYPE_MISC, NULL,
682 	    "nfs", "timer");
683 	evcnt_attach_dynamic(&nfs_timer_start_ev, EVCNT_TYPE_MISC, NULL,
684 	    "nfs", "timer start");
685 	evcnt_attach_dynamic(&nfs_timer_stop_ev, EVCNT_TYPE_MISC, NULL,
686 	    "nfs", "timer stop");
687 }
688 
689 void
690 nfs_timer_fini(void)
691 {
692 
693 	callout_halt(&nfs_timer_ch, NULL);
694 	callout_destroy(&nfs_timer_ch);
695 	mutex_destroy(&nfs_timer_lock);
696 	evcnt_detach(&nfs_timer_ev);
697 	evcnt_detach(&nfs_timer_start_ev);
698 	evcnt_detach(&nfs_timer_stop_ev);
699 }
700 
701 void
702 nfs_timer_srvinit(bool (*func)(void))
703 {
704 
705 	nfs_timer_srvvec = func;
706 }
707 
708 void
709 nfs_timer_srvfini(void)
710 {
711 
712 	mutex_enter(&nfs_timer_lock);
713 	nfs_timer_srvvec = NULL;
714 	mutex_exit(&nfs_timer_lock);
715 }
716 
717 
718 /*
719  * Nfs timer routine
720  * Scan the nfsreq list and retranmit any requests that have timed out
721  * To avoid retransmission attempts on STREAM sockets (in the future) make
722  * sure to set the r_retry field to 0 (implies nm_retry == 0).
723  */
724 void
725 nfs_timer(void *arg)
726 {
727 	struct nfsreq *rep;
728 	struct mbuf *m;
729 	struct socket *so;
730 	struct nfsmount *nmp;
731 	int timeo;
732 	int error;
733 	bool more = false;
734 
735 	nfs_timer_ev.ev_count++;
736 
737 	mutex_enter(softnet_lock);	/* XXX PR 40491 */
738 	TAILQ_FOREACH(rep, &nfs_reqq, r_chain) {
739 		more = true;
740 		nmp = rep->r_nmp;
741 		if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
742 			continue;
743 		if (nfs_sigintr(nmp, rep, rep->r_lwp)) {
744 			rep->r_flags |= R_SOFTTERM;
745 			continue;
746 		}
747 		if (rep->r_rtt >= 0) {
748 			rep->r_rtt++;
749 			if (nmp->nm_flag & NFSMNT_DUMBTIMR)
750 				timeo = nmp->nm_timeo;
751 			else
752 				timeo = NFS_RTO(nmp, nfs_proct[rep->r_procnum]);
753 			if (nmp->nm_timeouts > 0)
754 				timeo *= nfs_backoff[nmp->nm_timeouts - 1];
755 			if (timeo > NFS_MAXTIMEO)
756 				timeo = NFS_MAXTIMEO;
757 			if (rep->r_rtt <= timeo)
758 				continue;
759 			if (nmp->nm_timeouts <
760 			    (sizeof(nfs_backoff) / sizeof(nfs_backoff[0])))
761 				nmp->nm_timeouts++;
762 		}
763 		/*
764 		 * Check for server not responding
765 		 */
766 		if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
767 		     rep->r_rexmit > nmp->nm_deadthresh) {
768 			nfs_msg(rep->r_lwp,
769 			    nmp->nm_mountp->mnt_stat.f_mntfromname,
770 			    "not responding");
771 			rep->r_flags |= R_TPRINTFMSG;
772 		}
773 		if (rep->r_rexmit >= rep->r_retry) {	/* too many */
774 			nfsstats.rpctimeouts++;
775 			rep->r_flags |= R_SOFTTERM;
776 			continue;
777 		}
778 		if (nmp->nm_sotype != SOCK_DGRAM) {
779 			if (++rep->r_rexmit > NFS_MAXREXMIT)
780 				rep->r_rexmit = NFS_MAXREXMIT;
781 			continue;
782 		}
783 		if ((so = nmp->nm_so) == NULL)
784 			continue;
785 
786 		/*
787 		 * If there is enough space and the window allows..
788 		 *	Resend it
789 		 * Set r_rtt to -1 in case we fail to send it now.
790 		 */
791 		/* solock(so);		XXX PR 40491 */
792 		rep->r_rtt = -1;
793 		if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
794 		   ((nmp->nm_flag & NFSMNT_DUMBTIMR) ||
795 		    (rep->r_flags & R_SENT) ||
796 		    nmp->nm_sent < nmp->nm_cwnd) &&
797 		   (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
798 		        if (so->so_state & SS_ISCONNECTED)
799 			    error = (*so->so_proto->pr_usrreqs->pr_send)(so,
800 			    m, NULL, NULL, NULL);
801 			else
802 			    error = (*so->so_proto->pr_usrreqs->pr_send)(so,
803 				m, mtod(nmp->nm_nam, struct sockaddr *),
804 				NULL, NULL);
805 			if (error) {
806 				if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
807 #ifdef DEBUG
808 					if (ratecheck(&nfs_timer_last_err_time,
809 					    &nfs_err_interval))
810 						printf("%s: ignoring error "
811 						       "%d\n", __func__, error);
812 #endif
813 					so->so_error = 0;
814 				}
815 			} else {
816 				/*
817 				 * Iff first send, start timing
818 				 * else turn timing off, backoff timer
819 				 * and divide congestion window by 2.
820 				 */
821 				if (rep->r_flags & R_SENT) {
822 					rep->r_flags &= ~R_TIMING;
823 					if (++rep->r_rexmit > NFS_MAXREXMIT)
824 						rep->r_rexmit = NFS_MAXREXMIT;
825 					nmp->nm_cwnd >>= 1;
826 					if (nmp->nm_cwnd < NFS_CWNDSCALE)
827 						nmp->nm_cwnd = NFS_CWNDSCALE;
828 					nfsstats.rpcretries++;
829 				} else {
830 					rep->r_flags |= R_SENT;
831 					nmp->nm_sent += NFS_CWNDSCALE;
832 				}
833 				rep->r_rtt = 0;
834 			}
835 		}
836 		/* sounlock(so);	XXX PR 40491 */
837 	}
838 	mutex_exit(softnet_lock);	/* XXX PR 40491 */
839 
840 	mutex_enter(&nfs_timer_lock);
841 	if (nfs_timer_srvvec != NULL) {
842 		more |= (*nfs_timer_srvvec)();
843 	}
844 	mutex_exit(&nfs_timer_lock);
845 
846 	if (more) {
847 		nfs_timer_schedule();
848 	} else {
849 		nfs_timer_stop_ev.ev_count++;
850 	}
851 }
852 
853 /*
854  * Test for a termination condition pending on the process.
855  * This is used for NFSMNT_INT mounts.
856  */
857 int
858 nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct lwp *l)
859 {
860 	sigset_t ss;
861 
862 	if (rep && (rep->r_flags & R_SOFTTERM))
863 		return (EINTR);
864 	if (!(nmp->nm_flag & NFSMNT_INT))
865 		return (0);
866 	if (l) {
867 		sigpending1(l, &ss);
868 #if 0
869 		sigminusset(&l->l_proc->p_sigctx.ps_sigignore, &ss);
870 #endif
871 		if (sigismember(&ss, SIGINT) || sigismember(&ss, SIGTERM) ||
872 		    sigismember(&ss, SIGKILL) || sigismember(&ss, SIGHUP) ||
873 		    sigismember(&ss, SIGQUIT))
874 			return (EINTR);
875 	}
876 	return (0);
877 }
878 
879 int
880 nfs_rcvlock(struct nfsmount *nmp, struct nfsreq *rep)
881 {
882 	int *flagp = &nmp->nm_iflag;
883 	int slptimeo = 0;
884 	bool catch_p;
885 	int error = 0;
886 
887 	KASSERT(nmp == rep->r_nmp);
888 
889 	catch_p = (nmp->nm_flag & NFSMNT_INT) != 0;
890 	mutex_enter(&nmp->nm_lock);
891 	while (/* CONSTCOND */ true) {
892 		if (*flagp & NFSMNT_DISMNT) {
893 			cv_signal(&nmp->nm_disconcv);
894 			error = EIO;
895 			break;
896 		}
897 		/* If our reply was received while we were sleeping,
898 		 * then just return without taking the lock to avoid a
899 		 * situation where a single iod could 'capture' the
900 		 * receive lock.
901 		 */
902 		if (rep->r_mrep != NULL) {
903 			cv_signal(&nmp->nm_rcvcv);
904 			error = EALREADY;
905 			break;
906 		}
907 		if (nfs_sigintr(rep->r_nmp, rep, rep->r_lwp)) {
908 			cv_signal(&nmp->nm_rcvcv);
909 			error = EINTR;
910 			break;
911 		}
912 		if ((*flagp & NFSMNT_RCVLOCK) == 0) {
913 			*flagp |= NFSMNT_RCVLOCK;
914 			break;
915 		}
916 		if (catch_p) {
917 			cv_timedwait_sig(&nmp->nm_rcvcv, &nmp->nm_lock,
918 			    slptimeo);
919 		} else {
920 			cv_timedwait(&nmp->nm_rcvcv, &nmp->nm_lock,
921 			    slptimeo);
922 		}
923 		if (catch_p) {
924 			catch_p = false;
925 			slptimeo = 2 * hz;
926 		}
927 	}
928 	mutex_exit(&nmp->nm_lock);
929 	return error;
930 }
931 
932 /*
933  * Unlock the stream socket for others.
934  */
935 void
936 nfs_rcvunlock(struct nfsmount *nmp)
937 {
938 
939 	mutex_enter(&nmp->nm_lock);
940 	if ((nmp->nm_iflag & NFSMNT_RCVLOCK) == 0)
941 		panic("nfs rcvunlock");
942 	nmp->nm_iflag &= ~NFSMNT_RCVLOCK;
943 	cv_signal(&nmp->nm_rcvcv);
944 	mutex_exit(&nmp->nm_lock);
945 }
946 
947 /*
948  * Parse an RPC request
949  * - verify it
950  * - allocate and fill in the cred.
951  */
952 int
953 nfs_getreq(struct nfsrv_descript *nd, struct nfsd *nfsd, int has_header)
954 {
955 	int len, i;
956 	u_int32_t *tl;
957 	int32_t t1;
958 	struct uio uio;
959 	struct iovec iov;
960 	char *dpos, *cp2, *cp;
961 	u_int32_t nfsvers, auth_type;
962 	uid_t nickuid;
963 	int error = 0, ticklen;
964 	struct mbuf *mrep, *md;
965 	struct nfsuid *nuidp;
966 	struct timeval tvin, tvout;
967 
968 	memset(&tvout, 0, sizeof tvout);	/* XXX gcc */
969 
970 	KASSERT(nd->nd_cr == NULL);
971 	mrep = nd->nd_mrep;
972 	md = nd->nd_md;
973 	dpos = nd->nd_dpos;
974 	if (has_header) {
975 		nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
976 		nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++);
977 		if (*tl++ != rpc_call) {
978 			m_freem(mrep);
979 			return (EBADRPC);
980 		}
981 	} else
982 		nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
983 	nd->nd_repstat = 0;
984 	nd->nd_flag = 0;
985 	if (*tl++ != rpc_vers) {
986 		nd->nd_repstat = ERPCMISMATCH;
987 		nd->nd_procnum = NFSPROC_NOOP;
988 		return (0);
989 	}
990 	if (*tl != nfs_prog) {
991 		nd->nd_repstat = EPROGUNAVAIL;
992 		nd->nd_procnum = NFSPROC_NOOP;
993 		return (0);
994 	}
995 	tl++;
996 	nfsvers = fxdr_unsigned(u_int32_t, *tl++);
997 	if (nfsvers < NFS_VER2 || nfsvers > NFS_VER3) {
998 		nd->nd_repstat = EPROGMISMATCH;
999 		nd->nd_procnum = NFSPROC_NOOP;
1000 		return (0);
1001 	}
1002 	if (nfsvers == NFS_VER3)
1003 		nd->nd_flag = ND_NFSV3;
1004 	nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++);
1005 	if (nd->nd_procnum == NFSPROC_NULL)
1006 		return (0);
1007 	if (nd->nd_procnum > NFSPROC_COMMIT ||
1008 	    (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) {
1009 		nd->nd_repstat = EPROCUNAVAIL;
1010 		nd->nd_procnum = NFSPROC_NOOP;
1011 		return (0);
1012 	}
1013 	if ((nd->nd_flag & ND_NFSV3) == 0)
1014 		nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
1015 	auth_type = *tl++;
1016 	len = fxdr_unsigned(int, *tl++);
1017 	if (len < 0 || len > RPCAUTH_MAXSIZ) {
1018 		m_freem(mrep);
1019 		return (EBADRPC);
1020 	}
1021 
1022 	nd->nd_flag &= ~ND_KERBAUTH;
1023 	/*
1024 	 * Handle auth_unix or auth_kerb.
1025 	 */
1026 	if (auth_type == rpc_auth_unix) {
1027 		uid_t uid;
1028 		gid_t gid;
1029 
1030 		nd->nd_cr = kauth_cred_alloc();
1031 		len = fxdr_unsigned(int, *++tl);
1032 		if (len < 0 || len > NFS_MAXNAMLEN) {
1033 			m_freem(mrep);
1034 			error = EBADRPC;
1035 			goto errout;
1036 		}
1037 		nfsm_adv(nfsm_rndup(len));
1038 		nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1039 
1040 		uid = fxdr_unsigned(uid_t, *tl++);
1041 		gid = fxdr_unsigned(gid_t, *tl++);
1042 		kauth_cred_setuid(nd->nd_cr, uid);
1043 		kauth_cred_seteuid(nd->nd_cr, uid);
1044 		kauth_cred_setsvuid(nd->nd_cr, uid);
1045 		kauth_cred_setgid(nd->nd_cr, gid);
1046 		kauth_cred_setegid(nd->nd_cr, gid);
1047 		kauth_cred_setsvgid(nd->nd_cr, gid);
1048 
1049 		len = fxdr_unsigned(int, *tl);
1050 		if (len < 0 || len > RPCAUTH_UNIXGIDS) {
1051 			m_freem(mrep);
1052 			error = EBADRPC;
1053 			goto errout;
1054 		}
1055 		nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED);
1056 
1057 		if (len > 0) {
1058 			size_t grbuf_size = min(len, NGROUPS) * sizeof(gid_t);
1059 			gid_t *grbuf = kmem_alloc(grbuf_size, KM_SLEEP);
1060 
1061 			for (i = 0; i < len; i++) {
1062 				if (i < NGROUPS) /* XXX elad */
1063 					grbuf[i] = fxdr_unsigned(gid_t, *tl++);
1064 				else
1065 					tl++;
1066 			}
1067 			kauth_cred_setgroups(nd->nd_cr, grbuf,
1068 			    min(len, NGROUPS), -1, UIO_SYSSPACE);
1069 			kmem_free(grbuf, grbuf_size);
1070 		}
1071 
1072 		len = fxdr_unsigned(int, *++tl);
1073 		if (len < 0 || len > RPCAUTH_MAXSIZ) {
1074 			m_freem(mrep);
1075 			error = EBADRPC;
1076 			goto errout;
1077 		}
1078 		if (len > 0)
1079 			nfsm_adv(nfsm_rndup(len));
1080 	} else if (auth_type == rpc_auth_kerb) {
1081 		switch (fxdr_unsigned(int, *tl++)) {
1082 		case RPCAKN_FULLNAME:
1083 			ticklen = fxdr_unsigned(int, *tl);
1084 			*((u_int32_t *)nfsd->nfsd_authstr) = *tl;
1085 			uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED;
1086 			nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED;
1087 			if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
1088 				m_freem(mrep);
1089 				error = EBADRPC;
1090 				goto errout;
1091 			}
1092 			uio.uio_offset = 0;
1093 			uio.uio_iov = &iov;
1094 			uio.uio_iovcnt = 1;
1095 			UIO_SETUP_SYSSPACE(&uio);
1096 			iov.iov_base = (void *)&nfsd->nfsd_authstr[4];
1097 			iov.iov_len = RPCAUTH_MAXSIZ - 4;
1098 			nfsm_mtouio(&uio, uio.uio_resid);
1099 			nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1100 			if (*tl++ != rpc_auth_kerb ||
1101 				fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) {
1102 				printf("Bad kerb verifier\n");
1103 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
1104 				nd->nd_procnum = NFSPROC_NOOP;
1105 				return (0);
1106 			}
1107 			nfsm_dissect(cp, void *, 4 * NFSX_UNSIGNED);
1108 			tl = (u_int32_t *)cp;
1109 			if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) {
1110 				printf("Not fullname kerb verifier\n");
1111 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
1112 				nd->nd_procnum = NFSPROC_NOOP;
1113 				return (0);
1114 			}
1115 			cp += NFSX_UNSIGNED;
1116 			memcpy(nfsd->nfsd_verfstr, cp, 3 * NFSX_UNSIGNED);
1117 			nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED;
1118 			nd->nd_flag |= ND_KERBFULL;
1119 			nfsd->nfsd_flag |= NFSD_NEEDAUTH;
1120 			break;
1121 		case RPCAKN_NICKNAME:
1122 			if (len != 2 * NFSX_UNSIGNED) {
1123 				printf("Kerb nickname short\n");
1124 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED);
1125 				nd->nd_procnum = NFSPROC_NOOP;
1126 				return (0);
1127 			}
1128 			nickuid = fxdr_unsigned(uid_t, *tl);
1129 			nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1130 			if (*tl++ != rpc_auth_kerb ||
1131 				fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) {
1132 				printf("Kerb nick verifier bad\n");
1133 				nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
1134 				nd->nd_procnum = NFSPROC_NOOP;
1135 				return (0);
1136 			}
1137 			nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1138 			tvin.tv_sec = *tl++;
1139 			tvin.tv_usec = *tl;
1140 
1141 			LIST_FOREACH(nuidp, NUIDHASH(nfsd->nfsd_slp, nickuid),
1142 			    nu_hash) {
1143 				if (kauth_cred_geteuid(nuidp->nu_cr) == nickuid &&
1144 				    (!nd->nd_nam2 ||
1145 				     netaddr_match(NU_NETFAM(nuidp),
1146 				      &nuidp->nu_haddr, nd->nd_nam2)))
1147 					break;
1148 			}
1149 			if (!nuidp) {
1150 				nd->nd_repstat =
1151 					(NFSERR_AUTHERR|AUTH_REJECTCRED);
1152 				nd->nd_procnum = NFSPROC_NOOP;
1153 				return (0);
1154 			}
1155 
1156 			/*
1157 			 * Now, decrypt the timestamp using the session key
1158 			 * and validate it.
1159 			 */
1160 #ifdef NFSKERB
1161 			XXX
1162 #else
1163 			(void)tvin.tv_sec;
1164 #endif
1165 
1166 			tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec);
1167 			tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec);
1168 			if (nuidp->nu_expire < time_second ||
1169 			    nuidp->nu_timestamp.tv_sec > tvout.tv_sec ||
1170 			    (nuidp->nu_timestamp.tv_sec == tvout.tv_sec &&
1171 			     nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) {
1172 				nuidp->nu_expire = 0;
1173 				nd->nd_repstat =
1174 				    (NFSERR_AUTHERR|AUTH_REJECTVERF);
1175 				nd->nd_procnum = NFSPROC_NOOP;
1176 				return (0);
1177 			}
1178 			kauth_cred_hold(nuidp->nu_cr);
1179 			nd->nd_cr = nuidp->nu_cr;
1180 			nd->nd_flag |= ND_KERBNICK;
1181 		}
1182 	} else {
1183 		nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
1184 		nd->nd_procnum = NFSPROC_NOOP;
1185 		return (0);
1186 	}
1187 
1188 	nd->nd_md = md;
1189 	nd->nd_dpos = dpos;
1190 	KASSERT((nd->nd_cr == NULL && (nfsd->nfsd_flag & NFSD_NEEDAUTH) != 0)
1191 	     || (nd->nd_cr != NULL && (nfsd->nfsd_flag & NFSD_NEEDAUTH) == 0));
1192 	return (0);
1193 nfsmout:
1194 errout:
1195 	KASSERT(error != 0);
1196 	if (nd->nd_cr != NULL) {
1197 		kauth_cred_free(nd->nd_cr);
1198 		nd->nd_cr = NULL;
1199 	}
1200 	return (error);
1201 }
1202 
1203 int
1204 nfs_msg(struct lwp *l, const char *server, const char *msg)
1205 {
1206 	tpr_t tpr;
1207 
1208 #if 0 /* XXX nfs_timer can't block on proc_lock */
1209 	if (l)
1210 		tpr = tprintf_open(l->l_proc);
1211 	else
1212 #endif
1213 		tpr = NULL;
1214 	tprintf(tpr, "nfs server %s: %s\n", server, msg);
1215 	tprintf_close(tpr);
1216 	return (0);
1217 }
1218 
1219 static struct pool nfs_srvdesc_pool;
1220 
1221 void
1222 nfsdreq_init(void)
1223 {
1224 
1225 	pool_init(&nfs_srvdesc_pool, sizeof(struct nfsrv_descript),
1226 	    0, 0, 0, "nfsrvdescpl", &pool_allocator_nointr, IPL_NONE);
1227 }
1228 
1229 void
1230 nfsdreq_fini(void)
1231 {
1232 
1233 	pool_destroy(&nfs_srvdesc_pool);
1234 }
1235 
1236 struct nfsrv_descript *
1237 nfsdreq_alloc(void)
1238 {
1239 	struct nfsrv_descript *nd;
1240 
1241 	nd = pool_get(&nfs_srvdesc_pool, PR_WAITOK);
1242 	nd->nd_cr = NULL;
1243 	return nd;
1244 }
1245 
1246 void
1247 nfsdreq_free(struct nfsrv_descript *nd)
1248 {
1249 	kauth_cred_t cr;
1250 
1251 	cr = nd->nd_cr;
1252 	if (cr != NULL) {
1253 		kauth_cred_free(cr);
1254 	}
1255 	pool_put(&nfs_srvdesc_pool, nd);
1256 }
1257