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