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