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