nfs_socket.c revision 1.24 1 1.24 fvdl /* $NetBSD: nfs_socket.c,v 1.24 1996/02/18 11:53:48 fvdl Exp $ */
2 1.15 cgd
3 1.1 cgd /*
4 1.24 fvdl * Copyright (c) 1989, 1991, 1993, 1995
5 1.14 mycroft * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * Rick Macklem at The University of Guelph.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.1 cgd * 3. All advertising materials mentioning features or use of this software
19 1.1 cgd * must display the following acknowledgement:
20 1.1 cgd * This product includes software developed by the University of
21 1.1 cgd * California, Berkeley and its contributors.
22 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
23 1.1 cgd * may be used to endorse or promote products derived from this software
24 1.1 cgd * without specific prior written permission.
25 1.1 cgd *
26 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 1.1 cgd * SUCH DAMAGE.
37 1.1 cgd *
38 1.24 fvdl * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95
39 1.1 cgd */
40 1.1 cgd
41 1.1 cgd /*
42 1.1 cgd * Socket operations for use by nfs
43 1.1 cgd */
44 1.1 cgd
45 1.9 mycroft #include <sys/param.h>
46 1.9 mycroft #include <sys/systm.h>
47 1.9 mycroft #include <sys/proc.h>
48 1.9 mycroft #include <sys/mount.h>
49 1.9 mycroft #include <sys/kernel.h>
50 1.9 mycroft #include <sys/mbuf.h>
51 1.9 mycroft #include <sys/vnode.h>
52 1.9 mycroft #include <sys/domain.h>
53 1.9 mycroft #include <sys/protosw.h>
54 1.9 mycroft #include <sys/socket.h>
55 1.9 mycroft #include <sys/socketvar.h>
56 1.9 mycroft #include <sys/syslog.h>
57 1.9 mycroft #include <sys/tprintf.h>
58 1.23 christos #include <sys/namei.h>
59 1.1 cgd
60 1.9 mycroft #include <netinet/in.h>
61 1.9 mycroft #include <netinet/tcp.h>
62 1.24 fvdl
63 1.9 mycroft #include <nfs/rpcv2.h>
64 1.24 fvdl #include <nfs/nfsproto.h>
65 1.9 mycroft #include <nfs/nfs.h>
66 1.9 mycroft #include <nfs/xdr_subs.h>
67 1.9 mycroft #include <nfs/nfsm_subs.h>
68 1.9 mycroft #include <nfs/nfsmount.h>
69 1.14 mycroft #include <nfs/nfsnode.h>
70 1.14 mycroft #include <nfs/nfsrtt.h>
71 1.14 mycroft #include <nfs/nqnfs.h>
72 1.23 christos #include <nfs/nfs_var.h>
73 1.1 cgd
74 1.1 cgd #define TRUE 1
75 1.1 cgd #define FALSE 0
76 1.1 cgd
77 1.1 cgd /*
78 1.14 mycroft * Estimate rto for an nfs rpc sent via. an unreliable datagram.
79 1.14 mycroft * Use the mean and mean deviation of rtt for the appropriate type of rpc
80 1.14 mycroft * for the frequent rpcs and a default for the others.
81 1.14 mycroft * The justification for doing "other" this way is that these rpcs
82 1.14 mycroft * happen so infrequently that timer est. would probably be stale.
83 1.14 mycroft * Also, since many of these rpcs are
84 1.14 mycroft * non-idempotent, a conservative timeout is desired.
85 1.14 mycroft * getattr, lookup - A+2D
86 1.14 mycroft * read, write - A+4D
87 1.14 mycroft * other - nm_timeo
88 1.14 mycroft */
89 1.14 mycroft #define NFS_RTO(n, t) \
90 1.14 mycroft ((t) == 0 ? (n)->nm_timeo : \
91 1.14 mycroft ((t) < 3 ? \
92 1.14 mycroft (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \
93 1.14 mycroft ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1)))
94 1.14 mycroft #define NFS_SRTT(r) (r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1]
95 1.14 mycroft #define NFS_SDRTT(r) (r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1]
96 1.14 mycroft /*
97 1.1 cgd * External data, mostly RPC constants in XDR form
98 1.1 cgd */
99 1.22 cgd extern u_int32_t rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers,
100 1.24 fvdl rpc_auth_unix, rpc_msgaccepted, rpc_call, rpc_autherr,
101 1.14 mycroft rpc_auth_kerb;
102 1.24 fvdl extern u_int32_t nfs_prog, nqnfs_prog;
103 1.14 mycroft extern time_t nqnfsstarttime;
104 1.24 fvdl extern struct nfsstats nfsstats;
105 1.24 fvdl extern int nfsv3_procid[NFS_NPROCS];
106 1.24 fvdl extern int nfs_ticks;
107 1.14 mycroft
108 1.14 mycroft /*
109 1.14 mycroft * Defines which timer to use for the procnum.
110 1.14 mycroft * 0 - default
111 1.14 mycroft * 1 - getattr
112 1.14 mycroft * 2 - lookup
113 1.14 mycroft * 3 - read
114 1.14 mycroft * 4 - write
115 1.14 mycroft */
116 1.14 mycroft static int proct[NFS_NPROCS] = {
117 1.24 fvdl 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0,
118 1.24 fvdl 0, 0, 0,
119 1.1 cgd };
120 1.14 mycroft
121 1.14 mycroft /*
122 1.14 mycroft * There is a congestion window for outstanding rpcs maintained per mount
123 1.14 mycroft * point. The cwnd size is adjusted in roughly the way that:
124 1.14 mycroft * Van Jacobson, Congestion avoidance and Control, In "Proceedings of
125 1.14 mycroft * SIGCOMM '88". ACM, August 1988.
126 1.14 mycroft * describes for TCP. The cwnd size is chopped in half on a retransmit timeout
127 1.14 mycroft * and incremented by 1/cwnd when each rpc reply is received and a full cwnd
128 1.14 mycroft * of rpcs is in progress.
129 1.14 mycroft * (The sent count and cwnd are scaled for integer arith.)
130 1.14 mycroft * Variants of "slow start" were tried and were found to be too much of a
131 1.14 mycroft * performance hit (ave. rtt 3 times larger),
132 1.14 mycroft * I suspect due to the large rtt that nfs rpcs have.
133 1.14 mycroft */
134 1.14 mycroft #define NFS_CWNDSCALE 256
135 1.14 mycroft #define NFS_MAXCWND (NFS_CWNDSCALE * 32)
136 1.14 mycroft static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };
137 1.14 mycroft int nfsrtton = 0;
138 1.14 mycroft struct nfsrtt nfsrtt;
139 1.1 cgd
140 1.1 cgd /*
141 1.1 cgd * Initialize sockets and congestion for a new NFS connection.
142 1.1 cgd * We do not free the sockaddr if error.
143 1.1 cgd */
144 1.23 christos int
145 1.14 mycroft nfs_connect(nmp, rep)
146 1.1 cgd register struct nfsmount *nmp;
147 1.14 mycroft struct nfsreq *rep;
148 1.1 cgd {
149 1.1 cgd register struct socket *so;
150 1.14 mycroft int s, error, rcvreserve, sndreserve;
151 1.11 cgd struct sockaddr *saddr;
152 1.14 mycroft struct sockaddr_in *sin;
153 1.1 cgd struct mbuf *m;
154 1.22 cgd u_int16_t tport;
155 1.1 cgd
156 1.1 cgd nmp->nm_so = (struct socket *)0;
157 1.11 cgd saddr = mtod(nmp->nm_nam, struct sockaddr *);
158 1.24 fvdl error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype,
159 1.24 fvdl nmp->nm_soproto);
160 1.23 christos if (error)
161 1.1 cgd goto bad;
162 1.1 cgd so = nmp->nm_so;
163 1.1 cgd nmp->nm_soflags = so->so_proto->pr_flags;
164 1.1 cgd
165 1.2 cgd /*
166 1.2 cgd * Some servers require that the client port be a reserved port number.
167 1.2 cgd */
168 1.14 mycroft if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
169 1.2 cgd MGET(m, M_WAIT, MT_SONAME);
170 1.2 cgd sin = mtod(m, struct sockaddr_in *);
171 1.2 cgd sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
172 1.2 cgd sin->sin_family = AF_INET;
173 1.2 cgd sin->sin_addr.s_addr = INADDR_ANY;
174 1.2 cgd tport = IPPORT_RESERVED - 1;
175 1.2 cgd sin->sin_port = htons(tport);
176 1.14 mycroft while ((error = sobind(so, m)) == EADDRINUSE &&
177 1.2 cgd --tport > IPPORT_RESERVED / 2)
178 1.2 cgd sin->sin_port = htons(tport);
179 1.2 cgd m_freem(m);
180 1.14 mycroft if (error)
181 1.14 mycroft goto bad;
182 1.2 cgd }
183 1.2 cgd
184 1.1 cgd /*
185 1.1 cgd * Protocols that do not require connections may be optionally left
186 1.1 cgd * unconnected for servers that reply from a port other than NFS_PORT.
187 1.1 cgd */
188 1.1 cgd if (nmp->nm_flag & NFSMNT_NOCONN) {
189 1.1 cgd if (nmp->nm_soflags & PR_CONNREQUIRED) {
190 1.1 cgd error = ENOTCONN;
191 1.1 cgd goto bad;
192 1.1 cgd }
193 1.1 cgd } else {
194 1.24 fvdl error = soconnect(so, nmp->nm_nam);
195 1.24 fvdl if (error)
196 1.1 cgd goto bad;
197 1.1 cgd
198 1.1 cgd /*
199 1.1 cgd * Wait for the connection to complete. Cribbed from the
200 1.14 mycroft * connect system call but with the wait timing out so
201 1.14 mycroft * that interruptible mounts don't hang here for a long time.
202 1.1 cgd */
203 1.21 mycroft s = splsoftnet();
204 1.14 mycroft while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
205 1.14 mycroft (void) tsleep((caddr_t)&so->so_timeo, PSOCK,
206 1.14 mycroft "nfscon", 2 * hz);
207 1.14 mycroft if ((so->so_state & SS_ISCONNECTING) &&
208 1.14 mycroft so->so_error == 0 && rep &&
209 1.24 fvdl (error = nfs_sigintr(nmp, rep, rep->r_procp)) != 0){
210 1.14 mycroft so->so_state &= ~SS_ISCONNECTING;
211 1.14 mycroft splx(s);
212 1.14 mycroft goto bad;
213 1.14 mycroft }
214 1.14 mycroft }
215 1.1 cgd if (so->so_error) {
216 1.1 cgd error = so->so_error;
217 1.14 mycroft so->so_error = 0;
218 1.14 mycroft splx(s);
219 1.1 cgd goto bad;
220 1.1 cgd }
221 1.14 mycroft splx(s);
222 1.14 mycroft }
223 1.14 mycroft if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) {
224 1.14 mycroft so->so_rcv.sb_timeo = (5 * hz);
225 1.14 mycroft so->so_snd.sb_timeo = (5 * hz);
226 1.14 mycroft } else {
227 1.14 mycroft so->so_rcv.sb_timeo = 0;
228 1.14 mycroft so->so_snd.sb_timeo = 0;
229 1.1 cgd }
230 1.1 cgd if (nmp->nm_sotype == SOCK_DGRAM) {
231 1.14 mycroft sndreserve = nmp->nm_wsize + NFS_MAXPKTHDR;
232 1.14 mycroft rcvreserve = nmp->nm_rsize + NFS_MAXPKTHDR;
233 1.14 mycroft } else if (nmp->nm_sotype == SOCK_SEQPACKET) {
234 1.14 mycroft sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 2;
235 1.14 mycroft rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR) * 2;
236 1.1 cgd } else {
237 1.14 mycroft if (nmp->nm_sotype != SOCK_STREAM)
238 1.14 mycroft panic("nfscon sotype");
239 1.1 cgd if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
240 1.1 cgd MGET(m, M_WAIT, MT_SOOPTS);
241 1.22 cgd *mtod(m, int32_t *) = 1;
242 1.22 cgd m->m_len = sizeof(int32_t);
243 1.1 cgd sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
244 1.1 cgd }
245 1.14 mycroft if (so->so_proto->pr_protocol == IPPROTO_TCP) {
246 1.1 cgd MGET(m, M_WAIT, MT_SOOPTS);
247 1.22 cgd *mtod(m, int32_t *) = 1;
248 1.22 cgd m->m_len = sizeof(int32_t);
249 1.1 cgd sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
250 1.1 cgd }
251 1.22 cgd sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
252 1.22 cgd sizeof (u_int32_t)) * 2;
253 1.22 cgd rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
254 1.22 cgd sizeof (u_int32_t)) * 2;
255 1.1 cgd }
256 1.24 fvdl error = soreserve(so, sndreserve, rcvreserve);
257 1.24 fvdl if (error)
258 1.14 mycroft goto bad;
259 1.1 cgd so->so_rcv.sb_flags |= SB_NOINTR;
260 1.1 cgd so->so_snd.sb_flags |= SB_NOINTR;
261 1.1 cgd
262 1.1 cgd /* Initialize other non-zero congestion variables */
263 1.14 mycroft nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] =
264 1.14 mycroft nmp->nm_srtt[4] = (NFS_TIMEO << 3);
265 1.14 mycroft nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] =
266 1.14 mycroft nmp->nm_sdrtt[3] = nmp->nm_sdrtt[4] = 0;
267 1.14 mycroft nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */
268 1.1 cgd nmp->nm_sent = 0;
269 1.14 mycroft nmp->nm_timeouts = 0;
270 1.1 cgd return (0);
271 1.1 cgd
272 1.1 cgd bad:
273 1.1 cgd nfs_disconnect(nmp);
274 1.1 cgd return (error);
275 1.1 cgd }
276 1.1 cgd
277 1.1 cgd /*
278 1.1 cgd * Reconnect routine:
279 1.1 cgd * Called when a connection is broken on a reliable protocol.
280 1.1 cgd * - clean up the old socket
281 1.1 cgd * - nfs_connect() again
282 1.1 cgd * - set R_MUSTRESEND for all outstanding requests on mount point
283 1.1 cgd * If this fails the mount point is DEAD!
284 1.14 mycroft * nb: Must be called with the nfs_sndlock() set on the mount point.
285 1.1 cgd */
286 1.23 christos int
287 1.14 mycroft nfs_reconnect(rep)
288 1.1 cgd register struct nfsreq *rep;
289 1.1 cgd {
290 1.1 cgd register struct nfsreq *rp;
291 1.14 mycroft register struct nfsmount *nmp = rep->r_nmp;
292 1.1 cgd int error;
293 1.1 cgd
294 1.14 mycroft nfs_disconnect(nmp);
295 1.23 christos while ((error = nfs_connect(nmp, rep)) != 0) {
296 1.14 mycroft if (error == EINTR || error == ERESTART)
297 1.1 cgd return (EINTR);
298 1.1 cgd (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0);
299 1.1 cgd }
300 1.1 cgd
301 1.1 cgd /*
302 1.1 cgd * Loop through outstanding request list and fix up all requests
303 1.1 cgd * on old socket.
304 1.1 cgd */
305 1.16 mycroft for (rp = nfs_reqq.tqh_first; rp != 0; rp = rp->r_chain.tqe_next) {
306 1.1 cgd if (rp->r_nmp == nmp)
307 1.1 cgd rp->r_flags |= R_MUSTRESEND;
308 1.1 cgd }
309 1.1 cgd return (0);
310 1.1 cgd }
311 1.1 cgd
312 1.1 cgd /*
313 1.1 cgd * NFS disconnect. Clean up and unlink.
314 1.1 cgd */
315 1.1 cgd void
316 1.1 cgd nfs_disconnect(nmp)
317 1.1 cgd register struct nfsmount *nmp;
318 1.1 cgd {
319 1.1 cgd register struct socket *so;
320 1.1 cgd
321 1.1 cgd if (nmp->nm_so) {
322 1.1 cgd so = nmp->nm_so;
323 1.1 cgd nmp->nm_so = (struct socket *)0;
324 1.1 cgd soshutdown(so, 2);
325 1.1 cgd soclose(so);
326 1.1 cgd }
327 1.1 cgd }
328 1.1 cgd
329 1.1 cgd /*
330 1.1 cgd * This is the nfs send routine. For connection based socket types, it
331 1.14 mycroft * must be called with an nfs_sndlock() on the socket.
332 1.1 cgd * "rep == NULL" indicates that it has been called from a server.
333 1.14 mycroft * For the client side:
334 1.14 mycroft * - return EINTR if the RPC is terminated, 0 otherwise
335 1.14 mycroft * - set R_MUSTRESEND if the send fails for any reason
336 1.14 mycroft * - do any cleanup required by recoverable socket errors (???)
337 1.14 mycroft * For the server side:
338 1.14 mycroft * - return EINTR or ERESTART if interrupted by a signal
339 1.14 mycroft * - return EPIPE if a connection is lost for connection based sockets (TCP...)
340 1.14 mycroft * - do any cleanup required by recoverable socket errors (???)
341 1.1 cgd */
342 1.23 christos int
343 1.1 cgd nfs_send(so, nam, top, rep)
344 1.1 cgd register struct socket *so;
345 1.1 cgd struct mbuf *nam;
346 1.1 cgd register struct mbuf *top;
347 1.1 cgd struct nfsreq *rep;
348 1.1 cgd {
349 1.1 cgd struct mbuf *sendnam;
350 1.14 mycroft int error, soflags, flags;
351 1.1 cgd
352 1.1 cgd if (rep) {
353 1.1 cgd if (rep->r_flags & R_SOFTTERM) {
354 1.1 cgd m_freem(top);
355 1.1 cgd return (EINTR);
356 1.1 cgd }
357 1.14 mycroft if ((so = rep->r_nmp->nm_so) == NULL) {
358 1.14 mycroft rep->r_flags |= R_MUSTRESEND;
359 1.14 mycroft m_freem(top);
360 1.14 mycroft return (0);
361 1.14 mycroft }
362 1.1 cgd rep->r_flags &= ~R_MUSTRESEND;
363 1.1 cgd soflags = rep->r_nmp->nm_soflags;
364 1.1 cgd } else
365 1.1 cgd soflags = so->so_proto->pr_flags;
366 1.1 cgd if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
367 1.1 cgd sendnam = (struct mbuf *)0;
368 1.1 cgd else
369 1.1 cgd sendnam = nam;
370 1.14 mycroft if (so->so_type == SOCK_SEQPACKET)
371 1.14 mycroft flags = MSG_EOR;
372 1.14 mycroft else
373 1.14 mycroft flags = 0;
374 1.1 cgd
375 1.1 cgd error = sosend(so, sendnam, (struct uio *)0, top,
376 1.14 mycroft (struct mbuf *)0, flags);
377 1.14 mycroft if (error) {
378 1.14 mycroft if (rep) {
379 1.14 mycroft log(LOG_INFO, "nfs send error %d for server %s\n",error,
380 1.14 mycroft rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
381 1.14 mycroft /*
382 1.14 mycroft * Deal with errors for the client side.
383 1.14 mycroft */
384 1.14 mycroft if (rep->r_flags & R_SOFTTERM)
385 1.14 mycroft error = EINTR;
386 1.14 mycroft else
387 1.14 mycroft rep->r_flags |= R_MUSTRESEND;
388 1.14 mycroft } else
389 1.14 mycroft log(LOG_INFO, "nfsd send error %d\n", error);
390 1.14 mycroft
391 1.14 mycroft /*
392 1.14 mycroft * Handle any recoverable (soft) socket errors here. (???)
393 1.14 mycroft */
394 1.14 mycroft if (error != EINTR && error != ERESTART &&
395 1.14 mycroft error != EWOULDBLOCK && error != EPIPE)
396 1.1 cgd error = 0;
397 1.1 cgd }
398 1.1 cgd return (error);
399 1.1 cgd }
400 1.1 cgd
401 1.14 mycroft #ifdef NFSCLIENT
402 1.1 cgd /*
403 1.1 cgd * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
404 1.1 cgd * done by soreceive(), but for SOCK_STREAM we must deal with the Record
405 1.1 cgd * Mark and consolidate the data into a new mbuf list.
406 1.1 cgd * nb: Sometimes TCP passes the data up to soreceive() in long lists of
407 1.1 cgd * small mbufs.
408 1.1 cgd * For SOCK_STREAM we must be very careful to read an entire record once
409 1.1 cgd * we have read any of it, even if the system call has been interrupted.
410 1.1 cgd */
411 1.23 christos int
412 1.14 mycroft nfs_receive(rep, aname, mp)
413 1.14 mycroft register struct nfsreq *rep;
414 1.1 cgd struct mbuf **aname;
415 1.1 cgd struct mbuf **mp;
416 1.1 cgd {
417 1.14 mycroft register struct socket *so;
418 1.1 cgd struct uio auio;
419 1.1 cgd struct iovec aio;
420 1.1 cgd register struct mbuf *m;
421 1.14 mycroft struct mbuf *control;
422 1.22 cgd u_int32_t len;
423 1.1 cgd struct mbuf **getnam;
424 1.14 mycroft int error, sotype, rcvflg;
425 1.14 mycroft struct proc *p = curproc; /* XXX */
426 1.1 cgd
427 1.1 cgd /*
428 1.1 cgd * Set up arguments for soreceive()
429 1.1 cgd */
430 1.1 cgd *mp = (struct mbuf *)0;
431 1.1 cgd *aname = (struct mbuf *)0;
432 1.14 mycroft sotype = rep->r_nmp->nm_sotype;
433 1.1 cgd
434 1.1 cgd /*
435 1.1 cgd * For reliable protocols, lock against other senders/receivers
436 1.1 cgd * in case a reconnect is necessary.
437 1.1 cgd * For SOCK_STREAM, first get the Record Mark to find out how much
438 1.1 cgd * more there is to get.
439 1.1 cgd * We must lock the socket against other receivers
440 1.1 cgd * until we have an entire rpc request/reply.
441 1.1 cgd */
442 1.14 mycroft if (sotype != SOCK_DGRAM) {
443 1.24 fvdl error = nfs_sndlock(&rep->r_nmp->nm_flag, rep);
444 1.24 fvdl if (error)
445 1.14 mycroft return (error);
446 1.1 cgd tryagain:
447 1.1 cgd /*
448 1.1 cgd * Check for fatal errors and resending request.
449 1.1 cgd */
450 1.14 mycroft /*
451 1.14 mycroft * Ugh: If a reconnect attempt just happened, nm_so
452 1.14 mycroft * would have changed. NULL indicates a failed
453 1.14 mycroft * attempt that has essentially shut down this
454 1.14 mycroft * mount point.
455 1.14 mycroft */
456 1.14 mycroft if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {
457 1.14 mycroft nfs_sndunlock(&rep->r_nmp->nm_flag);
458 1.14 mycroft return (EINTR);
459 1.14 mycroft }
460 1.24 fvdl so = rep->r_nmp->nm_so;
461 1.24 fvdl if (!so) {
462 1.24 fvdl error = nfs_reconnect(rep);
463 1.24 fvdl if (error) {
464 1.14 mycroft nfs_sndunlock(&rep->r_nmp->nm_flag);
465 1.14 mycroft return (error);
466 1.14 mycroft }
467 1.14 mycroft goto tryagain;
468 1.14 mycroft }
469 1.14 mycroft while (rep->r_flags & R_MUSTRESEND) {
470 1.14 mycroft m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);
471 1.14 mycroft nfsstats.rpcretries++;
472 1.23 christos error = nfs_send(so, rep->r_nmp->nm_nam, m, rep);
473 1.23 christos if (error) {
474 1.14 mycroft if (error == EINTR || error == ERESTART ||
475 1.24 fvdl (error = nfs_reconnect(rep)) != 0) {
476 1.14 mycroft nfs_sndunlock(&rep->r_nmp->nm_flag);
477 1.14 mycroft return (error);
478 1.14 mycroft }
479 1.14 mycroft goto tryagain;
480 1.1 cgd }
481 1.1 cgd }
482 1.14 mycroft nfs_sndunlock(&rep->r_nmp->nm_flag);
483 1.14 mycroft if (sotype == SOCK_STREAM) {
484 1.1 cgd aio.iov_base = (caddr_t) &len;
485 1.22 cgd aio.iov_len = sizeof(u_int32_t);
486 1.1 cgd auio.uio_iov = &aio;
487 1.1 cgd auio.uio_iovcnt = 1;
488 1.1 cgd auio.uio_segflg = UIO_SYSSPACE;
489 1.1 cgd auio.uio_rw = UIO_READ;
490 1.1 cgd auio.uio_offset = 0;
491 1.22 cgd auio.uio_resid = sizeof(u_int32_t);
492 1.14 mycroft auio.uio_procp = p;
493 1.1 cgd do {
494 1.14 mycroft rcvflg = MSG_WAITALL;
495 1.14 mycroft error = soreceive(so, (struct mbuf **)0, &auio,
496 1.1 cgd (struct mbuf **)0, (struct mbuf **)0, &rcvflg);
497 1.14 mycroft if (error == EWOULDBLOCK && rep) {
498 1.1 cgd if (rep->r_flags & R_SOFTTERM)
499 1.1 cgd return (EINTR);
500 1.14 mycroft }
501 1.1 cgd } while (error == EWOULDBLOCK);
502 1.1 cgd if (!error && auio.uio_resid > 0) {
503 1.14 mycroft log(LOG_INFO,
504 1.14 mycroft "short receive (%d/%d) from nfs server %s\n",
505 1.22 cgd sizeof(u_int32_t) - auio.uio_resid,
506 1.22 cgd sizeof(u_int32_t),
507 1.1 cgd rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
508 1.1 cgd error = EPIPE;
509 1.1 cgd }
510 1.1 cgd if (error)
511 1.1 cgd goto errout;
512 1.1 cgd len = ntohl(len) & ~0x80000000;
513 1.1 cgd /*
514 1.1 cgd * This is SERIOUS! We are out of sync with the sender
515 1.1 cgd * and forcing a disconnect/reconnect is all I can do.
516 1.1 cgd */
517 1.1 cgd if (len > NFS_MAXPACKET) {
518 1.14 mycroft log(LOG_ERR, "%s (%d) from nfs server %s\n",
519 1.14 mycroft "impossible packet length",
520 1.14 mycroft len,
521 1.14 mycroft rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
522 1.1 cgd error = EFBIG;
523 1.1 cgd goto errout;
524 1.1 cgd }
525 1.1 cgd auio.uio_resid = len;
526 1.1 cgd do {
527 1.1 cgd rcvflg = MSG_WAITALL;
528 1.1 cgd error = soreceive(so, (struct mbuf **)0,
529 1.1 cgd &auio, mp, (struct mbuf **)0, &rcvflg);
530 1.1 cgd } while (error == EWOULDBLOCK || error == EINTR ||
531 1.1 cgd error == ERESTART);
532 1.1 cgd if (!error && auio.uio_resid > 0) {
533 1.14 mycroft log(LOG_INFO,
534 1.14 mycroft "short receive (%d/%d) from nfs server %s\n",
535 1.14 mycroft len - auio.uio_resid, len,
536 1.14 mycroft rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
537 1.1 cgd error = EPIPE;
538 1.1 cgd }
539 1.1 cgd } else {
540 1.14 mycroft /*
541 1.14 mycroft * NB: Since uio_resid is big, MSG_WAITALL is ignored
542 1.14 mycroft * and soreceive() will return when it has either a
543 1.14 mycroft * control msg or a data msg.
544 1.14 mycroft * We have no use for control msg., but must grab them
545 1.14 mycroft * and then throw them away so we know what is going
546 1.14 mycroft * on.
547 1.14 mycroft */
548 1.14 mycroft auio.uio_resid = len = 100000000; /* Anything Big */
549 1.14 mycroft auio.uio_procp = p;
550 1.1 cgd do {
551 1.1 cgd rcvflg = 0;
552 1.1 cgd error = soreceive(so, (struct mbuf **)0,
553 1.14 mycroft &auio, mp, &control, &rcvflg);
554 1.14 mycroft if (control)
555 1.14 mycroft m_freem(control);
556 1.1 cgd if (error == EWOULDBLOCK && rep) {
557 1.1 cgd if (rep->r_flags & R_SOFTTERM)
558 1.1 cgd return (EINTR);
559 1.1 cgd }
560 1.14 mycroft } while (error == EWOULDBLOCK ||
561 1.14 mycroft (!error && *mp == NULL && control));
562 1.14 mycroft if ((rcvflg & MSG_EOR) == 0)
563 1.14 mycroft printf("Egad!!\n");
564 1.1 cgd if (!error && *mp == NULL)
565 1.1 cgd error = EPIPE;
566 1.1 cgd len -= auio.uio_resid;
567 1.1 cgd }
568 1.1 cgd errout:
569 1.14 mycroft if (error && error != EINTR && error != ERESTART) {
570 1.1 cgd m_freem(*mp);
571 1.1 cgd *mp = (struct mbuf *)0;
572 1.14 mycroft if (error != EPIPE)
573 1.1 cgd log(LOG_INFO,
574 1.1 cgd "receive error %d from nfs server %s\n",
575 1.1 cgd error,
576 1.1 cgd rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
577 1.14 mycroft error = nfs_sndlock(&rep->r_nmp->nm_flag, rep);
578 1.14 mycroft if (!error)
579 1.14 mycroft error = nfs_reconnect(rep);
580 1.1 cgd if (!error)
581 1.1 cgd goto tryagain;
582 1.1 cgd }
583 1.1 cgd } else {
584 1.14 mycroft if ((so = rep->r_nmp->nm_so) == NULL)
585 1.14 mycroft return (EACCES);
586 1.1 cgd if (so->so_state & SS_ISCONNECTED)
587 1.1 cgd getnam = (struct mbuf **)0;
588 1.1 cgd else
589 1.1 cgd getnam = aname;
590 1.1 cgd auio.uio_resid = len = 1000000;
591 1.14 mycroft auio.uio_procp = p;
592 1.1 cgd do {
593 1.1 cgd rcvflg = 0;
594 1.1 cgd error = soreceive(so, getnam, &auio, mp,
595 1.1 cgd (struct mbuf **)0, &rcvflg);
596 1.14 mycroft if (error == EWOULDBLOCK &&
597 1.1 cgd (rep->r_flags & R_SOFTTERM))
598 1.1 cgd return (EINTR);
599 1.1 cgd } while (error == EWOULDBLOCK);
600 1.1 cgd len -= auio.uio_resid;
601 1.1 cgd }
602 1.1 cgd if (error) {
603 1.1 cgd m_freem(*mp);
604 1.1 cgd *mp = (struct mbuf *)0;
605 1.1 cgd }
606 1.1 cgd /*
607 1.14 mycroft * Search for any mbufs that are not a multiple of 4 bytes long
608 1.14 mycroft * or with m_data not longword aligned.
609 1.1 cgd * These could cause pointer alignment problems, so copy them to
610 1.1 cgd * well aligned mbufs.
611 1.1 cgd */
612 1.14 mycroft nfs_realign(*mp, 5 * NFSX_UNSIGNED);
613 1.1 cgd return (error);
614 1.1 cgd }
615 1.1 cgd
616 1.1 cgd /*
617 1.1 cgd * Implement receipt of reply on a socket.
618 1.1 cgd * We must search through the list of received datagrams matching them
619 1.1 cgd * with outstanding requests using the xid, until ours is found.
620 1.1 cgd */
621 1.1 cgd /* ARGSUSED */
622 1.23 christos int
623 1.14 mycroft nfs_reply(myrep)
624 1.1 cgd struct nfsreq *myrep;
625 1.1 cgd {
626 1.1 cgd register struct nfsreq *rep;
627 1.14 mycroft register struct nfsmount *nmp = myrep->r_nmp;
628 1.22 cgd register int32_t t1;
629 1.14 mycroft struct mbuf *mrep, *nam, *md;
630 1.22 cgd u_int32_t rxid, *tl;
631 1.14 mycroft caddr_t dpos, cp2;
632 1.14 mycroft int error;
633 1.1 cgd
634 1.1 cgd /*
635 1.1 cgd * Loop around until we get our own reply
636 1.1 cgd */
637 1.1 cgd for (;;) {
638 1.1 cgd /*
639 1.1 cgd * Lock against other receivers so that I don't get stuck in
640 1.1 cgd * sbwait() after someone else has received my reply for me.
641 1.1 cgd * Also necessary for connection based protocols to avoid
642 1.1 cgd * race conditions during a reconnect.
643 1.1 cgd */
644 1.24 fvdl error = nfs_rcvlock(myrep);
645 1.24 fvdl if (error)
646 1.14 mycroft return (error);
647 1.1 cgd /* Already received, bye bye */
648 1.1 cgd if (myrep->r_mrep != NULL) {
649 1.14 mycroft nfs_rcvunlock(&nmp->nm_flag);
650 1.1 cgd return (0);
651 1.1 cgd }
652 1.1 cgd /*
653 1.1 cgd * Get the next Rpc reply off the socket
654 1.1 cgd */
655 1.14 mycroft error = nfs_receive(myrep, &nam, &mrep);
656 1.14 mycroft nfs_rcvunlock(&nmp->nm_flag);
657 1.14 mycroft if (error) {
658 1.1 cgd
659 1.1 cgd /*
660 1.1 cgd * Ignore routing errors on connectionless protocols??
661 1.1 cgd */
662 1.1 cgd if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {
663 1.1 cgd nmp->nm_so->so_error = 0;
664 1.14 mycroft if (myrep->r_flags & R_GETONEREP)
665 1.14 mycroft return (0);
666 1.1 cgd continue;
667 1.1 cgd }
668 1.1 cgd return (error);
669 1.1 cgd }
670 1.14 mycroft if (nam)
671 1.14 mycroft m_freem(nam);
672 1.1 cgd
673 1.1 cgd /*
674 1.1 cgd * Get the xid and check that it is an rpc reply
675 1.1 cgd */
676 1.14 mycroft md = mrep;
677 1.14 mycroft dpos = mtod(md, caddr_t);
678 1.22 cgd nfsm_dissect(tl, u_int32_t *, 2*NFSX_UNSIGNED);
679 1.14 mycroft rxid = *tl++;
680 1.14 mycroft if (*tl != rpc_reply) {
681 1.14 mycroft if (nmp->nm_flag & NFSMNT_NQNFS) {
682 1.14 mycroft if (nqnfs_callback(nmp, mrep, md, dpos))
683 1.14 mycroft nfsstats.rpcinvalid++;
684 1.14 mycroft } else {
685 1.14 mycroft nfsstats.rpcinvalid++;
686 1.14 mycroft m_freem(mrep);
687 1.14 mycroft }
688 1.14 mycroft nfsmout:
689 1.14 mycroft if (myrep->r_flags & R_GETONEREP)
690 1.14 mycroft return (0);
691 1.1 cgd continue;
692 1.1 cgd }
693 1.14 mycroft
694 1.1 cgd /*
695 1.1 cgd * Loop through the request list to match up the reply
696 1.1 cgd * Iff no match, just drop the datagram
697 1.1 cgd */
698 1.16 mycroft for (rep = nfs_reqq.tqh_first; rep != 0;
699 1.16 mycroft rep = rep->r_chain.tqe_next) {
700 1.1 cgd if (rep->r_mrep == NULL && rxid == rep->r_xid) {
701 1.1 cgd /* Found it.. */
702 1.14 mycroft rep->r_mrep = mrep;
703 1.14 mycroft rep->r_md = md;
704 1.14 mycroft rep->r_dpos = dpos;
705 1.14 mycroft if (nfsrtton) {
706 1.14 mycroft struct rttl *rt;
707 1.14 mycroft
708 1.14 mycroft rt = &nfsrtt.rttl[nfsrtt.pos];
709 1.14 mycroft rt->proc = rep->r_procnum;
710 1.14 mycroft rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]);
711 1.14 mycroft rt->sent = nmp->nm_sent;
712 1.14 mycroft rt->cwnd = nmp->nm_cwnd;
713 1.14 mycroft rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1];
714 1.14 mycroft rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1];
715 1.14 mycroft rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid;
716 1.14 mycroft rt->tstamp = time;
717 1.14 mycroft if (rep->r_flags & R_TIMING)
718 1.14 mycroft rt->rtt = rep->r_rtt;
719 1.14 mycroft else
720 1.14 mycroft rt->rtt = 1000000;
721 1.14 mycroft nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ;
722 1.14 mycroft }
723 1.1 cgd /*
724 1.14 mycroft * Update congestion window.
725 1.14 mycroft * Do the additive increase of
726 1.14 mycroft * one rpc/rtt.
727 1.14 mycroft */
728 1.14 mycroft if (nmp->nm_cwnd <= nmp->nm_sent) {
729 1.14 mycroft nmp->nm_cwnd +=
730 1.14 mycroft (NFS_CWNDSCALE * NFS_CWNDSCALE +
731 1.14 mycroft (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd;
732 1.14 mycroft if (nmp->nm_cwnd > NFS_MAXCWND)
733 1.14 mycroft nmp->nm_cwnd = NFS_MAXCWND;
734 1.14 mycroft }
735 1.14 mycroft rep->r_flags &= ~R_SENT;
736 1.14 mycroft nmp->nm_sent -= NFS_CWNDSCALE;
737 1.14 mycroft /*
738 1.14 mycroft * Update rtt using a gain of 0.125 on the mean
739 1.14 mycroft * and a gain of 0.25 on the deviation.
740 1.1 cgd */
741 1.1 cgd if (rep->r_flags & R_TIMING) {
742 1.14 mycroft /*
743 1.14 mycroft * Since the timer resolution of
744 1.14 mycroft * NFS_HZ is so course, it can often
745 1.14 mycroft * result in r_rtt == 0. Since
746 1.14 mycroft * r_rtt == N means that the actual
747 1.14 mycroft * rtt is between N+dt and N+2-dt ticks,
748 1.14 mycroft * add 1.
749 1.14 mycroft */
750 1.14 mycroft t1 = rep->r_rtt + 1;
751 1.14 mycroft t1 -= (NFS_SRTT(rep) >> 3);
752 1.14 mycroft NFS_SRTT(rep) += t1;
753 1.14 mycroft if (t1 < 0)
754 1.14 mycroft t1 = -t1;
755 1.14 mycroft t1 -= (NFS_SDRTT(rep) >> 2);
756 1.14 mycroft NFS_SDRTT(rep) += t1;
757 1.1 cgd }
758 1.14 mycroft nmp->nm_timeouts = 0;
759 1.1 cgd break;
760 1.1 cgd }
761 1.1 cgd }
762 1.1 cgd /*
763 1.1 cgd * If not matched to a request, drop it.
764 1.1 cgd * If it's mine, get out.
765 1.1 cgd */
766 1.16 mycroft if (rep == 0) {
767 1.1 cgd nfsstats.rpcunexpected++;
768 1.14 mycroft m_freem(mrep);
769 1.14 mycroft } else if (rep == myrep) {
770 1.14 mycroft if (rep->r_mrep == NULL)
771 1.14 mycroft panic("nfsreply nil");
772 1.14 mycroft return (0);
773 1.14 mycroft }
774 1.14 mycroft if (myrep->r_flags & R_GETONEREP)
775 1.1 cgd return (0);
776 1.1 cgd }
777 1.1 cgd }
778 1.1 cgd
779 1.1 cgd /*
780 1.1 cgd * nfs_request - goes something like this
781 1.1 cgd * - fill in request struct
782 1.1 cgd * - links it into list
783 1.1 cgd * - calls nfs_send() for first transmit
784 1.1 cgd * - calls nfs_receive() to get reply
785 1.1 cgd * - break down rpc header and return with nfs reply pointed to
786 1.1 cgd * by mrep or error
787 1.1 cgd * nb: always frees up mreq mbuf list
788 1.1 cgd */
789 1.23 christos int
790 1.14 mycroft nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp)
791 1.1 cgd struct vnode *vp;
792 1.14 mycroft struct mbuf *mrest;
793 1.1 cgd int procnum;
794 1.1 cgd struct proc *procp;
795 1.14 mycroft struct ucred *cred;
796 1.1 cgd struct mbuf **mrp;
797 1.1 cgd struct mbuf **mdp;
798 1.1 cgd caddr_t *dposp;
799 1.1 cgd {
800 1.1 cgd register struct mbuf *m, *mrep;
801 1.1 cgd register struct nfsreq *rep;
802 1.22 cgd register u_int32_t *tl;
803 1.14 mycroft register int i;
804 1.1 cgd struct nfsmount *nmp;
805 1.14 mycroft struct mbuf *md, *mheadend;
806 1.14 mycroft struct nfsnode *np;
807 1.24 fvdl char nickv[RPCX_NICKVERF];
808 1.14 mycroft time_t reqtime, waituntil;
809 1.14 mycroft caddr_t dpos, cp2;
810 1.14 mycroft int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type;
811 1.14 mycroft int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0;
812 1.24 fvdl int verf_len, verf_type;
813 1.22 cgd u_int32_t xid;
814 1.14 mycroft u_quad_t frev;
815 1.24 fvdl char *auth_str, *verf_str;
816 1.24 fvdl NFSKERBKEY_T key; /* save session key */
817 1.1 cgd
818 1.14 mycroft nmp = VFSTONFS(vp->v_mount);
819 1.1 cgd MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
820 1.1 cgd rep->r_nmp = nmp;
821 1.1 cgd rep->r_vp = vp;
822 1.1 cgd rep->r_procp = procp;
823 1.14 mycroft rep->r_procnum = procnum;
824 1.14 mycroft i = 0;
825 1.14 mycroft m = mrest;
826 1.1 cgd while (m) {
827 1.14 mycroft i += m->m_len;
828 1.1 cgd m = m->m_next;
829 1.1 cgd }
830 1.14 mycroft mrest_len = i;
831 1.14 mycroft
832 1.14 mycroft /*
833 1.14 mycroft * Get the RPC header with authorization.
834 1.14 mycroft */
835 1.14 mycroft kerbauth:
836 1.24 fvdl verf_str = auth_str = (char *)0;
837 1.14 mycroft if (nmp->nm_flag & NFSMNT_KERB) {
838 1.24 fvdl verf_str = nickv;
839 1.24 fvdl verf_len = sizeof (nickv);
840 1.24 fvdl auth_type = RPCAUTH_KERB4;
841 1.24 fvdl bzero((caddr_t)key, sizeof (key));
842 1.24 fvdl if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str,
843 1.24 fvdl &auth_len, verf_str, verf_len)) {
844 1.24 fvdl error = nfs_getauth(nmp, rep, cred, &auth_str,
845 1.24 fvdl &auth_len, verf_str, &verf_len, key);
846 1.14 mycroft if (error) {
847 1.14 mycroft free((caddr_t)rep, M_NFSREQ);
848 1.14 mycroft m_freem(mrest);
849 1.14 mycroft return (error);
850 1.14 mycroft }
851 1.1 cgd }
852 1.14 mycroft } else {
853 1.14 mycroft auth_type = RPCAUTH_UNIX;
854 1.20 mycroft auth_len = (((cred->cr_ngroups > nmp->nm_numgrps) ?
855 1.20 mycroft nmp->nm_numgrps : cred->cr_ngroups) << 2) +
856 1.14 mycroft 5 * NFSX_UNSIGNED;
857 1.14 mycroft }
858 1.24 fvdl m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len,
859 1.24 fvdl auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid);
860 1.14 mycroft if (auth_str)
861 1.14 mycroft free(auth_str, M_TEMP);
862 1.14 mycroft
863 1.1 cgd /*
864 1.14 mycroft * For stream protocols, insert a Sun RPC Record Mark.
865 1.1 cgd */
866 1.14 mycroft if (nmp->nm_sotype == SOCK_STREAM) {
867 1.14 mycroft M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
868 1.22 cgd *mtod(m, u_int32_t *) = htonl(0x80000000 |
869 1.14 mycroft (m->m_pkthdr.len - NFSX_UNSIGNED));
870 1.1 cgd }
871 1.14 mycroft rep->r_mreq = m;
872 1.14 mycroft rep->r_xid = xid;
873 1.14 mycroft tryagain:
874 1.14 mycroft if (nmp->nm_flag & NFSMNT_SOFT)
875 1.14 mycroft rep->r_retry = nmp->nm_retry;
876 1.14 mycroft else
877 1.14 mycroft rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */
878 1.14 mycroft rep->r_rtt = rep->r_rexmit = 0;
879 1.14 mycroft if (proct[procnum] > 0)
880 1.14 mycroft rep->r_flags = R_TIMING;
881 1.14 mycroft else
882 1.14 mycroft rep->r_flags = 0;
883 1.14 mycroft rep->r_mrep = NULL;
884 1.1 cgd
885 1.1 cgd /*
886 1.1 cgd * Do the client side RPC.
887 1.1 cgd */
888 1.1 cgd nfsstats.rpcrequests++;
889 1.1 cgd /*
890 1.1 cgd * Chain request into list of outstanding requests. Be sure
891 1.1 cgd * to put it LAST so timer finds oldest requests first.
892 1.1 cgd */
893 1.14 mycroft s = splsoftclock();
894 1.16 mycroft TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain);
895 1.14 mycroft
896 1.14 mycroft /* Get send time for nqnfs */
897 1.14 mycroft reqtime = time.tv_sec;
898 1.14 mycroft
899 1.1 cgd /*
900 1.1 cgd * If backing off another request or avoiding congestion, don't
901 1.1 cgd * send this one now but let timer do it. If not timing a request,
902 1.1 cgd * do it now.
903 1.1 cgd */
904 1.14 mycroft if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM ||
905 1.14 mycroft (nmp->nm_flag & NFSMNT_DUMBTIMR) ||
906 1.14 mycroft nmp->nm_sent < nmp->nm_cwnd)) {
907 1.1 cgd splx(s);
908 1.1 cgd if (nmp->nm_soflags & PR_CONNREQUIRED)
909 1.14 mycroft error = nfs_sndlock(&nmp->nm_flag, rep);
910 1.14 mycroft if (!error) {
911 1.14 mycroft m = m_copym(m, 0, M_COPYALL, M_WAIT);
912 1.14 mycroft error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);
913 1.14 mycroft if (nmp->nm_soflags & PR_CONNREQUIRED)
914 1.14 mycroft nfs_sndunlock(&nmp->nm_flag);
915 1.14 mycroft }
916 1.14 mycroft if (!error && (rep->r_flags & R_MUSTRESEND) == 0) {
917 1.14 mycroft nmp->nm_sent += NFS_CWNDSCALE;
918 1.14 mycroft rep->r_flags |= R_SENT;
919 1.14 mycroft }
920 1.14 mycroft } else {
921 1.1 cgd splx(s);
922 1.14 mycroft rep->r_rtt = -1;
923 1.14 mycroft }
924 1.1 cgd
925 1.1 cgd /*
926 1.1 cgd * Wait for the reply from our send or the timer's.
927 1.1 cgd */
928 1.14 mycroft if (!error || error == EPIPE)
929 1.14 mycroft error = nfs_reply(rep);
930 1.1 cgd
931 1.1 cgd /*
932 1.1 cgd * RPC done, unlink the request.
933 1.1 cgd */
934 1.14 mycroft s = splsoftclock();
935 1.16 mycroft TAILQ_REMOVE(&nfs_reqq, rep, r_chain);
936 1.1 cgd splx(s);
937 1.1 cgd
938 1.1 cgd /*
939 1.14 mycroft * Decrement the outstanding request count.
940 1.14 mycroft */
941 1.14 mycroft if (rep->r_flags & R_SENT) {
942 1.14 mycroft rep->r_flags &= ~R_SENT; /* paranoia */
943 1.14 mycroft nmp->nm_sent -= NFS_CWNDSCALE;
944 1.14 mycroft }
945 1.14 mycroft
946 1.14 mycroft /*
947 1.1 cgd * If there was a successful reply and a tprintf msg.
948 1.1 cgd * tprintf a response.
949 1.1 cgd */
950 1.1 cgd if (!error && (rep->r_flags & R_TPRINTFMSG))
951 1.1 cgd nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname,
952 1.1 cgd "is alive again");
953 1.1 cgd mrep = rep->r_mrep;
954 1.14 mycroft md = rep->r_md;
955 1.14 mycroft dpos = rep->r_dpos;
956 1.14 mycroft if (error) {
957 1.14 mycroft m_freem(rep->r_mreq);
958 1.14 mycroft free((caddr_t)rep, M_NFSREQ);
959 1.1 cgd return (error);
960 1.14 mycroft }
961 1.1 cgd
962 1.1 cgd /*
963 1.1 cgd * break down the rpc header and check if ok
964 1.1 cgd */
965 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
966 1.1 cgd if (*tl++ == rpc_msgdenied) {
967 1.1 cgd if (*tl == rpc_mismatch)
968 1.1 cgd error = EOPNOTSUPP;
969 1.14 mycroft else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) {
970 1.24 fvdl if (!failed_auth) {
971 1.14 mycroft failed_auth++;
972 1.14 mycroft mheadend->m_next = (struct mbuf *)0;
973 1.14 mycroft m_freem(mrep);
974 1.14 mycroft m_freem(rep->r_mreq);
975 1.14 mycroft goto kerbauth;
976 1.14 mycroft } else
977 1.14 mycroft error = EAUTH;
978 1.14 mycroft } else
979 1.1 cgd error = EACCES;
980 1.1 cgd m_freem(mrep);
981 1.14 mycroft m_freem(rep->r_mreq);
982 1.14 mycroft free((caddr_t)rep, M_NFSREQ);
983 1.1 cgd return (error);
984 1.1 cgd }
985 1.14 mycroft
986 1.1 cgd /*
987 1.24 fvdl * Grab any Kerberos verifier, otherwise just throw it away.
988 1.1 cgd */
989 1.24 fvdl verf_type = fxdr_unsigned(int, *tl++);
990 1.24 fvdl i = fxdr_unsigned(int32_t, *tl);
991 1.24 fvdl if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) {
992 1.24 fvdl error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep);
993 1.24 fvdl if (error)
994 1.24 fvdl goto nfsmout;
995 1.24 fvdl } else if (i > 0)
996 1.24 fvdl nfsm_adv(nfsm_rndup(i));
997 1.22 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
998 1.1 cgd /* 0 == ok */
999 1.1 cgd if (*tl == 0) {
1000 1.22 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1001 1.1 cgd if (*tl != 0) {
1002 1.1 cgd error = fxdr_unsigned(int, *tl);
1003 1.24 fvdl if ((nmp->nm_flag & NFSMNT_NFSV3) &&
1004 1.24 fvdl error == NFSERR_TRYLATER) {
1005 1.24 fvdl m_freem(mrep);
1006 1.14 mycroft error = 0;
1007 1.14 mycroft waituntil = time.tv_sec + trylater_delay;
1008 1.14 mycroft while (time.tv_sec < waituntil)
1009 1.14 mycroft (void) tsleep((caddr_t)&lbolt,
1010 1.14 mycroft PSOCK, "nqnfstry", 0);
1011 1.14 mycroft trylater_delay *= nfs_backoff[trylater_cnt];
1012 1.14 mycroft if (trylater_cnt < 7)
1013 1.14 mycroft trylater_cnt++;
1014 1.14 mycroft goto tryagain;
1015 1.14 mycroft }
1016 1.14 mycroft
1017 1.14 mycroft /*
1018 1.14 mycroft * If the File Handle was stale, invalidate the
1019 1.14 mycroft * lookup cache, just in case.
1020 1.14 mycroft */
1021 1.14 mycroft if (error == ESTALE)
1022 1.14 mycroft cache_purge(vp);
1023 1.24 fvdl if (nmp->nm_flag & NFSMNT_NFSV3) {
1024 1.24 fvdl *mrp = mrep;
1025 1.24 fvdl *mdp = md;
1026 1.24 fvdl *dposp = dpos;
1027 1.24 fvdl error |= NFSERR_RETERR;
1028 1.24 fvdl } else
1029 1.24 fvdl m_freem(mrep);
1030 1.14 mycroft m_freem(rep->r_mreq);
1031 1.14 mycroft free((caddr_t)rep, M_NFSREQ);
1032 1.1 cgd return (error);
1033 1.1 cgd }
1034 1.14 mycroft
1035 1.14 mycroft /*
1036 1.14 mycroft * For nqnfs, get any lease in reply
1037 1.14 mycroft */
1038 1.14 mycroft if (nmp->nm_flag & NFSMNT_NQNFS) {
1039 1.22 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1040 1.14 mycroft if (*tl) {
1041 1.14 mycroft np = VTONFS(vp);
1042 1.14 mycroft nqlflag = fxdr_unsigned(int, *tl);
1043 1.22 cgd nfsm_dissect(tl, u_int32_t *, 4*NFSX_UNSIGNED);
1044 1.14 mycroft cachable = fxdr_unsigned(int, *tl++);
1045 1.14 mycroft reqtime += fxdr_unsigned(int, *tl++);
1046 1.14 mycroft if (reqtime > time.tv_sec) {
1047 1.14 mycroft fxdr_hyper(tl, &frev);
1048 1.14 mycroft nqnfs_clientlease(nmp, np, nqlflag,
1049 1.14 mycroft cachable, reqtime, frev);
1050 1.14 mycroft }
1051 1.14 mycroft }
1052 1.14 mycroft }
1053 1.1 cgd *mrp = mrep;
1054 1.1 cgd *mdp = md;
1055 1.1 cgd *dposp = dpos;
1056 1.14 mycroft m_freem(rep->r_mreq);
1057 1.14 mycroft FREE((caddr_t)rep, M_NFSREQ);
1058 1.1 cgd return (0);
1059 1.1 cgd }
1060 1.1 cgd m_freem(mrep);
1061 1.24 fvdl error = EPROTONOSUPPORT;
1062 1.24 fvdl nfsmout:
1063 1.14 mycroft m_freem(rep->r_mreq);
1064 1.14 mycroft free((caddr_t)rep, M_NFSREQ);
1065 1.1 cgd return (error);
1066 1.1 cgd }
1067 1.14 mycroft #endif /* NFSCLIENT */
1068 1.1 cgd
1069 1.1 cgd /*
1070 1.1 cgd * Generate the rpc reply header
1071 1.1 cgd * siz arg. is used to decide if adding a cluster is worthwhile
1072 1.1 cgd */
1073 1.23 christos int
1074 1.24 fvdl nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
1075 1.1 cgd int siz;
1076 1.24 fvdl struct nfsrv_descript *nd;
1077 1.24 fvdl struct nfssvc_sock *slp;
1078 1.1 cgd int err;
1079 1.14 mycroft int cache;
1080 1.14 mycroft u_quad_t *frev;
1081 1.1 cgd struct mbuf **mrq;
1082 1.1 cgd struct mbuf **mbp;
1083 1.1 cgd caddr_t *bposp;
1084 1.1 cgd {
1085 1.22 cgd register u_int32_t *tl;
1086 1.14 mycroft register struct mbuf *mreq;
1087 1.1 cgd caddr_t bpos;
1088 1.14 mycroft struct mbuf *mb, *mb2;
1089 1.1 cgd
1090 1.14 mycroft MGETHDR(mreq, M_WAIT, MT_DATA);
1091 1.1 cgd mb = mreq;
1092 1.14 mycroft /*
1093 1.14 mycroft * If this is a big reply, use a cluster else
1094 1.14 mycroft * try and leave leading space for the lower level headers.
1095 1.14 mycroft */
1096 1.14 mycroft siz += RPC_REPLYSIZ;
1097 1.14 mycroft if (siz >= MINCLSIZE) {
1098 1.1 cgd MCLGET(mreq, M_WAIT);
1099 1.14 mycroft } else
1100 1.14 mycroft mreq->m_data += max_hdr;
1101 1.22 cgd tl = mtod(mreq, u_int32_t *);
1102 1.24 fvdl mreq->m_len = 6 * NFSX_UNSIGNED;
1103 1.24 fvdl bpos = ((caddr_t)tl) + mreq->m_len;
1104 1.14 mycroft *tl++ = txdr_unsigned(nd->nd_retxid);
1105 1.1 cgd *tl++ = rpc_reply;
1106 1.24 fvdl if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
1107 1.1 cgd *tl++ = rpc_msgdenied;
1108 1.24 fvdl if (err & NFSERR_AUTHERR) {
1109 1.14 mycroft *tl++ = rpc_autherr;
1110 1.24 fvdl *tl = txdr_unsigned(err & ~NFSERR_AUTHERR);
1111 1.14 mycroft mreq->m_len -= NFSX_UNSIGNED;
1112 1.14 mycroft bpos -= NFSX_UNSIGNED;
1113 1.14 mycroft } else {
1114 1.14 mycroft *tl++ = rpc_mismatch;
1115 1.24 fvdl *tl++ = txdr_unsigned(RPC_VER2);
1116 1.24 fvdl *tl = txdr_unsigned(RPC_VER2);
1117 1.14 mycroft }
1118 1.1 cgd } else {
1119 1.1 cgd *tl++ = rpc_msgaccepted;
1120 1.24 fvdl
1121 1.24 fvdl /*
1122 1.24 fvdl * For Kerberos authentication, we must send the nickname
1123 1.24 fvdl * verifier back, otherwise just RPCAUTH_NULL.
1124 1.24 fvdl */
1125 1.24 fvdl if (nd->nd_flag & ND_KERBFULL) {
1126 1.24 fvdl register struct nfsuid *nuidp;
1127 1.24 fvdl struct timeval ktvin, ktvout;
1128 1.24 fvdl
1129 1.24 fvdl for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first;
1130 1.24 fvdl nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
1131 1.24 fvdl if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid &&
1132 1.24 fvdl (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp),
1133 1.24 fvdl &nuidp->nu_haddr, nd->nd_nam2)))
1134 1.24 fvdl break;
1135 1.24 fvdl }
1136 1.24 fvdl if (nuidp) {
1137 1.24 fvdl ktvin.tv_sec =
1138 1.24 fvdl txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1);
1139 1.24 fvdl ktvin.tv_usec =
1140 1.24 fvdl txdr_unsigned(nuidp->nu_timestamp.tv_usec);
1141 1.24 fvdl
1142 1.24 fvdl /*
1143 1.24 fvdl * Encrypt the timestamp in ecb mode using the
1144 1.24 fvdl * session key.
1145 1.24 fvdl */
1146 1.24 fvdl #ifdef NFSKERB
1147 1.24 fvdl XXX
1148 1.24 fvdl #endif
1149 1.24 fvdl
1150 1.24 fvdl *tl++ = rpc_auth_kerb;
1151 1.24 fvdl *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED);
1152 1.24 fvdl *tl = ktvout.tv_sec;
1153 1.24 fvdl nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1154 1.24 fvdl *tl++ = ktvout.tv_usec;
1155 1.24 fvdl *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid);
1156 1.24 fvdl } else {
1157 1.24 fvdl *tl++ = 0;
1158 1.24 fvdl *tl++ = 0;
1159 1.24 fvdl }
1160 1.24 fvdl } else {
1161 1.24 fvdl *tl++ = 0;
1162 1.24 fvdl *tl++ = 0;
1163 1.24 fvdl }
1164 1.1 cgd switch (err) {
1165 1.1 cgd case EPROGUNAVAIL:
1166 1.1 cgd *tl = txdr_unsigned(RPC_PROGUNAVAIL);
1167 1.1 cgd break;
1168 1.1 cgd case EPROGMISMATCH:
1169 1.1 cgd *tl = txdr_unsigned(RPC_PROGMISMATCH);
1170 1.24 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1171 1.24 fvdl if (nd->nd_flag & ND_NQNFS) {
1172 1.24 fvdl *tl++ = txdr_unsigned(3);
1173 1.24 fvdl *tl = txdr_unsigned(3);
1174 1.24 fvdl } else {
1175 1.24 fvdl *tl++ = txdr_unsigned(2);
1176 1.24 fvdl *tl = txdr_unsigned(3);
1177 1.24 fvdl }
1178 1.1 cgd break;
1179 1.1 cgd case EPROCUNAVAIL:
1180 1.1 cgd *tl = txdr_unsigned(RPC_PROCUNAVAIL);
1181 1.1 cgd break;
1182 1.24 fvdl case EBADRPC:
1183 1.24 fvdl *tl = txdr_unsigned(RPC_GARBAGE);
1184 1.24 fvdl break;
1185 1.1 cgd default:
1186 1.1 cgd *tl = 0;
1187 1.24 fvdl if (err != NFSERR_RETVOID) {
1188 1.22 cgd nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1189 1.14 mycroft if (err)
1190 1.24 fvdl *tl = txdr_unsigned(nfsrv_errmap(nd, err));
1191 1.14 mycroft else
1192 1.24 fvdl *tl = 0;
1193 1.1 cgd }
1194 1.1 cgd break;
1195 1.1 cgd };
1196 1.1 cgd }
1197 1.14 mycroft
1198 1.14 mycroft /*
1199 1.14 mycroft * For nqnfs, piggyback lease as requested.
1200 1.14 mycroft */
1201 1.24 fvdl if ((nd->nd_flag & ND_NQNFS) && err == 0) {
1202 1.24 fvdl if (nd->nd_flag & ND_LEASE) {
1203 1.24 fvdl nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1204 1.24 fvdl *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE);
1205 1.14 mycroft *tl++ = txdr_unsigned(cache);
1206 1.14 mycroft *tl++ = txdr_unsigned(nd->nd_duration);
1207 1.14 mycroft txdr_hyper(frev, tl);
1208 1.14 mycroft } else {
1209 1.22 cgd nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1210 1.14 mycroft *tl = 0;
1211 1.14 mycroft }
1212 1.14 mycroft }
1213 1.1 cgd *mrq = mreq;
1214 1.1 cgd *mbp = mb;
1215 1.1 cgd *bposp = bpos;
1216 1.24 fvdl if (err != 0 && err != NFSERR_RETVOID)
1217 1.1 cgd nfsstats.srvrpc_errs++;
1218 1.1 cgd return (0);
1219 1.1 cgd }
1220 1.1 cgd
1221 1.1 cgd /*
1222 1.1 cgd * Nfs timer routine
1223 1.1 cgd * Scan the nfsreq list and retranmit any requests that have timed out
1224 1.1 cgd * To avoid retransmission attempts on STREAM sockets (in the future) make
1225 1.1 cgd * sure to set the r_retry field to 0 (implies nm_retry == 0).
1226 1.1 cgd */
1227 1.7 mycroft void
1228 1.14 mycroft nfs_timer(arg)
1229 1.24 fvdl void *arg; /* never used */
1230 1.1 cgd {
1231 1.1 cgd register struct nfsreq *rep;
1232 1.1 cgd register struct mbuf *m;
1233 1.1 cgd register struct socket *so;
1234 1.1 cgd register struct nfsmount *nmp;
1235 1.14 mycroft register int timeo;
1236 1.24 fvdl register struct nfssvc_sock *slp;
1237 1.23 christos #ifdef NFSSERVER
1238 1.14 mycroft static long lasttime = 0;
1239 1.23 christos #endif
1240 1.1 cgd int s, error;
1241 1.24 fvdl u_quad_t cur_usec;
1242 1.1 cgd
1243 1.21 mycroft s = splsoftnet();
1244 1.16 mycroft for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) {
1245 1.1 cgd nmp = rep->r_nmp;
1246 1.14 mycroft if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
1247 1.1 cgd continue;
1248 1.14 mycroft if (nfs_sigintr(nmp, rep, rep->r_procp)) {
1249 1.1 cgd rep->r_flags |= R_SOFTTERM;
1250 1.1 cgd continue;
1251 1.1 cgd }
1252 1.14 mycroft if (rep->r_rtt >= 0) {
1253 1.14 mycroft rep->r_rtt++;
1254 1.14 mycroft if (nmp->nm_flag & NFSMNT_DUMBTIMR)
1255 1.14 mycroft timeo = nmp->nm_timeo;
1256 1.14 mycroft else
1257 1.14 mycroft timeo = NFS_RTO(nmp, proct[rep->r_procnum]);
1258 1.14 mycroft if (nmp->nm_timeouts > 0)
1259 1.14 mycroft timeo *= nfs_backoff[nmp->nm_timeouts - 1];
1260 1.14 mycroft if (rep->r_rtt <= timeo)
1261 1.14 mycroft continue;
1262 1.14 mycroft if (nmp->nm_timeouts < 8)
1263 1.14 mycroft nmp->nm_timeouts++;
1264 1.1 cgd }
1265 1.1 cgd /*
1266 1.1 cgd * Check for server not responding
1267 1.1 cgd */
1268 1.1 cgd if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
1269 1.14 mycroft rep->r_rexmit > nmp->nm_deadthresh) {
1270 1.1 cgd nfs_msg(rep->r_procp,
1271 1.1 cgd nmp->nm_mountp->mnt_stat.f_mntfromname,
1272 1.1 cgd "not responding");
1273 1.1 cgd rep->r_flags |= R_TPRINTFMSG;
1274 1.1 cgd }
1275 1.1 cgd if (rep->r_rexmit >= rep->r_retry) { /* too many */
1276 1.1 cgd nfsstats.rpctimeouts++;
1277 1.1 cgd rep->r_flags |= R_SOFTTERM;
1278 1.1 cgd continue;
1279 1.1 cgd }
1280 1.14 mycroft if (nmp->nm_sotype != SOCK_DGRAM) {
1281 1.14 mycroft if (++rep->r_rexmit > NFS_MAXREXMIT)
1282 1.14 mycroft rep->r_rexmit = NFS_MAXREXMIT;
1283 1.14 mycroft continue;
1284 1.14 mycroft }
1285 1.14 mycroft if ((so = nmp->nm_so) == NULL)
1286 1.1 cgd continue;
1287 1.1 cgd
1288 1.1 cgd /*
1289 1.1 cgd * If there is enough space and the window allows..
1290 1.1 cgd * Resend it
1291 1.14 mycroft * Set r_rtt to -1 in case we fail to send it now.
1292 1.1 cgd */
1293 1.14 mycroft rep->r_rtt = -1;
1294 1.1 cgd if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
1295 1.14 mycroft ((nmp->nm_flag & NFSMNT_DUMBTIMR) ||
1296 1.14 mycroft (rep->r_flags & R_SENT) ||
1297 1.14 mycroft nmp->nm_sent < nmp->nm_cwnd) &&
1298 1.14 mycroft (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){
1299 1.1 cgd if ((nmp->nm_flag & NFSMNT_NOCONN) == 0)
1300 1.1 cgd error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
1301 1.14 mycroft (struct mbuf *)0, (struct mbuf *)0);
1302 1.1 cgd else
1303 1.1 cgd error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, m,
1304 1.14 mycroft nmp->nm_nam, (struct mbuf *)0);
1305 1.1 cgd if (error) {
1306 1.1 cgd if (NFSIGNORE_SOERROR(nmp->nm_soflags, error))
1307 1.1 cgd so->so_error = 0;
1308 1.1 cgd } else {
1309 1.1 cgd /*
1310 1.14 mycroft * Iff first send, start timing
1311 1.14 mycroft * else turn timing off, backoff timer
1312 1.14 mycroft * and divide congestion window by 2.
1313 1.1 cgd */
1314 1.14 mycroft if (rep->r_flags & R_SENT) {
1315 1.14 mycroft rep->r_flags &= ~R_TIMING;
1316 1.14 mycroft if (++rep->r_rexmit > NFS_MAXREXMIT)
1317 1.14 mycroft rep->r_rexmit = NFS_MAXREXMIT;
1318 1.14 mycroft nmp->nm_cwnd >>= 1;
1319 1.14 mycroft if (nmp->nm_cwnd < NFS_CWNDSCALE)
1320 1.14 mycroft nmp->nm_cwnd = NFS_CWNDSCALE;
1321 1.14 mycroft nfsstats.rpcretries++;
1322 1.14 mycroft } else {
1323 1.14 mycroft rep->r_flags |= R_SENT;
1324 1.14 mycroft nmp->nm_sent += NFS_CWNDSCALE;
1325 1.14 mycroft }
1326 1.14 mycroft rep->r_rtt = 0;
1327 1.1 cgd }
1328 1.1 cgd }
1329 1.1 cgd }
1330 1.14 mycroft
1331 1.14 mycroft #ifdef NFSSERVER
1332 1.14 mycroft /*
1333 1.14 mycroft * Call the nqnfs server timer once a second to handle leases.
1334 1.14 mycroft */
1335 1.14 mycroft if (lasttime != time.tv_sec) {
1336 1.14 mycroft lasttime = time.tv_sec;
1337 1.14 mycroft nqnfs_serverd();
1338 1.14 mycroft }
1339 1.24 fvdl
1340 1.24 fvdl /*
1341 1.24 fvdl * Scan the write gathering queues for writes that need to be
1342 1.24 fvdl * completed now.
1343 1.24 fvdl */
1344 1.24 fvdl cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1345 1.24 fvdl for (slp = nfssvc_sockhead.tqh_first; slp != 0;
1346 1.24 fvdl slp = slp->ns_chain.tqe_next) {
1347 1.24 fvdl if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec)
1348 1.24 fvdl nfsrv_wakenfsd(slp);
1349 1.24 fvdl }
1350 1.14 mycroft #endif /* NFSSERVER */
1351 1.1 cgd splx(s);
1352 1.24 fvdl timeout(nfs_timer, (void *)0, nfs_ticks);
1353 1.1 cgd }
1354 1.1 cgd
1355 1.1 cgd /*
1356 1.14 mycroft * Test for a termination condition pending on the process.
1357 1.14 mycroft * This is used for NFSMNT_INT mounts.
1358 1.1 cgd */
1359 1.23 christos int
1360 1.14 mycroft nfs_sigintr(nmp, rep, p)
1361 1.14 mycroft struct nfsmount *nmp;
1362 1.14 mycroft struct nfsreq *rep;
1363 1.14 mycroft register struct proc *p;
1364 1.14 mycroft {
1365 1.14 mycroft
1366 1.14 mycroft if (rep && (rep->r_flags & R_SOFTTERM))
1367 1.14 mycroft return (EINTR);
1368 1.14 mycroft if (!(nmp->nm_flag & NFSMNT_INT))
1369 1.14 mycroft return (0);
1370 1.14 mycroft if (p && p->p_siglist &&
1371 1.14 mycroft (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) &
1372 1.14 mycroft NFSINT_SIGMASK))
1373 1.14 mycroft return (EINTR);
1374 1.14 mycroft return (0);
1375 1.14 mycroft }
1376 1.1 cgd
1377 1.1 cgd /*
1378 1.14 mycroft * Lock a socket against others.
1379 1.14 mycroft * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
1380 1.14 mycroft * and also to avoid race conditions between the processes with nfs requests
1381 1.14 mycroft * in progress when a reconnect is necessary.
1382 1.1 cgd */
1383 1.23 christos int
1384 1.14 mycroft nfs_sndlock(flagp, rep)
1385 1.14 mycroft register int *flagp;
1386 1.14 mycroft struct nfsreq *rep;
1387 1.14 mycroft {
1388 1.14 mycroft struct proc *p;
1389 1.14 mycroft int slpflag = 0, slptimeo = 0;
1390 1.14 mycroft
1391 1.14 mycroft if (rep) {
1392 1.14 mycroft p = rep->r_procp;
1393 1.14 mycroft if (rep->r_nmp->nm_flag & NFSMNT_INT)
1394 1.14 mycroft slpflag = PCATCH;
1395 1.14 mycroft } else
1396 1.14 mycroft p = (struct proc *)0;
1397 1.14 mycroft while (*flagp & NFSMNT_SNDLOCK) {
1398 1.14 mycroft if (nfs_sigintr(rep->r_nmp, rep, p))
1399 1.14 mycroft return (EINTR);
1400 1.14 mycroft *flagp |= NFSMNT_WANTSND;
1401 1.14 mycroft (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsndlck",
1402 1.14 mycroft slptimeo);
1403 1.14 mycroft if (slpflag == PCATCH) {
1404 1.14 mycroft slpflag = 0;
1405 1.14 mycroft slptimeo = 2 * hz;
1406 1.14 mycroft }
1407 1.14 mycroft }
1408 1.14 mycroft *flagp |= NFSMNT_SNDLOCK;
1409 1.14 mycroft return (0);
1410 1.14 mycroft }
1411 1.1 cgd
1412 1.14 mycroft /*
1413 1.14 mycroft * Unlock the stream socket for others.
1414 1.14 mycroft */
1415 1.14 mycroft void
1416 1.14 mycroft nfs_sndunlock(flagp)
1417 1.14 mycroft register int *flagp;
1418 1.1 cgd {
1419 1.1 cgd
1420 1.14 mycroft if ((*flagp & NFSMNT_SNDLOCK) == 0)
1421 1.14 mycroft panic("nfs sndunlock");
1422 1.14 mycroft *flagp &= ~NFSMNT_SNDLOCK;
1423 1.14 mycroft if (*flagp & NFSMNT_WANTSND) {
1424 1.14 mycroft *flagp &= ~NFSMNT_WANTSND;
1425 1.14 mycroft wakeup((caddr_t)flagp);
1426 1.1 cgd }
1427 1.14 mycroft }
1428 1.14 mycroft
1429 1.23 christos int
1430 1.14 mycroft nfs_rcvlock(rep)
1431 1.14 mycroft register struct nfsreq *rep;
1432 1.14 mycroft {
1433 1.14 mycroft register int *flagp = &rep->r_nmp->nm_flag;
1434 1.14 mycroft int slpflag, slptimeo = 0;
1435 1.14 mycroft
1436 1.14 mycroft if (*flagp & NFSMNT_INT)
1437 1.14 mycroft slpflag = PCATCH;
1438 1.14 mycroft else
1439 1.14 mycroft slpflag = 0;
1440 1.14 mycroft while (*flagp & NFSMNT_RCVLOCK) {
1441 1.14 mycroft if (nfs_sigintr(rep->r_nmp, rep, rep->r_procp))
1442 1.14 mycroft return (EINTR);
1443 1.14 mycroft *flagp |= NFSMNT_WANTRCV;
1444 1.14 mycroft (void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "nfsrcvlk",
1445 1.14 mycroft slptimeo);
1446 1.14 mycroft if (slpflag == PCATCH) {
1447 1.14 mycroft slpflag = 0;
1448 1.14 mycroft slptimeo = 2 * hz;
1449 1.1 cgd }
1450 1.1 cgd }
1451 1.14 mycroft *flagp |= NFSMNT_RCVLOCK;
1452 1.14 mycroft return (0);
1453 1.14 mycroft }
1454 1.14 mycroft
1455 1.14 mycroft /*
1456 1.14 mycroft * Unlock the stream socket for others.
1457 1.14 mycroft */
1458 1.14 mycroft void
1459 1.14 mycroft nfs_rcvunlock(flagp)
1460 1.14 mycroft register int *flagp;
1461 1.14 mycroft {
1462 1.14 mycroft
1463 1.14 mycroft if ((*flagp & NFSMNT_RCVLOCK) == 0)
1464 1.14 mycroft panic("nfs rcvunlock");
1465 1.14 mycroft *flagp &= ~NFSMNT_RCVLOCK;
1466 1.14 mycroft if (*flagp & NFSMNT_WANTRCV) {
1467 1.14 mycroft *flagp &= ~NFSMNT_WANTRCV;
1468 1.14 mycroft wakeup((caddr_t)flagp);
1469 1.14 mycroft }
1470 1.1 cgd }
1471 1.1 cgd
1472 1.14 mycroft /*
1473 1.14 mycroft * Check for badly aligned mbuf data areas and
1474 1.14 mycroft * realign data in an mbuf list by copying the data areas up, as required.
1475 1.14 mycroft */
1476 1.14 mycroft void
1477 1.14 mycroft nfs_realign(m, hsiz)
1478 1.14 mycroft register struct mbuf *m;
1479 1.14 mycroft int hsiz;
1480 1.1 cgd {
1481 1.14 mycroft register struct mbuf *m2;
1482 1.14 mycroft register int siz, mlen, olen;
1483 1.14 mycroft register caddr_t tcp, fcp;
1484 1.14 mycroft struct mbuf *mnew;
1485 1.1 cgd
1486 1.14 mycroft while (m) {
1487 1.14 mycroft /*
1488 1.14 mycroft * This never happens for UDP, rarely happens for TCP
1489 1.14 mycroft * but frequently happens for iso transport.
1490 1.14 mycroft */
1491 1.22 cgd if ((m->m_len & 0x3) || (mtod(m, long) & 0x3)) {
1492 1.14 mycroft olen = m->m_len;
1493 1.14 mycroft fcp = mtod(m, caddr_t);
1494 1.22 cgd if ((long)fcp & 0x3) {
1495 1.14 mycroft m->m_flags &= ~M_PKTHDR;
1496 1.14 mycroft if (m->m_flags & M_EXT)
1497 1.14 mycroft m->m_data = m->m_ext.ext_buf +
1498 1.14 mycroft ((m->m_ext.ext_size - olen) & ~0x3);
1499 1.14 mycroft else
1500 1.14 mycroft m->m_data = m->m_dat;
1501 1.14 mycroft }
1502 1.14 mycroft m->m_len = 0;
1503 1.14 mycroft tcp = mtod(m, caddr_t);
1504 1.14 mycroft mnew = m;
1505 1.14 mycroft m2 = m->m_next;
1506 1.14 mycroft
1507 1.14 mycroft /*
1508 1.14 mycroft * If possible, only put the first invariant part
1509 1.14 mycroft * of the RPC header in the first mbuf.
1510 1.14 mycroft */
1511 1.14 mycroft mlen = M_TRAILINGSPACE(m);
1512 1.14 mycroft if (olen <= hsiz && mlen > hsiz)
1513 1.14 mycroft mlen = hsiz;
1514 1.14 mycroft
1515 1.14 mycroft /*
1516 1.14 mycroft * Loop through the mbuf list consolidating data.
1517 1.14 mycroft */
1518 1.14 mycroft while (m) {
1519 1.14 mycroft while (olen > 0) {
1520 1.14 mycroft if (mlen == 0) {
1521 1.14 mycroft m2->m_flags &= ~M_PKTHDR;
1522 1.14 mycroft if (m2->m_flags & M_EXT)
1523 1.14 mycroft m2->m_data = m2->m_ext.ext_buf;
1524 1.14 mycroft else
1525 1.14 mycroft m2->m_data = m2->m_dat;
1526 1.14 mycroft m2->m_len = 0;
1527 1.14 mycroft mlen = M_TRAILINGSPACE(m2);
1528 1.14 mycroft tcp = mtod(m2, caddr_t);
1529 1.14 mycroft mnew = m2;
1530 1.14 mycroft m2 = m2->m_next;
1531 1.14 mycroft }
1532 1.14 mycroft siz = min(mlen, olen);
1533 1.14 mycroft if (tcp != fcp)
1534 1.14 mycroft bcopy(fcp, tcp, siz);
1535 1.14 mycroft mnew->m_len += siz;
1536 1.14 mycroft mlen -= siz;
1537 1.14 mycroft olen -= siz;
1538 1.14 mycroft tcp += siz;
1539 1.14 mycroft fcp += siz;
1540 1.1 cgd }
1541 1.14 mycroft m = m->m_next;
1542 1.14 mycroft if (m) {
1543 1.14 mycroft olen = m->m_len;
1544 1.14 mycroft fcp = mtod(m, caddr_t);
1545 1.14 mycroft }
1546 1.14 mycroft }
1547 1.14 mycroft
1548 1.14 mycroft /*
1549 1.14 mycroft * Finally, set m_len == 0 for any trailing mbufs that have
1550 1.14 mycroft * been copied out of.
1551 1.14 mycroft */
1552 1.14 mycroft while (m2) {
1553 1.14 mycroft m2->m_len = 0;
1554 1.14 mycroft m2 = m2->m_next;
1555 1.1 cgd }
1556 1.14 mycroft return;
1557 1.14 mycroft }
1558 1.14 mycroft m = m->m_next;
1559 1.1 cgd }
1560 1.1 cgd }
1561 1.1 cgd
1562 1.1 cgd /*
1563 1.14 mycroft * Parse an RPC request
1564 1.14 mycroft * - verify it
1565 1.14 mycroft * - fill in the cred struct.
1566 1.1 cgd */
1567 1.23 christos int
1568 1.24 fvdl nfs_getreq(nd, nfsd, has_header)
1569 1.24 fvdl register struct nfsrv_descript *nd;
1570 1.24 fvdl struct nfsd *nfsd;
1571 1.14 mycroft int has_header;
1572 1.1 cgd {
1573 1.14 mycroft register int len, i;
1574 1.22 cgd register u_int32_t *tl;
1575 1.22 cgd register int32_t t1;
1576 1.14 mycroft struct uio uio;
1577 1.14 mycroft struct iovec iov;
1578 1.24 fvdl caddr_t dpos, cp2, cp;
1579 1.22 cgd u_int32_t nfsvers, auth_type;
1580 1.24 fvdl uid_t nickuid;
1581 1.24 fvdl int error = 0, nqnfs = 0, ticklen;
1582 1.14 mycroft struct mbuf *mrep, *md;
1583 1.24 fvdl register struct nfsuid *nuidp;
1584 1.24 fvdl struct timeval tvin, tvout;
1585 1.14 mycroft
1586 1.14 mycroft mrep = nd->nd_mrep;
1587 1.14 mycroft md = nd->nd_md;
1588 1.14 mycroft dpos = nd->nd_dpos;
1589 1.14 mycroft if (has_header) {
1590 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1591 1.24 fvdl nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++);
1592 1.14 mycroft if (*tl++ != rpc_call) {
1593 1.14 mycroft m_freem(mrep);
1594 1.14 mycroft return (EBADRPC);
1595 1.14 mycroft }
1596 1.24 fvdl } else
1597 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
1598 1.14 mycroft nd->nd_repstat = 0;
1599 1.24 fvdl nd->nd_flag = 0;
1600 1.14 mycroft if (*tl++ != rpc_vers) {
1601 1.14 mycroft nd->nd_repstat = ERPCMISMATCH;
1602 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP;
1603 1.14 mycroft return (0);
1604 1.14 mycroft }
1605 1.14 mycroft if (*tl != nfs_prog) {
1606 1.24 fvdl if (*tl == nqnfs_prog)
1607 1.14 mycroft nqnfs++;
1608 1.24 fvdl else {
1609 1.14 mycroft nd->nd_repstat = EPROGUNAVAIL;
1610 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP;
1611 1.14 mycroft return (0);
1612 1.14 mycroft }
1613 1.14 mycroft }
1614 1.14 mycroft tl++;
1615 1.24 fvdl nfsvers = fxdr_unsigned(u_int32_t, *tl++);
1616 1.24 fvdl if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) ||
1617 1.24 fvdl (nfsvers != NQNFS_VER3 && nqnfs)) {
1618 1.14 mycroft nd->nd_repstat = EPROGMISMATCH;
1619 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP;
1620 1.14 mycroft return (0);
1621 1.14 mycroft }
1622 1.24 fvdl if (nqnfs)
1623 1.24 fvdl nd->nd_flag = (ND_NFSV3 | ND_NQNFS);
1624 1.24 fvdl else if (nfsvers == NFS_VER3)
1625 1.24 fvdl nd->nd_flag = ND_NFSV3;
1626 1.24 fvdl nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++);
1627 1.14 mycroft if (nd->nd_procnum == NFSPROC_NULL)
1628 1.14 mycroft return (0);
1629 1.14 mycroft if (nd->nd_procnum >= NFS_NPROCS ||
1630 1.24 fvdl (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) ||
1631 1.24 fvdl (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) {
1632 1.14 mycroft nd->nd_repstat = EPROCUNAVAIL;
1633 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP;
1634 1.1 cgd return (0);
1635 1.14 mycroft }
1636 1.24 fvdl if ((nd->nd_flag & ND_NFSV3) == 0)
1637 1.24 fvdl nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
1638 1.14 mycroft auth_type = *tl++;
1639 1.14 mycroft len = fxdr_unsigned(int, *tl++);
1640 1.14 mycroft if (len < 0 || len > RPCAUTH_MAXSIZ) {
1641 1.14 mycroft m_freem(mrep);
1642 1.14 mycroft return (EBADRPC);
1643 1.14 mycroft }
1644 1.14 mycroft
1645 1.24 fvdl nd->nd_flag &= ~ND_KERBAUTH;
1646 1.14 mycroft /*
1647 1.14 mycroft * Handle auth_unix or auth_kerb.
1648 1.14 mycroft */
1649 1.14 mycroft if (auth_type == rpc_auth_unix) {
1650 1.14 mycroft len = fxdr_unsigned(int, *++tl);
1651 1.14 mycroft if (len < 0 || len > NFS_MAXNAMLEN) {
1652 1.14 mycroft m_freem(mrep);
1653 1.14 mycroft return (EBADRPC);
1654 1.14 mycroft }
1655 1.14 mycroft nfsm_adv(nfsm_rndup(len));
1656 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1657 1.24 fvdl bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred));
1658 1.24 fvdl nd->nd_cr.cr_ref = 1;
1659 1.14 mycroft nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
1660 1.14 mycroft nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++);
1661 1.14 mycroft len = fxdr_unsigned(int, *tl);
1662 1.14 mycroft if (len < 0 || len > RPCAUTH_UNIXGIDS) {
1663 1.14 mycroft m_freem(mrep);
1664 1.14 mycroft return (EBADRPC);
1665 1.14 mycroft }
1666 1.24 fvdl nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED);
1667 1.18 mycroft for (i = 0; i < len; i++)
1668 1.24 fvdl if (i < NGROUPS)
1669 1.24 fvdl nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
1670 1.24 fvdl else
1671 1.24 fvdl tl++;
1672 1.19 mycroft nd->nd_cr.cr_ngroups = (len > NGROUPS) ? NGROUPS : len;
1673 1.24 fvdl if (nd->nd_cr.cr_ngroups > 1)
1674 1.24 fvdl nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups);
1675 1.24 fvdl len = fxdr_unsigned(int, *++tl);
1676 1.24 fvdl if (len < 0 || len > RPCAUTH_MAXSIZ) {
1677 1.14 mycroft m_freem(mrep);
1678 1.14 mycroft return (EBADRPC);
1679 1.14 mycroft }
1680 1.24 fvdl if (len > 0)
1681 1.24 fvdl nfsm_adv(nfsm_rndup(len));
1682 1.24 fvdl } else if (auth_type == rpc_auth_kerb) {
1683 1.24 fvdl switch (fxdr_unsigned(int, *tl++)) {
1684 1.24 fvdl case RPCAKN_FULLNAME:
1685 1.24 fvdl ticklen = fxdr_unsigned(int, *tl);
1686 1.24 fvdl *((u_int32_t *)nfsd->nfsd_authstr) = *tl;
1687 1.24 fvdl uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED;
1688 1.24 fvdl nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED;
1689 1.24 fvdl if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
1690 1.24 fvdl m_freem(mrep);
1691 1.24 fvdl return (EBADRPC);
1692 1.24 fvdl }
1693 1.24 fvdl uio.uio_offset = 0;
1694 1.24 fvdl uio.uio_iov = &iov;
1695 1.24 fvdl uio.uio_iovcnt = 1;
1696 1.24 fvdl uio.uio_segflg = UIO_SYSSPACE;
1697 1.24 fvdl iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4];
1698 1.24 fvdl iov.iov_len = RPCAUTH_MAXSIZ - 4;
1699 1.24 fvdl nfsm_mtouio(&uio, uio.uio_resid);
1700 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1701 1.24 fvdl if (*tl++ != rpc_auth_kerb ||
1702 1.24 fvdl fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) {
1703 1.24 fvdl printf("Bad kerb verifier\n");
1704 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
1705 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1706 1.24 fvdl return (0);
1707 1.24 fvdl }
1708 1.24 fvdl nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED);
1709 1.24 fvdl tl = (u_int32_t *)cp;
1710 1.24 fvdl if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) {
1711 1.24 fvdl printf("Not fullname kerb verifier\n");
1712 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
1713 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1714 1.24 fvdl return (0);
1715 1.24 fvdl }
1716 1.24 fvdl cp += NFSX_UNSIGNED;
1717 1.24 fvdl bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED);
1718 1.24 fvdl nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED;
1719 1.24 fvdl nd->nd_flag |= ND_KERBFULL;
1720 1.24 fvdl nfsd->nfsd_flag |= NFSD_NEEDAUTH;
1721 1.24 fvdl break;
1722 1.24 fvdl case RPCAKN_NICKNAME:
1723 1.24 fvdl if (len != 2 * NFSX_UNSIGNED) {
1724 1.24 fvdl printf("Kerb nickname short\n");
1725 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED);
1726 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1727 1.24 fvdl return (0);
1728 1.24 fvdl }
1729 1.24 fvdl nickuid = fxdr_unsigned(uid_t, *tl);
1730 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1731 1.24 fvdl if (*tl++ != rpc_auth_kerb ||
1732 1.24 fvdl fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) {
1733 1.24 fvdl printf("Kerb nick verifier bad\n");
1734 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
1735 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1736 1.24 fvdl return (0);
1737 1.24 fvdl }
1738 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1739 1.24 fvdl tvin.tv_sec = *tl++;
1740 1.24 fvdl tvin.tv_usec = *tl;
1741 1.24 fvdl
1742 1.24 fvdl for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first;
1743 1.24 fvdl nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
1744 1.24 fvdl if (nuidp->nu_cr.cr_uid == nickuid &&
1745 1.24 fvdl (!nd->nd_nam2 ||
1746 1.24 fvdl netaddr_match(NU_NETFAM(nuidp),
1747 1.24 fvdl &nuidp->nu_haddr, nd->nd_nam2)))
1748 1.24 fvdl break;
1749 1.24 fvdl }
1750 1.24 fvdl if (!nuidp) {
1751 1.24 fvdl nd->nd_repstat =
1752 1.24 fvdl (NFSERR_AUTHERR|AUTH_REJECTCRED);
1753 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1754 1.24 fvdl return (0);
1755 1.24 fvdl }
1756 1.24 fvdl
1757 1.24 fvdl /*
1758 1.24 fvdl * Now, decrypt the timestamp using the session key
1759 1.24 fvdl * and validate it.
1760 1.24 fvdl */
1761 1.24 fvdl #ifdef NFSKERB
1762 1.24 fvdl XXX
1763 1.24 fvdl #endif
1764 1.14 mycroft
1765 1.24 fvdl tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec);
1766 1.24 fvdl tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec);
1767 1.24 fvdl if (nuidp->nu_expire < time.tv_sec ||
1768 1.24 fvdl nuidp->nu_timestamp.tv_sec > tvout.tv_sec ||
1769 1.24 fvdl (nuidp->nu_timestamp.tv_sec == tvout.tv_sec &&
1770 1.24 fvdl nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) {
1771 1.24 fvdl nuidp->nu_expire = 0;
1772 1.24 fvdl nd->nd_repstat =
1773 1.24 fvdl (NFSERR_AUTHERR|AUTH_REJECTVERF);
1774 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1775 1.24 fvdl return (0);
1776 1.24 fvdl }
1777 1.24 fvdl nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr);
1778 1.24 fvdl nd->nd_flag |= ND_KERBNICK;
1779 1.24 fvdl };
1780 1.24 fvdl } else {
1781 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
1782 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP;
1783 1.24 fvdl return (0);
1784 1.14 mycroft }
1785 1.14 mycroft
1786 1.14 mycroft /*
1787 1.14 mycroft * For nqnfs, get piggybacked lease request.
1788 1.14 mycroft */
1789 1.14 mycroft if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) {
1790 1.22 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1791 1.24 fvdl nd->nd_flag |= fxdr_unsigned(int, *tl);
1792 1.24 fvdl if (nd->nd_flag & ND_LEASE) {
1793 1.22 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1794 1.24 fvdl nd->nd_duration = fxdr_unsigned(u_int32_t, *tl);
1795 1.14 mycroft } else
1796 1.14 mycroft nd->nd_duration = NQ_MINLEASE;
1797 1.24 fvdl } else
1798 1.14 mycroft nd->nd_duration = NQ_MINLEASE;
1799 1.14 mycroft nd->nd_md = md;
1800 1.14 mycroft nd->nd_dpos = dpos;
1801 1.14 mycroft return (0);
1802 1.14 mycroft nfsmout:
1803 1.14 mycroft return (error);
1804 1.1 cgd }
1805 1.1 cgd
1806 1.24 fvdl int
1807 1.1 cgd nfs_msg(p, server, msg)
1808 1.1 cgd struct proc *p;
1809 1.1 cgd char *server, *msg;
1810 1.1 cgd {
1811 1.1 cgd tpr_t tpr;
1812 1.1 cgd
1813 1.1 cgd if (p)
1814 1.1 cgd tpr = tprintf_open(p);
1815 1.1 cgd else
1816 1.1 cgd tpr = NULL;
1817 1.1 cgd tprintf(tpr, "nfs server %s: %s\n", server, msg);
1818 1.1 cgd tprintf_close(tpr);
1819 1.24 fvdl return (0);
1820 1.1 cgd }
1821 1.1 cgd
1822 1.14 mycroft #ifdef NFSSERVER
1823 1.24 fvdl int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *,
1824 1.24 fvdl struct nfssvc_sock *, struct proc *,
1825 1.23 christos struct mbuf **)) = {
1826 1.14 mycroft nfsrv_null,
1827 1.14 mycroft nfsrv_getattr,
1828 1.14 mycroft nfsrv_setattr,
1829 1.14 mycroft nfsrv_lookup,
1830 1.24 fvdl nfsrv3_access,
1831 1.14 mycroft nfsrv_readlink,
1832 1.14 mycroft nfsrv_read,
1833 1.14 mycroft nfsrv_write,
1834 1.14 mycroft nfsrv_create,
1835 1.24 fvdl nfsrv_mkdir,
1836 1.24 fvdl nfsrv_symlink,
1837 1.24 fvdl nfsrv_mknod,
1838 1.14 mycroft nfsrv_remove,
1839 1.24 fvdl nfsrv_rmdir,
1840 1.14 mycroft nfsrv_rename,
1841 1.14 mycroft nfsrv_link,
1842 1.14 mycroft nfsrv_readdir,
1843 1.24 fvdl nfsrv_readdirplus,
1844 1.14 mycroft nfsrv_statfs,
1845 1.24 fvdl nfsrv_fsinfo,
1846 1.24 fvdl nfsrv_pathconf,
1847 1.24 fvdl nfsrv_commit,
1848 1.14 mycroft nqnfsrv_getlease,
1849 1.14 mycroft nqnfsrv_vacated,
1850 1.14 mycroft nfsrv_noop,
1851 1.24 fvdl nfsrv_noop
1852 1.14 mycroft };
1853 1.14 mycroft
1854 1.1 cgd /*
1855 1.14 mycroft * Socket upcall routine for the nfsd sockets.
1856 1.14 mycroft * The caddr_t arg is a pointer to the "struct nfssvc_sock".
1857 1.14 mycroft * Essentially do as much as possible non-blocking, else punt and it will
1858 1.14 mycroft * be called with M_WAIT from an nfsd.
1859 1.1 cgd */
1860 1.14 mycroft void
1861 1.14 mycroft nfsrv_rcv(so, arg, waitflag)
1862 1.14 mycroft struct socket *so;
1863 1.14 mycroft caddr_t arg;
1864 1.14 mycroft int waitflag;
1865 1.1 cgd {
1866 1.14 mycroft register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg;
1867 1.14 mycroft register struct mbuf *m;
1868 1.14 mycroft struct mbuf *mp, *nam;
1869 1.14 mycroft struct uio auio;
1870 1.14 mycroft int flags, error;
1871 1.1 cgd
1872 1.14 mycroft if ((slp->ns_flag & SLP_VALID) == 0)
1873 1.14 mycroft return;
1874 1.14 mycroft #ifdef notdef
1875 1.14 mycroft /*
1876 1.14 mycroft * Define this to test for nfsds handling this under heavy load.
1877 1.14 mycroft */
1878 1.14 mycroft if (waitflag == M_DONTWAIT) {
1879 1.14 mycroft slp->ns_flag |= SLP_NEEDQ; goto dorecs;
1880 1.1 cgd }
1881 1.14 mycroft #endif
1882 1.14 mycroft auio.uio_procp = NULL;
1883 1.14 mycroft if (so->so_type == SOCK_STREAM) {
1884 1.14 mycroft /*
1885 1.14 mycroft * If there are already records on the queue, defer soreceive()
1886 1.14 mycroft * to an nfsd so that there is feedback to the TCP layer that
1887 1.14 mycroft * the nfs servers are heavily loaded.
1888 1.14 mycroft */
1889 1.14 mycroft if (slp->ns_rec && waitflag == M_DONTWAIT) {
1890 1.14 mycroft slp->ns_flag |= SLP_NEEDQ;
1891 1.14 mycroft goto dorecs;
1892 1.14 mycroft }
1893 1.14 mycroft
1894 1.14 mycroft /*
1895 1.14 mycroft * Do soreceive().
1896 1.14 mycroft */
1897 1.14 mycroft auio.uio_resid = 1000000000;
1898 1.14 mycroft flags = MSG_DONTWAIT;
1899 1.14 mycroft error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags);
1900 1.14 mycroft if (error || mp == (struct mbuf *)0) {
1901 1.14 mycroft if (error == EWOULDBLOCK)
1902 1.14 mycroft slp->ns_flag |= SLP_NEEDQ;
1903 1.14 mycroft else
1904 1.14 mycroft slp->ns_flag |= SLP_DISCONN;
1905 1.14 mycroft goto dorecs;
1906 1.14 mycroft }
1907 1.14 mycroft m = mp;
1908 1.14 mycroft if (slp->ns_rawend) {
1909 1.14 mycroft slp->ns_rawend->m_next = m;
1910 1.14 mycroft slp->ns_cc += 1000000000 - auio.uio_resid;
1911 1.14 mycroft } else {
1912 1.14 mycroft slp->ns_raw = m;
1913 1.14 mycroft slp->ns_cc = 1000000000 - auio.uio_resid;
1914 1.14 mycroft }
1915 1.14 mycroft while (m->m_next)
1916 1.14 mycroft m = m->m_next;
1917 1.14 mycroft slp->ns_rawend = m;
1918 1.14 mycroft
1919 1.14 mycroft /*
1920 1.14 mycroft * Now try and parse record(s) out of the raw stream data.
1921 1.14 mycroft */
1922 1.24 fvdl error = nfsrv_getstream(slp, waitflag);
1923 1.24 fvdl if (error) {
1924 1.14 mycroft if (error == EPERM)
1925 1.14 mycroft slp->ns_flag |= SLP_DISCONN;
1926 1.14 mycroft else
1927 1.14 mycroft slp->ns_flag |= SLP_NEEDQ;
1928 1.14 mycroft }
1929 1.14 mycroft } else {
1930 1.14 mycroft do {
1931 1.14 mycroft auio.uio_resid = 1000000000;
1932 1.14 mycroft flags = MSG_DONTWAIT;
1933 1.14 mycroft error = soreceive(so, &nam, &auio, &mp,
1934 1.14 mycroft (struct mbuf **)0, &flags);
1935 1.14 mycroft if (mp) {
1936 1.14 mycroft nfs_realign(mp, 10 * NFSX_UNSIGNED);
1937 1.14 mycroft if (nam) {
1938 1.14 mycroft m = nam;
1939 1.14 mycroft m->m_next = mp;
1940 1.14 mycroft } else
1941 1.14 mycroft m = mp;
1942 1.14 mycroft if (slp->ns_recend)
1943 1.14 mycroft slp->ns_recend->m_nextpkt = m;
1944 1.14 mycroft else
1945 1.14 mycroft slp->ns_rec = m;
1946 1.14 mycroft slp->ns_recend = m;
1947 1.14 mycroft m->m_nextpkt = (struct mbuf *)0;
1948 1.14 mycroft }
1949 1.14 mycroft if (error) {
1950 1.14 mycroft if ((so->so_proto->pr_flags & PR_CONNREQUIRED)
1951 1.14 mycroft && error != EWOULDBLOCK) {
1952 1.14 mycroft slp->ns_flag |= SLP_DISCONN;
1953 1.14 mycroft goto dorecs;
1954 1.14 mycroft }
1955 1.14 mycroft }
1956 1.14 mycroft } while (mp);
1957 1.14 mycroft }
1958 1.14 mycroft
1959 1.14 mycroft /*
1960 1.14 mycroft * Now try and process the request records, non-blocking.
1961 1.14 mycroft */
1962 1.14 mycroft dorecs:
1963 1.14 mycroft if (waitflag == M_DONTWAIT &&
1964 1.14 mycroft (slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN))))
1965 1.14 mycroft nfsrv_wakenfsd(slp);
1966 1.1 cgd }
1967 1.1 cgd
1968 1.1 cgd /*
1969 1.14 mycroft * Try and extract an RPC request from the mbuf data list received on a
1970 1.14 mycroft * stream socket. The "waitflag" argument indicates whether or not it
1971 1.14 mycroft * can sleep.
1972 1.14 mycroft */
1973 1.23 christos int
1974 1.14 mycroft nfsrv_getstream(slp, waitflag)
1975 1.14 mycroft register struct nfssvc_sock *slp;
1976 1.14 mycroft int waitflag;
1977 1.1 cgd {
1978 1.24 fvdl register struct mbuf *m, **mpp;
1979 1.14 mycroft register char *cp1, *cp2;
1980 1.14 mycroft register int len;
1981 1.23 christos struct mbuf *om, *m2, *recm = NULL;
1982 1.24 fvdl u_int32_t recmark;
1983 1.1 cgd
1984 1.14 mycroft if (slp->ns_flag & SLP_GETSTREAM)
1985 1.14 mycroft panic("nfs getstream");
1986 1.14 mycroft slp->ns_flag |= SLP_GETSTREAM;
1987 1.14 mycroft for (;;) {
1988 1.14 mycroft if (slp->ns_reclen == 0) {
1989 1.14 mycroft if (slp->ns_cc < NFSX_UNSIGNED) {
1990 1.14 mycroft slp->ns_flag &= ~SLP_GETSTREAM;
1991 1.14 mycroft return (0);
1992 1.14 mycroft }
1993 1.14 mycroft m = slp->ns_raw;
1994 1.14 mycroft if (m->m_len >= NFSX_UNSIGNED) {
1995 1.14 mycroft bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED);
1996 1.14 mycroft m->m_data += NFSX_UNSIGNED;
1997 1.14 mycroft m->m_len -= NFSX_UNSIGNED;
1998 1.14 mycroft } else {
1999 1.14 mycroft cp1 = (caddr_t)&recmark;
2000 1.14 mycroft cp2 = mtod(m, caddr_t);
2001 1.14 mycroft while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) {
2002 1.14 mycroft while (m->m_len == 0) {
2003 1.14 mycroft m = m->m_next;
2004 1.14 mycroft cp2 = mtod(m, caddr_t);
2005 1.14 mycroft }
2006 1.14 mycroft *cp1++ = *cp2++;
2007 1.14 mycroft m->m_data++;
2008 1.14 mycroft m->m_len--;
2009 1.14 mycroft }
2010 1.14 mycroft }
2011 1.14 mycroft slp->ns_cc -= NFSX_UNSIGNED;
2012 1.24 fvdl recmark = ntohl(recmark);
2013 1.24 fvdl slp->ns_reclen = recmark & ~0x80000000;
2014 1.24 fvdl if (recmark & 0x80000000)
2015 1.24 fvdl slp->ns_flag |= SLP_LASTFRAG;
2016 1.24 fvdl else
2017 1.24 fvdl slp->ns_flag &= ~SLP_LASTFRAG;
2018 1.14 mycroft if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) {
2019 1.14 mycroft slp->ns_flag &= ~SLP_GETSTREAM;
2020 1.14 mycroft return (EPERM);
2021 1.14 mycroft }
2022 1.14 mycroft }
2023 1.14 mycroft
2024 1.14 mycroft /*
2025 1.14 mycroft * Now get the record part.
2026 1.14 mycroft */
2027 1.14 mycroft if (slp->ns_cc == slp->ns_reclen) {
2028 1.14 mycroft recm = slp->ns_raw;
2029 1.14 mycroft slp->ns_raw = slp->ns_rawend = (struct mbuf *)0;
2030 1.14 mycroft slp->ns_cc = slp->ns_reclen = 0;
2031 1.14 mycroft } else if (slp->ns_cc > slp->ns_reclen) {
2032 1.14 mycroft len = 0;
2033 1.14 mycroft m = slp->ns_raw;
2034 1.14 mycroft om = (struct mbuf *)0;
2035 1.14 mycroft while (len < slp->ns_reclen) {
2036 1.14 mycroft if ((len + m->m_len) > slp->ns_reclen) {
2037 1.14 mycroft m2 = m_copym(m, 0, slp->ns_reclen - len,
2038 1.14 mycroft waitflag);
2039 1.14 mycroft if (m2) {
2040 1.14 mycroft if (om) {
2041 1.14 mycroft om->m_next = m2;
2042 1.14 mycroft recm = slp->ns_raw;
2043 1.14 mycroft } else
2044 1.14 mycroft recm = m2;
2045 1.14 mycroft m->m_data += slp->ns_reclen - len;
2046 1.14 mycroft m->m_len -= slp->ns_reclen - len;
2047 1.14 mycroft len = slp->ns_reclen;
2048 1.14 mycroft } else {
2049 1.14 mycroft slp->ns_flag &= ~SLP_GETSTREAM;
2050 1.14 mycroft return (EWOULDBLOCK);
2051 1.14 mycroft }
2052 1.14 mycroft } else if ((len + m->m_len) == slp->ns_reclen) {
2053 1.14 mycroft om = m;
2054 1.14 mycroft len += m->m_len;
2055 1.14 mycroft m = m->m_next;
2056 1.14 mycroft recm = slp->ns_raw;
2057 1.14 mycroft om->m_next = (struct mbuf *)0;
2058 1.14 mycroft } else {
2059 1.14 mycroft om = m;
2060 1.14 mycroft len += m->m_len;
2061 1.14 mycroft m = m->m_next;
2062 1.14 mycroft }
2063 1.14 mycroft }
2064 1.14 mycroft slp->ns_raw = m;
2065 1.14 mycroft slp->ns_cc -= len;
2066 1.14 mycroft slp->ns_reclen = 0;
2067 1.14 mycroft } else {
2068 1.14 mycroft slp->ns_flag &= ~SLP_GETSTREAM;
2069 1.14 mycroft return (0);
2070 1.14 mycroft }
2071 1.24 fvdl
2072 1.24 fvdl /*
2073 1.24 fvdl * Accumulate the fragments into a record.
2074 1.24 fvdl */
2075 1.24 fvdl mpp = &slp->ns_frag;
2076 1.24 fvdl while (*mpp)
2077 1.24 fvdl mpp = &((*mpp)->m_next);
2078 1.24 fvdl *mpp = recm;
2079 1.24 fvdl if (slp->ns_flag & SLP_LASTFRAG) {
2080 1.24 fvdl nfs_realign(slp->ns_frag, 10 * NFSX_UNSIGNED);
2081 1.24 fvdl if (slp->ns_recend)
2082 1.24 fvdl slp->ns_recend->m_nextpkt = slp->ns_frag;
2083 1.24 fvdl else
2084 1.24 fvdl slp->ns_rec = slp->ns_frag;
2085 1.24 fvdl slp->ns_recend = slp->ns_frag;
2086 1.24 fvdl slp->ns_frag = (struct mbuf *)0;
2087 1.24 fvdl }
2088 1.1 cgd }
2089 1.1 cgd }
2090 1.1 cgd
2091 1.1 cgd /*
2092 1.14 mycroft * Parse an RPC header.
2093 1.14 mycroft */
2094 1.23 christos int
2095 1.24 fvdl nfsrv_dorec(slp, nfsd, ndp)
2096 1.14 mycroft register struct nfssvc_sock *slp;
2097 1.24 fvdl struct nfsd *nfsd;
2098 1.24 fvdl struct nfsrv_descript **ndp;
2099 1.14 mycroft {
2100 1.24 fvdl register struct mbuf *m, *nam;
2101 1.24 fvdl register struct nfsrv_descript *nd;
2102 1.14 mycroft int error;
2103 1.1 cgd
2104 1.24 fvdl *ndp = NULL;
2105 1.14 mycroft if ((slp->ns_flag & SLP_VALID) == 0 ||
2106 1.14 mycroft (m = slp->ns_rec) == (struct mbuf *)0)
2107 1.14 mycroft return (ENOBUFS);
2108 1.24 fvdl slp->ns_rec = m->m_nextpkt;
2109 1.24 fvdl if (slp->ns_rec)
2110 1.14 mycroft m->m_nextpkt = (struct mbuf *)0;
2111 1.14 mycroft else
2112 1.14 mycroft slp->ns_recend = (struct mbuf *)0;
2113 1.14 mycroft if (m->m_type == MT_SONAME) {
2114 1.24 fvdl nam = m;
2115 1.24 fvdl m = m->m_next;
2116 1.24 fvdl nam->m_next = NULL;
2117 1.24 fvdl } else
2118 1.24 fvdl nam = NULL;
2119 1.24 fvdl MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript),
2120 1.24 fvdl M_NFSRVDESC, M_WAITOK);
2121 1.24 fvdl nd->nd_md = nd->nd_mrep = m;
2122 1.24 fvdl nd->nd_nam2 = nam;
2123 1.24 fvdl nd->nd_dpos = mtod(m, caddr_t);
2124 1.24 fvdl error = nfs_getreq(nd, nfsd, TRUE);
2125 1.24 fvdl if (error) {
2126 1.24 fvdl m_freem(nam);
2127 1.24 fvdl free((caddr_t)nd, M_NFSRVDESC);
2128 1.14 mycroft return (error);
2129 1.14 mycroft }
2130 1.24 fvdl *ndp = nd;
2131 1.24 fvdl nfsd->nfsd_nd = nd;
2132 1.1 cgd return (0);
2133 1.1 cgd }
2134 1.1 cgd
2135 1.24 fvdl
2136 1.1 cgd /*
2137 1.14 mycroft * Search for a sleeping nfsd and wake it up.
2138 1.14 mycroft * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the
2139 1.14 mycroft * running nfsds will go look for the work in the nfssvc_sock list.
2140 1.14 mycroft */
2141 1.14 mycroft void
2142 1.14 mycroft nfsrv_wakenfsd(slp)
2143 1.14 mycroft struct nfssvc_sock *slp;
2144 1.14 mycroft {
2145 1.17 mycroft register struct nfsd *nd;
2146 1.14 mycroft
2147 1.14 mycroft if ((slp->ns_flag & SLP_VALID) == 0)
2148 1.14 mycroft return;
2149 1.24 fvdl for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) {
2150 1.24 fvdl if (nd->nfsd_flag & NFSD_WAITING) {
2151 1.24 fvdl nd->nfsd_flag &= ~NFSD_WAITING;
2152 1.24 fvdl if (nd->nfsd_slp)
2153 1.14 mycroft panic("nfsd wakeup");
2154 1.14 mycroft slp->ns_sref++;
2155 1.24 fvdl nd->nfsd_slp = slp;
2156 1.14 mycroft wakeup((caddr_t)nd);
2157 1.14 mycroft return;
2158 1.14 mycroft }
2159 1.14 mycroft }
2160 1.14 mycroft slp->ns_flag |= SLP_DOREC;
2161 1.17 mycroft nfsd_head_flag |= NFSD_CHECKSLP;
2162 1.1 cgd }
2163 1.14 mycroft #endif /* NFSSERVER */
2164