138414Smckusick /* 247574Skarels * Copyright (c) 1989, 1991 The Regents of the University of California. 338414Smckusick * All rights reserved. 438414Smckusick * 538414Smckusick * This code is derived from software contributed to Berkeley by 638414Smckusick * Rick Macklem at The University of Guelph. 738414Smckusick * 844511Sbostic * %sccs.include.redist.c% 938414Smckusick * 10*54615Smckusick * @(#)nfs_socket.c 7.32 (Berkeley) 07/02/92 1138414Smckusick */ 1238414Smckusick 1338414Smckusick /* 1441900Smckusick * Socket operations for use by nfs 1538414Smckusick */ 1638414Smckusick 17*54615Smckusick #include <sys/param.h> 18*54615Smckusick #include <sys/proc.h> 19*54615Smckusick #include <sys/mount.h> 20*54615Smckusick #include <sys/kernel.h> 21*54615Smckusick #include <sys/mbuf.h> 22*54615Smckusick #include <sys/vnode.h> 23*54615Smckusick #include <sys/domain.h> 24*54615Smckusick #include <sys/protosw.h> 25*54615Smckusick #include <sys/socket.h> 26*54615Smckusick #include <sys/socketvar.h> 27*54615Smckusick #include <sys/syslog.h> 28*54615Smckusick #include <sys/tprintf.h> 29*54615Smckusick #include <netinet/in.h> 30*54615Smckusick #include <netinet/tcp.h> 31*54615Smckusick #include <nfs/rpcv2.h> 32*54615Smckusick #include <nfs/nfsv2.h> 33*54615Smckusick #include <nfs/nfs.h> 34*54615Smckusick #include <nfs/xdr_subs.h> 35*54615Smckusick #include <nfs/nfsm_subs.h> 36*54615Smckusick #include <nfs/nfsmount.h> 37*54615Smckusick #include <nfs/nfsnode.h> 38*54615Smckusick #include <nfs/nfsrtt.h> 39*54615Smckusick #include <nfs/nqnfs.h> 4038414Smckusick 4138414Smckusick #define TRUE 1 4243351Smckusick #define FALSE 0 4338414Smckusick 4452196Smckusick int netnetnet = sizeof (struct netaddrhash); 4540117Smckusick /* 4652196Smckusick * Estimate rto for an nfs rpc sent via. an unreliable datagram. 4752196Smckusick * Use the mean and mean deviation of rtt for the appropriate type of rpc 4852196Smckusick * for the frequent rpcs and a default for the others. 4952196Smckusick * The justification for doing "other" this way is that these rpcs 5052196Smckusick * happen so infrequently that timer est. would probably be stale. 5152196Smckusick * Also, since many of these rpcs are 5252196Smckusick * non-idempotent, a conservative timeout is desired. 5352196Smckusick * getattr, lookup - A+2D 5452196Smckusick * read, write - A+4D 5552196Smckusick * other - nm_timeo 5652196Smckusick */ 5752196Smckusick #define NFS_RTO(n, t) \ 5852196Smckusick ((t) == 0 ? (n)->nm_timeo : \ 5952196Smckusick ((t) < 3 ? \ 6052196Smckusick (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \ 6152196Smckusick ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1))) 6252196Smckusick #define NFS_SRTT(r) (r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1] 6352196Smckusick #define NFS_SDRTT(r) (r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1] 6452196Smckusick /* 6538414Smckusick * External data, mostly RPC constants in XDR form 6638414Smckusick */ 6738414Smckusick extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, 6852196Smckusick rpc_msgaccepted, rpc_call, rpc_autherr, rpc_rejectedcred, 6952196Smckusick rpc_auth_kerb; 7052196Smckusick extern u_long nfs_prog, nfs_vers, nqnfs_prog, nqnfs_vers; 7152196Smckusick extern time_t nqnfsstarttime; 7241900Smckusick extern int nonidempotent[NFS_NPROCS]; 7352196Smckusick 7452196Smckusick /* 7552196Smckusick * Maps errno values to nfs error numbers. 7652196Smckusick * Use NFSERR_IO as the catch all for ones not specifically defined in 7752196Smckusick * RFC 1094. 7852196Smckusick */ 7952196Smckusick static int nfsrv_errmap[ELAST] = { 8052196Smckusick NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8152196Smckusick NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8252196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 8352196Smckusick NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 8452196Smckusick NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8552196Smckusick NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 8652196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8752196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8852196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8952196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9052196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9152196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9252196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 9352196Smckusick NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 9452196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9552196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9652196Smckusick NFSERR_IO, 9745281Smckusick }; 9852196Smckusick 9952196Smckusick /* 10052196Smckusick * Defines which timer to use for the procnum. 10152196Smckusick * 0 - default 10252196Smckusick * 1 - getattr 10352196Smckusick * 2 - lookup 10452196Smckusick * 3 - read 10552196Smckusick * 4 - write 10652196Smckusick */ 10752196Smckusick static int proct[NFS_NPROCS] = { 10852196Smckusick 0, 1, 0, 0, 2, 3, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 10952196Smckusick }; 11052196Smckusick 11152196Smckusick /* 11252196Smckusick * There is a congestion window for outstanding rpcs maintained per mount 11352196Smckusick * point. The cwnd size is adjusted in roughly the way that: 11452196Smckusick * Van Jacobson, Congestion avoidance and Control, In "Proceedings of 11552196Smckusick * SIGCOMM '88". ACM, August 1988. 11652196Smckusick * describes for TCP. The cwnd size is chopped in half on a retransmit timeout 11752196Smckusick * and incremented by 1/cwnd when each rpc reply is received and a full cwnd 11852196Smckusick * of rpcs is in progress. 11952196Smckusick * (The sent count and cwnd are scaled for integer arith.) 12052196Smckusick * Variants of "slow start" were tried and were found to be too much of a 12152196Smckusick * performance hit (ave. rtt 3 times larger), 12252196Smckusick * I suspect due to the large rtt that nfs rpcs have. 12352196Smckusick */ 12452196Smckusick #define NFS_CWNDSCALE 256 12552196Smckusick #define NFS_MAXCWND (NFS_CWNDSCALE * 32) 12652196Smckusick static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, }; 12741900Smckusick int nfs_sbwait(); 12852196Smckusick void nfs_disconnect(), nfs_realign(), nfsrv_wakenfsd(), nfs_sndunlock(); 12952196Smckusick void nfs_rcvunlock(), nqnfs_serverd(); 13052196Smckusick struct mbuf *nfsm_rpchead(); 13152196Smckusick int nfsrtton = 0; 13252196Smckusick struct nfsrtt nfsrtt; 13352196Smckusick struct nfsd nfsd_head; 13441900Smckusick 13538414Smckusick int nfsrv_null(), 13638414Smckusick nfsrv_getattr(), 13738414Smckusick nfsrv_setattr(), 13838414Smckusick nfsrv_lookup(), 13938414Smckusick nfsrv_readlink(), 14038414Smckusick nfsrv_read(), 14138414Smckusick nfsrv_write(), 14238414Smckusick nfsrv_create(), 14338414Smckusick nfsrv_remove(), 14438414Smckusick nfsrv_rename(), 14538414Smckusick nfsrv_link(), 14638414Smckusick nfsrv_symlink(), 14738414Smckusick nfsrv_mkdir(), 14838414Smckusick nfsrv_rmdir(), 14938414Smckusick nfsrv_readdir(), 15038414Smckusick nfsrv_statfs(), 15152196Smckusick nfsrv_noop(), 15252196Smckusick nqnfsrv_readdirlook(), 15352196Smckusick nqnfsrv_getlease(), 15452196Smckusick nqnfsrv_vacated(); 15538414Smckusick 15638414Smckusick int (*nfsrv_procs[NFS_NPROCS])() = { 15738414Smckusick nfsrv_null, 15838414Smckusick nfsrv_getattr, 15938414Smckusick nfsrv_setattr, 16038414Smckusick nfsrv_noop, 16138414Smckusick nfsrv_lookup, 16238414Smckusick nfsrv_readlink, 16338414Smckusick nfsrv_read, 16438414Smckusick nfsrv_noop, 16538414Smckusick nfsrv_write, 16638414Smckusick nfsrv_create, 16738414Smckusick nfsrv_remove, 16838414Smckusick nfsrv_rename, 16938414Smckusick nfsrv_link, 17038414Smckusick nfsrv_symlink, 17138414Smckusick nfsrv_mkdir, 17238414Smckusick nfsrv_rmdir, 17338414Smckusick nfsrv_readdir, 17438414Smckusick nfsrv_statfs, 17552196Smckusick nqnfsrv_readdirlook, 17652196Smckusick nqnfsrv_getlease, 17752196Smckusick nqnfsrv_vacated, 17838414Smckusick }; 17938414Smckusick 18040117Smckusick struct nfsreq nfsreqh; 18138414Smckusick 18238414Smckusick /* 18341900Smckusick * Initialize sockets and congestion for a new NFS connection. 18440117Smckusick * We do not free the sockaddr if error. 18538414Smckusick */ 18652196Smckusick nfs_connect(nmp, rep) 18740117Smckusick register struct nfsmount *nmp; 18852196Smckusick struct nfsreq *rep; 18940117Smckusick { 19041900Smckusick register struct socket *so; 19152196Smckusick int s, error, rcvreserve, sndreserve; 19252988Smckusick struct sockaddr *saddr; 19352988Smckusick struct sockaddr_in *sin; 19440117Smckusick struct mbuf *m; 19552988Smckusick u_short tport; 19640117Smckusick 19741900Smckusick nmp->nm_so = (struct socket *)0; 19852988Smckusick saddr = mtod(nmp->nm_nam, struct sockaddr *); 19952988Smckusick if (error = socreate(saddr->sa_family, 20041900Smckusick &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto)) 20140117Smckusick goto bad; 20241900Smckusick so = nmp->nm_so; 20341900Smckusick nmp->nm_soflags = so->so_proto->pr_flags; 20440117Smckusick 20541900Smckusick /* 20652988Smckusick * Some servers require that the client port be a reserved port number. 20752988Smckusick */ 20852988Smckusick if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) { 20952988Smckusick MGET(m, M_WAIT, MT_SONAME); 21052988Smckusick sin = mtod(m, struct sockaddr_in *); 21152988Smckusick sin->sin_len = m->m_len = sizeof (struct sockaddr_in); 21252988Smckusick sin->sin_family = AF_INET; 21352988Smckusick sin->sin_addr.s_addr = INADDR_ANY; 21452988Smckusick tport = IPPORT_RESERVED - 1; 21552988Smckusick sin->sin_port = htons(tport); 21652988Smckusick while ((error = sobind(so, m)) == EADDRINUSE && 21752988Smckusick --tport > IPPORT_RESERVED / 2) 21852988Smckusick sin->sin_port = htons(tport); 21952988Smckusick m_freem(m); 22052988Smckusick if (error) 22152988Smckusick goto bad; 22252988Smckusick } 22352988Smckusick 22452988Smckusick /* 22541900Smckusick * Protocols that do not require connections may be optionally left 22641900Smckusick * unconnected for servers that reply from a port other than NFS_PORT. 22741900Smckusick */ 22841900Smckusick if (nmp->nm_flag & NFSMNT_NOCONN) { 22941900Smckusick if (nmp->nm_soflags & PR_CONNREQUIRED) { 23041900Smckusick error = ENOTCONN; 23140117Smckusick goto bad; 23240117Smckusick } 23341900Smckusick } else { 23441900Smckusick if (error = soconnect(so, nmp->nm_nam)) 23540117Smckusick goto bad; 23641900Smckusick 23741900Smckusick /* 23841900Smckusick * Wait for the connection to complete. Cribbed from the 23952196Smckusick * connect system call but with the wait timing out so 24052196Smckusick * that interruptible mounts don't hang here for a long time. 24141900Smckusick */ 24241900Smckusick s = splnet(); 24352196Smckusick while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 24452196Smckusick (void) tsleep((caddr_t)&so->so_timeo, PSOCK, 24552196Smckusick "nfscon", 2 * hz); 24652196Smckusick if ((so->so_state & SS_ISCONNECTING) && 24752196Smckusick so->so_error == 0 && rep && 24852196Smckusick (error = nfs_sigintr(nmp, rep, rep->r_procp))) { 24952196Smckusick so->so_state &= ~SS_ISCONNECTING; 25052196Smckusick splx(s); 25152196Smckusick goto bad; 25252196Smckusick } 25352196Smckusick } 25441900Smckusick if (so->so_error) { 25541900Smckusick error = so->so_error; 25652196Smckusick so->so_error = 0; 25752196Smckusick splx(s); 25841900Smckusick goto bad; 25941900Smckusick } 26052196Smckusick splx(s); 26140117Smckusick } 26252196Smckusick if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) { 26352196Smckusick so->so_rcv.sb_timeo = (5 * hz); 26452196Smckusick so->so_snd.sb_timeo = (5 * hz); 26552196Smckusick } else { 26652196Smckusick so->so_rcv.sb_timeo = 0; 26752196Smckusick so->so_snd.sb_timeo = 0; 26852196Smckusick } 26941900Smckusick if (nmp->nm_sotype == SOCK_DGRAM) { 27052196Smckusick sndreserve = nmp->nm_wsize + NFS_MAXPKTHDR; 27152196Smckusick rcvreserve = nmp->nm_rsize + NFS_MAXPKTHDR; 27252196Smckusick } else if (nmp->nm_sotype == SOCK_SEQPACKET) { 27352196Smckusick sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2; 27452196Smckusick rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2; 27541900Smckusick } else { 27652196Smckusick if (nmp->nm_sotype != SOCK_STREAM) 27752196Smckusick panic("nfscon sotype"); 27841900Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 27941900Smckusick MGET(m, M_WAIT, MT_SOOPTS); 28041900Smckusick *mtod(m, int *) = 1; 28141900Smckusick m->m_len = sizeof(int); 28241900Smckusick sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 28341900Smckusick } 28452196Smckusick if (so->so_proto->pr_protocol == IPPROTO_TCP) { 28541900Smckusick MGET(m, M_WAIT, MT_SOOPTS); 28641900Smckusick *mtod(m, int *) = 1; 28741900Smckusick m->m_len = sizeof(int); 28841900Smckusick sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 28941900Smckusick } 29052196Smckusick sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof (u_long)) 29152196Smckusick * 2; 29252196Smckusick rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_long)) 29352196Smckusick * 2; 29441900Smckusick } 29552196Smckusick if (error = soreserve(so, sndreserve, rcvreserve)) 29652196Smckusick goto bad; 29741900Smckusick so->so_rcv.sb_flags |= SB_NOINTR; 29841900Smckusick so->so_snd.sb_flags |= SB_NOINTR; 29940117Smckusick 30041900Smckusick /* Initialize other non-zero congestion variables */ 30152196Smckusick nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] = 30252196Smckusick nmp->nm_srtt[4] = (NFS_TIMEO << 3); 30352196Smckusick nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] = 30452196Smckusick nmp->nm_sdrtt[3] = nmp->nm_sdrtt[4] = 0; 30552196Smckusick nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */ 30641900Smckusick nmp->nm_sent = 0; 30752196Smckusick nmp->nm_timeouts = 0; 30841900Smckusick return (0); 30940117Smckusick 31041900Smckusick bad: 31141900Smckusick nfs_disconnect(nmp); 31241900Smckusick return (error); 31341900Smckusick } 31440117Smckusick 31541900Smckusick /* 31641900Smckusick * Reconnect routine: 31741900Smckusick * Called when a connection is broken on a reliable protocol. 31841900Smckusick * - clean up the old socket 31941900Smckusick * - nfs_connect() again 32041900Smckusick * - set R_MUSTRESEND for all outstanding requests on mount point 32141900Smckusick * If this fails the mount point is DEAD! 32252196Smckusick * nb: Must be called with the nfs_sndlock() set on the mount point. 32341900Smckusick */ 32452196Smckusick nfs_reconnect(rep) 32541900Smckusick register struct nfsreq *rep; 32641900Smckusick { 32741900Smckusick register struct nfsreq *rp; 32852196Smckusick register struct nfsmount *nmp = rep->r_nmp; 32941900Smckusick int error; 33040117Smckusick 33152196Smckusick nfs_disconnect(nmp); 33252196Smckusick while (error = nfs_connect(nmp, rep)) { 33352196Smckusick if (error == EINTR || error == ERESTART) 33441900Smckusick return (EINTR); 33543351Smckusick (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0); 33640117Smckusick } 33741900Smckusick 33841900Smckusick /* 33941900Smckusick * Loop through outstanding request list and fix up all requests 34041900Smckusick * on old socket. 34141900Smckusick */ 34241900Smckusick rp = nfsreqh.r_next; 34341900Smckusick while (rp != &nfsreqh) { 34441900Smckusick if (rp->r_nmp == nmp) 34541900Smckusick rp->r_flags |= R_MUSTRESEND; 34641900Smckusick rp = rp->r_next; 34740117Smckusick } 34840117Smckusick return (0); 34940117Smckusick } 35040117Smckusick 35140117Smckusick /* 35240117Smckusick * NFS disconnect. Clean up and unlink. 35340117Smckusick */ 35441900Smckusick void 35540117Smckusick nfs_disconnect(nmp) 35640117Smckusick register struct nfsmount *nmp; 35740117Smckusick { 35841900Smckusick register struct socket *so; 35940117Smckusick 36041900Smckusick if (nmp->nm_so) { 36141900Smckusick so = nmp->nm_so; 36241900Smckusick nmp->nm_so = (struct socket *)0; 36341900Smckusick soshutdown(so, 2); 36441900Smckusick soclose(so); 36540117Smckusick } 36640117Smckusick } 36740117Smckusick 36840117Smckusick /* 36941900Smckusick * This is the nfs send routine. For connection based socket types, it 37052196Smckusick * must be called with an nfs_sndlock() on the socket. 37141900Smckusick * "rep == NULL" indicates that it has been called from a server. 37252196Smckusick * For the client side: 37352196Smckusick * - return EINTR if the RPC is terminated, 0 otherwise 37452196Smckusick * - set R_MUSTRESEND if the send fails for any reason 37552196Smckusick * - do any cleanup required by recoverable socket errors (???) 37652196Smckusick * For the server side: 37752196Smckusick * - return EINTR or ERESTART if interrupted by a signal 37852196Smckusick * - return EPIPE if a connection is lost for connection based sockets (TCP...) 37952196Smckusick * - do any cleanup required by recoverable socket errors (???) 38040117Smckusick */ 38141900Smckusick nfs_send(so, nam, top, rep) 38238414Smckusick register struct socket *so; 38338414Smckusick struct mbuf *nam; 38441900Smckusick register struct mbuf *top; 38541900Smckusick struct nfsreq *rep; 38638414Smckusick { 38741900Smckusick struct mbuf *sendnam; 38852196Smckusick int error, soflags, flags; 38938414Smckusick 39041900Smckusick if (rep) { 39141900Smckusick if (rep->r_flags & R_SOFTTERM) { 39240117Smckusick m_freem(top); 39341900Smckusick return (EINTR); 39440117Smckusick } 39552196Smckusick if ((so = rep->r_nmp->nm_so) == NULL) { 39652196Smckusick rep->r_flags |= R_MUSTRESEND; 39752196Smckusick m_freem(top); 39852196Smckusick return (0); 39952196Smckusick } 40041900Smckusick rep->r_flags &= ~R_MUSTRESEND; 40141900Smckusick soflags = rep->r_nmp->nm_soflags; 40241900Smckusick } else 40341900Smckusick soflags = so->so_proto->pr_flags; 40441900Smckusick if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) 40541900Smckusick sendnam = (struct mbuf *)0; 40641900Smckusick else 40741900Smckusick sendnam = nam; 40852196Smckusick if (so->so_type == SOCK_SEQPACKET) 40952196Smckusick flags = MSG_EOR; 41052196Smckusick else 41152196Smckusick flags = 0; 41241900Smckusick 41341900Smckusick error = sosend(so, sendnam, (struct uio *)0, top, 41452196Smckusick (struct mbuf *)0, flags); 41552196Smckusick if (error) { 41652196Smckusick if (rep) { 41752934Smckusick log(LOG_INFO, "nfs send error %d for server %s\n",error, 41852934Smckusick rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 41952196Smckusick /* 42052196Smckusick * Deal with errors for the client side. 42152196Smckusick */ 42252196Smckusick if (rep->r_flags & R_SOFTTERM) 42352196Smckusick error = EINTR; 42452196Smckusick else 42552196Smckusick rep->r_flags |= R_MUSTRESEND; 42652934Smckusick } else 42752934Smckusick log(LOG_INFO, "nfsd send error %d\n", error); 42852196Smckusick 42952196Smckusick /* 43052196Smckusick * Handle any recoverable (soft) socket errors here. (???) 43152196Smckusick */ 43252196Smckusick if (error != EINTR && error != ERESTART && 43352196Smckusick error != EWOULDBLOCK && error != EPIPE) 43441900Smckusick error = 0; 43538414Smckusick } 43638414Smckusick return (error); 43738414Smckusick } 43838414Smckusick 43938414Smckusick /* 44041900Smckusick * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all 44141900Smckusick * done by soreceive(), but for SOCK_STREAM we must deal with the Record 44241900Smckusick * Mark and consolidate the data into a new mbuf list. 44341900Smckusick * nb: Sometimes TCP passes the data up to soreceive() in long lists of 44441900Smckusick * small mbufs. 44541900Smckusick * For SOCK_STREAM we must be very careful to read an entire record once 44641900Smckusick * we have read any of it, even if the system call has been interrupted. 44738414Smckusick */ 44852196Smckusick nfs_receive(rep, aname, mp) 44952196Smckusick register struct nfsreq *rep; 45038414Smckusick struct mbuf **aname; 45138414Smckusick struct mbuf **mp; 45238414Smckusick { 45352196Smckusick register struct socket *so; 45441900Smckusick struct uio auio; 45541900Smckusick struct iovec aio; 45638414Smckusick register struct mbuf *m; 45752196Smckusick struct mbuf *control; 45841900Smckusick u_long len; 45941900Smckusick struct mbuf **getnam; 46052196Smckusick int error, sotype, rcvflg; 46152932Smckusick struct proc *p = curproc; /* XXX */ 46238414Smckusick 46341900Smckusick /* 46441900Smckusick * Set up arguments for soreceive() 46541900Smckusick */ 46641900Smckusick *mp = (struct mbuf *)0; 46741900Smckusick *aname = (struct mbuf *)0; 46852196Smckusick sotype = rep->r_nmp->nm_sotype; 46938414Smckusick 47041900Smckusick /* 47141900Smckusick * For reliable protocols, lock against other senders/receivers 47241900Smckusick * in case a reconnect is necessary. 47341900Smckusick * For SOCK_STREAM, first get the Record Mark to find out how much 47441900Smckusick * more there is to get. 47541900Smckusick * We must lock the socket against other receivers 47641900Smckusick * until we have an entire rpc request/reply. 47741900Smckusick */ 47852196Smckusick if (sotype != SOCK_DGRAM) { 47952196Smckusick if (error = nfs_sndlock(&rep->r_nmp->nm_flag, rep)) 48052196Smckusick return (error); 48141900Smckusick tryagain: 48241900Smckusick /* 48341900Smckusick * Check for fatal errors and resending request. 48441900Smckusick */ 48552196Smckusick /* 48652196Smckusick * Ugh: If a reconnect attempt just happened, nm_so 48752196Smckusick * would have changed. NULL indicates a failed 48852196Smckusick * attempt that has essentially shut down this 48952196Smckusick * mount point. 49052196Smckusick */ 49152196Smckusick if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) { 49252196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 49352196Smckusick return (EINTR); 49452196Smckusick } 49552196Smckusick if ((so = rep->r_nmp->nm_so) == NULL) { 49652196Smckusick if (error = nfs_reconnect(rep)) { 49752196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 49852196Smckusick return (error); 49940117Smckusick } 50052196Smckusick goto tryagain; 50141900Smckusick } 50252196Smckusick while (rep->r_flags & R_MUSTRESEND) { 50352196Smckusick m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT); 50452196Smckusick nfsstats.rpcretries++; 50552196Smckusick if (error = nfs_send(so, rep->r_nmp->nm_nam, m, rep)) { 50652196Smckusick if (error == EINTR || error == ERESTART || 50752196Smckusick (error = nfs_reconnect(rep))) { 50852196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 50952196Smckusick return (error); 51052196Smckusick } 51152196Smckusick goto tryagain; 51252196Smckusick } 51352196Smckusick } 51452196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 51552196Smckusick if (sotype == SOCK_STREAM) { 51641900Smckusick aio.iov_base = (caddr_t) &len; 51741900Smckusick aio.iov_len = sizeof(u_long); 51841900Smckusick auio.uio_iov = &aio; 51941900Smckusick auio.uio_iovcnt = 1; 52041900Smckusick auio.uio_segflg = UIO_SYSSPACE; 52141900Smckusick auio.uio_rw = UIO_READ; 52241900Smckusick auio.uio_offset = 0; 52341900Smckusick auio.uio_resid = sizeof(u_long); 52452932Smckusick auio.uio_procp = p; 52541900Smckusick do { 52652196Smckusick rcvflg = MSG_WAITALL; 52752196Smckusick error = soreceive(so, (struct mbuf **)0, &auio, 52841900Smckusick (struct mbuf **)0, (struct mbuf **)0, &rcvflg); 52952196Smckusick if (error == EWOULDBLOCK && rep) { 53041900Smckusick if (rep->r_flags & R_SOFTTERM) 53141900Smckusick return (EINTR); 53252196Smckusick } 53341900Smckusick } while (error == EWOULDBLOCK); 53447737Skarels if (!error && auio.uio_resid > 0) { 53552934Smckusick log(LOG_INFO, 53652934Smckusick "short receive (%d/%d) from nfs server %s\n", 53752934Smckusick sizeof(u_long) - auio.uio_resid, 53852934Smckusick sizeof(u_long), 53947737Skarels rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 54047737Skarels error = EPIPE; 54147737Skarels } 54240761Skarels if (error) 54341900Smckusick goto errout; 54441900Smckusick len = ntohl(len) & ~0x80000000; 54541900Smckusick /* 54641900Smckusick * This is SERIOUS! We are out of sync with the sender 54741900Smckusick * and forcing a disconnect/reconnect is all I can do. 54841900Smckusick */ 54941900Smckusick if (len > NFS_MAXPACKET) { 55052934Smckusick log(LOG_ERR, "%s (%d) from nfs server %s\n", 55152934Smckusick "impossible packet length", 55252934Smckusick len, 55352934Smckusick rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 55447737Skarels error = EFBIG; 55547737Skarels goto errout; 55641900Smckusick } 55741900Smckusick auio.uio_resid = len; 55841900Smckusick do { 55947737Skarels rcvflg = MSG_WAITALL; 56041900Smckusick error = soreceive(so, (struct mbuf **)0, 56141900Smckusick &auio, mp, (struct mbuf **)0, &rcvflg); 56241900Smckusick } while (error == EWOULDBLOCK || error == EINTR || 56341900Smckusick error == ERESTART); 56447737Skarels if (!error && auio.uio_resid > 0) { 56552934Smckusick log(LOG_INFO, 56652934Smckusick "short receive (%d/%d) from nfs server %s\n", 56752934Smckusick len - auio.uio_resid, len, 56852934Smckusick rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 56947737Skarels error = EPIPE; 57047737Skarels } 57140117Smckusick } else { 57252196Smckusick /* 57352196Smckusick * NB: Since uio_resid is big, MSG_WAITALL is ignored 57452196Smckusick * and soreceive() will return when it has either a 57552196Smckusick * control msg or a data msg. 57652196Smckusick * We have no use for control msg., but must grab them 57752196Smckusick * and then throw them away so we know what is going 57852196Smckusick * on. 57952196Smckusick */ 58052196Smckusick auio.uio_resid = len = 100000000; /* Anything Big */ 58152932Smckusick auio.uio_procp = p; 58241900Smckusick do { 58347737Skarels rcvflg = 0; 58441900Smckusick error = soreceive(so, (struct mbuf **)0, 58552196Smckusick &auio, mp, &control, &rcvflg); 58652196Smckusick if (control) 58752196Smckusick m_freem(control); 58841900Smckusick if (error == EWOULDBLOCK && rep) { 58941900Smckusick if (rep->r_flags & R_SOFTTERM) 59041900Smckusick return (EINTR); 59141900Smckusick } 59252196Smckusick } while (error == EWOULDBLOCK || 59352196Smckusick (!error && *mp == NULL && control)); 59452196Smckusick if ((rcvflg & MSG_EOR) == 0) 59552196Smckusick printf("Egad!!\n"); 59641900Smckusick if (!error && *mp == NULL) 59741900Smckusick error = EPIPE; 59841900Smckusick len -= auio.uio_resid; 59940117Smckusick } 60041900Smckusick errout: 60152196Smckusick if (error && error != EINTR && error != ERESTART) { 60241900Smckusick m_freem(*mp); 60341900Smckusick *mp = (struct mbuf *)0; 60452934Smckusick if (error != EPIPE) 60547737Skarels log(LOG_INFO, 60647737Skarels "receive error %d from nfs server %s\n", 60747737Skarels error, 60847737Skarels rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 60952196Smckusick error = nfs_sndlock(&rep->r_nmp->nm_flag, rep); 61041900Smckusick if (!error) 61152196Smckusick error = nfs_reconnect(rep); 61252196Smckusick if (!error) 61341900Smckusick goto tryagain; 61440117Smckusick } 61541900Smckusick } else { 61652196Smckusick if ((so = rep->r_nmp->nm_so) == NULL) 61752196Smckusick return (EACCES); 61841900Smckusick if (so->so_state & SS_ISCONNECTED) 61941900Smckusick getnam = (struct mbuf **)0; 62041900Smckusick else 62141900Smckusick getnam = aname; 62241900Smckusick auio.uio_resid = len = 1000000; 62352932Smckusick auio.uio_procp = p; 62441900Smckusick do { 62547737Skarels rcvflg = 0; 62641900Smckusick error = soreceive(so, getnam, &auio, mp, 62741900Smckusick (struct mbuf **)0, &rcvflg); 62852196Smckusick if (error == EWOULDBLOCK && 62941900Smckusick (rep->r_flags & R_SOFTTERM)) 63041900Smckusick return (EINTR); 63141900Smckusick } while (error == EWOULDBLOCK); 63241900Smckusick len -= auio.uio_resid; 63341900Smckusick } 63441900Smckusick if (error) { 63541900Smckusick m_freem(*mp); 63641900Smckusick *mp = (struct mbuf *)0; 63741900Smckusick } 63841900Smckusick /* 63952196Smckusick * Search for any mbufs that are not a multiple of 4 bytes long 64052196Smckusick * or with m_data not longword aligned. 64141900Smckusick * These could cause pointer alignment problems, so copy them to 64241900Smckusick * well aligned mbufs. 64341900Smckusick */ 64452196Smckusick nfs_realign(*mp, 5 * NFSX_UNSIGNED); 64538414Smckusick return (error); 64638414Smckusick } 64738414Smckusick 64838414Smckusick /* 64941900Smckusick * Implement receipt of reply on a socket. 65038414Smckusick * We must search through the list of received datagrams matching them 65138414Smckusick * with outstanding requests using the xid, until ours is found. 65238414Smckusick */ 65341900Smckusick /* ARGSUSED */ 65452196Smckusick nfs_reply(myrep) 65539344Smckusick struct nfsreq *myrep; 65638414Smckusick { 65738414Smckusick register struct nfsreq *rep; 65852196Smckusick register struct nfsmount *nmp = myrep->r_nmp; 65952196Smckusick register long t1; 66052196Smckusick struct mbuf *mrep, *nam, *md; 66152196Smckusick u_long rxid, *tl; 66252196Smckusick caddr_t dpos, cp2; 66352196Smckusick int error; 66438414Smckusick 66541900Smckusick /* 66641900Smckusick * Loop around until we get our own reply 66741900Smckusick */ 66841900Smckusick for (;;) { 66941900Smckusick /* 67041900Smckusick * Lock against other receivers so that I don't get stuck in 67141900Smckusick * sbwait() after someone else has received my reply for me. 67241900Smckusick * Also necessary for connection based protocols to avoid 67341900Smckusick * race conditions during a reconnect. 67441900Smckusick */ 67552196Smckusick if (error = nfs_rcvlock(myrep)) 67652196Smckusick return (error); 67741900Smckusick /* Already received, bye bye */ 67841900Smckusick if (myrep->r_mrep != NULL) { 67952196Smckusick nfs_rcvunlock(&nmp->nm_flag); 68041900Smckusick return (0); 68140117Smckusick } 68241900Smckusick /* 68341900Smckusick * Get the next Rpc reply off the socket 68441900Smckusick */ 68552196Smckusick error = nfs_receive(myrep, &nam, &mrep); 68652196Smckusick nfs_rcvunlock(&nmp->nm_flag); 68752196Smckusick if (error) printf("rcv err=%d\n",error); 68852196Smckusick if (error) { 68938414Smckusick 69041900Smckusick /* 69141900Smckusick * Ignore routing errors on connectionless protocols?? 69241900Smckusick */ 69341900Smckusick if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) { 69441900Smckusick nmp->nm_so->so_error = 0; 69541900Smckusick continue; 69641900Smckusick } 69741900Smckusick return (error); 69838414Smckusick } 69952196Smckusick if (nam) 70052196Smckusick m_freem(nam); 70141900Smckusick 70241900Smckusick /* 70341900Smckusick * Get the xid and check that it is an rpc reply 70441900Smckusick */ 70552196Smckusick md = mrep; 70652196Smckusick dpos = mtod(md, caddr_t); 70752196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 70852196Smckusick rxid = *tl++; 70952196Smckusick if (*tl != rpc_reply) { 71052196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 71152196Smckusick if (nqnfs_callback(nmp, mrep, md, dpos)) 71252196Smckusick nfsstats.rpcinvalid++; 71352196Smckusick } else { 71452196Smckusick nfsstats.rpcinvalid++; 71552196Smckusick m_freem(mrep); 71652196Smckusick } 71752196Smckusick nfsmout: 71841900Smckusick continue; 71938414Smckusick } 72052196Smckusick 72141900Smckusick /* 72241900Smckusick * Loop through the request list to match up the reply 72341900Smckusick * Iff no match, just drop the datagram 72441900Smckusick */ 72541900Smckusick rep = nfsreqh.r_next; 72641900Smckusick while (rep != &nfsreqh) { 72745281Smckusick if (rep->r_mrep == NULL && rxid == rep->r_xid) { 72841900Smckusick /* Found it.. */ 72952196Smckusick rep->r_mrep = mrep; 73052196Smckusick rep->r_md = md; 73152196Smckusick rep->r_dpos = dpos; 73252196Smckusick if (nfsrtton) { 73352196Smckusick struct rttl *rt; 73452196Smckusick 73552196Smckusick rt = &nfsrtt.rttl[nfsrtt.pos]; 73652196Smckusick rt->proc = rep->r_procnum; 73752196Smckusick rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]); 73852196Smckusick rt->sent = nmp->nm_sent; 73952196Smckusick rt->cwnd = nmp->nm_cwnd; 74052196Smckusick rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1]; 74152196Smckusick rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1]; 74252196Smckusick rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid; 74352196Smckusick rt->tstamp = time; 74452196Smckusick if (rep->r_flags & R_TIMING) 74552196Smckusick rt->rtt = rep->r_rtt; 74652196Smckusick else 74752196Smckusick rt->rtt = 1000000; 74852196Smckusick nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ; 74952196Smckusick } 75041900Smckusick /* 75152196Smckusick * Update congestion window. 75252196Smckusick * Do the additive increase of 75352196Smckusick * one rpc/rtt. 75441900Smckusick */ 75552196Smckusick if (nmp->nm_cwnd <= nmp->nm_sent) { 75652196Smckusick nmp->nm_cwnd += 75752196Smckusick (NFS_CWNDSCALE * NFS_CWNDSCALE + 75852196Smckusick (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd; 75952196Smckusick if (nmp->nm_cwnd > NFS_MAXCWND) 76052196Smckusick nmp->nm_cwnd = NFS_MAXCWND; 76152196Smckusick } 76252196Smckusick nmp->nm_sent -= NFS_CWNDSCALE; 76352196Smckusick /* 76452196Smckusick * Update rtt using a gain of 0.125 on the mean 76552196Smckusick * and a gain of 0.25 on the deviation. 76652196Smckusick */ 76741900Smckusick if (rep->r_flags & R_TIMING) { 76852196Smckusick /* 76952196Smckusick * Since the timer resolution of 77052196Smckusick * NFS_HZ is so course, it can often 77152196Smckusick * result in r_rtt == 0. Since 77252196Smckusick * r_rtt == N means that the actual 77352196Smckusick * rtt is between N+dt and N+2-dt ticks, 77452196Smckusick * add 1. 77552196Smckusick */ 77652196Smckusick t1 = rep->r_rtt + 1; 77752196Smckusick t1 -= (NFS_SRTT(rep) >> 3); 77852196Smckusick NFS_SRTT(rep) += t1; 77952196Smckusick if (t1 < 0) 78052196Smckusick t1 = -t1; 78152196Smckusick t1 -= (NFS_SDRTT(rep) >> 2); 78252196Smckusick NFS_SDRTT(rep) += t1; 78341900Smckusick } 78452196Smckusick nmp->nm_timeouts = 0; 78540117Smckusick break; 78638414Smckusick } 78741900Smckusick rep = rep->r_next; 78838414Smckusick } 78941900Smckusick /* 79041900Smckusick * If not matched to a request, drop it. 79141900Smckusick * If it's mine, get out. 79241900Smckusick */ 79341900Smckusick if (rep == &nfsreqh) { 79441900Smckusick nfsstats.rpcunexpected++; 79552196Smckusick m_freem(mrep); 79653426Smckusick } else if (rep == myrep) { 79753426Smckusick if (rep->r_mrep == NULL) 79853426Smckusick panic("nfsreply nil"); 79941900Smckusick return (0); 80053426Smckusick } 80138414Smckusick } 80238414Smckusick } 80338414Smckusick 80438414Smckusick /* 80538414Smckusick * nfs_request - goes something like this 80638414Smckusick * - fill in request struct 80738414Smckusick * - links it into list 80841900Smckusick * - calls nfs_send() for first transmit 80941900Smckusick * - calls nfs_receive() to get reply 81038414Smckusick * - break down rpc header and return with nfs reply pointed to 81138414Smckusick * by mrep or error 81238414Smckusick * nb: always frees up mreq mbuf list 81338414Smckusick */ 81452196Smckusick nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) 81538414Smckusick struct vnode *vp; 81652196Smckusick struct mbuf *mrest; 81741900Smckusick int procnum; 81841900Smckusick struct proc *procp; 81952196Smckusick struct ucred *cred; 82038414Smckusick struct mbuf **mrp; 82138414Smckusick struct mbuf **mdp; 82238414Smckusick caddr_t *dposp; 82338414Smckusick { 82438414Smckusick register struct mbuf *m, *mrep; 82538414Smckusick register struct nfsreq *rep; 82648048Smckusick register u_long *tl; 82752196Smckusick register int i; 82841900Smckusick struct nfsmount *nmp; 82952196Smckusick struct mbuf *md, *mheadend; 83039344Smckusick struct nfsreq *reph; 83152196Smckusick struct nfsnode *tp, *np; 83252196Smckusick time_t reqtime, waituntil; 83352196Smckusick caddr_t dpos, cp2; 83452196Smckusick int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; 83552196Smckusick int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; 83652196Smckusick u_long xid; 83752196Smckusick char *auth_str; 83838414Smckusick 83952196Smckusick nmp = VFSTONFS(vp->v_mount); 84038414Smckusick MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); 84141900Smckusick rep->r_nmp = nmp; 84238414Smckusick rep->r_vp = vp; 84341900Smckusick rep->r_procp = procp; 84452196Smckusick rep->r_procnum = procnum; 84552196Smckusick i = 0; 84652196Smckusick m = mrest; 84738414Smckusick while (m) { 84852196Smckusick i += m->m_len; 84938414Smckusick m = m->m_next; 85038414Smckusick } 85152196Smckusick mrest_len = i; 85252196Smckusick 85352196Smckusick /* 85452196Smckusick * Get the RPC header with authorization. 85552196Smckusick */ 85652196Smckusick kerbauth: 85752196Smckusick auth_str = (char *)0; 85852196Smckusick if (nmp->nm_flag & NFSMNT_KERB) { 85952196Smckusick if (failed_auth) { 86052196Smckusick error = nfs_getauth(nmp, rep, cred, &auth_type, 86152196Smckusick &auth_str, &auth_len); 86252196Smckusick if (error) { 86352196Smckusick free((caddr_t)rep, M_NFSREQ); 86452196Smckusick m_freem(mrest); 86552196Smckusick return (error); 86652196Smckusick } 86752196Smckusick } else { 86852196Smckusick auth_type = RPCAUTH_UNIX; 86952196Smckusick auth_len = 5 * NFSX_UNSIGNED; 87045281Smckusick } 87152196Smckusick } else { 87252196Smckusick auth_type = RPCAUTH_UNIX; 87353426Smckusick if (cred->cr_ngroups < 1) 87453426Smckusick panic("nfsreq nogrps"); 87552196Smckusick auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ? 87652196Smckusick nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + 87752196Smckusick 5 * NFSX_UNSIGNED; 87845281Smckusick } 87952196Smckusick m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum, 88052196Smckusick auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid); 88152196Smckusick if (auth_str) 88252196Smckusick free(auth_str, M_TEMP); 88352196Smckusick 88441900Smckusick /* 88552196Smckusick * For stream protocols, insert a Sun RPC Record Mark. 88641900Smckusick */ 88752196Smckusick if (nmp->nm_sotype == SOCK_STREAM) { 88852196Smckusick M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 88952196Smckusick *mtod(m, u_long *) = htonl(0x80000000 | 89052196Smckusick (m->m_pkthdr.len - NFSX_UNSIGNED)); 89141900Smckusick } 89252196Smckusick rep->r_mreq = m; 89352196Smckusick rep->r_xid = xid; 89452196Smckusick tryagain: 89552196Smckusick if (nmp->nm_flag & NFSMNT_SOFT) 89652196Smckusick rep->r_retry = nmp->nm_retry; 89752196Smckusick else 89852196Smckusick rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */ 89952196Smckusick rep->r_rtt = rep->r_rexmit = 0; 90052196Smckusick if (proct[procnum] > 0) 90152196Smckusick rep->r_flags = R_TIMING; 90252196Smckusick else 90352196Smckusick rep->r_flags = 0; 90452196Smckusick rep->r_mrep = NULL; 90538414Smckusick 90640117Smckusick /* 90740117Smckusick * Do the client side RPC. 90840117Smckusick */ 90940117Smckusick nfsstats.rpcrequests++; 91041900Smckusick /* 91141900Smckusick * Chain request into list of outstanding requests. Be sure 91241900Smckusick * to put it LAST so timer finds oldest requests first. 91341900Smckusick */ 91452196Smckusick s = splsoftclock(); 91539344Smckusick reph = &nfsreqh; 91641900Smckusick reph->r_prev->r_next = rep; 91741900Smckusick rep->r_prev = reph->r_prev; 91839344Smckusick reph->r_prev = rep; 91939344Smckusick rep->r_next = reph; 92052196Smckusick 92152196Smckusick /* Get send time for nqnfs */ 92252196Smckusick reqtime = time.tv_sec; 92352196Smckusick 92440117Smckusick /* 92540117Smckusick * If backing off another request or avoiding congestion, don't 92640117Smckusick * send this one now but let timer do it. If not timing a request, 92740117Smckusick * do it now. 92840117Smckusick */ 92952196Smckusick if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM || 93052196Smckusick (nmp->nm_flag & NFSMNT_DUMBTIMR) || 93152196Smckusick nmp->nm_sent < nmp->nm_cwnd)) { 93240117Smckusick splx(s); 93341900Smckusick if (nmp->nm_soflags & PR_CONNREQUIRED) 93452196Smckusick error = nfs_sndlock(&nmp->nm_flag, rep); 93552196Smckusick if (!error) { 93652196Smckusick m = m_copym(m, 0, M_COPYALL, M_WAIT); 93752196Smckusick error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep); 93852196Smckusick if (nmp->nm_soflags & PR_CONNREQUIRED) 93952196Smckusick nfs_sndunlock(&nmp->nm_flag); 94052196Smckusick } 94152196Smckusick if (!error && (rep->r_flags & R_MUSTRESEND) == 0) { 94252196Smckusick nmp->nm_sent += NFS_CWNDSCALE; 94352196Smckusick rep->r_flags |= R_SENT; 94452196Smckusick } 94552196Smckusick } else { 94641900Smckusick splx(s); 94752196Smckusick rep->r_rtt = -1; 94852196Smckusick } 94938414Smckusick 95038414Smckusick /* 95140117Smckusick * Wait for the reply from our send or the timer's. 95240117Smckusick */ 95354610Smckusick if (!error || error == EPIPE) 95452196Smckusick error = nfs_reply(rep); 95538414Smckusick 95640117Smckusick /* 95740117Smckusick * RPC done, unlink the request. 95840117Smckusick */ 95952196Smckusick s = splsoftclock(); 96038414Smckusick rep->r_prev->r_next = rep->r_next; 96139344Smckusick rep->r_next->r_prev = rep->r_prev; 96238414Smckusick splx(s); 96341900Smckusick 96441900Smckusick /* 96541900Smckusick * If there was a successful reply and a tprintf msg. 96641900Smckusick * tprintf a response. 96741900Smckusick */ 96847737Skarels if (!error && (rep->r_flags & R_TPRINTFMSG)) 96947737Skarels nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname, 97047737Skarels "is alive again"); 97145281Smckusick mrep = rep->r_mrep; 97252196Smckusick md = rep->r_md; 97352196Smckusick dpos = rep->r_dpos; 97452196Smckusick if (error) { 97552196Smckusick m_freem(rep->r_mreq); 97652196Smckusick free((caddr_t)rep, M_NFSREQ); 97738414Smckusick return (error); 97852196Smckusick } 97938414Smckusick 98038414Smckusick /* 98138414Smckusick * break down the rpc header and check if ok 98238414Smckusick */ 98352196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 98448048Smckusick if (*tl++ == rpc_msgdenied) { 98548048Smckusick if (*tl == rpc_mismatch) 98638414Smckusick error = EOPNOTSUPP; 98752196Smckusick else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { 98852196Smckusick if (*tl == rpc_rejectedcred && failed_auth == 0) { 98952196Smckusick failed_auth++; 99052196Smckusick mheadend->m_next = (struct mbuf *)0; 99152196Smckusick m_freem(mrep); 99252196Smckusick m_freem(rep->r_mreq); 99352196Smckusick goto kerbauth; 99452196Smckusick } else 99552196Smckusick error = EAUTH; 99652196Smckusick } else 99738414Smckusick error = EACCES; 99838414Smckusick m_freem(mrep); 99952196Smckusick m_freem(rep->r_mreq); 100052196Smckusick free((caddr_t)rep, M_NFSREQ); 100138414Smckusick return (error); 100238414Smckusick } 100352196Smckusick 100438414Smckusick /* 100538414Smckusick * skip over the auth_verf, someday we may want to cache auth_short's 100638414Smckusick * for nfs_reqhead(), but for now just dump it 100738414Smckusick */ 100848048Smckusick if (*++tl != 0) { 100952196Smckusick i = nfsm_rndup(fxdr_unsigned(long, *tl)); 101052196Smckusick nfsm_adv(i); 101138414Smckusick } 101252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 101338414Smckusick /* 0 == ok */ 101448048Smckusick if (*tl == 0) { 101552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 101648048Smckusick if (*tl != 0) { 101748048Smckusick error = fxdr_unsigned(int, *tl); 101838414Smckusick m_freem(mrep); 101952196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) && 102052196Smckusick error == NQNFS_TRYLATER) { 102152196Smckusick error = 0; 102252196Smckusick waituntil = time.tv_sec + trylater_delay; 102352196Smckusick while (time.tv_sec < waituntil) 102452196Smckusick (void) tsleep((caddr_t)&lbolt, 102552196Smckusick PSOCK, "nqnfstry", 0); 102652196Smckusick trylater_delay *= nfs_backoff[trylater_cnt]; 102752196Smckusick if (trylater_cnt < 7) 102852196Smckusick trylater_cnt++; 102952196Smckusick goto tryagain; 103052196Smckusick } 103152196Smckusick m_freem(rep->r_mreq); 103252196Smckusick free((caddr_t)rep, M_NFSREQ); 103338414Smckusick return (error); 103438414Smckusick } 103552196Smckusick 103652196Smckusick /* 103752196Smckusick * For nqnfs, get any lease in reply 103852196Smckusick */ 103952196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 104052196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 104152196Smckusick if (*tl) { 104252196Smckusick np = VTONFS(vp); 104352196Smckusick nqlflag = fxdr_unsigned(int, *tl); 104452196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 104552196Smckusick cachable = fxdr_unsigned(int, *tl++); 104652196Smckusick reqtime += fxdr_unsigned(int, *tl++); 104752196Smckusick if (reqtime > time.tv_sec) { 104852196Smckusick if (np->n_tnext) { 104952196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 105052196Smckusick nmp->nm_tprev = np->n_tprev; 105152196Smckusick else 105252196Smckusick np->n_tnext->n_tprev = np->n_tprev; 105352196Smckusick if (np->n_tprev == (struct nfsnode *)nmp) 105452196Smckusick nmp->nm_tnext = np->n_tnext; 105552196Smckusick else 105652196Smckusick np->n_tprev->n_tnext = np->n_tnext; 105752196Smckusick if (nqlflag == NQL_WRITE) 105852196Smckusick np->n_flag |= NQNFSWRITE; 105952196Smckusick } else if (nqlflag == NQL_READ) 106052196Smckusick np->n_flag &= ~NQNFSWRITE; 106152196Smckusick else 106252196Smckusick np->n_flag |= NQNFSWRITE; 106352196Smckusick if (cachable) 106452196Smckusick np->n_flag &= ~NQNFSNONCACHE; 106552196Smckusick else 106652196Smckusick np->n_flag |= NQNFSNONCACHE; 106752196Smckusick np->n_expiry = reqtime; 106852196Smckusick fxdr_hyper(tl, &np->n_lrev); 106952196Smckusick tp = nmp->nm_tprev; 107052196Smckusick while (tp != (struct nfsnode *)nmp && 107152196Smckusick tp->n_expiry > np->n_expiry) 107252196Smckusick tp = tp->n_tprev; 107352196Smckusick if (tp == (struct nfsnode *)nmp) { 107452196Smckusick np->n_tnext = nmp->nm_tnext; 107552196Smckusick nmp->nm_tnext = np; 107652196Smckusick } else { 107752196Smckusick np->n_tnext = tp->n_tnext; 107852196Smckusick tp->n_tnext = np; 107952196Smckusick } 108052196Smckusick np->n_tprev = tp; 108152196Smckusick if (np->n_tnext == (struct nfsnode *)nmp) 108252196Smckusick nmp->nm_tprev = np; 108352196Smckusick else 108452196Smckusick np->n_tnext->n_tprev = np; 108552196Smckusick } 108652196Smckusick } 108752196Smckusick } 108838414Smckusick *mrp = mrep; 108938414Smckusick *mdp = md; 109038414Smckusick *dposp = dpos; 109152196Smckusick m_freem(rep->r_mreq); 109252196Smckusick FREE((caddr_t)rep, M_NFSREQ); 109338414Smckusick return (0); 109438414Smckusick } 109538414Smckusick m_freem(mrep); 109652196Smckusick m_freem(rep->r_mreq); 109752196Smckusick free((caddr_t)rep, M_NFSREQ); 109852196Smckusick error = EPROTONOSUPPORT; 109938414Smckusick nfsmout: 110038414Smckusick return (error); 110138414Smckusick } 110238414Smckusick 110338414Smckusick /* 110438414Smckusick * Generate the rpc reply header 110538414Smckusick * siz arg. is used to decide if adding a cluster is worthwhile 110638414Smckusick */ 110752196Smckusick nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) 110838414Smckusick int siz; 110952196Smckusick struct nfsd *nd; 111038414Smckusick int err; 111152196Smckusick int cache; 111252196Smckusick u_quad_t *frev; 111338414Smckusick struct mbuf **mrq; 111438414Smckusick struct mbuf **mbp; 111538414Smckusick caddr_t *bposp; 111638414Smckusick { 111748048Smckusick register u_long *tl; 111852196Smckusick register struct mbuf *mreq; 111939494Smckusick caddr_t bpos; 112052196Smckusick struct mbuf *mb, *mb2; 112138414Smckusick 112252196Smckusick MGETHDR(mreq, M_WAIT, MT_DATA); 112338414Smckusick mb = mreq; 112452196Smckusick /* 112552196Smckusick * If this is a big reply, use a cluster else 112652196Smckusick * try and leave leading space for the lower level headers. 112752196Smckusick */ 112852196Smckusick siz += RPC_REPLYSIZ; 112952196Smckusick if (siz >= MINCLSIZE) { 113041900Smckusick MCLGET(mreq, M_WAIT); 113152196Smckusick } else 113252196Smckusick mreq->m_data += max_hdr; 113348048Smckusick tl = mtod(mreq, u_long *); 113438414Smckusick mreq->m_len = 6*NFSX_UNSIGNED; 113548048Smckusick bpos = ((caddr_t)tl)+mreq->m_len; 113652196Smckusick *tl++ = nd->nd_retxid; 113748048Smckusick *tl++ = rpc_reply; 113852196Smckusick if (err == ERPCMISMATCH || err == NQNFS_AUTHERR) { 113948048Smckusick *tl++ = rpc_msgdenied; 114052196Smckusick if (err == NQNFS_AUTHERR) { 114152196Smckusick *tl++ = rpc_autherr; 114252196Smckusick *tl = rpc_rejectedcred; 114352196Smckusick mreq->m_len -= NFSX_UNSIGNED; 114452196Smckusick bpos -= NFSX_UNSIGNED; 114552196Smckusick } else { 114652196Smckusick *tl++ = rpc_mismatch; 114752196Smckusick *tl++ = txdr_unsigned(2); 114852196Smckusick *tl = txdr_unsigned(2); 114952196Smckusick } 115038414Smckusick } else { 115148048Smckusick *tl++ = rpc_msgaccepted; 115248048Smckusick *tl++ = 0; 115348048Smckusick *tl++ = 0; 115438414Smckusick switch (err) { 115538414Smckusick case EPROGUNAVAIL: 115648048Smckusick *tl = txdr_unsigned(RPC_PROGUNAVAIL); 115738414Smckusick break; 115838414Smckusick case EPROGMISMATCH: 115948048Smckusick *tl = txdr_unsigned(RPC_PROGMISMATCH); 116048048Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 116148048Smckusick *tl++ = txdr_unsigned(2); 116248048Smckusick *tl = txdr_unsigned(2); /* someday 3 */ 116338414Smckusick break; 116438414Smckusick case EPROCUNAVAIL: 116548048Smckusick *tl = txdr_unsigned(RPC_PROCUNAVAIL); 116638414Smckusick break; 116738414Smckusick default: 116848048Smckusick *tl = 0; 116938414Smckusick if (err != VNOVAL) { 117048048Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 117152196Smckusick if (err) 117252196Smckusick *tl = txdr_unsigned(nfsrv_errmap[err - 1]); 117352196Smckusick else 117452196Smckusick *tl = 0; 117538414Smckusick } 117638414Smckusick break; 117738414Smckusick }; 117838414Smckusick } 117952196Smckusick 118052196Smckusick /* 118152196Smckusick * For nqnfs, piggyback lease as requested. 118252196Smckusick */ 118352196Smckusick if (nd->nd_nqlflag != NQL_NOVAL && err == 0) { 118452196Smckusick if (nd->nd_nqlflag) { 118552196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 118652196Smckusick *tl++ = txdr_unsigned(nd->nd_nqlflag); 118752196Smckusick *tl++ = txdr_unsigned(cache); 118852196Smckusick *tl++ = txdr_unsigned(nd->nd_duration); 118952196Smckusick txdr_hyper(frev, tl); 119052196Smckusick } else { 119152196Smckusick if (nd->nd_nqlflag != 0) 119252196Smckusick panic("nqreph"); 119352196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 119452196Smckusick *tl = 0; 119552196Smckusick } 119652196Smckusick } 119738414Smckusick *mrq = mreq; 119838414Smckusick *mbp = mb; 119938414Smckusick *bposp = bpos; 120038414Smckusick if (err != 0 && err != VNOVAL) 120138414Smckusick nfsstats.srvrpc_errs++; 120238414Smckusick return (0); 120338414Smckusick } 120438414Smckusick 120538414Smckusick /* 120638414Smckusick * Nfs timer routine 120738414Smckusick * Scan the nfsreq list and retranmit any requests that have timed out 120838414Smckusick * To avoid retransmission attempts on STREAM sockets (in the future) make 120940117Smckusick * sure to set the r_retry field to 0 (implies nm_retry == 0). 121038414Smckusick */ 121138414Smckusick nfs_timer() 121238414Smckusick { 121338414Smckusick register struct nfsreq *rep; 121438414Smckusick register struct mbuf *m; 121538414Smckusick register struct socket *so; 121641900Smckusick register struct nfsmount *nmp; 121752196Smckusick register int timeo; 121852196Smckusick static long lasttime = 0; 121940117Smckusick int s, error; 122038414Smckusick 122138414Smckusick s = splnet(); 122241900Smckusick for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) { 122341900Smckusick nmp = rep->r_nmp; 122452196Smckusick if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) 122541900Smckusick continue; 122652196Smckusick if (nfs_sigintr(nmp, rep, rep->r_procp)) { 122741900Smckusick rep->r_flags |= R_SOFTTERM; 122841900Smckusick continue; 122941900Smckusick } 123052196Smckusick if (rep->r_rtt >= 0) { 123152196Smckusick rep->r_rtt++; 123252196Smckusick if (nmp->nm_flag & NFSMNT_DUMBTIMR) 123352196Smckusick timeo = nmp->nm_timeo; 123452196Smckusick else 123552196Smckusick timeo = NFS_RTO(nmp, proct[rep->r_procnum]); 123652196Smckusick if (nmp->nm_timeouts > 0) 123752196Smckusick timeo *= nfs_backoff[nmp->nm_timeouts - 1]; 123852196Smckusick if (rep->r_rtt <= timeo) 123952196Smckusick continue; 124052196Smckusick if (nmp->nm_timeouts < 8) 124152196Smckusick nmp->nm_timeouts++; 124240117Smckusick } 124341900Smckusick /* 124441900Smckusick * Check for server not responding 124541900Smckusick */ 124641900Smckusick if ((rep->r_flags & R_TPRINTFMSG) == 0 && 124752196Smckusick rep->r_rexmit > nmp->nm_deadthresh) { 124847737Skarels nfs_msg(rep->r_procp, 124947737Skarels nmp->nm_mountp->mnt_stat.f_mntfromname, 125047737Skarels "not responding"); 125141900Smckusick rep->r_flags |= R_TPRINTFMSG; 125241900Smckusick } 125343351Smckusick if (rep->r_rexmit >= rep->r_retry) { /* too many */ 125441900Smckusick nfsstats.rpctimeouts++; 125541900Smckusick rep->r_flags |= R_SOFTTERM; 125641900Smckusick continue; 125741900Smckusick } 125852196Smckusick if (nmp->nm_sotype != SOCK_DGRAM) { 125952196Smckusick if (++rep->r_rexmit > NFS_MAXREXMIT) 126052196Smckusick rep->r_rexmit = NFS_MAXREXMIT; 126143351Smckusick continue; 126252196Smckusick } 126352196Smckusick if ((so = nmp->nm_so) == NULL) 126452196Smckusick continue; 126541900Smckusick 126641900Smckusick /* 126741900Smckusick * If there is enough space and the window allows.. 126841900Smckusick * Resend it 126952196Smckusick * Set r_rtt to -1 in case we fail to send it now. 127041900Smckusick */ 127152196Smckusick rep->r_rtt = -1; 127241900Smckusick if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && 127352196Smckusick ((nmp->nm_flag & NFSMNT_DUMBTIMR) || 127452196Smckusick (rep->r_flags & R_SENT) || 127552196Smckusick nmp->nm_sent < nmp->nm_cwnd) && 127652196Smckusick (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){ 127741900Smckusick if ((nmp->nm_flag & NFSMNT_NOCONN) == 0) 127841900Smckusick error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, 127952196Smckusick (struct mbuf *)0, (struct mbuf *)0); 128041900Smckusick else 128141900Smckusick error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, 128252196Smckusick nmp->nm_nam, (struct mbuf *)0); 128341900Smckusick if (error) { 128441900Smckusick if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) 128541900Smckusick so->so_error = 0; 128641900Smckusick } else { 128741900Smckusick /* 128852196Smckusick * Iff first send, start timing 128952196Smckusick * else turn timing off, backoff timer 129052196Smckusick * and divide congestion window by 2. 129141900Smckusick */ 129252196Smckusick if (rep->r_flags & R_SENT) { 129352196Smckusick rep->r_flags &= ~R_TIMING; 129452196Smckusick if (++rep->r_rexmit > NFS_MAXREXMIT) 129552196Smckusick rep->r_rexmit = NFS_MAXREXMIT; 129652196Smckusick nmp->nm_cwnd >>= 1; 129752196Smckusick if (nmp->nm_cwnd < NFS_CWNDSCALE) 129852196Smckusick nmp->nm_cwnd = NFS_CWNDSCALE; 129952196Smckusick nfsstats.rpcretries++; 130052196Smckusick } else { 130152196Smckusick rep->r_flags |= R_SENT; 130252196Smckusick nmp->nm_sent += NFS_CWNDSCALE; 130352196Smckusick } 130452196Smckusick rep->r_rtt = 0; 130541900Smckusick } 130641900Smckusick } 130740117Smckusick } 130852196Smckusick 130952196Smckusick /* 131052196Smckusick * Call the nqnfs server timer once a second to handle leases. 131152196Smckusick */ 131252196Smckusick if (lasttime != time.tv_sec) { 131352196Smckusick lasttime = time.tv_sec; 131452196Smckusick nqnfs_serverd(); 131552196Smckusick } 131640117Smckusick splx(s); 131740117Smckusick timeout(nfs_timer, (caddr_t)0, hz/NFS_HZ); 131840117Smckusick } 131940117Smckusick 132040117Smckusick /* 132152196Smckusick * Test for a termination condition pending on the process. 132252196Smckusick * This is used for NFSMNT_INT mounts. 132340117Smckusick */ 132452196Smckusick nfs_sigintr(nmp, rep, p) 132552196Smckusick struct nfsmount *nmp; 132652196Smckusick struct nfsreq *rep; 132752196Smckusick register struct proc *p; 132852196Smckusick { 132940117Smckusick 133052196Smckusick if (rep && (rep->r_flags & R_SOFTTERM)) 133152196Smckusick return (EINTR); 133252196Smckusick if (!(nmp->nm_flag & NFSMNT_INT)) 133352196Smckusick return (0); 133452196Smckusick if (p && p->p_sig && (((p->p_sig &~ p->p_sigmask) &~ p->p_sigignore) & 133552196Smckusick NFSINT_SIGMASK)) 133652196Smckusick return (EINTR); 133752196Smckusick return (0); 133852196Smckusick } 133952196Smckusick 134040117Smckusick /* 134152196Smckusick * Lock a socket against others. 134252196Smckusick * Necessary for STREAM sockets to ensure you get an entire rpc request/reply 134352196Smckusick * and also to avoid race conditions between the processes with nfs requests 134452196Smckusick * in progress when a reconnect is necessary. 134540117Smckusick */ 134652196Smckusick nfs_sndlock(flagp, rep) 134752196Smckusick register int *flagp; 134852196Smckusick struct nfsreq *rep; 134952196Smckusick { 135052196Smckusick struct proc *p; 135140117Smckusick 135252196Smckusick if (rep) 135352196Smckusick p = rep->r_procp; 135452196Smckusick else 135552196Smckusick p = (struct proc *)0; 135652196Smckusick while (*flagp & NFSMNT_SNDLOCK) { 135752196Smckusick if (nfs_sigintr(rep->r_nmp, rep, p)) 135852196Smckusick return (EINTR); 135952196Smckusick *flagp |= NFSMNT_WANTSND; 136052196Smckusick (void) tsleep((caddr_t)flagp, PZERO-1, "nfsndlck", 0); 136152196Smckusick } 136252196Smckusick *flagp |= NFSMNT_SNDLOCK; 136352196Smckusick return (0); 136452196Smckusick } 136552196Smckusick 136652196Smckusick /* 136752196Smckusick * Unlock the stream socket for others. 136852196Smckusick */ 136952196Smckusick void 137052196Smckusick nfs_sndunlock(flagp) 137152196Smckusick register int *flagp; 137240117Smckusick { 137340117Smckusick 137452196Smckusick if ((*flagp & NFSMNT_SNDLOCK) == 0) 137552196Smckusick panic("nfs sndunlock"); 137652196Smckusick *flagp &= ~NFSMNT_SNDLOCK; 137752196Smckusick if (*flagp & NFSMNT_WANTSND) { 137852196Smckusick *flagp &= ~NFSMNT_WANTSND; 137952196Smckusick wakeup((caddr_t)flagp); 138040117Smckusick } 138152196Smckusick } 138252196Smckusick 138352196Smckusick nfs_rcvlock(rep) 138452196Smckusick register struct nfsreq *rep; 138552196Smckusick { 138652196Smckusick register int *flagp = &rep->r_nmp->nm_flag; 138752196Smckusick 138852196Smckusick while (*flagp & NFSMNT_RCVLOCK) { 138952196Smckusick if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp)) 139052196Smckusick return (EINTR); 139152196Smckusick *flagp |= NFSMNT_WANTRCV; 139252196Smckusick (void) tsleep((caddr_t)flagp, PZERO-1, "nfsrcvlck", 0); 139340117Smckusick } 139452196Smckusick *flagp |= NFSMNT_RCVLOCK; 139552196Smckusick return (0); 139652196Smckusick } 139740117Smckusick 139852196Smckusick /* 139952196Smckusick * Unlock the stream socket for others. 140052196Smckusick */ 140152196Smckusick void 140252196Smckusick nfs_rcvunlock(flagp) 140352196Smckusick register int *flagp; 140452196Smckusick { 140552196Smckusick 140652196Smckusick if ((*flagp & NFSMNT_RCVLOCK) == 0) 140752196Smckusick panic("nfs rcvunlock"); 140852196Smckusick *flagp &= ~NFSMNT_RCVLOCK; 140952196Smckusick if (*flagp & NFSMNT_WANTRCV) { 141052196Smckusick *flagp &= ~NFSMNT_WANTRCV; 141152196Smckusick wakeup((caddr_t)flagp); 141252196Smckusick } 141352196Smckusick } 141452196Smckusick 141552196Smckusick /* 141652196Smckusick * Check for badly aligned mbuf data areas and 141752196Smckusick * realign data in an mbuf list by copying the data areas up, as required. 141852196Smckusick */ 141952196Smckusick void 142052196Smckusick nfs_realign(m, hsiz) 142152196Smckusick register struct mbuf *m; 142252196Smckusick int hsiz; 142347737Skarels { 142452196Smckusick register struct mbuf *m2; 142552196Smckusick register int siz, mlen, olen; 142652196Smckusick register caddr_t tcp, fcp; 142752196Smckusick struct mbuf *mnew; 142847737Skarels 142952196Smckusick while (m) { 143052196Smckusick /* 143152196Smckusick * This never happens for UDP, rarely happens for TCP 143252196Smckusick * but frequently happens for iso transport. 143352196Smckusick */ 143452196Smckusick if ((m->m_len & 0x3) || (mtod(m, int) & 0x3)) { 143552196Smckusick olen = m->m_len; 143652196Smckusick fcp = mtod(m, caddr_t); 143752196Smckusick m->m_flags &= ~M_PKTHDR; 143852196Smckusick if (m->m_flags & M_EXT) 143952196Smckusick m->m_data = m->m_ext.ext_buf; 144052196Smckusick else 144152196Smckusick m->m_data = m->m_dat; 144252196Smckusick m->m_len = 0; 144352196Smckusick tcp = mtod(m, caddr_t); 144452196Smckusick mnew = m; 144552196Smckusick m2 = m->m_next; 144652196Smckusick 144752196Smckusick /* 144852196Smckusick * If possible, only put the first invariant part 144952196Smckusick * of the RPC header in the first mbuf. 145052196Smckusick */ 145152196Smckusick if (olen <= hsiz) 145252196Smckusick mlen = hsiz; 145352196Smckusick else 145452196Smckusick mlen = M_TRAILINGSPACE(m); 145552196Smckusick 145652196Smckusick /* 145752196Smckusick * Loop through the mbuf list consolidating data. 145852196Smckusick */ 145952196Smckusick while (m) { 146052196Smckusick while (olen > 0) { 146152196Smckusick if (mlen == 0) { 146252196Smckusick m2->m_flags &= ~M_PKTHDR; 146352196Smckusick if (m2->m_flags & M_EXT) 146452196Smckusick m2->m_data = m2->m_ext.ext_buf; 146552196Smckusick else 146652196Smckusick m2->m_data = m2->m_dat; 146752196Smckusick m2->m_len = 0; 146852196Smckusick mlen = M_TRAILINGSPACE(m2); 146952196Smckusick tcp = mtod(m2, caddr_t); 147052196Smckusick mnew = m2; 147152196Smckusick m2 = m2->m_next; 147252196Smckusick } 147352196Smckusick siz = MIN(mlen, olen); 147452196Smckusick if (tcp != fcp) 147552196Smckusick bcopy(fcp, tcp, siz); 147652196Smckusick mnew->m_len += siz; 147752196Smckusick mlen -= siz; 147852196Smckusick olen -= siz; 147952196Smckusick tcp += siz; 148052196Smckusick fcp += siz; 148152196Smckusick } 148252196Smckusick m = m->m_next; 148352196Smckusick if (m) { 148452196Smckusick olen = m->m_len; 148552196Smckusick fcp = mtod(m, caddr_t); 148652196Smckusick } 148752196Smckusick } 148852196Smckusick 148952196Smckusick /* 149052196Smckusick * Finally, set m_len == 0 for any trailing mbufs that have 149152196Smckusick * been copied out of. 149252196Smckusick */ 149352196Smckusick while (m2) { 149452196Smckusick m2->m_len = 0; 149552196Smckusick m2 = m2->m_next; 149652196Smckusick } 149752196Smckusick return; 149852196Smckusick } 149952196Smckusick m = m->m_next; 150052196Smckusick } 150147737Skarels } 150247737Skarels 150341900Smckusick /* 150452196Smckusick * Socket upcall routine for the nfsd sockets. 150552196Smckusick * The caddr_t arg is a pointer to the "struct nfssvc_sock". 150652196Smckusick * Essentially do as much as possible non-blocking, else punt and it will 150752196Smckusick * be called with M_WAIT from an nfsd. 150841900Smckusick */ 150952196Smckusick void 151052196Smckusick nfsrv_rcv(so, arg, waitflag) 151152196Smckusick struct socket *so; 151252196Smckusick caddr_t arg; 151352196Smckusick int waitflag; 151438414Smckusick { 151552196Smckusick register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg; 151652196Smckusick register struct mbuf *m; 151752196Smckusick struct mbuf *mp, *nam; 151852196Smckusick struct uio auio; 151952196Smckusick int flags, error; 152040117Smckusick 152152903Smckusick if ((slp->ns_flag & SLP_VALID) == 0) 152252903Smckusick return; 152352903Smckusick #ifdef notdef 152452903Smckusick /* 152552903Smckusick * Define this to test for nfsds handling this under heavy load. 152652903Smckusick */ 152752903Smckusick if (waitflag == M_DONTWAIT) { 152852903Smckusick slp->ns_flag |= SLP_NEEDQ; goto dorecs; 152952903Smckusick } 153052903Smckusick #endif 153152932Smckusick auio.uio_procp = NULL; 153252196Smckusick if (so->so_type == SOCK_STREAM) { 153352196Smckusick /* 153452196Smckusick * If there are already records on the queue, defer soreceive() 153552196Smckusick * to an nfsd so that there is feedback to the TCP layer that 153652196Smckusick * the nfs servers are heavily loaded. 153752196Smckusick */ 153852196Smckusick if (slp->ns_rec && waitflag == M_DONTWAIT) { 153952196Smckusick slp->ns_flag |= SLP_NEEDQ; 154052903Smckusick goto dorecs; 154152196Smckusick } 154252196Smckusick 154352196Smckusick /* 154452196Smckusick * Do soreceive(). 154552196Smckusick */ 154652196Smckusick auio.uio_resid = 1000000000; 154752196Smckusick flags = MSG_DONTWAIT; 154852196Smckusick error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags); 154952196Smckusick if (error || mp == (struct mbuf *)0) { 155052903Smckusick if (error == EWOULDBLOCK) 155152903Smckusick slp->ns_flag |= SLP_NEEDQ; 155252903Smckusick else 155352196Smckusick slp->ns_flag |= SLP_DISCONN; 155452196Smckusick goto dorecs; 155552196Smckusick } 155652196Smckusick m = mp; 155752196Smckusick if (slp->ns_rawend) { 155852196Smckusick slp->ns_rawend->m_next = m; 155952196Smckusick slp->ns_cc += 1000000000 - auio.uio_resid; 156052196Smckusick } else { 156152196Smckusick slp->ns_raw = m; 156252196Smckusick slp->ns_cc = 1000000000 - auio.uio_resid; 156352196Smckusick } 156452196Smckusick while (m->m_next) 156552196Smckusick m = m->m_next; 156652196Smckusick slp->ns_rawend = m; 156752196Smckusick 156852196Smckusick /* 156952196Smckusick * Now try and parse record(s) out of the raw stream data. 157052196Smckusick */ 157152196Smckusick if (error = nfsrv_getstream(slp, waitflag)) { 157252196Smckusick if (error == EPERM) 157352196Smckusick slp->ns_flag |= SLP_DISCONN; 157452903Smckusick else 157552196Smckusick slp->ns_flag |= SLP_NEEDQ; 157652196Smckusick } 157752196Smckusick } else { 157852196Smckusick do { 157952196Smckusick auio.uio_resid = 1000000000; 158052196Smckusick flags = MSG_DONTWAIT; 158152196Smckusick error = soreceive(so, &nam, &auio, &mp, 158252196Smckusick (struct mbuf **)0, &flags); 158352196Smckusick if (mp) { 158452196Smckusick nfs_realign(mp, 10 * NFSX_UNSIGNED); 158552196Smckusick if (nam) { 158652196Smckusick m = nam; 158752196Smckusick m->m_next = mp; 158852196Smckusick } else 158952196Smckusick m = mp; 159052196Smckusick if (slp->ns_recend) 159152196Smckusick slp->ns_recend->m_nextpkt = m; 159252196Smckusick else 159352196Smckusick slp->ns_rec = m; 159452196Smckusick slp->ns_recend = m; 159552196Smckusick m->m_nextpkt = (struct mbuf *)0; 159652196Smckusick } 159752196Smckusick if (error) { 159852196Smckusick if ((so->so_proto->pr_flags & PR_CONNREQUIRED) 159952196Smckusick && error != EWOULDBLOCK) { 160052196Smckusick slp->ns_flag |= SLP_DISCONN; 160152903Smckusick goto dorecs; 160252196Smckusick } 160352196Smckusick } 160452196Smckusick } while (mp); 160540117Smckusick } 160652196Smckusick 160752196Smckusick /* 160852196Smckusick * Now try and process the request records, non-blocking. 160952196Smckusick */ 161052196Smckusick dorecs: 161152903Smckusick if (waitflag == M_DONTWAIT && 161252903Smckusick (slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) 161352196Smckusick nfsrv_wakenfsd(slp); 161441900Smckusick } 161540117Smckusick 161641900Smckusick /* 161752196Smckusick * Try and extract an RPC request from the mbuf data list received on a 161852196Smckusick * stream socket. The "waitflag" argument indicates whether or not it 161952196Smckusick * can sleep. 162041900Smckusick */ 162152196Smckusick nfsrv_getstream(slp, waitflag) 162252196Smckusick register struct nfssvc_sock *slp; 162352196Smckusick int waitflag; 162441900Smckusick { 162552196Smckusick register struct mbuf *m; 162652196Smckusick register char *cp1, *cp2; 162752196Smckusick register int len; 162852196Smckusick struct mbuf *om, *m2, *recm; 162952196Smckusick u_long recmark; 163041900Smckusick 163152196Smckusick if (slp->ns_flag & SLP_GETSTREAM) 163252196Smckusick panic("nfs getstream"); 163352196Smckusick slp->ns_flag |= SLP_GETSTREAM; 163452196Smckusick for (;;) { 163552196Smckusick if (slp->ns_reclen == 0) { 163652196Smckusick if (slp->ns_cc < NFSX_UNSIGNED) { 163752196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 163852196Smckusick return (0); 163952196Smckusick } 164052196Smckusick m = slp->ns_raw; 164152196Smckusick if (m->m_len >= NFSX_UNSIGNED) { 164252196Smckusick bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED); 164352196Smckusick m->m_data += NFSX_UNSIGNED; 164452196Smckusick m->m_len -= NFSX_UNSIGNED; 164552196Smckusick } else { 164652196Smckusick cp1 = (caddr_t)&recmark; 164752196Smckusick cp2 = mtod(m, caddr_t); 164852196Smckusick while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) { 164952196Smckusick while (m->m_len == 0) { 165052196Smckusick m = m->m_next; 165152196Smckusick cp2 = mtod(m, caddr_t); 165252196Smckusick } 165352196Smckusick *cp1++ = *cp2++; 165452196Smckusick m->m_data++; 165552196Smckusick m->m_len--; 165652196Smckusick } 165752196Smckusick } 165852196Smckusick slp->ns_cc -= NFSX_UNSIGNED; 165952196Smckusick slp->ns_reclen = ntohl(recmark) & ~0x80000000; 166052196Smckusick if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) { 166152196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 166252196Smckusick return (EPERM); 166352196Smckusick } 166452196Smckusick } 166552196Smckusick 166652196Smckusick /* 166752196Smckusick * Now get the record part. 166852196Smckusick */ 166952196Smckusick if (slp->ns_cc == slp->ns_reclen) { 167052196Smckusick recm = slp->ns_raw; 167152196Smckusick slp->ns_raw = slp->ns_rawend = (struct mbuf *)0; 167252196Smckusick slp->ns_cc = slp->ns_reclen = 0; 167352196Smckusick } else if (slp->ns_cc > slp->ns_reclen) { 167452196Smckusick len = 0; 167552196Smckusick m = slp->ns_raw; 167652196Smckusick om = (struct mbuf *)0; 167752196Smckusick while (len < slp->ns_reclen) { 167852196Smckusick if ((len + m->m_len) > slp->ns_reclen) { 167952196Smckusick m2 = m_copym(m, 0, slp->ns_reclen - len, 168052196Smckusick waitflag); 168152196Smckusick if (m2) { 168252196Smckusick if (om) { 168352196Smckusick om->m_next = m2; 168452196Smckusick recm = slp->ns_raw; 168552196Smckusick } else 168652196Smckusick recm = m2; 168752196Smckusick m->m_data += slp->ns_reclen - len; 168852196Smckusick m->m_len -= slp->ns_reclen - len; 168952196Smckusick len = slp->ns_reclen; 169052196Smckusick } else { 169152196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 169252196Smckusick return (EWOULDBLOCK); 169352196Smckusick } 169452196Smckusick } else if ((len + m->m_len) == slp->ns_reclen) { 169552196Smckusick om = m; 169652196Smckusick len += m->m_len; 169752196Smckusick m = m->m_next; 169852196Smckusick recm = slp->ns_raw; 169952196Smckusick om->m_next = (struct mbuf *)0; 170052196Smckusick } else { 170152196Smckusick om = m; 170252196Smckusick len += m->m_len; 170352196Smckusick m = m->m_next; 170452196Smckusick } 170552196Smckusick } 170652196Smckusick slp->ns_raw = m; 170752196Smckusick slp->ns_cc -= len; 170852196Smckusick slp->ns_reclen = 0; 170952196Smckusick } else { 171052196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 171152196Smckusick return (0); 171252196Smckusick } 171352196Smckusick nfs_realign(recm, 10 * NFSX_UNSIGNED); 171452196Smckusick if (slp->ns_recend) 171552196Smckusick slp->ns_recend->m_nextpkt = recm; 171652196Smckusick else 171752196Smckusick slp->ns_rec = recm; 171852196Smckusick slp->ns_recend = recm; 171940117Smckusick } 172038414Smckusick } 172141900Smckusick 172241900Smckusick /* 172352196Smckusick * Parse an RPC header. 172441900Smckusick */ 172552196Smckusick nfsrv_dorec(slp, nd) 172652196Smckusick register struct nfssvc_sock *slp; 172752196Smckusick register struct nfsd *nd; 172841900Smckusick { 172952196Smckusick register struct mbuf *m; 173052196Smckusick int error; 173141900Smckusick 173252903Smckusick if ((slp->ns_flag & SLP_VALID) == 0 || 173352196Smckusick (m = slp->ns_rec) == (struct mbuf *)0) 173452196Smckusick return (ENOBUFS); 173552196Smckusick if (slp->ns_rec = m->m_nextpkt) 173652196Smckusick m->m_nextpkt = (struct mbuf *)0; 173752196Smckusick else 173852196Smckusick slp->ns_recend = (struct mbuf *)0; 173952196Smckusick if (m->m_type == MT_SONAME) { 174052196Smckusick nd->nd_nam = m; 174152196Smckusick nd->nd_md = nd->nd_mrep = m->m_next; 174252196Smckusick m->m_next = (struct mbuf *)0; 174352196Smckusick } else { 174452196Smckusick nd->nd_nam = (struct mbuf *)0; 174552196Smckusick nd->nd_md = nd->nd_mrep = m; 174652196Smckusick } 174752196Smckusick nd->nd_dpos = mtod(nd->nd_md, caddr_t); 174852196Smckusick if (error = nfs_getreq(nd, TRUE)) { 174952196Smckusick m_freem(nd->nd_nam); 175052196Smckusick return (error); 175152196Smckusick } 175252196Smckusick return (0); 175352196Smckusick } 175452196Smckusick 175552196Smckusick /* 175652196Smckusick * Parse an RPC request 175752196Smckusick * - verify it 175852196Smckusick * - fill in the cred struct. 175952196Smckusick */ 176052196Smckusick nfs_getreq(nd, has_header) 176152196Smckusick register struct nfsd *nd; 176252196Smckusick int has_header; 176352196Smckusick { 176452196Smckusick register int len, i; 176552196Smckusick register u_long *tl; 176652196Smckusick register long t1; 176752196Smckusick struct uio uio; 176852196Smckusick struct iovec iov; 176952196Smckusick caddr_t dpos, cp2; 177052196Smckusick u_long nfsvers, auth_type; 177152196Smckusick int error = 0, nqnfs = 0; 177252196Smckusick struct mbuf *mrep, *md; 177352196Smckusick 177452196Smckusick mrep = nd->nd_mrep; 177552196Smckusick md = nd->nd_md; 177652196Smckusick dpos = nd->nd_dpos; 177752196Smckusick if (has_header) { 177852196Smckusick nfsm_dissect(tl, u_long *, 10*NFSX_UNSIGNED); 177952196Smckusick nd->nd_retxid = *tl++; 178052196Smckusick if (*tl++ != rpc_call) { 178152196Smckusick m_freem(mrep); 178252196Smckusick return (EBADRPC); 178352196Smckusick } 178452196Smckusick } else { 178552196Smckusick nfsm_dissect(tl, u_long *, 8*NFSX_UNSIGNED); 178652196Smckusick } 178752196Smckusick nd->nd_repstat = 0; 178852196Smckusick if (*tl++ != rpc_vers) { 178952196Smckusick nd->nd_repstat = ERPCMISMATCH; 179052196Smckusick nd->nd_procnum = NFSPROC_NOOP; 179141900Smckusick return (0); 179252196Smckusick } 179352196Smckusick nfsvers = nfs_vers; 179452196Smckusick if (*tl != nfs_prog) { 179552196Smckusick if (*tl == nqnfs_prog) { 179652196Smckusick nqnfs++; 179752196Smckusick nfsvers = nqnfs_vers; 179852196Smckusick } else { 179952196Smckusick nd->nd_repstat = EPROGUNAVAIL; 180052196Smckusick nd->nd_procnum = NFSPROC_NOOP; 180152196Smckusick return (0); 180252196Smckusick } 180352196Smckusick } 180452196Smckusick tl++; 180552196Smckusick if (*tl++ != nfsvers) { 180652196Smckusick nd->nd_repstat = EPROGMISMATCH; 180752196Smckusick nd->nd_procnum = NFSPROC_NOOP; 180852196Smckusick return (0); 180952196Smckusick } 181052196Smckusick nd->nd_procnum = fxdr_unsigned(u_long, *tl++); 181152196Smckusick if (nd->nd_procnum == NFSPROC_NULL) 181252196Smckusick return (0); 181352196Smckusick if (nd->nd_procnum >= NFS_NPROCS || 181452196Smckusick (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) || 181552196Smckusick (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) { 181652196Smckusick nd->nd_repstat = EPROCUNAVAIL; 181752196Smckusick nd->nd_procnum = NFSPROC_NOOP; 181852196Smckusick return (0); 181952196Smckusick } 182052196Smckusick auth_type = *tl++; 182152196Smckusick len = fxdr_unsigned(int, *tl++); 182252196Smckusick if (len < 0 || len > RPCAUTH_MAXSIZ) { 182352196Smckusick m_freem(mrep); 182452196Smckusick return (EBADRPC); 182552196Smckusick } 182641900Smckusick 182741900Smckusick /* 182852196Smckusick * Handle auth_unix or auth_kerb. 182941900Smckusick */ 183052196Smckusick if (auth_type == rpc_auth_unix) { 183152196Smckusick len = fxdr_unsigned(int, *++tl); 183252196Smckusick if (len < 0 || len > NFS_MAXNAMLEN) { 183352196Smckusick m_freem(mrep); 183452196Smckusick return (EBADRPC); 183552196Smckusick } 183652196Smckusick nfsm_adv(nfsm_rndup(len)); 183752196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 183852196Smckusick nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); 183952196Smckusick nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); 184052196Smckusick len = fxdr_unsigned(int, *tl); 184152196Smckusick if (len < 0 || len > RPCAUTH_UNIXGIDS) { 184252196Smckusick m_freem(mrep); 184352196Smckusick return (EBADRPC); 184452196Smckusick } 184552196Smckusick nfsm_dissect(tl, u_long *, (len + 2)*NFSX_UNSIGNED); 184652196Smckusick for (i = 1; i <= len; i++) 184752196Smckusick if (i < NGROUPS) 184852196Smckusick nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); 184952196Smckusick else 185052196Smckusick tl++; 185152196Smckusick nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); 185252196Smckusick } else if (auth_type == rpc_auth_kerb) { 185352196Smckusick nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); 185452196Smckusick nd->nd_authlen = fxdr_unsigned(int, *tl); 185552196Smckusick iov.iov_len = uio.uio_resid = nfsm_rndup(nd->nd_authlen); 185652196Smckusick if (uio.uio_resid > (len - 2*NFSX_UNSIGNED)) { 185752196Smckusick m_freem(mrep); 185852196Smckusick return (EBADRPC); 185952196Smckusick } 186052196Smckusick uio.uio_offset = 0; 186152196Smckusick uio.uio_iov = &iov; 186252196Smckusick uio.uio_iovcnt = 1; 186352196Smckusick uio.uio_segflg = UIO_SYSSPACE; 186452196Smckusick iov.iov_base = (caddr_t)nd->nd_authstr; 186552196Smckusick nfsm_mtouio(&uio, uio.uio_resid); 186652196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 186752196Smckusick nd->nd_flag |= NFSD_NEEDAUTH; 186852196Smckusick } 186952196Smckusick 187052196Smckusick /* 187152196Smckusick * Do we have any use for the verifier. 187252196Smckusick * According to the "Remote Procedure Call Protocol Spec." it 187352196Smckusick * should be AUTH_NULL, but some clients make it AUTH_UNIX? 187452196Smckusick * For now, just skip over it 187552196Smckusick */ 187652196Smckusick len = fxdr_unsigned(int, *++tl); 187752196Smckusick if (len < 0 || len > RPCAUTH_MAXSIZ) { 187852196Smckusick m_freem(mrep); 187952196Smckusick return (EBADRPC); 188052196Smckusick } 188152196Smckusick if (len > 0) { 188252196Smckusick nfsm_adv(nfsm_rndup(len)); 188352196Smckusick } 188452196Smckusick 188552196Smckusick /* 188652196Smckusick * For nqnfs, get piggybacked lease request. 188752196Smckusick */ 188852196Smckusick if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { 188952196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 189052196Smckusick nd->nd_nqlflag = fxdr_unsigned(int, *tl); 189152196Smckusick if (nd->nd_nqlflag) { 189252196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 189352196Smckusick nd->nd_duration = fxdr_unsigned(int, *tl); 189452196Smckusick } else 189552196Smckusick nd->nd_duration = NQ_MINLEASE; 189652196Smckusick } else { 189752196Smckusick nd->nd_nqlflag = NQL_NOVAL; 189852196Smckusick nd->nd_duration = NQ_MINLEASE; 189952196Smckusick } 190052196Smckusick nd->nd_md = md; 190152196Smckusick nd->nd_dpos = dpos; 190241900Smckusick return (0); 190352196Smckusick nfsmout: 190452196Smckusick return (error); 190541900Smckusick } 190641900Smckusick 190741900Smckusick /* 190852196Smckusick * Search for a sleeping nfsd and wake it up. 190952196Smckusick * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the 191052196Smckusick * running nfsds will go look for the work in the nfssvc_sock list. 191141900Smckusick */ 191252196Smckusick void 191352196Smckusick nfsrv_wakenfsd(slp) 191452196Smckusick struct nfssvc_sock *slp; 191541900Smckusick { 191652196Smckusick register struct nfsd *nd = nfsd_head.nd_next; 191752196Smckusick 191852903Smckusick if ((slp->ns_flag & SLP_VALID) == 0) 191952903Smckusick return; 192052196Smckusick while (nd != (struct nfsd *)&nfsd_head) { 192152196Smckusick if (nd->nd_flag & NFSD_WAITING) { 192252196Smckusick nd->nd_flag &= ~NFSD_WAITING; 192352196Smckusick if (nd->nd_slp) 192452196Smckusick panic("nfsd wakeup"); 192552978Smckusick slp->ns_sref++; 192652196Smckusick nd->nd_slp = slp; 192752196Smckusick wakeup((caddr_t)nd); 192852196Smckusick return; 192952196Smckusick } 193052196Smckusick nd = nd->nd_next; 193152196Smckusick } 193252903Smckusick slp->ns_flag |= SLP_DOREC; 193352196Smckusick nfsd_head.nd_flag |= NFSD_CHECKSLP; 193441900Smckusick } 193552196Smckusick 193652196Smckusick nfs_msg(p, server, msg) 193752196Smckusick struct proc *p; 193852196Smckusick char *server, *msg; 193952196Smckusick { 194052196Smckusick tpr_t tpr; 194152196Smckusick 194252196Smckusick if (p) 194352196Smckusick tpr = tprintf_open(p); 194452196Smckusick else 194552196Smckusick tpr = NULL; 194652196Smckusick tprintf(tpr, "nfs server %s: %s\n", server, msg); 194752196Smckusick tprintf_close(tpr); 194852196Smckusick } 1949