138414Smckusick /* 263484Sbostic * Copyright (c) 1989, 1991, 1993 363484Sbostic * The Regents of the University of California. 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*65623Sbostic * @(#)nfs_socket.c 8.3 (Berkeley) 01/12/94 1138414Smckusick */ 1238414Smckusick 1338414Smckusick /* 1441900Smckusick * Socket operations for use by nfs 1538414Smckusick */ 1638414Smckusick 1754615Smckusick #include <sys/param.h> 1855063Spendry #include <sys/systm.h> 1954615Smckusick #include <sys/proc.h> 2054615Smckusick #include <sys/mount.h> 2154615Smckusick #include <sys/kernel.h> 2254615Smckusick #include <sys/mbuf.h> 2354615Smckusick #include <sys/vnode.h> 2454615Smckusick #include <sys/domain.h> 2554615Smckusick #include <sys/protosw.h> 2654615Smckusick #include <sys/socket.h> 2754615Smckusick #include <sys/socketvar.h> 2854615Smckusick #include <sys/syslog.h> 2954615Smckusick #include <sys/tprintf.h> 3056535Sbostic 3154615Smckusick #include <netinet/in.h> 3254615Smckusick #include <netinet/tcp.h> 3354615Smckusick #include <nfs/rpcv2.h> 3454615Smckusick #include <nfs/nfsv2.h> 3554615Smckusick #include <nfs/nfs.h> 3654615Smckusick #include <nfs/xdr_subs.h> 3754615Smckusick #include <nfs/nfsm_subs.h> 3854615Smckusick #include <nfs/nfsmount.h> 3954615Smckusick #include <nfs/nfsnode.h> 4054615Smckusick #include <nfs/nfsrtt.h> 4154615Smckusick #include <nfs/nqnfs.h> 4238414Smckusick 4338414Smckusick #define TRUE 1 4443351Smckusick #define FALSE 0 4538414Smckusick 4640117Smckusick /* 4752196Smckusick * Estimate rto for an nfs rpc sent via. an unreliable datagram. 4852196Smckusick * Use the mean and mean deviation of rtt for the appropriate type of rpc 4952196Smckusick * for the frequent rpcs and a default for the others. 5052196Smckusick * The justification for doing "other" this way is that these rpcs 5152196Smckusick * happen so infrequently that timer est. would probably be stale. 5252196Smckusick * Also, since many of these rpcs are 5352196Smckusick * non-idempotent, a conservative timeout is desired. 5452196Smckusick * getattr, lookup - A+2D 5552196Smckusick * read, write - A+4D 5652196Smckusick * other - nm_timeo 5752196Smckusick */ 5852196Smckusick #define NFS_RTO(n, t) \ 5952196Smckusick ((t) == 0 ? (n)->nm_timeo : \ 6052196Smckusick ((t) < 3 ? \ 6152196Smckusick (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \ 6252196Smckusick ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1))) 6352196Smckusick #define NFS_SRTT(r) (r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1] 6452196Smckusick #define NFS_SDRTT(r) (r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1] 6552196Smckusick /* 6638414Smckusick * External data, mostly RPC constants in XDR form 6738414Smckusick */ 6838414Smckusick extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, 6952196Smckusick rpc_msgaccepted, rpc_call, rpc_autherr, rpc_rejectedcred, 7052196Smckusick rpc_auth_kerb; 7152196Smckusick extern u_long nfs_prog, nfs_vers, nqnfs_prog, nqnfs_vers; 7252196Smckusick extern time_t nqnfsstarttime; 7341900Smckusick extern int nonidempotent[NFS_NPROCS]; 7452196Smckusick 7552196Smckusick /* 7652196Smckusick * Maps errno values to nfs error numbers. 7752196Smckusick * Use NFSERR_IO as the catch all for ones not specifically defined in 7852196Smckusick * RFC 1094. 7952196Smckusick */ 8052196Smckusick static int nfsrv_errmap[ELAST] = { 8152196Smckusick NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8252196Smckusick NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8352196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 8452196Smckusick NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 8552196Smckusick NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 8652196Smckusick NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 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_IO, NFSERR_IO, NFSERR_IO, 9352196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 9452196Smckusick NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 9552196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9652196Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 9752196Smckusick NFSERR_IO, 9845281Smckusick }; 9952196Smckusick 10052196Smckusick /* 10152196Smckusick * Defines which timer to use for the procnum. 10252196Smckusick * 0 - default 10352196Smckusick * 1 - getattr 10452196Smckusick * 2 - lookup 10552196Smckusick * 3 - read 10652196Smckusick * 4 - write 10752196Smckusick */ 10852196Smckusick static int proct[NFS_NPROCS] = { 10956361Smckusick 0, 1, 0, 0, 2, 3, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 11052196Smckusick }; 11152196Smckusick 11252196Smckusick /* 11352196Smckusick * There is a congestion window for outstanding rpcs maintained per mount 11452196Smckusick * point. The cwnd size is adjusted in roughly the way that: 11552196Smckusick * Van Jacobson, Congestion avoidance and Control, In "Proceedings of 11652196Smckusick * SIGCOMM '88". ACM, August 1988. 11752196Smckusick * describes for TCP. The cwnd size is chopped in half on a retransmit timeout 11852196Smckusick * and incremented by 1/cwnd when each rpc reply is received and a full cwnd 11952196Smckusick * of rpcs is in progress. 12052196Smckusick * (The sent count and cwnd are scaled for integer arith.) 12152196Smckusick * Variants of "slow start" were tried and were found to be too much of a 12252196Smckusick * performance hit (ave. rtt 3 times larger), 12352196Smckusick * I suspect due to the large rtt that nfs rpcs have. 12452196Smckusick */ 12552196Smckusick #define NFS_CWNDSCALE 256 12652196Smckusick #define NFS_MAXCWND (NFS_CWNDSCALE * 32) 12752196Smckusick static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, }; 12841900Smckusick int nfs_sbwait(); 12952196Smckusick void nfs_disconnect(), nfs_realign(), nfsrv_wakenfsd(), nfs_sndunlock(); 13056286Smckusick void nfs_rcvunlock(), nqnfs_serverd(), nqnfs_clientlease(); 13152196Smckusick struct mbuf *nfsm_rpchead(); 13252196Smckusick int nfsrtton = 0; 13352196Smckusick struct nfsrtt nfsrtt; 13452196Smckusick struct nfsd nfsd_head; 13541900Smckusick 13638414Smckusick int nfsrv_null(), 13738414Smckusick nfsrv_getattr(), 13838414Smckusick nfsrv_setattr(), 13938414Smckusick nfsrv_lookup(), 14038414Smckusick nfsrv_readlink(), 14138414Smckusick nfsrv_read(), 14238414Smckusick nfsrv_write(), 14338414Smckusick nfsrv_create(), 14438414Smckusick nfsrv_remove(), 14538414Smckusick nfsrv_rename(), 14638414Smckusick nfsrv_link(), 14738414Smckusick nfsrv_symlink(), 14838414Smckusick nfsrv_mkdir(), 14938414Smckusick nfsrv_rmdir(), 15038414Smckusick nfsrv_readdir(), 15138414Smckusick nfsrv_statfs(), 15252196Smckusick nfsrv_noop(), 15352196Smckusick nqnfsrv_readdirlook(), 15452196Smckusick nqnfsrv_getlease(), 15556361Smckusick nqnfsrv_vacated(), 15656361Smckusick nqnfsrv_access(); 15738414Smckusick 15838414Smckusick int (*nfsrv_procs[NFS_NPROCS])() = { 15938414Smckusick nfsrv_null, 16038414Smckusick nfsrv_getattr, 16138414Smckusick nfsrv_setattr, 16238414Smckusick nfsrv_noop, 16338414Smckusick nfsrv_lookup, 16438414Smckusick nfsrv_readlink, 16538414Smckusick nfsrv_read, 16638414Smckusick nfsrv_noop, 16738414Smckusick nfsrv_write, 16838414Smckusick nfsrv_create, 16938414Smckusick nfsrv_remove, 17038414Smckusick nfsrv_rename, 17138414Smckusick nfsrv_link, 17238414Smckusick nfsrv_symlink, 17338414Smckusick nfsrv_mkdir, 17438414Smckusick nfsrv_rmdir, 17538414Smckusick nfsrv_readdir, 17638414Smckusick nfsrv_statfs, 17752196Smckusick nqnfsrv_readdirlook, 17852196Smckusick nqnfsrv_getlease, 17952196Smckusick nqnfsrv_vacated, 18056361Smckusick nfsrv_noop, 18156361Smckusick nqnfsrv_access, 18238414Smckusick }; 18338414Smckusick 18440117Smckusick struct nfsreq nfsreqh; 18538414Smckusick 18638414Smckusick /* 18741900Smckusick * Initialize sockets and congestion for a new NFS connection. 18840117Smckusick * We do not free the sockaddr if error. 18938414Smckusick */ 19052196Smckusick nfs_connect(nmp, rep) 19140117Smckusick register struct nfsmount *nmp; 19252196Smckusick struct nfsreq *rep; 19340117Smckusick { 19441900Smckusick register struct socket *so; 19552196Smckusick int s, error, rcvreserve, sndreserve; 19652988Smckusick struct sockaddr *saddr; 19752988Smckusick struct sockaddr_in *sin; 19840117Smckusick struct mbuf *m; 19952988Smckusick u_short tport; 20040117Smckusick 20141900Smckusick nmp->nm_so = (struct socket *)0; 20252988Smckusick saddr = mtod(nmp->nm_nam, struct sockaddr *); 20352988Smckusick if (error = socreate(saddr->sa_family, 20441900Smckusick &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto)) 20540117Smckusick goto bad; 20641900Smckusick so = nmp->nm_so; 20741900Smckusick nmp->nm_soflags = so->so_proto->pr_flags; 20840117Smckusick 20941900Smckusick /* 21052988Smckusick * Some servers require that the client port be a reserved port number. 21152988Smckusick */ 21252988Smckusick if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) { 21352988Smckusick MGET(m, M_WAIT, MT_SONAME); 21452988Smckusick sin = mtod(m, struct sockaddr_in *); 21552988Smckusick sin->sin_len = m->m_len = sizeof (struct sockaddr_in); 21652988Smckusick sin->sin_family = AF_INET; 21752988Smckusick sin->sin_addr.s_addr = INADDR_ANY; 21852988Smckusick tport = IPPORT_RESERVED - 1; 21952988Smckusick sin->sin_port = htons(tport); 22052988Smckusick while ((error = sobind(so, m)) == EADDRINUSE && 22152988Smckusick --tport > IPPORT_RESERVED / 2) 22252988Smckusick sin->sin_port = htons(tport); 22352988Smckusick m_freem(m); 22452988Smckusick if (error) 22552988Smckusick goto bad; 22652988Smckusick } 22752988Smckusick 22852988Smckusick /* 22941900Smckusick * Protocols that do not require connections may be optionally left 23041900Smckusick * unconnected for servers that reply from a port other than NFS_PORT. 23141900Smckusick */ 23241900Smckusick if (nmp->nm_flag & NFSMNT_NOCONN) { 23341900Smckusick if (nmp->nm_soflags & PR_CONNREQUIRED) { 23441900Smckusick error = ENOTCONN; 23540117Smckusick goto bad; 23640117Smckusick } 23741900Smckusick } else { 23841900Smckusick if (error = soconnect(so, nmp->nm_nam)) 23940117Smckusick goto bad; 24041900Smckusick 24141900Smckusick /* 24241900Smckusick * Wait for the connection to complete. Cribbed from the 24352196Smckusick * connect system call but with the wait timing out so 24452196Smckusick * that interruptible mounts don't hang here for a long time. 24541900Smckusick */ 24641900Smckusick s = splnet(); 24752196Smckusick while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 24852196Smckusick (void) tsleep((caddr_t)&so->so_timeo, PSOCK, 24952196Smckusick "nfscon", 2 * hz); 25052196Smckusick if ((so->so_state & SS_ISCONNECTING) && 25152196Smckusick so->so_error == 0 && rep && 25252196Smckusick (error = nfs_sigintr(nmp, rep, rep->r_procp))) { 25352196Smckusick so->so_state &= ~SS_ISCONNECTING; 25452196Smckusick splx(s); 25552196Smckusick goto bad; 25652196Smckusick } 25752196Smckusick } 25841900Smckusick if (so->so_error) { 25941900Smckusick error = so->so_error; 26052196Smckusick so->so_error = 0; 26152196Smckusick splx(s); 26241900Smckusick goto bad; 26341900Smckusick } 26452196Smckusick splx(s); 26540117Smckusick } 26652196Smckusick if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) { 26752196Smckusick so->so_rcv.sb_timeo = (5 * hz); 26852196Smckusick so->so_snd.sb_timeo = (5 * hz); 26952196Smckusick } else { 27052196Smckusick so->so_rcv.sb_timeo = 0; 27152196Smckusick so->so_snd.sb_timeo = 0; 27252196Smckusick } 27341900Smckusick if (nmp->nm_sotype == SOCK_DGRAM) { 27452196Smckusick sndreserve = nmp->nm_wsize + NFS_MAXPKTHDR; 27552196Smckusick rcvreserve = nmp->nm_rsize + NFS_MAXPKTHDR; 27652196Smckusick } else if (nmp->nm_sotype == SOCK_SEQPACKET) { 27752196Smckusick sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2; 27852196Smckusick rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2; 27941900Smckusick } else { 28052196Smckusick if (nmp->nm_sotype != SOCK_STREAM) 28152196Smckusick panic("nfscon sotype"); 28241900Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 28341900Smckusick MGET(m, M_WAIT, MT_SOOPTS); 28441900Smckusick *mtod(m, int *) = 1; 28541900Smckusick m->m_len = sizeof(int); 28641900Smckusick sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m); 28741900Smckusick } 28852196Smckusick if (so->so_proto->pr_protocol == IPPROTO_TCP) { 28941900Smckusick MGET(m, M_WAIT, MT_SOOPTS); 29041900Smckusick *mtod(m, int *) = 1; 29141900Smckusick m->m_len = sizeof(int); 29241900Smckusick sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m); 29341900Smckusick } 29452196Smckusick sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof (u_long)) 29552196Smckusick * 2; 29652196Smckusick rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + sizeof (u_long)) 29752196Smckusick * 2; 29841900Smckusick } 29952196Smckusick if (error = soreserve(so, sndreserve, rcvreserve)) 30052196Smckusick goto bad; 30141900Smckusick so->so_rcv.sb_flags |= SB_NOINTR; 30241900Smckusick so->so_snd.sb_flags |= SB_NOINTR; 30340117Smckusick 30441900Smckusick /* Initialize other non-zero congestion variables */ 30552196Smckusick nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] = 30652196Smckusick nmp->nm_srtt[4] = (NFS_TIMEO << 3); 30752196Smckusick nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] = 30852196Smckusick nmp->nm_sdrtt[3] = nmp->nm_sdrtt[4] = 0; 30952196Smckusick nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */ 31041900Smckusick nmp->nm_sent = 0; 31152196Smckusick nmp->nm_timeouts = 0; 31241900Smckusick return (0); 31340117Smckusick 31441900Smckusick bad: 31541900Smckusick nfs_disconnect(nmp); 31641900Smckusick return (error); 31741900Smckusick } 31840117Smckusick 31941900Smckusick /* 32041900Smckusick * Reconnect routine: 32141900Smckusick * Called when a connection is broken on a reliable protocol. 32241900Smckusick * - clean up the old socket 32341900Smckusick * - nfs_connect() again 32441900Smckusick * - set R_MUSTRESEND for all outstanding requests on mount point 32541900Smckusick * If this fails the mount point is DEAD! 32652196Smckusick * nb: Must be called with the nfs_sndlock() set on the mount point. 32741900Smckusick */ 32852196Smckusick nfs_reconnect(rep) 32941900Smckusick register struct nfsreq *rep; 33041900Smckusick { 33141900Smckusick register struct nfsreq *rp; 33252196Smckusick register struct nfsmount *nmp = rep->r_nmp; 33341900Smckusick int error; 33440117Smckusick 33552196Smckusick nfs_disconnect(nmp); 33652196Smckusick while (error = nfs_connect(nmp, rep)) { 33752196Smckusick if (error == EINTR || error == ERESTART) 33841900Smckusick return (EINTR); 33943351Smckusick (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0); 34040117Smckusick } 34141900Smckusick 34241900Smckusick /* 34341900Smckusick * Loop through outstanding request list and fix up all requests 34441900Smckusick * on old socket. 34541900Smckusick */ 34641900Smckusick rp = nfsreqh.r_next; 34741900Smckusick while (rp != &nfsreqh) { 34841900Smckusick if (rp->r_nmp == nmp) 34941900Smckusick rp->r_flags |= R_MUSTRESEND; 35041900Smckusick rp = rp->r_next; 35140117Smckusick } 35240117Smckusick return (0); 35340117Smckusick } 35440117Smckusick 35540117Smckusick /* 35640117Smckusick * NFS disconnect. Clean up and unlink. 35740117Smckusick */ 35841900Smckusick void 35940117Smckusick nfs_disconnect(nmp) 36040117Smckusick register struct nfsmount *nmp; 36140117Smckusick { 36241900Smckusick register struct socket *so; 36340117Smckusick 36441900Smckusick if (nmp->nm_so) { 36541900Smckusick so = nmp->nm_so; 36641900Smckusick nmp->nm_so = (struct socket *)0; 36741900Smckusick soshutdown(so, 2); 36841900Smckusick soclose(so); 36940117Smckusick } 37040117Smckusick } 37140117Smckusick 37240117Smckusick /* 37341900Smckusick * This is the nfs send routine. For connection based socket types, it 37452196Smckusick * must be called with an nfs_sndlock() on the socket. 37541900Smckusick * "rep == NULL" indicates that it has been called from a server. 37652196Smckusick * For the client side: 37752196Smckusick * - return EINTR if the RPC is terminated, 0 otherwise 37852196Smckusick * - set R_MUSTRESEND if the send fails for any reason 37952196Smckusick * - do any cleanup required by recoverable socket errors (???) 38052196Smckusick * For the server side: 38152196Smckusick * - return EINTR or ERESTART if interrupted by a signal 38252196Smckusick * - return EPIPE if a connection is lost for connection based sockets (TCP...) 38352196Smckusick * - do any cleanup required by recoverable socket errors (???) 38440117Smckusick */ 38541900Smckusick nfs_send(so, nam, top, rep) 38638414Smckusick register struct socket *so; 38738414Smckusick struct mbuf *nam; 38841900Smckusick register struct mbuf *top; 38941900Smckusick struct nfsreq *rep; 39038414Smckusick { 39141900Smckusick struct mbuf *sendnam; 39252196Smckusick int error, soflags, flags; 39338414Smckusick 39441900Smckusick if (rep) { 39541900Smckusick if (rep->r_flags & R_SOFTTERM) { 39640117Smckusick m_freem(top); 39741900Smckusick return (EINTR); 39840117Smckusick } 39952196Smckusick if ((so = rep->r_nmp->nm_so) == NULL) { 40052196Smckusick rep->r_flags |= R_MUSTRESEND; 40152196Smckusick m_freem(top); 40252196Smckusick return (0); 40352196Smckusick } 40441900Smckusick rep->r_flags &= ~R_MUSTRESEND; 40541900Smckusick soflags = rep->r_nmp->nm_soflags; 40641900Smckusick } else 40741900Smckusick soflags = so->so_proto->pr_flags; 40841900Smckusick if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) 40941900Smckusick sendnam = (struct mbuf *)0; 41041900Smckusick else 41141900Smckusick sendnam = nam; 41252196Smckusick if (so->so_type == SOCK_SEQPACKET) 41352196Smckusick flags = MSG_EOR; 41452196Smckusick else 41552196Smckusick flags = 0; 41641900Smckusick 41741900Smckusick error = sosend(so, sendnam, (struct uio *)0, top, 41852196Smckusick (struct mbuf *)0, flags); 41952196Smckusick if (error) { 42052196Smckusick if (rep) { 42152934Smckusick log(LOG_INFO, "nfs send error %d for server %s\n",error, 42252934Smckusick rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 42352196Smckusick /* 42452196Smckusick * Deal with errors for the client side. 42552196Smckusick */ 42652196Smckusick if (rep->r_flags & R_SOFTTERM) 42752196Smckusick error = EINTR; 42852196Smckusick else 42952196Smckusick rep->r_flags |= R_MUSTRESEND; 43052934Smckusick } else 43152934Smckusick log(LOG_INFO, "nfsd send error %d\n", error); 43252196Smckusick 43352196Smckusick /* 43452196Smckusick * Handle any recoverable (soft) socket errors here. (???) 43552196Smckusick */ 43652196Smckusick if (error != EINTR && error != ERESTART && 43752196Smckusick error != EWOULDBLOCK && error != EPIPE) 43841900Smckusick error = 0; 43938414Smckusick } 44038414Smckusick return (error); 44138414Smckusick } 44238414Smckusick 44338414Smckusick /* 44441900Smckusick * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all 44541900Smckusick * done by soreceive(), but for SOCK_STREAM we must deal with the Record 44641900Smckusick * Mark and consolidate the data into a new mbuf list. 44741900Smckusick * nb: Sometimes TCP passes the data up to soreceive() in long lists of 44841900Smckusick * small mbufs. 44941900Smckusick * For SOCK_STREAM we must be very careful to read an entire record once 45041900Smckusick * we have read any of it, even if the system call has been interrupted. 45138414Smckusick */ 45252196Smckusick nfs_receive(rep, aname, mp) 45352196Smckusick register struct nfsreq *rep; 45438414Smckusick struct mbuf **aname; 45538414Smckusick struct mbuf **mp; 45638414Smckusick { 45752196Smckusick register struct socket *so; 45841900Smckusick struct uio auio; 45941900Smckusick struct iovec aio; 46038414Smckusick register struct mbuf *m; 46152196Smckusick struct mbuf *control; 46241900Smckusick u_long len; 46341900Smckusick struct mbuf **getnam; 46452196Smckusick int error, sotype, rcvflg; 46552932Smckusick struct proc *p = curproc; /* XXX */ 46638414Smckusick 46741900Smckusick /* 46841900Smckusick * Set up arguments for soreceive() 46941900Smckusick */ 47041900Smckusick *mp = (struct mbuf *)0; 47141900Smckusick *aname = (struct mbuf *)0; 47252196Smckusick sotype = rep->r_nmp->nm_sotype; 47338414Smckusick 47441900Smckusick /* 47541900Smckusick * For reliable protocols, lock against other senders/receivers 47641900Smckusick * in case a reconnect is necessary. 47741900Smckusick * For SOCK_STREAM, first get the Record Mark to find out how much 47841900Smckusick * more there is to get. 47941900Smckusick * We must lock the socket against other receivers 48041900Smckusick * until we have an entire rpc request/reply. 48141900Smckusick */ 48252196Smckusick if (sotype != SOCK_DGRAM) { 48352196Smckusick if (error = nfs_sndlock(&rep->r_nmp->nm_flag, rep)) 48452196Smckusick return (error); 48541900Smckusick tryagain: 48641900Smckusick /* 48741900Smckusick * Check for fatal errors and resending request. 48841900Smckusick */ 48952196Smckusick /* 49052196Smckusick * Ugh: If a reconnect attempt just happened, nm_so 49152196Smckusick * would have changed. NULL indicates a failed 49252196Smckusick * attempt that has essentially shut down this 49352196Smckusick * mount point. 49452196Smckusick */ 49552196Smckusick if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) { 49652196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 49752196Smckusick return (EINTR); 49852196Smckusick } 49952196Smckusick if ((so = rep->r_nmp->nm_so) == NULL) { 50052196Smckusick if (error = nfs_reconnect(rep)) { 50152196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 50252196Smckusick return (error); 50340117Smckusick } 50452196Smckusick goto tryagain; 50541900Smckusick } 50652196Smckusick while (rep->r_flags & R_MUSTRESEND) { 50752196Smckusick m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT); 50852196Smckusick nfsstats.rpcretries++; 50952196Smckusick if (error = nfs_send(so, rep->r_nmp->nm_nam, m, rep)) { 51052196Smckusick if (error == EINTR || error == ERESTART || 51152196Smckusick (error = nfs_reconnect(rep))) { 51252196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 51352196Smckusick return (error); 51452196Smckusick } 51552196Smckusick goto tryagain; 51652196Smckusick } 51752196Smckusick } 51852196Smckusick nfs_sndunlock(&rep->r_nmp->nm_flag); 51952196Smckusick if (sotype == SOCK_STREAM) { 52041900Smckusick aio.iov_base = (caddr_t) &len; 52141900Smckusick aio.iov_len = sizeof(u_long); 52241900Smckusick auio.uio_iov = &aio; 52341900Smckusick auio.uio_iovcnt = 1; 52441900Smckusick auio.uio_segflg = UIO_SYSSPACE; 52541900Smckusick auio.uio_rw = UIO_READ; 52641900Smckusick auio.uio_offset = 0; 52741900Smckusick auio.uio_resid = sizeof(u_long); 52852932Smckusick auio.uio_procp = p; 52941900Smckusick do { 53052196Smckusick rcvflg = MSG_WAITALL; 53152196Smckusick error = soreceive(so, (struct mbuf **)0, &auio, 53241900Smckusick (struct mbuf **)0, (struct mbuf **)0, &rcvflg); 53352196Smckusick if (error == EWOULDBLOCK && rep) { 53441900Smckusick if (rep->r_flags & R_SOFTTERM) 53541900Smckusick return (EINTR); 53652196Smckusick } 53741900Smckusick } while (error == EWOULDBLOCK); 53847737Skarels if (!error && auio.uio_resid > 0) { 53952934Smckusick log(LOG_INFO, 54052934Smckusick "short receive (%d/%d) from nfs server %s\n", 54152934Smckusick sizeof(u_long) - auio.uio_resid, 54252934Smckusick sizeof(u_long), 54347737Skarels rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 54447737Skarels error = EPIPE; 54547737Skarels } 54640761Skarels if (error) 54741900Smckusick goto errout; 54841900Smckusick len = ntohl(len) & ~0x80000000; 54941900Smckusick /* 55041900Smckusick * This is SERIOUS! We are out of sync with the sender 55141900Smckusick * and forcing a disconnect/reconnect is all I can do. 55241900Smckusick */ 55341900Smckusick if (len > NFS_MAXPACKET) { 55452934Smckusick log(LOG_ERR, "%s (%d) from nfs server %s\n", 55552934Smckusick "impossible packet length", 55652934Smckusick len, 55752934Smckusick rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 55847737Skarels error = EFBIG; 55947737Skarels goto errout; 56041900Smckusick } 56141900Smckusick auio.uio_resid = len; 56241900Smckusick do { 56347737Skarels rcvflg = MSG_WAITALL; 56441900Smckusick error = soreceive(so, (struct mbuf **)0, 56541900Smckusick &auio, mp, (struct mbuf **)0, &rcvflg); 56641900Smckusick } while (error == EWOULDBLOCK || error == EINTR || 56741900Smckusick error == ERESTART); 56847737Skarels if (!error && auio.uio_resid > 0) { 56952934Smckusick log(LOG_INFO, 57052934Smckusick "short receive (%d/%d) from nfs server %s\n", 57152934Smckusick len - auio.uio_resid, len, 57252934Smckusick rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 57347737Skarels error = EPIPE; 57447737Skarels } 57540117Smckusick } else { 57652196Smckusick /* 57752196Smckusick * NB: Since uio_resid is big, MSG_WAITALL is ignored 57852196Smckusick * and soreceive() will return when it has either a 57952196Smckusick * control msg or a data msg. 58052196Smckusick * We have no use for control msg., but must grab them 58152196Smckusick * and then throw them away so we know what is going 58252196Smckusick * on. 58352196Smckusick */ 58452196Smckusick auio.uio_resid = len = 100000000; /* Anything Big */ 58552932Smckusick auio.uio_procp = p; 58641900Smckusick do { 58747737Skarels rcvflg = 0; 58841900Smckusick error = soreceive(so, (struct mbuf **)0, 58952196Smckusick &auio, mp, &control, &rcvflg); 59052196Smckusick if (control) 59152196Smckusick m_freem(control); 59241900Smckusick if (error == EWOULDBLOCK && rep) { 59341900Smckusick if (rep->r_flags & R_SOFTTERM) 59441900Smckusick return (EINTR); 59541900Smckusick } 59652196Smckusick } while (error == EWOULDBLOCK || 59752196Smckusick (!error && *mp == NULL && control)); 59852196Smckusick if ((rcvflg & MSG_EOR) == 0) 59952196Smckusick printf("Egad!!\n"); 60041900Smckusick if (!error && *mp == NULL) 60141900Smckusick error = EPIPE; 60241900Smckusick len -= auio.uio_resid; 60340117Smckusick } 60441900Smckusick errout: 60552196Smckusick if (error && error != EINTR && error != ERESTART) { 60641900Smckusick m_freem(*mp); 60741900Smckusick *mp = (struct mbuf *)0; 60852934Smckusick if (error != EPIPE) 60947737Skarels log(LOG_INFO, 61047737Skarels "receive error %d from nfs server %s\n", 61147737Skarels error, 61247737Skarels rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); 61352196Smckusick error = nfs_sndlock(&rep->r_nmp->nm_flag, rep); 61441900Smckusick if (!error) 61552196Smckusick error = nfs_reconnect(rep); 61652196Smckusick if (!error) 61741900Smckusick goto tryagain; 61840117Smckusick } 61941900Smckusick } else { 62052196Smckusick if ((so = rep->r_nmp->nm_so) == NULL) 62152196Smckusick return (EACCES); 62241900Smckusick if (so->so_state & SS_ISCONNECTED) 62341900Smckusick getnam = (struct mbuf **)0; 62441900Smckusick else 62541900Smckusick getnam = aname; 62641900Smckusick auio.uio_resid = len = 1000000; 62752932Smckusick auio.uio_procp = p; 62841900Smckusick do { 62947737Skarels rcvflg = 0; 63041900Smckusick error = soreceive(so, getnam, &auio, mp, 63141900Smckusick (struct mbuf **)0, &rcvflg); 63252196Smckusick if (error == EWOULDBLOCK && 63341900Smckusick (rep->r_flags & R_SOFTTERM)) 63441900Smckusick return (EINTR); 63541900Smckusick } while (error == EWOULDBLOCK); 63641900Smckusick len -= auio.uio_resid; 63741900Smckusick } 63841900Smckusick if (error) { 63941900Smckusick m_freem(*mp); 64041900Smckusick *mp = (struct mbuf *)0; 64141900Smckusick } 64241900Smckusick /* 64352196Smckusick * Search for any mbufs that are not a multiple of 4 bytes long 64452196Smckusick * or with m_data not longword aligned. 64541900Smckusick * These could cause pointer alignment problems, so copy them to 64641900Smckusick * well aligned mbufs. 64741900Smckusick */ 64852196Smckusick nfs_realign(*mp, 5 * NFSX_UNSIGNED); 64938414Smckusick return (error); 65038414Smckusick } 65138414Smckusick 65238414Smckusick /* 65341900Smckusick * Implement receipt of reply on a socket. 65438414Smckusick * We must search through the list of received datagrams matching them 65538414Smckusick * with outstanding requests using the xid, until ours is found. 65638414Smckusick */ 65741900Smckusick /* ARGSUSED */ 65852196Smckusick nfs_reply(myrep) 65939344Smckusick struct nfsreq *myrep; 66038414Smckusick { 66138414Smckusick register struct nfsreq *rep; 66252196Smckusick register struct nfsmount *nmp = myrep->r_nmp; 66352196Smckusick register long t1; 66452196Smckusick struct mbuf *mrep, *nam, *md; 66552196Smckusick u_long rxid, *tl; 66652196Smckusick caddr_t dpos, cp2; 66752196Smckusick int error; 66838414Smckusick 66941900Smckusick /* 67041900Smckusick * Loop around until we get our own reply 67141900Smckusick */ 67241900Smckusick for (;;) { 67341900Smckusick /* 67441900Smckusick * Lock against other receivers so that I don't get stuck in 67541900Smckusick * sbwait() after someone else has received my reply for me. 67641900Smckusick * Also necessary for connection based protocols to avoid 67741900Smckusick * race conditions during a reconnect. 67841900Smckusick */ 67952196Smckusick if (error = nfs_rcvlock(myrep)) 68052196Smckusick return (error); 68141900Smckusick /* Already received, bye bye */ 68241900Smckusick if (myrep->r_mrep != NULL) { 68352196Smckusick nfs_rcvunlock(&nmp->nm_flag); 68441900Smckusick return (0); 68540117Smckusick } 68641900Smckusick /* 68741900Smckusick * Get the next Rpc reply off the socket 68841900Smckusick */ 68952196Smckusick error = nfs_receive(myrep, &nam, &mrep); 69052196Smckusick nfs_rcvunlock(&nmp->nm_flag); 69152196Smckusick if (error) { 69238414Smckusick 69341900Smckusick /* 69441900Smckusick * Ignore routing errors on connectionless protocols?? 69541900Smckusick */ 69641900Smckusick if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) { 69741900Smckusick nmp->nm_so->so_error = 0; 69859387Smckusick if (myrep->r_flags & R_GETONEREP) 69959387Smckusick return (0); 70041900Smckusick continue; 70141900Smckusick } 70241900Smckusick return (error); 70338414Smckusick } 70452196Smckusick if (nam) 70552196Smckusick m_freem(nam); 70641900Smckusick 70741900Smckusick /* 70841900Smckusick * Get the xid and check that it is an rpc reply 70941900Smckusick */ 71052196Smckusick md = mrep; 71152196Smckusick dpos = mtod(md, caddr_t); 71252196Smckusick nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 71352196Smckusick rxid = *tl++; 71452196Smckusick if (*tl != rpc_reply) { 71552196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 71652196Smckusick if (nqnfs_callback(nmp, mrep, md, dpos)) 71752196Smckusick nfsstats.rpcinvalid++; 71852196Smckusick } else { 71952196Smckusick nfsstats.rpcinvalid++; 72052196Smckusick m_freem(mrep); 72152196Smckusick } 72252196Smckusick nfsmout: 72359387Smckusick if (myrep->r_flags & R_GETONEREP) 72459387Smckusick return (0); 72541900Smckusick continue; 72638414Smckusick } 72752196Smckusick 72841900Smckusick /* 72941900Smckusick * Loop through the request list to match up the reply 73041900Smckusick * Iff no match, just drop the datagram 73141900Smckusick */ 73241900Smckusick rep = nfsreqh.r_next; 73341900Smckusick while (rep != &nfsreqh) { 73445281Smckusick if (rep->r_mrep == NULL && rxid == rep->r_xid) { 73541900Smckusick /* Found it.. */ 73652196Smckusick rep->r_mrep = mrep; 73752196Smckusick rep->r_md = md; 73852196Smckusick rep->r_dpos = dpos; 73952196Smckusick if (nfsrtton) { 74052196Smckusick struct rttl *rt; 74152196Smckusick 74252196Smckusick rt = &nfsrtt.rttl[nfsrtt.pos]; 74352196Smckusick rt->proc = rep->r_procnum; 74452196Smckusick rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]); 74552196Smckusick rt->sent = nmp->nm_sent; 74652196Smckusick rt->cwnd = nmp->nm_cwnd; 74752196Smckusick rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1]; 74852196Smckusick rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1]; 74952196Smckusick rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid; 75052196Smckusick rt->tstamp = time; 75152196Smckusick if (rep->r_flags & R_TIMING) 75252196Smckusick rt->rtt = rep->r_rtt; 75352196Smckusick else 75452196Smckusick rt->rtt = 1000000; 75552196Smckusick nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ; 75652196Smckusick } 75741900Smckusick /* 75852196Smckusick * Update congestion window. 75952196Smckusick * Do the additive increase of 76052196Smckusick * one rpc/rtt. 76141900Smckusick */ 76252196Smckusick if (nmp->nm_cwnd <= nmp->nm_sent) { 76352196Smckusick nmp->nm_cwnd += 76452196Smckusick (NFS_CWNDSCALE * NFS_CWNDSCALE + 76552196Smckusick (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd; 76652196Smckusick if (nmp->nm_cwnd > NFS_MAXCWND) 76752196Smckusick nmp->nm_cwnd = NFS_MAXCWND; 76852196Smckusick } 76956671Smckusick rep->r_flags &= ~R_SENT; 77056671Smckusick nmp->nm_sent -= NFS_CWNDSCALE; 77152196Smckusick /* 77252196Smckusick * Update rtt using a gain of 0.125 on the mean 77352196Smckusick * and a gain of 0.25 on the deviation. 77452196Smckusick */ 77541900Smckusick if (rep->r_flags & R_TIMING) { 77652196Smckusick /* 77752196Smckusick * Since the timer resolution of 77852196Smckusick * NFS_HZ is so course, it can often 77952196Smckusick * result in r_rtt == 0. Since 78052196Smckusick * r_rtt == N means that the actual 78152196Smckusick * rtt is between N+dt and N+2-dt ticks, 78252196Smckusick * add 1. 78352196Smckusick */ 78452196Smckusick t1 = rep->r_rtt + 1; 78552196Smckusick t1 -= (NFS_SRTT(rep) >> 3); 78652196Smckusick NFS_SRTT(rep) += t1; 78752196Smckusick if (t1 < 0) 78852196Smckusick t1 = -t1; 78952196Smckusick t1 -= (NFS_SDRTT(rep) >> 2); 79052196Smckusick NFS_SDRTT(rep) += t1; 79141900Smckusick } 79252196Smckusick nmp->nm_timeouts = 0; 79340117Smckusick break; 79438414Smckusick } 79541900Smckusick rep = rep->r_next; 79638414Smckusick } 79741900Smckusick /* 79841900Smckusick * If not matched to a request, drop it. 79941900Smckusick * If it's mine, get out. 80041900Smckusick */ 80141900Smckusick if (rep == &nfsreqh) { 80241900Smckusick nfsstats.rpcunexpected++; 80352196Smckusick m_freem(mrep); 80453426Smckusick } else if (rep == myrep) { 80553426Smckusick if (rep->r_mrep == NULL) 80653426Smckusick panic("nfsreply nil"); 80741900Smckusick return (0); 80853426Smckusick } 80959387Smckusick if (myrep->r_flags & R_GETONEREP) 81059387Smckusick return (0); 81138414Smckusick } 81238414Smckusick } 81338414Smckusick 81438414Smckusick /* 81538414Smckusick * nfs_request - goes something like this 81638414Smckusick * - fill in request struct 81738414Smckusick * - links it into list 81841900Smckusick * - calls nfs_send() for first transmit 81941900Smckusick * - calls nfs_receive() to get reply 82038414Smckusick * - break down rpc header and return with nfs reply pointed to 82138414Smckusick * by mrep or error 82238414Smckusick * nb: always frees up mreq mbuf list 82338414Smckusick */ 82452196Smckusick nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) 82538414Smckusick struct vnode *vp; 82652196Smckusick struct mbuf *mrest; 82741900Smckusick int procnum; 82841900Smckusick struct proc *procp; 82952196Smckusick struct ucred *cred; 83038414Smckusick struct mbuf **mrp; 83138414Smckusick struct mbuf **mdp; 83238414Smckusick caddr_t *dposp; 83338414Smckusick { 83438414Smckusick register struct mbuf *m, *mrep; 83538414Smckusick register struct nfsreq *rep; 83648048Smckusick register u_long *tl; 83752196Smckusick register int i; 83841900Smckusick struct nfsmount *nmp; 83952196Smckusick struct mbuf *md, *mheadend; 84039344Smckusick struct nfsreq *reph; 841*65623Sbostic struct nfsnode *np; 84252196Smckusick time_t reqtime, waituntil; 84352196Smckusick caddr_t dpos, cp2; 84452196Smckusick int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; 84552196Smckusick int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; 84652196Smckusick u_long xid; 84756286Smckusick u_quad_t frev; 84852196Smckusick char *auth_str; 84938414Smckusick 85052196Smckusick nmp = VFSTONFS(vp->v_mount); 85138414Smckusick MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); 85241900Smckusick rep->r_nmp = nmp; 85338414Smckusick rep->r_vp = vp; 85441900Smckusick rep->r_procp = procp; 85552196Smckusick rep->r_procnum = procnum; 85652196Smckusick i = 0; 85752196Smckusick m = mrest; 85838414Smckusick while (m) { 85952196Smckusick i += m->m_len; 86038414Smckusick m = m->m_next; 86138414Smckusick } 86252196Smckusick mrest_len = i; 86352196Smckusick 86452196Smckusick /* 86552196Smckusick * Get the RPC header with authorization. 86652196Smckusick */ 86752196Smckusick kerbauth: 86852196Smckusick auth_str = (char *)0; 86952196Smckusick if (nmp->nm_flag & NFSMNT_KERB) { 87052196Smckusick if (failed_auth) { 87152196Smckusick error = nfs_getauth(nmp, rep, cred, &auth_type, 87252196Smckusick &auth_str, &auth_len); 87352196Smckusick if (error) { 87452196Smckusick free((caddr_t)rep, M_NFSREQ); 87552196Smckusick m_freem(mrest); 87652196Smckusick return (error); 87752196Smckusick } 87852196Smckusick } else { 87952196Smckusick auth_type = RPCAUTH_UNIX; 88052196Smckusick auth_len = 5 * NFSX_UNSIGNED; 88145281Smckusick } 88252196Smckusick } else { 88352196Smckusick auth_type = RPCAUTH_UNIX; 88453426Smckusick if (cred->cr_ngroups < 1) 88553426Smckusick panic("nfsreq nogrps"); 88652196Smckusick auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ? 88752196Smckusick nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + 88852196Smckusick 5 * NFSX_UNSIGNED; 88945281Smckusick } 89052196Smckusick m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum, 89152196Smckusick auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid); 89252196Smckusick if (auth_str) 89352196Smckusick free(auth_str, M_TEMP); 89452196Smckusick 89541900Smckusick /* 89652196Smckusick * For stream protocols, insert a Sun RPC Record Mark. 89741900Smckusick */ 89852196Smckusick if (nmp->nm_sotype == SOCK_STREAM) { 89952196Smckusick M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 90052196Smckusick *mtod(m, u_long *) = htonl(0x80000000 | 90152196Smckusick (m->m_pkthdr.len - NFSX_UNSIGNED)); 90241900Smckusick } 90352196Smckusick rep->r_mreq = m; 90452196Smckusick rep->r_xid = xid; 90552196Smckusick tryagain: 90652196Smckusick if (nmp->nm_flag & NFSMNT_SOFT) 90752196Smckusick rep->r_retry = nmp->nm_retry; 90852196Smckusick else 90952196Smckusick rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */ 91052196Smckusick rep->r_rtt = rep->r_rexmit = 0; 91152196Smckusick if (proct[procnum] > 0) 91252196Smckusick rep->r_flags = R_TIMING; 91352196Smckusick else 91452196Smckusick rep->r_flags = 0; 91552196Smckusick rep->r_mrep = NULL; 91638414Smckusick 91740117Smckusick /* 91840117Smckusick * Do the client side RPC. 91940117Smckusick */ 92040117Smckusick nfsstats.rpcrequests++; 92141900Smckusick /* 92241900Smckusick * Chain request into list of outstanding requests. Be sure 92341900Smckusick * to put it LAST so timer finds oldest requests first. 92441900Smckusick */ 92552196Smckusick s = splsoftclock(); 92639344Smckusick reph = &nfsreqh; 92741900Smckusick reph->r_prev->r_next = rep; 92841900Smckusick rep->r_prev = reph->r_prev; 92939344Smckusick reph->r_prev = rep; 93039344Smckusick rep->r_next = reph; 93152196Smckusick 93252196Smckusick /* Get send time for nqnfs */ 93352196Smckusick reqtime = time.tv_sec; 93452196Smckusick 93540117Smckusick /* 93640117Smckusick * If backing off another request or avoiding congestion, don't 93740117Smckusick * send this one now but let timer do it. If not timing a request, 93840117Smckusick * do it now. 93940117Smckusick */ 94052196Smckusick if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM || 94152196Smckusick (nmp->nm_flag & NFSMNT_DUMBTIMR) || 94252196Smckusick nmp->nm_sent < nmp->nm_cwnd)) { 94340117Smckusick splx(s); 94441900Smckusick if (nmp->nm_soflags & PR_CONNREQUIRED) 94552196Smckusick error = nfs_sndlock(&nmp->nm_flag, rep); 94652196Smckusick if (!error) { 94752196Smckusick m = m_copym(m, 0, M_COPYALL, M_WAIT); 94852196Smckusick error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep); 94952196Smckusick if (nmp->nm_soflags & PR_CONNREQUIRED) 95052196Smckusick nfs_sndunlock(&nmp->nm_flag); 95152196Smckusick } 95252196Smckusick if (!error && (rep->r_flags & R_MUSTRESEND) == 0) { 95352196Smckusick nmp->nm_sent += NFS_CWNDSCALE; 95452196Smckusick rep->r_flags |= R_SENT; 95552196Smckusick } 95652196Smckusick } else { 95741900Smckusick splx(s); 95852196Smckusick rep->r_rtt = -1; 95952196Smckusick } 96038414Smckusick 96138414Smckusick /* 96240117Smckusick * Wait for the reply from our send or the timer's. 96340117Smckusick */ 96454610Smckusick if (!error || error == EPIPE) 96552196Smckusick error = nfs_reply(rep); 96638414Smckusick 96740117Smckusick /* 96840117Smckusick * RPC done, unlink the request. 96940117Smckusick */ 97052196Smckusick s = splsoftclock(); 97138414Smckusick rep->r_prev->r_next = rep->r_next; 97239344Smckusick rep->r_next->r_prev = rep->r_prev; 97338414Smckusick splx(s); 97441900Smckusick 97541900Smckusick /* 97656602Smckusick * Decrement the outstanding request count. 97756602Smckusick */ 97856671Smckusick if (rep->r_flags & R_SENT) { 97956671Smckusick rep->r_flags &= ~R_SENT; /* paranoia */ 98056602Smckusick nmp->nm_sent -= NFS_CWNDSCALE; 98156671Smckusick } 98256602Smckusick 98356602Smckusick /* 98441900Smckusick * If there was a successful reply and a tprintf msg. 98541900Smckusick * tprintf a response. 98641900Smckusick */ 98747737Skarels if (!error && (rep->r_flags & R_TPRINTFMSG)) 98847737Skarels nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname, 98947737Skarels "is alive again"); 99045281Smckusick mrep = rep->r_mrep; 99152196Smckusick md = rep->r_md; 99252196Smckusick dpos = rep->r_dpos; 99352196Smckusick if (error) { 99452196Smckusick m_freem(rep->r_mreq); 99552196Smckusick free((caddr_t)rep, M_NFSREQ); 99638414Smckusick return (error); 99752196Smckusick } 99838414Smckusick 99938414Smckusick /* 100038414Smckusick * break down the rpc header and check if ok 100138414Smckusick */ 100252196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 100348048Smckusick if (*tl++ == rpc_msgdenied) { 100448048Smckusick if (*tl == rpc_mismatch) 100538414Smckusick error = EOPNOTSUPP; 100652196Smckusick else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { 100752196Smckusick if (*tl == rpc_rejectedcred && failed_auth == 0) { 100852196Smckusick failed_auth++; 100952196Smckusick mheadend->m_next = (struct mbuf *)0; 101052196Smckusick m_freem(mrep); 101152196Smckusick m_freem(rep->r_mreq); 101252196Smckusick goto kerbauth; 101352196Smckusick } else 101452196Smckusick error = EAUTH; 101552196Smckusick } else 101638414Smckusick error = EACCES; 101738414Smckusick m_freem(mrep); 101852196Smckusick m_freem(rep->r_mreq); 101952196Smckusick free((caddr_t)rep, M_NFSREQ); 102038414Smckusick return (error); 102138414Smckusick } 102252196Smckusick 102338414Smckusick /* 102438414Smckusick * skip over the auth_verf, someday we may want to cache auth_short's 102538414Smckusick * for nfs_reqhead(), but for now just dump it 102638414Smckusick */ 102748048Smckusick if (*++tl != 0) { 102852196Smckusick i = nfsm_rndup(fxdr_unsigned(long, *tl)); 102952196Smckusick nfsm_adv(i); 103038414Smckusick } 103152196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 103238414Smckusick /* 0 == ok */ 103348048Smckusick if (*tl == 0) { 103452196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 103548048Smckusick if (*tl != 0) { 103648048Smckusick error = fxdr_unsigned(int, *tl); 103738414Smckusick m_freem(mrep); 103852196Smckusick if ((nmp->nm_flag & NFSMNT_NQNFS) && 103952196Smckusick error == NQNFS_TRYLATER) { 104052196Smckusick error = 0; 104152196Smckusick waituntil = time.tv_sec + trylater_delay; 104252196Smckusick while (time.tv_sec < waituntil) 104352196Smckusick (void) tsleep((caddr_t)&lbolt, 104452196Smckusick PSOCK, "nqnfstry", 0); 104552196Smckusick trylater_delay *= nfs_backoff[trylater_cnt]; 104652196Smckusick if (trylater_cnt < 7) 104752196Smckusick trylater_cnt++; 104852196Smckusick goto tryagain; 104952196Smckusick } 105056286Smckusick 105156286Smckusick /* 105256286Smckusick * If the File Handle was stale, invalidate the 105356286Smckusick * lookup cache, just in case. 105456286Smckusick */ 105556286Smckusick if (error == ESTALE) 105656286Smckusick cache_purge(vp); 105752196Smckusick m_freem(rep->r_mreq); 105852196Smckusick free((caddr_t)rep, M_NFSREQ); 105938414Smckusick return (error); 106038414Smckusick } 106152196Smckusick 106252196Smckusick /* 106352196Smckusick * For nqnfs, get any lease in reply 106452196Smckusick */ 106552196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 106652196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 106752196Smckusick if (*tl) { 106852196Smckusick np = VTONFS(vp); 106952196Smckusick nqlflag = fxdr_unsigned(int, *tl); 107052196Smckusick nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 107152196Smckusick cachable = fxdr_unsigned(int, *tl++); 107252196Smckusick reqtime += fxdr_unsigned(int, *tl++); 107352196Smckusick if (reqtime > time.tv_sec) { 107456286Smckusick fxdr_hyper(tl, &frev); 107556286Smckusick nqnfs_clientlease(nmp, np, nqlflag, 107656286Smckusick cachable, reqtime, frev); 107752196Smckusick } 107852196Smckusick } 107952196Smckusick } 108038414Smckusick *mrp = mrep; 108138414Smckusick *mdp = md; 108238414Smckusick *dposp = dpos; 108352196Smckusick m_freem(rep->r_mreq); 108452196Smckusick FREE((caddr_t)rep, M_NFSREQ); 108538414Smckusick return (0); 108638414Smckusick } 108738414Smckusick m_freem(mrep); 108852196Smckusick m_freem(rep->r_mreq); 108952196Smckusick free((caddr_t)rep, M_NFSREQ); 109052196Smckusick error = EPROTONOSUPPORT; 109138414Smckusick nfsmout: 109238414Smckusick return (error); 109338414Smckusick } 109438414Smckusick 109538414Smckusick /* 109638414Smckusick * Generate the rpc reply header 109738414Smckusick * siz arg. is used to decide if adding a cluster is worthwhile 109838414Smckusick */ 109952196Smckusick nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp) 110038414Smckusick int siz; 110152196Smckusick struct nfsd *nd; 110238414Smckusick int err; 110352196Smckusick int cache; 110452196Smckusick u_quad_t *frev; 110538414Smckusick struct mbuf **mrq; 110638414Smckusick struct mbuf **mbp; 110738414Smckusick caddr_t *bposp; 110838414Smckusick { 110948048Smckusick register u_long *tl; 111052196Smckusick register struct mbuf *mreq; 111139494Smckusick caddr_t bpos; 111252196Smckusick struct mbuf *mb, *mb2; 111338414Smckusick 111452196Smckusick MGETHDR(mreq, M_WAIT, MT_DATA); 111538414Smckusick mb = mreq; 111652196Smckusick /* 111752196Smckusick * If this is a big reply, use a cluster else 111852196Smckusick * try and leave leading space for the lower level headers. 111952196Smckusick */ 112052196Smckusick siz += RPC_REPLYSIZ; 112152196Smckusick if (siz >= MINCLSIZE) { 112241900Smckusick MCLGET(mreq, M_WAIT); 112352196Smckusick } else 112452196Smckusick mreq->m_data += max_hdr; 112548048Smckusick tl = mtod(mreq, u_long *); 112638414Smckusick mreq->m_len = 6*NFSX_UNSIGNED; 112748048Smckusick bpos = ((caddr_t)tl)+mreq->m_len; 112852196Smckusick *tl++ = nd->nd_retxid; 112948048Smckusick *tl++ = rpc_reply; 113052196Smckusick if (err == ERPCMISMATCH || err == NQNFS_AUTHERR) { 113148048Smckusick *tl++ = rpc_msgdenied; 113252196Smckusick if (err == NQNFS_AUTHERR) { 113352196Smckusick *tl++ = rpc_autherr; 113452196Smckusick *tl = rpc_rejectedcred; 113552196Smckusick mreq->m_len -= NFSX_UNSIGNED; 113652196Smckusick bpos -= NFSX_UNSIGNED; 113752196Smckusick } else { 113852196Smckusick *tl++ = rpc_mismatch; 113952196Smckusick *tl++ = txdr_unsigned(2); 114052196Smckusick *tl = txdr_unsigned(2); 114152196Smckusick } 114238414Smckusick } else { 114348048Smckusick *tl++ = rpc_msgaccepted; 114448048Smckusick *tl++ = 0; 114548048Smckusick *tl++ = 0; 114638414Smckusick switch (err) { 114738414Smckusick case EPROGUNAVAIL: 114848048Smckusick *tl = txdr_unsigned(RPC_PROGUNAVAIL); 114938414Smckusick break; 115038414Smckusick case EPROGMISMATCH: 115148048Smckusick *tl = txdr_unsigned(RPC_PROGMISMATCH); 115248048Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 115348048Smckusick *tl++ = txdr_unsigned(2); 115448048Smckusick *tl = txdr_unsigned(2); /* someday 3 */ 115538414Smckusick break; 115638414Smckusick case EPROCUNAVAIL: 115748048Smckusick *tl = txdr_unsigned(RPC_PROCUNAVAIL); 115838414Smckusick break; 115938414Smckusick default: 116048048Smckusick *tl = 0; 116138414Smckusick if (err != VNOVAL) { 116248048Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 116352196Smckusick if (err) 116452196Smckusick *tl = txdr_unsigned(nfsrv_errmap[err - 1]); 116552196Smckusick else 116652196Smckusick *tl = 0; 116738414Smckusick } 116838414Smckusick break; 116938414Smckusick }; 117038414Smckusick } 117152196Smckusick 117252196Smckusick /* 117352196Smckusick * For nqnfs, piggyback lease as requested. 117452196Smckusick */ 117552196Smckusick if (nd->nd_nqlflag != NQL_NOVAL && err == 0) { 117652196Smckusick if (nd->nd_nqlflag) { 117752196Smckusick nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 117852196Smckusick *tl++ = txdr_unsigned(nd->nd_nqlflag); 117952196Smckusick *tl++ = txdr_unsigned(cache); 118052196Smckusick *tl++ = txdr_unsigned(nd->nd_duration); 118152196Smckusick txdr_hyper(frev, tl); 118252196Smckusick } else { 118352196Smckusick if (nd->nd_nqlflag != 0) 118452196Smckusick panic("nqreph"); 118552196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 118652196Smckusick *tl = 0; 118752196Smckusick } 118852196Smckusick } 118938414Smckusick *mrq = mreq; 119038414Smckusick *mbp = mb; 119138414Smckusick *bposp = bpos; 119238414Smckusick if (err != 0 && err != VNOVAL) 119338414Smckusick nfsstats.srvrpc_errs++; 119438414Smckusick return (0); 119538414Smckusick } 119638414Smckusick 119738414Smckusick /* 119838414Smckusick * Nfs timer routine 119938414Smckusick * Scan the nfsreq list and retranmit any requests that have timed out 120038414Smckusick * To avoid retransmission attempts on STREAM sockets (in the future) make 120140117Smckusick * sure to set the r_retry field to 0 (implies nm_retry == 0). 120238414Smckusick */ 120355079Smckusick void 120455079Smckusick nfs_timer(arg) 120555079Smckusick void *arg; 120638414Smckusick { 120738414Smckusick register struct nfsreq *rep; 120838414Smckusick register struct mbuf *m; 120938414Smckusick register struct socket *so; 121041900Smckusick register struct nfsmount *nmp; 121152196Smckusick register int timeo; 121252196Smckusick static long lasttime = 0; 121340117Smckusick int s, error; 121438414Smckusick 121538414Smckusick s = splnet(); 121641900Smckusick for (rep = nfsreqh.r_next; rep != &nfsreqh; rep = rep->r_next) { 121741900Smckusick nmp = rep->r_nmp; 121852196Smckusick if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) 121941900Smckusick continue; 122052196Smckusick if (nfs_sigintr(nmp, rep, rep->r_procp)) { 122141900Smckusick rep->r_flags |= R_SOFTTERM; 122241900Smckusick continue; 122341900Smckusick } 122452196Smckusick if (rep->r_rtt >= 0) { 122552196Smckusick rep->r_rtt++; 122652196Smckusick if (nmp->nm_flag & NFSMNT_DUMBTIMR) 122752196Smckusick timeo = nmp->nm_timeo; 122852196Smckusick else 122952196Smckusick timeo = NFS_RTO(nmp, proct[rep->r_procnum]); 123052196Smckusick if (nmp->nm_timeouts > 0) 123152196Smckusick timeo *= nfs_backoff[nmp->nm_timeouts - 1]; 123252196Smckusick if (rep->r_rtt <= timeo) 123352196Smckusick continue; 123452196Smckusick if (nmp->nm_timeouts < 8) 123552196Smckusick nmp->nm_timeouts++; 123640117Smckusick } 123741900Smckusick /* 123841900Smckusick * Check for server not responding 123941900Smckusick */ 124041900Smckusick if ((rep->r_flags & R_TPRINTFMSG) == 0 && 124152196Smckusick rep->r_rexmit > nmp->nm_deadthresh) { 124247737Skarels nfs_msg(rep->r_procp, 124347737Skarels nmp->nm_mountp->mnt_stat.f_mntfromname, 124447737Skarels "not responding"); 124541900Smckusick rep->r_flags |= R_TPRINTFMSG; 124641900Smckusick } 124743351Smckusick if (rep->r_rexmit >= rep->r_retry) { /* too many */ 124841900Smckusick nfsstats.rpctimeouts++; 124941900Smckusick rep->r_flags |= R_SOFTTERM; 125041900Smckusick continue; 125141900Smckusick } 125252196Smckusick if (nmp->nm_sotype != SOCK_DGRAM) { 125352196Smckusick if (++rep->r_rexmit > NFS_MAXREXMIT) 125452196Smckusick rep->r_rexmit = NFS_MAXREXMIT; 125543351Smckusick continue; 125652196Smckusick } 125752196Smckusick if ((so = nmp->nm_so) == NULL) 125852196Smckusick continue; 125941900Smckusick 126041900Smckusick /* 126141900Smckusick * If there is enough space and the window allows.. 126241900Smckusick * Resend it 126352196Smckusick * Set r_rtt to -1 in case we fail to send it now. 126441900Smckusick */ 126552196Smckusick rep->r_rtt = -1; 126641900Smckusick if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && 126752196Smckusick ((nmp->nm_flag & NFSMNT_DUMBTIMR) || 126852196Smckusick (rep->r_flags & R_SENT) || 126952196Smckusick nmp->nm_sent < nmp->nm_cwnd) && 127052196Smckusick (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){ 127141900Smckusick if ((nmp->nm_flag & NFSMNT_NOCONN) == 0) 127241900Smckusick error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, 127352196Smckusick (struct mbuf *)0, (struct mbuf *)0); 127441900Smckusick else 127541900Smckusick error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m, 127652196Smckusick nmp->nm_nam, (struct mbuf *)0); 127741900Smckusick if (error) { 127841900Smckusick if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) 127941900Smckusick so->so_error = 0; 128041900Smckusick } else { 128141900Smckusick /* 128252196Smckusick * Iff first send, start timing 128352196Smckusick * else turn timing off, backoff timer 128452196Smckusick * and divide congestion window by 2. 128541900Smckusick */ 128652196Smckusick if (rep->r_flags & R_SENT) { 128752196Smckusick rep->r_flags &= ~R_TIMING; 128852196Smckusick if (++rep->r_rexmit > NFS_MAXREXMIT) 128952196Smckusick rep->r_rexmit = NFS_MAXREXMIT; 129052196Smckusick nmp->nm_cwnd >>= 1; 129152196Smckusick if (nmp->nm_cwnd < NFS_CWNDSCALE) 129252196Smckusick nmp->nm_cwnd = NFS_CWNDSCALE; 129352196Smckusick nfsstats.rpcretries++; 129452196Smckusick } else { 129552196Smckusick rep->r_flags |= R_SENT; 129652196Smckusick nmp->nm_sent += NFS_CWNDSCALE; 129752196Smckusick } 129852196Smckusick rep->r_rtt = 0; 129941900Smckusick } 130041900Smckusick } 130140117Smckusick } 130252196Smckusick 130352196Smckusick /* 130452196Smckusick * Call the nqnfs server timer once a second to handle leases. 130552196Smckusick */ 130652196Smckusick if (lasttime != time.tv_sec) { 130752196Smckusick lasttime = time.tv_sec; 130852196Smckusick nqnfs_serverd(); 130952196Smckusick } 131040117Smckusick splx(s); 131159387Smckusick timeout(nfs_timer, (void *)0, hz / NFS_HZ); 131240117Smckusick } 131340117Smckusick 131440117Smckusick /* 131552196Smckusick * Test for a termination condition pending on the process. 131652196Smckusick * This is used for NFSMNT_INT mounts. 131740117Smckusick */ 131852196Smckusick nfs_sigintr(nmp, rep, p) 131952196Smckusick struct nfsmount *nmp; 132052196Smckusick struct nfsreq *rep; 132152196Smckusick register struct proc *p; 132252196Smckusick { 132340117Smckusick 132452196Smckusick if (rep && (rep->r_flags & R_SOFTTERM)) 132552196Smckusick return (EINTR); 132652196Smckusick if (!(nmp->nm_flag & NFSMNT_INT)) 132752196Smckusick return (0); 132864595Sbostic if (p && p->p_siglist && 132964595Sbostic (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) & 133052196Smckusick NFSINT_SIGMASK)) 133152196Smckusick return (EINTR); 133252196Smckusick return (0); 133352196Smckusick } 133452196Smckusick 133540117Smckusick /* 133652196Smckusick * Lock a socket against others. 133752196Smckusick * Necessary for STREAM sockets to ensure you get an entire rpc request/reply 133852196Smckusick * and also to avoid race conditions between the processes with nfs requests 133952196Smckusick * in progress when a reconnect is necessary. 134040117Smckusick */ 134152196Smckusick nfs_sndlock(flagp, rep) 134252196Smckusick register int *flagp; 134352196Smckusick struct nfsreq *rep; 134452196Smckusick { 134552196Smckusick struct proc *p; 134657786Smckusick int slpflag = 0, slptimeo = 0; 134740117Smckusick 134857786Smckusick if (rep) { 134952196Smckusick p = rep->r_procp; 135057786Smckusick if (rep->r_nmp->nm_flag & NFSMNT_INT) 135157786Smckusick slpflag = PCATCH; 135257786Smckusick } else 135352196Smckusick p = (struct proc *)0; 135452196Smckusick while (*flagp & NFSMNT_SNDLOCK) { 135552196Smckusick if (nfs_sigintr(rep->r_nmp, rep, p)) 135652196Smckusick return (EINTR); 135752196Smckusick *flagp |= NFSMNT_WANTSND; 135857786Smckusick (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsndlck", 135957786Smckusick slptimeo); 136057786Smckusick if (slpflag == PCATCH) { 136157786Smckusick slpflag = 0; 136257786Smckusick slptimeo = 2 * hz; 136357786Smckusick } 136452196Smckusick } 136552196Smckusick *flagp |= NFSMNT_SNDLOCK; 136652196Smckusick return (0); 136752196Smckusick } 136852196Smckusick 136952196Smckusick /* 137052196Smckusick * Unlock the stream socket for others. 137152196Smckusick */ 137252196Smckusick void 137352196Smckusick nfs_sndunlock(flagp) 137452196Smckusick register int *flagp; 137540117Smckusick { 137640117Smckusick 137752196Smckusick if ((*flagp & NFSMNT_SNDLOCK) == 0) 137852196Smckusick panic("nfs sndunlock"); 137952196Smckusick *flagp &= ~NFSMNT_SNDLOCK; 138052196Smckusick if (*flagp & NFSMNT_WANTSND) { 138152196Smckusick *flagp &= ~NFSMNT_WANTSND; 138252196Smckusick wakeup((caddr_t)flagp); 138340117Smckusick } 138452196Smckusick } 138552196Smckusick 138652196Smckusick nfs_rcvlock(rep) 138752196Smckusick register struct nfsreq *rep; 138852196Smckusick { 138952196Smckusick register int *flagp = &rep->r_nmp->nm_flag; 139057786Smckusick int slpflag, slptimeo = 0; 139152196Smckusick 139257786Smckusick if (*flagp & NFSMNT_INT) 139357786Smckusick slpflag = PCATCH; 139457786Smckusick else 139557786Smckusick slpflag = 0; 139652196Smckusick while (*flagp & NFSMNT_RCVLOCK) { 139752196Smckusick if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp)) 139852196Smckusick return (EINTR); 139952196Smckusick *flagp |= NFSMNT_WANTRCV; 140057786Smckusick (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsrcvlk", 140157786Smckusick slptimeo); 140257786Smckusick if (slpflag == PCATCH) { 140357786Smckusick slpflag = 0; 140457786Smckusick slptimeo = 2 * hz; 140557786Smckusick } 140640117Smckusick } 140752196Smckusick *flagp |= NFSMNT_RCVLOCK; 140852196Smckusick return (0); 140952196Smckusick } 141040117Smckusick 141152196Smckusick /* 141252196Smckusick * Unlock the stream socket for others. 141352196Smckusick */ 141452196Smckusick void 141552196Smckusick nfs_rcvunlock(flagp) 141652196Smckusick register int *flagp; 141752196Smckusick { 141852196Smckusick 141952196Smckusick if ((*flagp & NFSMNT_RCVLOCK) == 0) 142052196Smckusick panic("nfs rcvunlock"); 142152196Smckusick *flagp &= ~NFSMNT_RCVLOCK; 142252196Smckusick if (*flagp & NFSMNT_WANTRCV) { 142352196Smckusick *flagp &= ~NFSMNT_WANTRCV; 142452196Smckusick wakeup((caddr_t)flagp); 142552196Smckusick } 142652196Smckusick } 142752196Smckusick 142852196Smckusick /* 142952196Smckusick * Check for badly aligned mbuf data areas and 143052196Smckusick * realign data in an mbuf list by copying the data areas up, as required. 143152196Smckusick */ 143252196Smckusick void 143352196Smckusick nfs_realign(m, hsiz) 143452196Smckusick register struct mbuf *m; 143552196Smckusick int hsiz; 143647737Skarels { 143752196Smckusick register struct mbuf *m2; 143852196Smckusick register int siz, mlen, olen; 143952196Smckusick register caddr_t tcp, fcp; 144052196Smckusick struct mbuf *mnew; 144147737Skarels 144252196Smckusick while (m) { 144352196Smckusick /* 144452196Smckusick * This never happens for UDP, rarely happens for TCP 144552196Smckusick * but frequently happens for iso transport. 144652196Smckusick */ 144752196Smckusick if ((m->m_len & 0x3) || (mtod(m, int) & 0x3)) { 144852196Smckusick olen = m->m_len; 144952196Smckusick fcp = mtod(m, caddr_t); 145063481Smckusick if ((int)fcp & 0x3) { 145163481Smckusick m->m_flags &= ~M_PKTHDR; 145263481Smckusick if (m->m_flags & M_EXT) 145363481Smckusick m->m_data = m->m_ext.ext_buf + 145463481Smckusick ((m->m_ext.ext_size - olen) & ~0x3); 145563481Smckusick else 145663481Smckusick m->m_data = m->m_dat; 145763481Smckusick } 145852196Smckusick m->m_len = 0; 145952196Smckusick tcp = mtod(m, caddr_t); 146052196Smckusick mnew = m; 146152196Smckusick m2 = m->m_next; 146252196Smckusick 146352196Smckusick /* 146452196Smckusick * If possible, only put the first invariant part 146552196Smckusick * of the RPC header in the first mbuf. 146652196Smckusick */ 146763481Smckusick mlen = M_TRAILINGSPACE(m); 146863481Smckusick if (olen <= hsiz && mlen > hsiz) 146952196Smckusick mlen = hsiz; 147052196Smckusick 147152196Smckusick /* 147252196Smckusick * Loop through the mbuf list consolidating data. 147352196Smckusick */ 147452196Smckusick while (m) { 147552196Smckusick while (olen > 0) { 147652196Smckusick if (mlen == 0) { 147752196Smckusick m2->m_flags &= ~M_PKTHDR; 147852196Smckusick if (m2->m_flags & M_EXT) 147952196Smckusick m2->m_data = m2->m_ext.ext_buf; 148052196Smckusick else 148152196Smckusick m2->m_data = m2->m_dat; 148252196Smckusick m2->m_len = 0; 148352196Smckusick mlen = M_TRAILINGSPACE(m2); 148452196Smckusick tcp = mtod(m2, caddr_t); 148552196Smckusick mnew = m2; 148652196Smckusick m2 = m2->m_next; 148752196Smckusick } 148855057Spendry siz = min(mlen, olen); 148952196Smckusick if (tcp != fcp) 149052196Smckusick bcopy(fcp, tcp, siz); 149152196Smckusick mnew->m_len += siz; 149252196Smckusick mlen -= siz; 149352196Smckusick olen -= siz; 149452196Smckusick tcp += siz; 149552196Smckusick fcp += siz; 149652196Smckusick } 149752196Smckusick m = m->m_next; 149852196Smckusick if (m) { 149952196Smckusick olen = m->m_len; 150052196Smckusick fcp = mtod(m, caddr_t); 150152196Smckusick } 150252196Smckusick } 150352196Smckusick 150452196Smckusick /* 150552196Smckusick * Finally, set m_len == 0 for any trailing mbufs that have 150652196Smckusick * been copied out of. 150752196Smckusick */ 150852196Smckusick while (m2) { 150952196Smckusick m2->m_len = 0; 151052196Smckusick m2 = m2->m_next; 151152196Smckusick } 151252196Smckusick return; 151352196Smckusick } 151452196Smckusick m = m->m_next; 151552196Smckusick } 151647737Skarels } 151747737Skarels 151841900Smckusick /* 151952196Smckusick * Socket upcall routine for the nfsd sockets. 152052196Smckusick * The caddr_t arg is a pointer to the "struct nfssvc_sock". 152152196Smckusick * Essentially do as much as possible non-blocking, else punt and it will 152252196Smckusick * be called with M_WAIT from an nfsd. 152341900Smckusick */ 152452196Smckusick void 152552196Smckusick nfsrv_rcv(so, arg, waitflag) 152652196Smckusick struct socket *so; 152752196Smckusick caddr_t arg; 152852196Smckusick int waitflag; 152938414Smckusick { 153052196Smckusick register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg; 153152196Smckusick register struct mbuf *m; 153252196Smckusick struct mbuf *mp, *nam; 153352196Smckusick struct uio auio; 153452196Smckusick int flags, error; 153540117Smckusick 153652903Smckusick if ((slp->ns_flag & SLP_VALID) == 0) 153752903Smckusick return; 153852903Smckusick #ifdef notdef 153952903Smckusick /* 154052903Smckusick * Define this to test for nfsds handling this under heavy load. 154152903Smckusick */ 154252903Smckusick if (waitflag == M_DONTWAIT) { 154352903Smckusick slp->ns_flag |= SLP_NEEDQ; goto dorecs; 154452903Smckusick } 154552903Smckusick #endif 154652932Smckusick auio.uio_procp = NULL; 154752196Smckusick if (so->so_type == SOCK_STREAM) { 154852196Smckusick /* 154952196Smckusick * If there are already records on the queue, defer soreceive() 155052196Smckusick * to an nfsd so that there is feedback to the TCP layer that 155152196Smckusick * the nfs servers are heavily loaded. 155252196Smckusick */ 155352196Smckusick if (slp->ns_rec && waitflag == M_DONTWAIT) { 155452196Smckusick slp->ns_flag |= SLP_NEEDQ; 155552903Smckusick goto dorecs; 155652196Smckusick } 155752196Smckusick 155852196Smckusick /* 155952196Smckusick * Do soreceive(). 156052196Smckusick */ 156152196Smckusick auio.uio_resid = 1000000000; 156252196Smckusick flags = MSG_DONTWAIT; 156352196Smckusick error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags); 156452196Smckusick if (error || mp == (struct mbuf *)0) { 156552903Smckusick if (error == EWOULDBLOCK) 156652903Smckusick slp->ns_flag |= SLP_NEEDQ; 156752903Smckusick else 156852196Smckusick slp->ns_flag |= SLP_DISCONN; 156952196Smckusick goto dorecs; 157052196Smckusick } 157152196Smckusick m = mp; 157252196Smckusick if (slp->ns_rawend) { 157352196Smckusick slp->ns_rawend->m_next = m; 157452196Smckusick slp->ns_cc += 1000000000 - auio.uio_resid; 157552196Smckusick } else { 157652196Smckusick slp->ns_raw = m; 157752196Smckusick slp->ns_cc = 1000000000 - auio.uio_resid; 157852196Smckusick } 157952196Smckusick while (m->m_next) 158052196Smckusick m = m->m_next; 158152196Smckusick slp->ns_rawend = m; 158252196Smckusick 158352196Smckusick /* 158452196Smckusick * Now try and parse record(s) out of the raw stream data. 158552196Smckusick */ 158652196Smckusick if (error = nfsrv_getstream(slp, waitflag)) { 158752196Smckusick if (error == EPERM) 158852196Smckusick slp->ns_flag |= SLP_DISCONN; 158952903Smckusick else 159052196Smckusick slp->ns_flag |= SLP_NEEDQ; 159152196Smckusick } 159252196Smckusick } else { 159352196Smckusick do { 159452196Smckusick auio.uio_resid = 1000000000; 159552196Smckusick flags = MSG_DONTWAIT; 159652196Smckusick error = soreceive(so, &nam, &auio, &mp, 159752196Smckusick (struct mbuf **)0, &flags); 159852196Smckusick if (mp) { 159952196Smckusick nfs_realign(mp, 10 * NFSX_UNSIGNED); 160052196Smckusick if (nam) { 160152196Smckusick m = nam; 160252196Smckusick m->m_next = mp; 160352196Smckusick } else 160452196Smckusick m = mp; 160552196Smckusick if (slp->ns_recend) 160652196Smckusick slp->ns_recend->m_nextpkt = m; 160752196Smckusick else 160852196Smckusick slp->ns_rec = m; 160952196Smckusick slp->ns_recend = m; 161052196Smckusick m->m_nextpkt = (struct mbuf *)0; 161152196Smckusick } 161252196Smckusick if (error) { 161352196Smckusick if ((so->so_proto->pr_flags & PR_CONNREQUIRED) 161452196Smckusick && error != EWOULDBLOCK) { 161552196Smckusick slp->ns_flag |= SLP_DISCONN; 161652903Smckusick goto dorecs; 161752196Smckusick } 161852196Smckusick } 161952196Smckusick } while (mp); 162040117Smckusick } 162152196Smckusick 162252196Smckusick /* 162352196Smckusick * Now try and process the request records, non-blocking. 162452196Smckusick */ 162552196Smckusick dorecs: 162652903Smckusick if (waitflag == M_DONTWAIT && 162752903Smckusick (slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) 162852196Smckusick nfsrv_wakenfsd(slp); 162941900Smckusick } 163040117Smckusick 163141900Smckusick /* 163252196Smckusick * Try and extract an RPC request from the mbuf data list received on a 163352196Smckusick * stream socket. The "waitflag" argument indicates whether or not it 163452196Smckusick * can sleep. 163541900Smckusick */ 163652196Smckusick nfsrv_getstream(slp, waitflag) 163752196Smckusick register struct nfssvc_sock *slp; 163852196Smckusick int waitflag; 163941900Smckusick { 164052196Smckusick register struct mbuf *m; 164152196Smckusick register char *cp1, *cp2; 164252196Smckusick register int len; 164352196Smckusick struct mbuf *om, *m2, *recm; 164452196Smckusick u_long recmark; 164541900Smckusick 164652196Smckusick if (slp->ns_flag & SLP_GETSTREAM) 164752196Smckusick panic("nfs getstream"); 164852196Smckusick slp->ns_flag |= SLP_GETSTREAM; 164952196Smckusick for (;;) { 165052196Smckusick if (slp->ns_reclen == 0) { 165152196Smckusick if (slp->ns_cc < NFSX_UNSIGNED) { 165252196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 165352196Smckusick return (0); 165452196Smckusick } 165552196Smckusick m = slp->ns_raw; 165652196Smckusick if (m->m_len >= NFSX_UNSIGNED) { 165752196Smckusick bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED); 165852196Smckusick m->m_data += NFSX_UNSIGNED; 165952196Smckusick m->m_len -= NFSX_UNSIGNED; 166052196Smckusick } else { 166152196Smckusick cp1 = (caddr_t)&recmark; 166252196Smckusick cp2 = mtod(m, caddr_t); 166352196Smckusick while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) { 166452196Smckusick while (m->m_len == 0) { 166552196Smckusick m = m->m_next; 166652196Smckusick cp2 = mtod(m, caddr_t); 166752196Smckusick } 166852196Smckusick *cp1++ = *cp2++; 166952196Smckusick m->m_data++; 167052196Smckusick m->m_len--; 167152196Smckusick } 167252196Smckusick } 167352196Smckusick slp->ns_cc -= NFSX_UNSIGNED; 167452196Smckusick slp->ns_reclen = ntohl(recmark) & ~0x80000000; 167552196Smckusick if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) { 167652196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 167752196Smckusick return (EPERM); 167852196Smckusick } 167952196Smckusick } 168052196Smckusick 168152196Smckusick /* 168252196Smckusick * Now get the record part. 168352196Smckusick */ 168452196Smckusick if (slp->ns_cc == slp->ns_reclen) { 168552196Smckusick recm = slp->ns_raw; 168652196Smckusick slp->ns_raw = slp->ns_rawend = (struct mbuf *)0; 168752196Smckusick slp->ns_cc = slp->ns_reclen = 0; 168852196Smckusick } else if (slp->ns_cc > slp->ns_reclen) { 168952196Smckusick len = 0; 169052196Smckusick m = slp->ns_raw; 169152196Smckusick om = (struct mbuf *)0; 169252196Smckusick while (len < slp->ns_reclen) { 169352196Smckusick if ((len + m->m_len) > slp->ns_reclen) { 169452196Smckusick m2 = m_copym(m, 0, slp->ns_reclen - len, 169552196Smckusick waitflag); 169652196Smckusick if (m2) { 169752196Smckusick if (om) { 169852196Smckusick om->m_next = m2; 169952196Smckusick recm = slp->ns_raw; 170052196Smckusick } else 170152196Smckusick recm = m2; 170252196Smckusick m->m_data += slp->ns_reclen - len; 170352196Smckusick m->m_len -= slp->ns_reclen - len; 170452196Smckusick len = slp->ns_reclen; 170552196Smckusick } else { 170652196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 170752196Smckusick return (EWOULDBLOCK); 170852196Smckusick } 170952196Smckusick } else if ((len + m->m_len) == slp->ns_reclen) { 171052196Smckusick om = m; 171152196Smckusick len += m->m_len; 171252196Smckusick m = m->m_next; 171352196Smckusick recm = slp->ns_raw; 171452196Smckusick om->m_next = (struct mbuf *)0; 171552196Smckusick } else { 171652196Smckusick om = m; 171752196Smckusick len += m->m_len; 171852196Smckusick m = m->m_next; 171952196Smckusick } 172052196Smckusick } 172152196Smckusick slp->ns_raw = m; 172252196Smckusick slp->ns_cc -= len; 172352196Smckusick slp->ns_reclen = 0; 172452196Smckusick } else { 172552196Smckusick slp->ns_flag &= ~SLP_GETSTREAM; 172652196Smckusick return (0); 172752196Smckusick } 172852196Smckusick nfs_realign(recm, 10 * NFSX_UNSIGNED); 172952196Smckusick if (slp->ns_recend) 173052196Smckusick slp->ns_recend->m_nextpkt = recm; 173152196Smckusick else 173252196Smckusick slp->ns_rec = recm; 173352196Smckusick slp->ns_recend = recm; 173440117Smckusick } 173538414Smckusick } 173641900Smckusick 173741900Smckusick /* 173852196Smckusick * Parse an RPC header. 173941900Smckusick */ 174052196Smckusick nfsrv_dorec(slp, nd) 174152196Smckusick register struct nfssvc_sock *slp; 174252196Smckusick register struct nfsd *nd; 174341900Smckusick { 174452196Smckusick register struct mbuf *m; 174552196Smckusick int error; 174641900Smckusick 174752903Smckusick if ((slp->ns_flag & SLP_VALID) == 0 || 174852196Smckusick (m = slp->ns_rec) == (struct mbuf *)0) 174952196Smckusick return (ENOBUFS); 175052196Smckusick if (slp->ns_rec = m->m_nextpkt) 175152196Smckusick m->m_nextpkt = (struct mbuf *)0; 175252196Smckusick else 175352196Smckusick slp->ns_recend = (struct mbuf *)0; 175452196Smckusick if (m->m_type == MT_SONAME) { 175552196Smckusick nd->nd_nam = m; 175652196Smckusick nd->nd_md = nd->nd_mrep = m->m_next; 175752196Smckusick m->m_next = (struct mbuf *)0; 175852196Smckusick } else { 175952196Smckusick nd->nd_nam = (struct mbuf *)0; 176052196Smckusick nd->nd_md = nd->nd_mrep = m; 176152196Smckusick } 176252196Smckusick nd->nd_dpos = mtod(nd->nd_md, caddr_t); 176352196Smckusick if (error = nfs_getreq(nd, TRUE)) { 176452196Smckusick m_freem(nd->nd_nam); 176552196Smckusick return (error); 176652196Smckusick } 176752196Smckusick return (0); 176852196Smckusick } 176952196Smckusick 177052196Smckusick /* 177152196Smckusick * Parse an RPC request 177252196Smckusick * - verify it 177352196Smckusick * - fill in the cred struct. 177452196Smckusick */ 177552196Smckusick nfs_getreq(nd, has_header) 177652196Smckusick register struct nfsd *nd; 177752196Smckusick int has_header; 177852196Smckusick { 177952196Smckusick register int len, i; 178052196Smckusick register u_long *tl; 178152196Smckusick register long t1; 178252196Smckusick struct uio uio; 178352196Smckusick struct iovec iov; 178452196Smckusick caddr_t dpos, cp2; 178552196Smckusick u_long nfsvers, auth_type; 178652196Smckusick int error = 0, nqnfs = 0; 178752196Smckusick struct mbuf *mrep, *md; 178852196Smckusick 178952196Smckusick mrep = nd->nd_mrep; 179052196Smckusick md = nd->nd_md; 179152196Smckusick dpos = nd->nd_dpos; 179252196Smckusick if (has_header) { 179352196Smckusick nfsm_dissect(tl, u_long *, 10*NFSX_UNSIGNED); 179452196Smckusick nd->nd_retxid = *tl++; 179552196Smckusick if (*tl++ != rpc_call) { 179652196Smckusick m_freem(mrep); 179752196Smckusick return (EBADRPC); 179852196Smckusick } 179952196Smckusick } else { 180052196Smckusick nfsm_dissect(tl, u_long *, 8*NFSX_UNSIGNED); 180152196Smckusick } 180252196Smckusick nd->nd_repstat = 0; 180352196Smckusick if (*tl++ != rpc_vers) { 180452196Smckusick nd->nd_repstat = ERPCMISMATCH; 180552196Smckusick nd->nd_procnum = NFSPROC_NOOP; 180641900Smckusick return (0); 180752196Smckusick } 180852196Smckusick nfsvers = nfs_vers; 180952196Smckusick if (*tl != nfs_prog) { 181052196Smckusick if (*tl == nqnfs_prog) { 181152196Smckusick nqnfs++; 181252196Smckusick nfsvers = nqnfs_vers; 181352196Smckusick } else { 181452196Smckusick nd->nd_repstat = EPROGUNAVAIL; 181552196Smckusick nd->nd_procnum = NFSPROC_NOOP; 181652196Smckusick return (0); 181752196Smckusick } 181852196Smckusick } 181952196Smckusick tl++; 182052196Smckusick if (*tl++ != nfsvers) { 182152196Smckusick nd->nd_repstat = EPROGMISMATCH; 182252196Smckusick nd->nd_procnum = NFSPROC_NOOP; 182352196Smckusick return (0); 182452196Smckusick } 182552196Smckusick nd->nd_procnum = fxdr_unsigned(u_long, *tl++); 182652196Smckusick if (nd->nd_procnum == NFSPROC_NULL) 182752196Smckusick return (0); 182852196Smckusick if (nd->nd_procnum >= NFS_NPROCS || 182952196Smckusick (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) || 183052196Smckusick (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) { 183152196Smckusick nd->nd_repstat = EPROCUNAVAIL; 183252196Smckusick nd->nd_procnum = NFSPROC_NOOP; 183352196Smckusick return (0); 183452196Smckusick } 183552196Smckusick auth_type = *tl++; 183652196Smckusick len = fxdr_unsigned(int, *tl++); 183752196Smckusick if (len < 0 || len > RPCAUTH_MAXSIZ) { 183852196Smckusick m_freem(mrep); 183952196Smckusick return (EBADRPC); 184052196Smckusick } 184141900Smckusick 184241900Smckusick /* 184352196Smckusick * Handle auth_unix or auth_kerb. 184441900Smckusick */ 184552196Smckusick if (auth_type == rpc_auth_unix) { 184652196Smckusick len = fxdr_unsigned(int, *++tl); 184752196Smckusick if (len < 0 || len > NFS_MAXNAMLEN) { 184852196Smckusick m_freem(mrep); 184952196Smckusick return (EBADRPC); 185052196Smckusick } 185152196Smckusick nfsm_adv(nfsm_rndup(len)); 185252196Smckusick nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 185352196Smckusick nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); 185452196Smckusick nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); 185552196Smckusick len = fxdr_unsigned(int, *tl); 185652196Smckusick if (len < 0 || len > RPCAUTH_UNIXGIDS) { 185752196Smckusick m_freem(mrep); 185852196Smckusick return (EBADRPC); 185952196Smckusick } 186052196Smckusick nfsm_dissect(tl, u_long *, (len + 2)*NFSX_UNSIGNED); 186152196Smckusick for (i = 1; i <= len; i++) 186252196Smckusick if (i < NGROUPS) 186352196Smckusick nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); 186452196Smckusick else 186552196Smckusick tl++; 186652196Smckusick nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); 186752196Smckusick } else if (auth_type == rpc_auth_kerb) { 186852196Smckusick nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); 186952196Smckusick nd->nd_authlen = fxdr_unsigned(int, *tl); 187057786Smckusick uio.uio_resid = nfsm_rndup(nd->nd_authlen); 187157786Smckusick if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { 187252196Smckusick m_freem(mrep); 187352196Smckusick return (EBADRPC); 187452196Smckusick } 187552196Smckusick uio.uio_offset = 0; 187652196Smckusick uio.uio_iov = &iov; 187752196Smckusick uio.uio_iovcnt = 1; 187852196Smckusick uio.uio_segflg = UIO_SYSSPACE; 187952196Smckusick iov.iov_base = (caddr_t)nd->nd_authstr; 188057786Smckusick iov.iov_len = RPCAUTH_MAXSIZ; 188152196Smckusick nfsm_mtouio(&uio, uio.uio_resid); 188257786Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); 188352196Smckusick nd->nd_flag |= NFSD_NEEDAUTH; 188452196Smckusick } 188552196Smckusick 188652196Smckusick /* 188752196Smckusick * Do we have any use for the verifier. 188852196Smckusick * According to the "Remote Procedure Call Protocol Spec." it 188952196Smckusick * should be AUTH_NULL, but some clients make it AUTH_UNIX? 189052196Smckusick * For now, just skip over it 189152196Smckusick */ 189252196Smckusick len = fxdr_unsigned(int, *++tl); 189352196Smckusick if (len < 0 || len > RPCAUTH_MAXSIZ) { 189452196Smckusick m_freem(mrep); 189552196Smckusick return (EBADRPC); 189652196Smckusick } 189752196Smckusick if (len > 0) { 189852196Smckusick nfsm_adv(nfsm_rndup(len)); 189952196Smckusick } 190052196Smckusick 190152196Smckusick /* 190252196Smckusick * For nqnfs, get piggybacked lease request. 190352196Smckusick */ 190452196Smckusick if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { 190552196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 190652196Smckusick nd->nd_nqlflag = fxdr_unsigned(int, *tl); 190752196Smckusick if (nd->nd_nqlflag) { 190852196Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 190952196Smckusick nd->nd_duration = fxdr_unsigned(int, *tl); 191052196Smckusick } else 191152196Smckusick nd->nd_duration = NQ_MINLEASE; 191252196Smckusick } else { 191352196Smckusick nd->nd_nqlflag = NQL_NOVAL; 191452196Smckusick nd->nd_duration = NQ_MINLEASE; 191552196Smckusick } 191652196Smckusick nd->nd_md = md; 191752196Smckusick nd->nd_dpos = dpos; 191841900Smckusick return (0); 191952196Smckusick nfsmout: 192052196Smckusick return (error); 192141900Smckusick } 192241900Smckusick 192341900Smckusick /* 192452196Smckusick * Search for a sleeping nfsd and wake it up. 192552196Smckusick * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the 192652196Smckusick * running nfsds will go look for the work in the nfssvc_sock list. 192741900Smckusick */ 192852196Smckusick void 192952196Smckusick nfsrv_wakenfsd(slp) 193052196Smckusick struct nfssvc_sock *slp; 193141900Smckusick { 193252196Smckusick register struct nfsd *nd = nfsd_head.nd_next; 193352196Smckusick 193452903Smckusick if ((slp->ns_flag & SLP_VALID) == 0) 193552903Smckusick return; 193652196Smckusick while (nd != (struct nfsd *)&nfsd_head) { 193752196Smckusick if (nd->nd_flag & NFSD_WAITING) { 193852196Smckusick nd->nd_flag &= ~NFSD_WAITING; 193952196Smckusick if (nd->nd_slp) 194052196Smckusick panic("nfsd wakeup"); 194152978Smckusick slp->ns_sref++; 194252196Smckusick nd->nd_slp = slp; 194352196Smckusick wakeup((caddr_t)nd); 194452196Smckusick return; 194552196Smckusick } 194652196Smckusick nd = nd->nd_next; 194752196Smckusick } 194852903Smckusick slp->ns_flag |= SLP_DOREC; 194952196Smckusick nfsd_head.nd_flag |= NFSD_CHECKSLP; 195041900Smckusick } 195152196Smckusick 195252196Smckusick nfs_msg(p, server, msg) 195352196Smckusick struct proc *p; 195452196Smckusick char *server, *msg; 195552196Smckusick { 195652196Smckusick tpr_t tpr; 195752196Smckusick 195852196Smckusick if (p) 195952196Smckusick tpr = tprintf_open(p); 196052196Smckusick else 196152196Smckusick tpr = NULL; 196252196Smckusick tprintf(tpr, "nfs server %s: %s\n", server, msg); 196352196Smckusick tprintf_close(tpr); 196452196Smckusick } 1965