new parameter to tprintf
[unix-history] / usr / src / sys / nfs / nfs_socket.c
CommitLineData
a2907882
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
5580a343 20 * @(#)nfs_socket.c 7.15 (Berkeley) %G%
a2907882
KM
21 */
22
23/*
f0f1cbaa 24 * Socket operations for use by nfs
a2907882
KM
25 */
26
27#include "types.h"
28#include "param.h"
29#include "uio.h"
30#include "user.h"
2f08b65a
KM
31#include "proc.h"
32#include "signal.h"
a2907882
KM
33#include "mount.h"
34#include "kernel.h"
35#include "malloc.h"
36#include "mbuf.h"
37#include "vnode.h"
38#include "domain.h"
39#include "protosw.h"
40#include "socket.h"
41#include "socketvar.h"
37ced908
KM
42#include "../netinet/in.h"
43#include "../netinet/tcp.h"
a2907882
KM
44#include "rpcv2.h"
45#include "nfsv2.h"
46#include "nfs.h"
47#include "xdr_subs.h"
48#include "nfsm_subs.h"
49#include "nfsmount.h"
50
2f08b65a 51#include "syslog.h"
2f08b65a 52
a2907882
KM
53#define TRUE 1
54
a2907882
KM
55/*
56 * External data, mostly RPC constants in XDR form
57 */
58extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
59 rpc_msgaccepted, rpc_call;
60extern u_long nfs_prog, nfs_vers;
f0f1cbaa
KM
61extern int nonidempotent[NFS_NPROCS];
62int nfs_sbwait();
63void nfs_disconnect();
64
a2907882
KM
65int nfsrv_null(),
66 nfsrv_getattr(),
67 nfsrv_setattr(),
68 nfsrv_lookup(),
69 nfsrv_readlink(),
70 nfsrv_read(),
71 nfsrv_write(),
72 nfsrv_create(),
73 nfsrv_remove(),
74 nfsrv_rename(),
75 nfsrv_link(),
76 nfsrv_symlink(),
77 nfsrv_mkdir(),
78 nfsrv_rmdir(),
79 nfsrv_readdir(),
80 nfsrv_statfs(),
81 nfsrv_noop();
82
83int (*nfsrv_procs[NFS_NPROCS])() = {
84 nfsrv_null,
85 nfsrv_getattr,
86 nfsrv_setattr,
87 nfsrv_noop,
88 nfsrv_lookup,
89 nfsrv_readlink,
90 nfsrv_read,
91 nfsrv_noop,
92 nfsrv_write,
93 nfsrv_create,
94 nfsrv_remove,
95 nfsrv_rename,
96 nfsrv_link,
97 nfsrv_symlink,
98 nfsrv_mkdir,
99 nfsrv_rmdir,
100 nfsrv_readdir,
101 nfsrv_statfs,
102};
103
2f08b65a
KM
104struct nfsreq nfsreqh;
105int nfsrexmtthresh = NFS_FISHY;
f0f1cbaa 106int nfs_tcpnodelay = 1;
2f08b65a
KM
107
108/*
f0f1cbaa 109 * Initialize sockets and congestion for a new NFS connection.
2f08b65a
KM
110 * We do not free the sockaddr if error.
111 */
f0f1cbaa 112nfs_connect(nmp)
2f08b65a 113 register struct nfsmount *nmp;
2f08b65a 114{
f0f1cbaa
KM
115 register struct socket *so;
116 int s, error;
2f08b65a 117 struct mbuf *m;
2f08b65a 118
f0f1cbaa
KM
119 nmp->nm_so = (struct socket *)0;
120 if (error = socreate(mtod(nmp->nm_nam, struct sockaddr *)->sa_family,
121 &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto))
2f08b65a 122 goto bad;
f0f1cbaa
KM
123 so = nmp->nm_so;
124 nmp->nm_soflags = so->so_proto->pr_flags;
2f08b65a 125
f0f1cbaa
KM
126 /*
127 * Protocols that do not require connections may be optionally left
128 * unconnected for servers that reply from a port other than NFS_PORT.
129 */
130 if (nmp->nm_flag & NFSMNT_NOCONN) {
131 if (nmp->nm_soflags & PR_CONNREQUIRED) {
132 error = ENOTCONN;
2f08b65a
KM
133 goto bad;
134 }
f0f1cbaa
KM
135 } else {
136 if (error = soconnect(so, nmp->nm_nam))
2f08b65a 137 goto bad;
f0f1cbaa
KM
138
139 /*
140 * Wait for the connection to complete. Cribbed from the
141 * connect system call but with the wait at negative prio.
142 */
143 s = splnet();
144 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
145 sleep((caddr_t)&so->so_timeo, PZERO-2);
146 splx(s);
147 if (so->so_error) {
148 error = so->so_error;
149 goto bad;
150 }
2f08b65a 151 }
f0f1cbaa
KM
152 if (nmp->nm_sotype == SOCK_DGRAM) {
153 if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
154 so->so_rcv.sb_timeo = (5 * hz);
155 so->so_snd.sb_timeo = (5 * hz);
156 } else {
157 so->so_rcv.sb_timeo = 0;
158 so->so_snd.sb_timeo = 0;
159 }
160 if (error = soreserve(so, nmp->nm_wsize + NFS_MAXPKTHDR,
161 (nmp->nm_rsize + NFS_MAXPKTHDR) * 4))
162 goto bad;
163 } else {
164 if (nmp->nm_flag & NFSMNT_INT) {
165 so->so_rcv.sb_timeo = (5 * hz);
166 so->so_snd.sb_timeo = (5 * hz);
167 } else {
168 so->so_rcv.sb_timeo = 0;
169 so->so_snd.sb_timeo = 0;
170 }
171 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
172 MGET(m, M_WAIT, MT_SOOPTS);
173 *mtod(m, int *) = 1;
174 m->m_len = sizeof(int);
175 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
176 }
177 if (so->so_proto->pr_domain->dom_family == AF_INET &&
178 so->so_proto->pr_protocol == IPPROTO_TCP &&
179 nfs_tcpnodelay) {
180 MGET(m, M_WAIT, MT_SOOPTS);
181 *mtod(m, int *) = 1;
182 m->m_len = sizeof(int);
183 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
184 }
185 if (error = soreserve(so,
186 (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof(u_long)) * 2,
187 nmp->nm_rsize + NFS_MAXPKTHDR + sizeof(u_long)))
188 goto bad;
189 }
190 so->so_rcv.sb_flags |= SB_NOINTR;
191 so->so_snd.sb_flags |= SB_NOINTR;
2f08b65a 192
f0f1cbaa
KM
193 /* Initialize other non-zero congestion variables */
194 nmp->nm_rto = NFS_TIMEO;
195 nmp->nm_window = 2; /* Initial send window */
196 nmp->nm_ssthresh = NFS_MAXWINDOW; /* Slowstart threshold */
197 nmp->nm_rttvar = nmp->nm_rto << 1;
198 nmp->nm_sent = 0;
199 nmp->nm_currexmit = 0;
200 return (0);
2f08b65a 201
f0f1cbaa
KM
202bad:
203 nfs_disconnect(nmp);
204 return (error);
205}
2f08b65a 206
f0f1cbaa
KM
207/*
208 * Reconnect routine:
209 * Called when a connection is broken on a reliable protocol.
210 * - clean up the old socket
211 * - nfs_connect() again
212 * - set R_MUSTRESEND for all outstanding requests on mount point
213 * If this fails the mount point is DEAD!
214 * nb: Must be called with the nfs_solock() set on the mount point.
215 */
216nfs_reconnect(rep, nmp)
217 register struct nfsreq *rep;
218 register struct nfsmount *nmp;
219{
220 register struct nfsreq *rp;
f0f1cbaa 221 int error;
2f08b65a 222
f0f1cbaa 223 if (rep->r_procp)
5580a343 224 tprintf(rep->r_procp->p_session,
f0f1cbaa
KM
225 "Nfs server %s, trying reconnect\n",
226 nmp->nm_mountp->mnt_stat.f_mntfromname);
227 else
5580a343 228 tprintf(NULL, "Nfs server %s, trying a reconnect\n",
f0f1cbaa
KM
229 nmp->nm_mountp->mnt_stat.f_mntfromname);
230 while (error = nfs_connect(nmp)) {
d4e5799e
KM
231#ifdef lint
232 error = error;
233#endif /* lint */
f0f1cbaa
KM
234 if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp))
235 return (EINTR);
236 tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
2f08b65a 237 }
f0f1cbaa 238 if (rep->r_procp)
5580a343 239 tprintf(rep->r_procp->p_session,
f0f1cbaa
KM
240 "Nfs server %s, reconnected\n",
241 nmp->nm_mountp->mnt_stat.f_mntfromname);
242 else
5580a343 243 tprintf(NULL, "Nfs server %s, reconnected\n",
f0f1cbaa
KM
244 nmp->nm_mountp->mnt_stat.f_mntfromname);
245
246 /*
247 * Loop through outstanding request list and fix up all requests
248 * on old socket.
249 */
250 rp = nfsreqh.r_next;
251 while (rp != &nfsreqh) {
252 if (rp->r_nmp == nmp)
253 rp->r_flags |= R_MUSTRESEND;
254 rp = rp->r_next;
2f08b65a
KM
255 }
256 return (0);
2f08b65a
KM
257}
258
259/*
260 * NFS disconnect. Clean up and unlink.
261 */
f0f1cbaa 262void
2f08b65a
KM
263nfs_disconnect(nmp)
264 register struct nfsmount *nmp;
265{
f0f1cbaa 266 register struct socket *so;
2f08b65a 267
f0f1cbaa
KM
268 if (nmp->nm_so) {
269 so = nmp->nm_so;
270 nmp->nm_so = (struct socket *)0;
271 soshutdown(so, 2);
272 soclose(so);
2f08b65a
KM
273 }
274}
a2907882
KM
275
276/*
f0f1cbaa
KM
277 * This is the nfs send routine. For connection based socket types, it
278 * must be called with an nfs_solock() on the socket.
279 * "rep == NULL" indicates that it has been called from a server.
a2907882 280 */
f0f1cbaa 281nfs_send(so, nam, top, rep)
a2907882
KM
282 register struct socket *so;
283 struct mbuf *nam;
f0f1cbaa
KM
284 register struct mbuf *top;
285 struct nfsreq *rep;
a2907882 286{
f0f1cbaa
KM
287 struct mbuf *sendnam;
288 int error, soflags;
a2907882 289
f0f1cbaa
KM
290 if (rep) {
291 if (rep->r_flags & R_SOFTTERM) {
2f08b65a 292 m_freem(top);
f0f1cbaa 293 return (EINTR);
2f08b65a 294 }
f0f1cbaa
KM
295 if ((so = rep->r_nmp->nm_so) == NULL &&
296 (error = nfs_reconnect(rep, rep->r_nmp)))
297 return (error);
298 rep->r_flags &= ~R_MUSTRESEND;
299 soflags = rep->r_nmp->nm_soflags;
300 } else
301 soflags = so->so_proto->pr_flags;
302 if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
303 sendnam = (struct mbuf *)0;
304 else
305 sendnam = nam;
306
307 error = sosend(so, sendnam, (struct uio *)0, top,
308 (struct mbuf *)0, 0);
309 if (error == EWOULDBLOCK && rep) {
310 if (rep->r_flags & R_SOFTTERM)
311 error = EINTR;
312 else {
313 rep->r_flags |= R_MUSTRESEND;
314 error = 0;
2f08b65a 315 }
a2907882 316 }
f0f1cbaa
KM
317 /*
318 * Ignore socket errors??
319 */
320 if (error && error != EINTR && error != ERESTART)
321 error = 0;
a2907882
KM
322 return (error);
323}
324
325/*
f0f1cbaa
KM
326 * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
327 * done by soreceive(), but for SOCK_STREAM we must deal with the Record
328 * Mark and consolidate the data into a new mbuf list.
329 * nb: Sometimes TCP passes the data up to soreceive() in long lists of
330 * small mbufs.
331 * For SOCK_STREAM we must be very careful to read an entire record once
332 * we have read any of it, even if the system call has been interrupted.
a2907882 333 */
f0f1cbaa 334nfs_receive(so, aname, mp, rep)
a2907882
KM
335 register struct socket *so;
336 struct mbuf **aname;
337 struct mbuf **mp;
f0f1cbaa 338 register struct nfsreq *rep;
a2907882 339{
f0f1cbaa
KM
340 struct uio auio;
341 struct iovec aio;
a2907882 342 register struct mbuf *m;
f0f1cbaa
KM
343 struct mbuf *m2, *m3, *mnew, **mbp;
344 caddr_t fcp, tcp;
345 u_long len;
346 struct mbuf **getnam;
347 int error, siz, mlen, soflags, rcvflg = MSG_WAITALL;
a2907882 348
f0f1cbaa
KM
349 /*
350 * Set up arguments for soreceive()
351 */
352 *mp = (struct mbuf *)0;
353 *aname = (struct mbuf *)0;
354 if (rep)
355 soflags = rep->r_nmp->nm_soflags;
356 else
357 soflags = so->so_proto->pr_flags;
a2907882 358
f0f1cbaa
KM
359 /*
360 * For reliable protocols, lock against other senders/receivers
361 * in case a reconnect is necessary.
362 * For SOCK_STREAM, first get the Record Mark to find out how much
363 * more there is to get.
364 * We must lock the socket against other receivers
365 * until we have an entire rpc request/reply.
366 */
367 if (soflags & PR_CONNREQUIRED) {
368tryagain:
369 /*
370 * Check for fatal errors and resending request.
371 */
372 if (rep) {
373 /*
374 * Ugh: If a reconnect attempt just happened, nm_so
375 * would have changed. NULL indicates a failed
376 * attempt that has essentially shut down this
377 * mount point.
378 */
379 if (rep->r_mrep || (so = rep->r_nmp->nm_so) == NULL ||
380 (rep->r_flags & R_SOFTTERM))
381 return (EINTR);
382 while (rep->r_flags & R_MUSTRESEND) {
383 m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
384 nfsstats.rpcretries++;
385 if (error = nfs_send(so, rep->r_nmp->nm_nam, m,
386 rep))
387 goto errout;
2f08b65a 388 }
e8540f59 389 }
f0f1cbaa
KM
390 if ((soflags & PR_ATOMIC) == 0) {
391 aio.iov_base = (caddr_t) &len;
392 aio.iov_len = sizeof(u_long);
393 auio.uio_iov = &aio;
394 auio.uio_iovcnt = 1;
395 auio.uio_segflg = UIO_SYSSPACE;
396 auio.uio_rw = UIO_READ;
397 auio.uio_offset = 0;
398 auio.uio_resid = sizeof(u_long);
399 do {
400 error = soreceive(so, (struct mbuf **)0, &auio,
401 (struct mbuf **)0, (struct mbuf **)0, &rcvflg);
402 if (error == EWOULDBLOCK && rep) {
403 if (rep->r_flags & R_SOFTTERM)
404 return (EINTR);
405 if (rep->r_flags & R_MUSTRESEND)
406 goto tryagain;
407 }
408 } while (error == EWOULDBLOCK);
409 if (!error && auio.uio_resid > 0)
410 error = EPIPE;
411 if (error)
412 goto errout;
413 len = ntohl(len) & ~0x80000000;
414 /*
415 * This is SERIOUS! We are out of sync with the sender
416 * and forcing a disconnect/reconnect is all I can do.
417 */
418 if (len > NFS_MAXPACKET) {
419 error = EFBIG;
420 goto errout;
421 }
422 auio.uio_resid = len;
423 do {
424 error = soreceive(so, (struct mbuf **)0,
425 &auio, mp, (struct mbuf **)0, &rcvflg);
426 } while (error == EWOULDBLOCK || error == EINTR ||
427 error == ERESTART);
428 if (!error && auio.uio_resid > 0)
429 error = EPIPE;
2f08b65a 430 } else {
f0f1cbaa
KM
431 auio.uio_resid = len = 1000000; /* Anything Big */
432 do {
433 error = soreceive(so, (struct mbuf **)0,
434 &auio, mp, (struct mbuf **)0, &rcvflg);
435 if (error == EWOULDBLOCK && rep) {
436 if (rep->r_flags & R_SOFTTERM)
437 return (EINTR);
438 if (rep->r_flags & R_MUSTRESEND)
439 goto tryagain;
440 }
441 } while (error == EWOULDBLOCK);
442 if (!error && *mp == NULL)
443 error = EPIPE;
444 len -= auio.uio_resid;
2f08b65a 445 }
f0f1cbaa
KM
446errout:
447 if (error && rep && error != EINTR && error != ERESTART) {
448 m_freem(*mp);
449 *mp = (struct mbuf *)0;
450 nfs_disconnect(rep->r_nmp);
451 error = nfs_reconnect(rep, rep->r_nmp);
452 if (!error)
453 goto tryagain;
2f08b65a 454 }
f0f1cbaa
KM
455 } else {
456 if (so->so_state & SS_ISCONNECTED)
457 getnam = (struct mbuf **)0;
458 else
459 getnam = aname;
460 auio.uio_resid = len = 1000000;
461 do {
462 error = soreceive(so, getnam, &auio, mp,
463 (struct mbuf **)0, &rcvflg);
464 if (error == EWOULDBLOCK && rep &&
465 (rep->r_flags & R_SOFTTERM))
466 return (EINTR);
467 } while (error == EWOULDBLOCK);
468 len -= auio.uio_resid;
469 }
470 if (error) {
471 m_freem(*mp);
472 *mp = (struct mbuf *)0;
473 }
474 /*
475 * Search for any mbufs that are not a multiple of 4 bytes long.
476 * These could cause pointer alignment problems, so copy them to
477 * well aligned mbufs.
478 */
479 m = *mp;
480 mbp = mp;
481 while (m) {
482 /*
483 * All this for something that may never happen.
484 */
485 if (m->m_len & 0x3) {
486 printf("nfs_rcv odd length!\n");
487 fcp = mtod(m, caddr_t);
488 mnew = m2 = (struct mbuf *)0;
d4e5799e
KM
489#ifdef lint
490 m3 = (struct mbuf *)0;
491 mlen = 0;
492#endif /* lint */
f0f1cbaa
KM
493 while (m) {
494 if (m2 == NULL || mlen == 0) {
495 MGET(m2, M_WAIT, MT_DATA);
496 if (len > MINCLSIZE)
497 MCLGET(m2, M_WAIT);
498 m2->m_len = 0;
499 mlen = M_TRAILINGSPACE(m2);
500 tcp = mtod(m2, caddr_t);
501 if (mnew) {
502 m3->m_next = m2;
503 m3 = m2;
504 } else
505 mnew = m3 = m2;
506 }
507 siz = (mlen > m->m_len) ? m->m_len : mlen;
508 bcopy(fcp, tcp, siz);
509 m2->m_len += siz;
510 mlen -= siz;
511 len -= siz;
512 tcp += siz;
513 m->m_len -= siz;
514 fcp += siz;
515 if (m->m_len == 0) {
516 do {
517 m = m->m_next;
518 } while (m && m->m_len == 0);
519 if (m)
520 fcp = mtod(m, caddr_t);
521 }
522 }
523 m = *mbp;
524 *mbp = mnew;
525 m_freem(m);
526 break;
2f08b65a 527 }
f0f1cbaa
KM
528 len -= m->m_len;
529 mbp = &m->m_next;
530 m = m->m_next;
a2907882 531 }
a2907882
KM
532 return (error);
533}
534
a2907882
KM
535struct rpc_replyhead {
536 u_long r_xid;
537 u_long r_rep;
538};
539
540/*
f0f1cbaa 541 * Implement receipt of reply on a socket.
a2907882
KM
542 * We must search through the list of received datagrams matching them
543 * with outstanding requests using the xid, until ours is found.
544 */
f0f1cbaa
KM
545/* ARGSUSED */
546nfs_reply(nmp, myrep)
547 struct nfsmount *nmp;
ffe6f482 548 struct nfsreq *myrep;
a2907882
KM
549{
550 register struct mbuf *m;
551 register struct nfsreq *rep;
f0f1cbaa 552 register int error = 0;
a2907882 553 struct rpc_replyhead replyh;
f0f1cbaa
KM
554 struct mbuf *mp, *nam;
555 char *cp;
556 int cnt, xfer;
a2907882
KM
557
558 /*
f0f1cbaa 559 * Loop around until we get our own reply
a2907882 560 */
f0f1cbaa
KM
561 for (;;) {
562 /*
563 * Lock against other receivers so that I don't get stuck in
564 * sbwait() after someone else has received my reply for me.
565 * Also necessary for connection based protocols to avoid
566 * race conditions during a reconnect.
567 */
568 nfs_solock(&nmp->nm_flag, 1);
569 /* Already received, bye bye */
570 if (myrep->r_mrep != NULL) {
571 nfs_sounlock(&nmp->nm_flag);
572 return (0);
573 }
574 /*
575 * Get the next Rpc reply off the socket
576 */
577 if (error = nfs_receive(nmp->nm_so, &nam, &mp, myrep)) {
578 nfs_sounlock(&nmp->nm_flag);
a2907882 579
f0f1cbaa
KM
580 /*
581 * Ignore routing errors on connectionless protocols??
582 */
583 if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
584 nmp->nm_so->so_error = 0;
585 continue;
a2907882 586 }
f0f1cbaa
KM
587
588 /*
589 * Otherwise cleanup and return a fatal error.
590 */
591 if (myrep->r_flags & R_TIMING) {
592 myrep->r_flags &= ~R_TIMING;
593 nmp->nm_rtt = -1;
a2907882 594 }
f0f1cbaa
KM
595 if (myrep->r_flags & R_SENT) {
596 myrep->r_flags &= ~R_SENT;
597 nmp->nm_sent--;
2f08b65a 598 }
f0f1cbaa
KM
599 return (error);
600 }
601
602 /*
603 * Get the xid and check that it is an rpc reply
604 */
605 m = mp;
606 if (m->m_len >= 2*NFSX_UNSIGNED)
607 bcopy(mtod(m, caddr_t), (caddr_t)&replyh,
608 2*NFSX_UNSIGNED);
609 else {
610 cnt = 2*NFSX_UNSIGNED;
611 cp = (caddr_t)&replyh;
612 while (m && cnt > 0) {
613 if (m->m_len > 0) {
614 xfer = (m->m_len >= cnt) ? cnt :
615 m->m_len;
616 bcopy(mtod(m, caddr_t), cp, xfer);
617 cnt -= xfer;
618 cp += xfer;
619 }
620 if (cnt > 0)
621 m = m->m_next;
2f08b65a 622 }
f0f1cbaa
KM
623 }
624 if (replyh.r_rep != rpc_reply || m == NULL) {
625 nfsstats.rpcinvalid++;
626 m_freem(mp);
627 nfs_sounlock(&nmp->nm_flag);
628 continue;
629 }
630 /*
631 * Loop through the request list to match up the reply
632 * Iff no match, just drop the datagram
633 */
634 m = mp;
635 rep = nfsreqh.r_next;
636 while (rep != &nfsreqh) {
637 if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid) {
638 /* Found it.. */
639 rep->r_mrep = m;
640 /*
641 * Update timing
642 */
643 if (rep->r_flags & R_TIMING) {
644 nfs_updatetimer(rep->r_nmp);
645 rep->r_flags &= ~R_TIMING;
646 rep->r_nmp->nm_rtt = -1;
647 }
648 if (rep->r_flags & R_SENT) {
649 rep->r_flags &= ~R_SENT;
650 rep->r_nmp->nm_sent--;
651 }
652 break;
2f08b65a 653 }
f0f1cbaa 654 rep = rep->r_next;
a2907882 655 }
f0f1cbaa
KM
656 nfs_sounlock(&nmp->nm_flag);
657 if (nam)
658 m_freem(nam);
659 /*
660 * If not matched to a request, drop it.
661 * If it's mine, get out.
662 */
663 if (rep == &nfsreqh) {
664 nfsstats.rpcunexpected++;
665 m_freem(m);
666 } else if (rep == myrep)
667 return (0);
a2907882 668 }
a2907882
KM
669}
670
671/*
672 * nfs_request - goes something like this
673 * - fill in request struct
674 * - links it into list
f0f1cbaa
KM
675 * - calls nfs_send() for first transmit
676 * - calls nfs_receive() to get reply
a2907882
KM
677 * - break down rpc header and return with nfs reply pointed to
678 * by mrep or error
679 * nb: always frees up mreq mbuf list
680 */
f0f1cbaa 681nfs_request(vp, mreq, xid, procnum, procp, mp, mrp, mdp, dposp)
a2907882
KM
682 struct vnode *vp;
683 struct mbuf *mreq;
684 u_long xid;
f0f1cbaa
KM
685 int procnum;
686 struct proc *procp;
a2907882
KM
687 struct mount *mp;
688 struct mbuf **mrp;
689 struct mbuf **mdp;
690 caddr_t *dposp;
691{
692 register struct mbuf *m, *mrep;
693 register struct nfsreq *rep;
694 register u_long *p;
695 register int len;
f0f1cbaa 696 struct nfsmount *nmp;
a2907882 697 struct mbuf *md;
ffe6f482 698 struct nfsreq *reph;
a2907882
KM
699 caddr_t dpos;
700 char *cp2;
701 int t1;
702 int s;
f0f1cbaa 703 int error = 0;
a2907882 704
f0f1cbaa 705 nmp = VFSTONFS(mp);
a2907882
KM
706 m = mreq;
707 MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
708 rep->r_xid = xid;
f0f1cbaa 709 rep->r_nmp = nmp;
a2907882 710 rep->r_vp = vp;
f0f1cbaa
KM
711 rep->r_procp = procp;
712 if (nmp->nm_flag & NFSMNT_SOFT)
713 rep->r_retry = nmp->nm_retry;
a2907882 714 else
2f08b65a
KM
715 rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */
716 rep->r_flags = rep->r_rexmit = 0;
f0f1cbaa
KM
717 /*
718 * Three cases:
719 * - non-idempotent requests on SOCK_DGRAM use NFS_MINIDEMTIMEO
720 * - idempotent requests on SOCK_DGRAM use 0
721 * - Reliable transports, NFS_RELIABLETIMEO
722 * Timeouts are still done on reliable transports to ensure detection
723 * of connection loss.
724 */
725 if (nmp->nm_sotype != SOCK_DGRAM)
726 rep->r_timerinit = -NFS_RELIABLETIMEO;
727 else if (nonidempotent[procnum])
728 rep->r_timerinit = -NFS_MINIDEMTIMEO;
729 else
730 rep->r_timerinit = 0;
731 rep->r_timer = rep->r_timerinit;
a2907882 732 rep->r_mrep = NULL;
a2907882
KM
733 len = 0;
734 while (m) {
735 len += m->m_len;
736 m = m->m_next;
737 }
f0f1cbaa
KM
738 mreq->m_pkthdr.len = len;
739 mreq->m_pkthdr.rcvif = (struct ifnet *)0;
740 /*
741 * For non-atomic protocols, insert a Sun RPC Record Mark.
742 */
743 if ((nmp->nm_soflags & PR_ATOMIC) == 0) {
744 M_PREPEND(mreq, sizeof(u_long), M_WAIT);
745 *mtod(mreq, u_long *) = htonl(0x80000000 | len);
746 }
747 rep->r_mreq = mreq;
a2907882 748
2f08b65a
KM
749 /*
750 * Do the client side RPC.
751 */
752 nfsstats.rpcrequests++;
f0f1cbaa
KM
753 /*
754 * Chain request into list of outstanding requests. Be sure
755 * to put it LAST so timer finds oldest requests first.
756 */
a2907882 757 s = splnet();
2f08b65a 758 reph = &nfsreqh;
f0f1cbaa
KM
759 reph->r_prev->r_next = rep;
760 rep->r_prev = reph->r_prev;
ffe6f482
KM
761 reph->r_prev = rep;
762 rep->r_next = reph;
2f08b65a
KM
763 /*
764 * If backing off another request or avoiding congestion, don't
765 * send this one now but let timer do it. If not timing a request,
766 * do it now.
767 */
f0f1cbaa
KM
768 if (nmp->nm_sent <= 0 || nmp->nm_sotype != SOCK_DGRAM ||
769 (nmp->nm_currexmit == 0 && nmp->nm_sent < nmp->nm_window)) {
770 nmp->nm_sent++;
771 rep->r_flags |= R_SENT;
772 if (nmp->nm_rtt == -1) {
773 nmp->nm_rtt = 0;
774 rep->r_flags |= R_TIMING;
775 }
776 splx(s);
777 m = m_copym(mreq, 0, M_COPYALL, M_WAIT);
778 if (nmp->nm_soflags & PR_CONNREQUIRED)
779 nfs_solock(&nmp->nm_flag, 1);
780 error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
781 if (nmp->nm_soflags & PR_CONNREQUIRED)
782 nfs_sounlock(&nmp->nm_flag);
783 if (error && NFSIGNORE_SOERROR(nmp->nm_soflags, error))
784 nmp->nm_so->so_error = error = 0;
785 } else
2f08b65a 786 splx(s);
a2907882 787
2f08b65a
KM
788 /*
789 * Wait for the reply from our send or the timer's.
790 */
f0f1cbaa
KM
791 if (!error)
792 error = nfs_reply(nmp, rep);
a2907882 793
2f08b65a
KM
794 /*
795 * RPC done, unlink the request.
796 */
a2907882
KM
797 s = splnet();
798 rep->r_prev->r_next = rep->r_next;
ffe6f482 799 rep->r_next->r_prev = rep->r_prev;
a2907882 800 splx(s);
f0f1cbaa
KM
801
802 /*
803 * If there was a successful reply and a tprintf msg.
804 * tprintf a response.
805 */
806 if (!error && (rep->r_flags & R_TPRINTFMSG)) {
807 if (rep->r_procp)
5580a343 808 tprintf(rep->r_procp->p_session,
f0f1cbaa
KM
809 "Nfs server %s, is alive again\n",
810 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
811 else
5580a343 812 tprintf(NULL, "Nfs server %s, is alive again\n",
f0f1cbaa
KM
813 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
814 }
a2907882
KM
815 m_freem(rep->r_mreq);
816 mrep = md = rep->r_mrep;
817 FREE((caddr_t)rep, M_NFSREQ);
818 if (error)
819 return (error);
820
821 /*
822 * break down the rpc header and check if ok
823 */
824 dpos = mtod(md, caddr_t);
825 nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED);
826 p += 2;
827 if (*p++ == rpc_msgdenied) {
828 if (*p == rpc_mismatch)
829 error = EOPNOTSUPP;
830 else
831 error = EACCES;
832 m_freem(mrep);
833 return (error);
834 }
835 /*
836 * skip over the auth_verf, someday we may want to cache auth_short's
837 * for nfs_reqhead(), but for now just dump it
838 */
839 if (*++p != 0) {
840 len = nfsm_rndup(fxdr_unsigned(long, *p));
841 nfsm_adv(len);
842 }
843 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
844 /* 0 == ok */
845 if (*p == 0) {
846 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
847 if (*p != 0) {
848 error = fxdr_unsigned(int, *p);
849 m_freem(mrep);
850 return (error);
851 }
852 *mrp = mrep;
853 *mdp = md;
854 *dposp = dpos;
855 return (0);
856 }
857 m_freem(mrep);
858 return (EPROTONOSUPPORT);
859nfsmout:
860 return (error);
861}
862
863/*
864 * Get a request for the server main loop
865 * - receive a request via. nfs_soreceive()
866 * - verify it
867 * - fill in the cred struct.
868 */
d4e5799e 869nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
f0f1cbaa 870 lockp, msk, mtch)
a2907882
KM
871 struct socket *so;
872 u_long prog;
873 u_long vers;
874 int maxproc;
875 struct mbuf **nam;
876 struct mbuf **mrp;
877 struct mbuf **mdp;
878 caddr_t *dposp;
879 u_long *retxid;
d4e5799e 880 u_long *procnum;
a2907882 881 register struct ucred *cr;
f0f1cbaa
KM
882 int *lockp;
883 struct mbuf *msk, *mtch;
a2907882
KM
884{
885 register int i;
0bd503ad
KM
886 register u_long *p;
887 register long t1;
888 caddr_t dpos, cp2;
889 int error = 0;
890 struct mbuf *mrep, *md;
891 int len;
a2907882 892
f0f1cbaa
KM
893 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
894 nfs_solock(lockp, 0);
895 error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
896 nfs_sounlock(lockp);
897 } else {
898 mrep = (struct mbuf *)0;
899 do {
900 if (mrep) {
901 m_freem(*nam);
902 m_freem(mrep);
903 }
904 error = nfs_receive(so, nam, &mrep, (struct nfsreq *)0);
905 } while (!error && nfs_badnam(*nam, msk, mtch));
906 }
907 if (error)
a2907882
KM
908 return (error);
909 md = mrep;
910 dpos = mtod(mrep, caddr_t);
911 nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED);
912 *retxid = *p++;
913 if (*p++ != rpc_call) {
914 m_freem(mrep);
915 return (ERPCMISMATCH);
916 }
917 if (*p++ != rpc_vers) {
918 m_freem(mrep);
919 return (ERPCMISMATCH);
920 }
921 if (*p++ != prog) {
922 m_freem(mrep);
923 return (EPROGUNAVAIL);
924 }
925 if (*p++ != vers) {
926 m_freem(mrep);
927 return (EPROGMISMATCH);
928 }
d4e5799e
KM
929 *procnum = fxdr_unsigned(u_long, *p++);
930 if (*procnum == NFSPROC_NULL) {
a2907882
KM
931 *mrp = mrep;
932 return (0);
933 }
d4e5799e 934 if (*procnum > maxproc || *p++ != rpc_auth_unix) {
a2907882
KM
935 m_freem(mrep);
936 return (EPROCUNAVAIL);
937 }
f0f1cbaa
KM
938 len = fxdr_unsigned(int, *p++);
939 if (len < 0 || len > RPCAUTH_MAXSIZ) {
940 m_freem(mrep);
941 return (EBADRPC);
942 }
0bd503ad 943 len = fxdr_unsigned(int, *++p);
f0f1cbaa
KM
944 if (len < 0 || len > NFS_MAXNAMLEN) {
945 m_freem(mrep);
946 return (EBADRPC);
947 }
0bd503ad 948 nfsm_adv(nfsm_rndup(len));
a2907882
KM
949 nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED);
950 cr->cr_uid = fxdr_unsigned(uid_t, *p++);
951 cr->cr_gid = fxdr_unsigned(gid_t, *p++);
0bd503ad 952 len = fxdr_unsigned(int, *p);
f0f1cbaa 953 if (len < 0 || len > RPCAUTH_UNIXGIDS) {
a2907882
KM
954 m_freem(mrep);
955 return (EBADRPC);
956 }
0bd503ad
KM
957 nfsm_disect(p, u_long *, (len + 2)*NFSX_UNSIGNED);
958 for (i = 1; i <= len; i++)
f0f1cbaa
KM
959 if (i < NGROUPS)
960 cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++);
961 else
962 p++;
963 cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
a2907882
KM
964 /*
965 * Do we have any use for the verifier.
966 * According to the "Remote Procedure Call Protocol Spec." it
967 * should be AUTH_NULL, but some clients make it AUTH_UNIX?
968 * For now, just skip over it
969 */
0bd503ad 970 len = fxdr_unsigned(int, *++p);
f0f1cbaa
KM
971 if (len < 0 || len > RPCAUTH_MAXSIZ) {
972 m_freem(mrep);
973 return (EBADRPC);
974 }
0bd503ad
KM
975 if (len > 0)
976 nfsm_adv(nfsm_rndup(len));
a2907882
KM
977 *mrp = mrep;
978 *mdp = md;
979 *dposp = dpos;
980 return (0);
981nfsmout:
982 return (error);
983}
984
985/*
986 * Generate the rpc reply header
987 * siz arg. is used to decide if adding a cluster is worthwhile
988 */
989nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
990 int siz;
991 u_long retxid;
992 int err;
993 struct mbuf **mrq;
994 struct mbuf **mbp;
995 caddr_t *bposp;
996{
0bd503ad
KM
997 register u_long *p;
998 register long t1;
999 caddr_t bpos;
1000 struct mbuf *mreq, *mb, *mb2;
a2907882
KM
1001
1002 NFSMGETHDR(mreq);
1003 mb = mreq;
1004 if ((siz+RPC_REPLYSIZ) > MHLEN)
f0f1cbaa 1005 MCLGET(mreq, M_WAIT);
a2907882
KM
1006 p = mtod(mreq, u_long *);
1007 mreq->m_len = 6*NFSX_UNSIGNED;
1008 bpos = ((caddr_t)p)+mreq->m_len;
1009 *p++ = retxid;
1010 *p++ = rpc_reply;
1011 if (err == ERPCMISMATCH) {
1012 *p++ = rpc_msgdenied;
1013 *p++ = rpc_mismatch;
1014 *p++ = txdr_unsigned(2);
1015 *p = txdr_unsigned(2);
1016 } else {
1017 *p++ = rpc_msgaccepted;
1018 *p++ = 0;
1019 *p++ = 0;
1020 switch (err) {
1021 case EPROGUNAVAIL:
1022 *p = txdr_unsigned(RPC_PROGUNAVAIL);
1023 break;
1024 case EPROGMISMATCH:
1025 *p = txdr_unsigned(RPC_PROGMISMATCH);
1026 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
1027 *p++ = txdr_unsigned(2);
1028 *p = txdr_unsigned(2); /* someday 3 */
1029 break;
1030 case EPROCUNAVAIL:
1031 *p = txdr_unsigned(RPC_PROCUNAVAIL);
1032 break;
1033 default:
1034 *p = 0;
1035 if (err != VNOVAL) {
1036 nfsm_build(p, u_long *, NFSX_UNSIGNED);
1037 *p = txdr_unsigned(err);
1038 }
1039 break;
1040 };
1041 }
1042 *mrq = mreq;
1043 *mbp = mb;
1044 *bposp = bpos;
1045 if (err != 0 && err != VNOVAL)
1046 nfsstats.srvrpc_errs++;
1047 return (0);
1048}
1049
1050/*
1051 * Nfs timer routine
1052 * Scan the nfsreq list and retranmit any requests that have timed out
1053 * To avoid retransmission attempts on STREAM sockets (in the future) make
2f08b65a 1054 * sure to set the r_retry field to 0 (implies nm_retry == 0).
a2907882
KM
1055 */
1056nfs_timer()
1057{
1058 register struct nfsreq *rep;
1059 register struct mbuf *m;
1060 register struct socket *so;
f0f1cbaa 1061 register struct nfsmount *nmp;
2f08b65a 1062 int s, error;
a2907882
KM
1063
1064 s = splnet();
f0f1cbaa
KM
1065 for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) {
1066 nmp = rep->r_nmp;
1067 if (rep->r_mrep || (rep->r_flags & R_SOFTTERM) ||
1068 (so = nmp->nm_so) == NULL)
1069 continue;
1070 if ((nmp->nm_flag & NFSMNT_INT) && nfs_sigintr(rep->r_procp)) {
1071 rep->r_flags |= R_SOFTTERM;
1072 continue;
1073 }
2f08b65a 1074 if (rep->r_flags & R_TIMING) /* update rtt in mount */
f0f1cbaa
KM
1075 nmp->nm_rtt++;
1076 if (nmp->nm_sotype != SOCK_DGRAM)
1077 continue;
1078 /* If not timed out */
1079 if (++rep->r_timer < nmp->nm_rto)
2f08b65a 1080 continue;
f0f1cbaa
KM
1081#ifdef notdef
1082 if (nmp->nm_sotype != SOCK_DGRAM) {
1083 rep->r_flags |= R_MUSTRESEND;
1084 rep->r_timer = rep->r_timerinit;
1085 continue;
1086 }
1087#endif
2f08b65a
KM
1088 /* Do backoff and save new timeout in mount */
1089 if (rep->r_flags & R_TIMING) {
f0f1cbaa 1090 nfs_backofftimer(nmp);
2f08b65a 1091 rep->r_flags &= ~R_TIMING;
f0f1cbaa 1092 nmp->nm_rtt = -1;
2f08b65a
KM
1093 }
1094 if (rep->r_flags & R_SENT) {
1095 rep->r_flags &= ~R_SENT;
f0f1cbaa 1096 nmp->nm_sent--;
2f08b65a 1097 }
f0f1cbaa
KM
1098
1099 /*
1100 * Check for too many retries on soft mount.
1101 * nb: For hard mounts, r_retry == NFS_MAXREXMIT+1
1102 */
1103 if (++rep->r_rexmit > NFS_MAXREXMIT)
2f08b65a 1104 rep->r_rexmit = NFS_MAXREXMIT;
2f08b65a 1105
f0f1cbaa
KM
1106 /*
1107 * Check for server not responding
1108 */
1109 if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
1110 rep->r_rexmit > 8) {
1111 if (rep->r_procp && rep->r_procp->p_session)
5580a343 1112 tprintf(rep->r_procp->p_session,
f0f1cbaa
KM
1113 "Nfs server %s, not responding\n",
1114 nmp->nm_mountp->mnt_stat.f_mntfromname);
1115 else
5580a343 1116 tprintf(NULL,
f0f1cbaa
KM
1117 "Nfs server %s, not responding\n",
1118 nmp->nm_mountp->mnt_stat.f_mntfromname);
1119 rep->r_flags |= R_TPRINTFMSG;
1120 }
1121 if (rep->r_rexmit > rep->r_retry) { /* too many */
1122 nfsstats.rpctimeouts++;
1123 rep->r_flags |= R_SOFTTERM;
1124 continue;
1125 }
1126
1127 /*
1128 * If there is enough space and the window allows..
1129 * Resend it
1130 */
1131 if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
1132 nmp->nm_sent < nmp->nm_window &&
1133 (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
1134 nfsstats.rpcretries++;
1135 if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
1136 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
1137 (caddr_t)0, (struct mbuf *)0, (struct mbuf *)0);
1138 else
1139 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
1140 nmp->nm_nam, (struct mbuf *)0, (struct mbuf *)0);
1141 if (error) {
1142 if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
1143 so->so_error = 0;
1144 } else {
1145 /*
1146 * We need to time the request even though we
1147 * are retransmitting.
1148 */
1149 nmp->nm_rtt = 0;
1150 nmp->nm_sent++;
1151 rep->r_flags |= (R_SENT|R_TIMING);
1152 rep->r_timer = rep->r_timerinit;
1153 }
1154 }
2f08b65a
KM
1155 }
1156 splx(s);
1157 timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ);
1158}
1159
1160/*
1161 * NFS timer update and backoff. The "Jacobson/Karels/Karn" scheme is
1162 * used here. The timer state is held in the nfsmount structure and
1163 * a single request is used to clock the response. When successful
1164 * the rtt smoothing in nfs_updatetimer is used, when failed the backoff
1165 * is done by nfs_backofftimer. We also log failure messages in these
1166 * routines.
1167 *
1168 * Congestion variables are held in the nfshost structure which
1169 * is referenced by nfsmounts and shared per-server. This separation
1170 * makes it possible to do per-mount timing which allows varying disk
1171 * access times to be dealt with, while preserving a network oriented
1172 * congestion control scheme.
1173 *
1174 * The windowing implements the Jacobson/Karels slowstart algorithm
1175 * with adjusted scaling factors. We start with one request, then send
1176 * 4 more after each success until the ssthresh limit is reached, then
1177 * we increment at a rate proportional to the window. On failure, we
1178 * remember 3/4 the current window and clamp the send limit to 1. Note
1179 * ICMP source quench is not reflected in so->so_error so we ignore that
1180 * for now.
1181 *
1182 * NFS behaves much more like a transport protocol with these changes,
1183 * shedding the teenage pedal-to-the-metal tendencies of "other"
1184 * implementations.
1185 *
1186 * Timers and congestion avoidance by Tom Talpey, Open Software Foundation.
1187 */
1188
1189/*
1190 * The TCP algorithm was not forgiving enough. Because the NFS server
1191 * responds only after performing lookups/diskio/etc, we have to be
1192 * more prepared to accept a spiky variance. The TCP algorithm is:
f0f1cbaa 1193 * TCP_RTO(nmp) ((((nmp)->nm_srtt >> 2) + (nmp)->nm_rttvar) >> 1)
2f08b65a 1194 */
f0f1cbaa 1195#define NFS_RTO(nmp) (((nmp)->nm_srtt >> 3) + (nmp)->nm_rttvar)
2f08b65a 1196
f0f1cbaa
KM
1197nfs_updatetimer(nmp)
1198 register struct nfsmount *nmp;
2f08b65a 1199{
2f08b65a
KM
1200
1201 /* If retransmitted, clear and return */
f0f1cbaa
KM
1202 if (nmp->nm_rexmit || nmp->nm_currexmit) {
1203 nmp->nm_rexmit = nmp->nm_currexmit = 0;
2f08b65a
KM
1204 return;
1205 }
1206 /* If have a measurement, do smoothing */
f0f1cbaa 1207 if (nmp->nm_srtt) {
2f08b65a 1208 register short delta;
f0f1cbaa
KM
1209 delta = nmp->nm_rtt - (nmp->nm_srtt >> 3);
1210 if ((nmp->nm_srtt += delta) <= 0)
1211 nmp->nm_srtt = 1;
2f08b65a
KM
1212 if (delta < 0)
1213 delta = -delta;
f0f1cbaa
KM
1214 delta -= (nmp->nm_rttvar >> 2);
1215 if ((nmp->nm_rttvar += delta) <= 0)
1216 nmp->nm_rttvar = 1;
2f08b65a
KM
1217 /* Else initialize */
1218 } else {
f0f1cbaa
KM
1219 nmp->nm_rttvar = nmp->nm_rtt << 1;
1220 if (nmp->nm_rttvar == 0) nmp->nm_rttvar = 2;
1221 nmp->nm_srtt = nmp->nm_rttvar << 2;
2f08b65a
KM
1222 }
1223 /* Compute new Retransmission TimeOut and clip */
f0f1cbaa
KM
1224 nmp->nm_rto = NFS_RTO(nmp);
1225 if (nmp->nm_rto < NFS_MINTIMEO)
1226 nmp->nm_rto = NFS_MINTIMEO;
1227 else if (nmp->nm_rto > NFS_MAXTIMEO)
1228 nmp->nm_rto = NFS_MAXTIMEO;
2f08b65a
KM
1229
1230 /* Update window estimate */
f0f1cbaa
KM
1231 if (nmp->nm_window < nmp->nm_ssthresh) /* quickly */
1232 nmp->nm_window += 4;
2f08b65a 1233 else { /* slowly */
f0f1cbaa
KM
1234 register long incr = ++nmp->nm_winext;
1235 incr = (incr * incr) / nmp->nm_window;
2f08b65a 1236 if (incr > 0) {
f0f1cbaa
KM
1237 nmp->nm_winext = 0;
1238 ++nmp->nm_window;
2f08b65a
KM
1239 }
1240 }
f0f1cbaa
KM
1241 if (nmp->nm_window > NFS_MAXWINDOW)
1242 nmp->nm_window = NFS_MAXWINDOW;
2f08b65a
KM
1243}
1244
f0f1cbaa
KM
1245nfs_backofftimer(nmp)
1246 register struct nfsmount *nmp;
2f08b65a 1247{
2f08b65a
KM
1248 register unsigned long newrto;
1249
1250 /* Clip shift count */
f0f1cbaa
KM
1251 if (++nmp->nm_rexmit > 8 * sizeof nmp->nm_rto)
1252 nmp->nm_rexmit = 8 * sizeof nmp->nm_rto;
2f08b65a 1253 /* Back off RTO exponentially */
f0f1cbaa
KM
1254 newrto = NFS_RTO(nmp);
1255 newrto <<= (nmp->nm_rexmit - 1);
2f08b65a
KM
1256 if (newrto == 0 || newrto > NFS_MAXTIMEO)
1257 newrto = NFS_MAXTIMEO;
f0f1cbaa 1258 nmp->nm_rto = newrto;
2f08b65a
KM
1259
1260 /* If too many retries, message, assume a bogus RTT and re-measure */
f0f1cbaa
KM
1261 if (nmp->nm_currexmit < nmp->nm_rexmit) {
1262 nmp->nm_currexmit = nmp->nm_rexmit;
1263 if (nmp->nm_currexmit >= nfsrexmtthresh) {
1264 if (nmp->nm_currexmit == nfsrexmtthresh) {
1265 nmp->nm_rttvar += (nmp->nm_srtt >> 2);
1266 nmp->nm_srtt = 0;
a2907882
KM
1267 }
1268 }
a2907882 1269 }
2f08b65a 1270 /* Close down window but remember this point (3/4 current) for later */
f0f1cbaa
KM
1271 nmp->nm_ssthresh = ((nmp->nm_window << 1) + nmp->nm_window) >> 2;
1272 nmp->nm_window = 1;
1273 nmp->nm_winext = 0;
a2907882
KM
1274}
1275
1276/*
f0f1cbaa
KM
1277 * Test for a termination signal pending on procp.
1278 * This is used for NFSMNT_INT mounts.
a2907882 1279 */
f0f1cbaa
KM
1280nfs_sigintr(p)
1281 register struct proc *p;
1282{
1283 if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) &
1284 NFSINT_SIGMASK))
1285 return (1);
1286 else
1287 return (0);
1288}
2f08b65a 1289
f0f1cbaa
KM
1290/*
1291 * Lock a socket against others.
1292 * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
1293 * and also to avoid race conditions between the processes with nfs requests
1294 * in progress when a reconnect is necessary.
1295 */
1296nfs_solock(flagp, cant_intr)
1297 int *flagp;
1298 int cant_intr;
a2907882 1299{
2f08b65a 1300
f0f1cbaa
KM
1301 while (*flagp & NFSMNT_SCKLOCK) {
1302 *flagp |= NFSMNT_WANTSCK;
1303 if (cant_intr)
1304 (void) sleep((caddr_t)flagp, PZERO-7);
1305 else
1306 (void) tsleep((caddr_t)flagp, PZERO+1, "nfssolck", 0);
2f08b65a 1307 }
f0f1cbaa
KM
1308 *flagp |= NFSMNT_SCKLOCK;
1309}
2f08b65a 1310
f0f1cbaa
KM
1311/*
1312 * Unlock the stream socket for others.
1313 */
1314nfs_sounlock(flagp)
1315 int *flagp;
1316{
1317
1318 if ((*flagp & NFSMNT_SCKLOCK) == 0)
1319 panic("nfs sounlock");
1320 *flagp &= ~NFSMNT_SCKLOCK;
1321 if (*flagp & NFSMNT_WANTSCK) {
1322 *flagp &= ~NFSMNT_WANTSCK;
1323 wakeup((caddr_t)flagp);
2f08b65a 1324 }
f0f1cbaa
KM
1325}
1326
1327/*
1328 * This function compares two net addresses by family and returns TRUE
1329 * if they are the same.
1330 * If there is any doubt, return FALSE.
1331 */
1332nfs_netaddr_match(nam1, nam2)
1333 struct mbuf *nam1, *nam2;
1334{
1335 register struct sockaddr *saddr1, *saddr2;
1336
1337 saddr1 = mtod(nam1, struct sockaddr *);
1338 saddr2 = mtod(nam2, struct sockaddr *);
1339 if (saddr1->sa_family != saddr2->sa_family)
1340 return (0);
1341
1342 /*
1343 * Must do each address family separately since unused fields
1344 * are undefined values and not always zeroed.
1345 */
1346 switch (saddr1->sa_family) {
1347 case AF_INET:
1348 if (((struct sockaddr_in *)saddr1)->sin_addr.s_addr ==
1349 ((struct sockaddr_in *)saddr2)->sin_addr.s_addr)
1350 return (1);
1351 break;
1352 default:
1353 break;
1354 };
1355 return (0);
1356}
1357
1358/*
1359 * Check the hostname fields for nfsd's mask and match fields.
1360 * By address family:
1361 * - Bitwise AND the mask with the host address field
1362 * - Compare for == with match
1363 * return TRUE if not equal
1364 */
1365nfs_badnam(nam, msk, mtch)
1366 register struct mbuf *nam, *msk, *mtch;
1367{
1368 switch (mtod(nam, struct sockaddr *)->sa_family) {
1369 case AF_INET:
1370 return ((mtod(nam, struct sockaddr_in *)->sin_addr.s_addr &
1371 mtod(msk, struct sockaddr_in *)->sin_addr.s_addr) !=
1372 mtod(mtch, struct sockaddr_in *)->sin_addr.s_addr);
1373 default:
1374 printf("nfs_badmatch, unknown sa_family\n");
1375 return (0);
1376 };
a2907882 1377}