add LINE_MAX for POSIX 1003.2
[unix-history] / usr / src / sys / nfs / nfs_socket.c
CommitLineData
a2907882
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
0bd503ad 20 * @(#)nfs_socket.c 7.4 (Berkeley) %G%
a2907882
KM
21 */
22
23/*
24 * Socket operations for use by nfs (similar to uipc_socket.c, but never
25 * with copies to/from a uio vector)
26 * NB: For now, they only work for UDP datagram sockets.
27 * (Use on stream sockets would require some record boundary mark in the
28 * stream such as Sun's RM (Section 3.2 of the Sun RPC Message Protocol
29 * manual, in Networking on the Sun Workstation, Part #800-1324-03
30 * and different versions of send, receive and reply that do not assume
31 * an atomic protocol
32 */
33
34#include "types.h"
35#include "param.h"
36#include "uio.h"
37#include "user.h"
38#include "mount.h"
39#include "kernel.h"
40#include "malloc.h"
41#include "mbuf.h"
42#include "vnode.h"
43#include "domain.h"
44#include "protosw.h"
45#include "socket.h"
46#include "socketvar.h"
47#include "netinet/in.h"
48#include "rpcv2.h"
49#include "nfsv2.h"
50#include "nfs.h"
51#include "xdr_subs.h"
52#include "nfsm_subs.h"
53#include "nfsmount.h"
54
55#define TRUE 1
56
57/* set lock on sockbuf sb, sleep at neg prio */
58#define nfs_sblock(sb) { \
59 while ((sb)->sb_flags & SB_LOCK) { \
60 (sb)->sb_flags |= SB_WANT; \
61 sleep((caddr_t)&(sb)->sb_flags, PZERO-1); \
62 } \
63 (sb)->sb_flags |= SB_LOCK; \
64}
65
66/*
67 * External data, mostly RPC constants in XDR form
68 */
69extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
70 rpc_msgaccepted, rpc_call;
71extern u_long nfs_prog, nfs_vers;
72int nfsrv_null(),
73 nfsrv_getattr(),
74 nfsrv_setattr(),
75 nfsrv_lookup(),
76 nfsrv_readlink(),
77 nfsrv_read(),
78 nfsrv_write(),
79 nfsrv_create(),
80 nfsrv_remove(),
81 nfsrv_rename(),
82 nfsrv_link(),
83 nfsrv_symlink(),
84 nfsrv_mkdir(),
85 nfsrv_rmdir(),
86 nfsrv_readdir(),
87 nfsrv_statfs(),
88 nfsrv_noop();
89
90int (*nfsrv_procs[NFS_NPROCS])() = {
91 nfsrv_null,
92 nfsrv_getattr,
93 nfsrv_setattr,
94 nfsrv_noop,
95 nfsrv_lookup,
96 nfsrv_readlink,
97 nfsrv_read,
98 nfsrv_noop,
99 nfsrv_write,
100 nfsrv_create,
101 nfsrv_remove,
102 nfsrv_rename,
103 nfsrv_link,
104 nfsrv_symlink,
105 nfsrv_mkdir,
106 nfsrv_rmdir,
107 nfsrv_readdir,
108 nfsrv_statfs,
109};
110
111
112/*
113 * This is a stripped down version of sosend() specific to
114 * udp/ip and uses the mbuf list provdied
115 */
116nfs_udpsend(so, nam, top, flags, siz)
117 register struct socket *so;
118 struct mbuf *nam;
119 struct mbuf *top;
120 int flags;
121 int siz;
122{
123 register int space;
0bd503ad 124 int error = 0, s, dontroute;
a2907882
KM
125
126 dontroute =
127 (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
128 (so->so_proto->pr_flags & PR_ATOMIC);
129#define snderr(errno) { error = errno; splx(s); goto release; }
130
131#ifdef MGETHDR
132 top->m_pkthdr.len = siz;
133#endif
134restart:
135 nfs_sblock(&so->so_snd);
136 s = splnet();
137 if (so->so_state & SS_CANTSENDMORE)
138 snderr(EPIPE);
139 if (so->so_error)
140 snderr(so->so_error);
141 space = sbspace(&so->so_snd);
142 if (space < siz) {
143 sbunlock(&so->so_snd);
144 nfs_sbwait(&so->so_snd);
145 splx(s);
146 goto restart;
147 }
148 splx(s);
149 if (dontroute)
150 so->so_options |= SO_DONTROUTE;
151 s = splnet(); /* XXX */
152 error = (*so->so_proto->pr_usrreq)(so,
153 PRU_SEND,
154 top, (caddr_t)nam, (struct mbuf *)0, (struct mbuf *)0);
155 splx(s);
156 if (dontroute)
157 so->so_options &= ~SO_DONTROUTE;
158 top = (struct mbuf *)0;
159
160release:
161 sbunlock(&so->so_snd);
162 if (top)
163 m_freem(top);
164 return (error);
165}
166
167/*
168 * This is a stripped down udp specific version of soreceive()
169 */
170nfs_udpreceive(so, aname, mp)
171 register struct socket *so;
172 struct mbuf **aname;
173 struct mbuf **mp;
174{
175 register struct mbuf *m;
176 int s, error = 0;
a2907882
KM
177 struct mbuf *nextrecord;
178
179 if (aname)
180 *aname = 0;
181
182restart:
183 sblock(&so->so_rcv);
184 s = splnet();
185
186 if (so->so_rcv.sb_cc == 0) {
187 if (so->so_error) {
188 error = so->so_error;
189 so->so_error = 0;
190 goto release;
191 }
192 if (so->so_state & SS_CANTRCVMORE)
193 goto release;
194 sbunlock(&so->so_rcv);
195 sbwait(&so->so_rcv);
196 splx(s);
197 goto restart;
198 }
199 m = so->so_rcv.sb_mb;
200 if (m == 0)
201 panic("nfs_receive 1");
202 nextrecord = m->m_nextpkt;
203 if (m->m_type != MT_SONAME)
204 panic("nfs_receive 1a");
205 sbfree(&so->so_rcv, m);
206 if (aname) {
207 *aname = m;
208 so->so_rcv.sb_mb = m->m_next;
209 m->m_next = 0;
210 m = so->so_rcv.sb_mb;
211 } else {
212 MFREE(m, so->so_rcv.sb_mb);
213 m = so->so_rcv.sb_mb;
214 }
215 if (m && m->m_type == MT_RIGHTS)
216 panic("nfs_receive 2");
217 if (m && m->m_type == MT_CONTROL) {
218 sbfree(&so->so_rcv, m);
219 MFREE(m, so->so_rcv.sb_mb);
220 m = so->so_rcv.sb_mb;
221 }
222 *mp = m;
223 while (m) {
224 if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
225 panic("nfs_receive 3");
226 sbfree(&so->so_rcv, m);
227 m = so->so_rcv.sb_mb = m->m_next;
228 }
229 so->so_rcv.sb_mb = nextrecord;
230 so->so_state &= ~SS_RCVATMARK; /* Necessary ?? */
231release:
232 sbunlock(&so->so_rcv);
233 splx(s);
234 return (error);
235}
236
237struct nfsreq nfsreqh = {
238 (struct nfsreq *)0,
239 (struct nfsreq *)0,
240 (struct mbuf *)0,
241 (struct mbuf *)0,
242 (struct nfsmount *)0,
243 0, 0, 0, 0, 0,
244};
245
246struct rpc_replyhead {
247 u_long r_xid;
248 u_long r_rep;
249};
250
251/*
252 * Implement receipt of reply on a socket.
253 * We depend on the way that records are added to the sockbuf
254 * by sbappend*. In particular, each record (mbufs linked through m_next)
255 * must begin with an address, followed by optional MT_CONTROL mbuf
256 * and then zero or more mbufs of data.
257 * Although the sockbuf is locked, new data may still be appended,
258 * and thus we must maintain consistency of the sockbuf during that time.
259 * We must search through the list of received datagrams matching them
260 * with outstanding requests using the xid, until ours is found.
261 */
0bd503ad 262/* ARGSUSED */
ffe6f482 263nfs_udpreply(so, mntp, myrep)
a2907882
KM
264 register struct socket *so;
265 struct nfsmount *mntp;
ffe6f482 266 struct nfsreq *myrep;
a2907882
KM
267{
268 register struct mbuf *m;
269 register struct nfsreq *rep;
270 register int error = 0, s;
a2907882 271 struct mbuf *nextrecord;
ffe6f482
KM
272 struct sockaddr_in *saddr;
273 u_long inaddr;
a2907882
KM
274 struct rpc_replyhead replyh;
275 struct mbuf *mp;
276 char *cp;
277 int cnt, xfer;
278 int found;
279
280restart:
ffe6f482 281 nfs_sblock(&so->so_rcv);
a2907882 282 /* Already received, bye bye */
ffe6f482
KM
283 if (myrep->r_mrep != NULL) {
284 sbunlock(&so->so_rcv);
a2907882 285 return (0);
ffe6f482 286 }
a2907882 287 /* If a soft mount and we have run out of retries */
ffe6f482
KM
288 if (myrep->r_retry == 0 && myrep->r_timer == 0) {
289 sbunlock(&so->so_rcv);
a2907882 290 return (ETIMEDOUT);
ffe6f482 291 }
a2907882
KM
292 s = splnet();
293
ffe6f482
KM
294 m = so->so_rcv.sb_mb;
295 if (m == 0) {
296 if (so->so_rcv.sb_cc)
297 panic("nfs_soreply 1");
a2907882
KM
298 if (so->so_error) {
299 error = so->so_error;
300 so->so_error = 0;
301 goto release;
302 }
303 if (so->so_state & SS_CANTRCVMORE)
304 goto release;
305 sbunlock(&so->so_rcv);
306 nfs_sbwait(&so->so_rcv);
307 splx(s);
308 goto restart;
309 }
a2907882
KM
310 nextrecord = m->m_nextpkt;
311
312 /*
313 * Take off the address, check for rights and ditch any control
314 * mbufs.
315 */
316 if (m->m_type != MT_SONAME)
317 panic("nfs reply SONAME");
ffe6f482
KM
318 saddr = mtod(m, struct sockaddr_in *);
319 inaddr = saddr->sin_addr.s_addr;
a2907882
KM
320 sbfree(&so->so_rcv, m);
321 MFREE(m, so->so_rcv.sb_mb);
322 m = so->so_rcv.sb_mb;
323 if (m && m->m_type == MT_RIGHTS)
324 panic("nfs reply RIGHTS");
325 if (m && m->m_type == MT_CONTROL) {
326 sbfree(&so->so_rcv, m);
327 MFREE(m, so->so_rcv.sb_mb);
328 m = so->so_rcv.sb_mb;
329 }
ffe6f482 330 if (m) {
a2907882 331 m->m_nextpkt = nextrecord;
ffe6f482
KM
332 } else {
333 so->so_rcv.sb_mb = nextrecord;
a2907882
KM
334 sbunlock(&so->so_rcv);
335 splx(s);
336 goto restart;
337 }
338
339 /*
340 * Get the xid and check that it is an rpc reply
341 */
342 mp = m;
343 if (m->m_len >= 2*NFSX_UNSIGNED)
344 bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED);
345 else {
346 cnt = 2*NFSX_UNSIGNED;
347 cp = (caddr_t)&replyh;
348 while (mp && cnt > 0) {
349 if (mp->m_len > 0) {
350 xfer = (mp->m_len >= cnt) ? cnt : mp->m_len;
351 bcopy(mtod(mp, caddr_t), cp, xfer);
352 cnt -= xfer;
353 cp += xfer;
354 }
355 if (cnt > 0)
356 mp = mp->m_next;
357 }
358 }
ffe6f482 359 found = 0;
a2907882
KM
360 if (replyh.r_rep != rpc_reply || mp == NULL)
361 goto dropit;
362 /*
363 * Loop through the request list to match up the reply
364 * Iff no match, just drop the datagram
365 */
ffe6f482
KM
366 rep = nfsreqh.r_next;
367 while (!found && rep != &nfsreqh) {
368 if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid &&
369 inaddr == rep->r_inaddr) {
a2907882
KM
370 /* Found it.. */
371 rep->r_mrep = m;
372 while (m) {
373 if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
374 panic("nfs_soreply 3");
375 sbfree(&so->so_rcv, m);
376 m = so->so_rcv.sb_mb = m->m_next;
377 }
378 so->so_rcv.sb_mb = nextrecord;
379 if (rep == myrep)
380 goto release;
381 found++;
382 }
383 rep = rep->r_next;
384 }
385 /* Iff not matched to request, drop it */
386dropit:
ffe6f482 387 if (!found) {
a2907882 388 sbdroprecord(&so->so_rcv);
ffe6f482
KM
389 } else if (so->so_rcv.sb_flags & SB_WAIT) {
390 so->so_rcv.sb_flags &= ~SB_WAIT;
391 wakeup((caddr_t)&so->so_rcv.sb_cc);
392 }
a2907882
KM
393 sbunlock(&so->so_rcv);
394 splx(s);
395 goto restart;
396release:
397 sbunlock(&so->so_rcv);
398 splx(s);
399 return (error);
400}
401
402/*
403 * nfs_request - goes something like this
404 * - fill in request struct
405 * - links it into list
406 * - calls nfs_sosend() for first transmit
407 * - calls nfs_soreceive() to get reply
408 * - break down rpc header and return with nfs reply pointed to
409 * by mrep or error
410 * nb: always frees up mreq mbuf list
411 */
412nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp)
413 struct vnode *vp;
414 struct mbuf *mreq;
415 u_long xid;
416 struct mount *mp;
417 struct mbuf **mrp;
418 struct mbuf **mdp;
419 caddr_t *dposp;
420{
421 register struct mbuf *m, *mrep;
422 register struct nfsreq *rep;
423 register u_long *p;
424 register int len;
425 struct nfsmount *mntp;
426 struct mbuf *md;
ffe6f482
KM
427 struct sockaddr_in *saddr;
428 struct nfsreq *reph;
a2907882
KM
429 caddr_t dpos;
430 char *cp2;
431 int t1;
432 int s;
433 int error;
434
435 mntp = vfs_to_nfs(mp);
436 m = mreq;
437 MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
438 rep->r_xid = xid;
439 rep->r_mntp = mntp;
ffe6f482
KM
440 saddr = mtod(mntp->nm_sockaddr, struct sockaddr_in *);
441 rep->r_inaddr = saddr->sin_addr.s_addr;
a2907882
KM
442 rep->r_vp = vp;
443 if (mntp->nm_flag & NFSMNT_SOFT)
444 rep->r_retry = mntp->nm_retrans;
445 else
446 rep->r_retry = VNOVAL;
447 rep->r_mrep = NULL;
448 rep->r_mreq = m;
449 rep->r_timer = rep->r_timeout = mntp->nm_timeo;
450 len = 0;
451 while (m) {
452 len += m->m_len;
453 m = m->m_next;
454 }
455 rep->r_msiz = len;
456 m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT);
457
458 /* Chain it into list of outstanding requests */
ffe6f482 459 reph = &nfsreqh;
a2907882 460 s = splnet();
ffe6f482
KM
461 if (reph->r_prev == NULL) {
462 reph->r_next = rep;
463 rep->r_prev = reph;
464 } else {
465 reph->r_prev->r_next = rep;
466 rep->r_prev = reph->r_prev;
467 }
468 reph->r_prev = rep;
469 rep->r_next = reph;
a2907882
KM
470 splx(s);
471
472 /*
473 * Iff the NFSMCOPY above succeeded, send it off...
474 * otherwise the timer will retransmit later
475 */
476 if (m != NULL)
477 error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len);
ffe6f482 478 error = nfs_udpreply(mntp->nm_so, mntp, rep);
a2907882
KM
479
480 s = splnet();
481 rep->r_prev->r_next = rep->r_next;
ffe6f482 482 rep->r_next->r_prev = rep->r_prev;
a2907882
KM
483 splx(s);
484 m_freem(rep->r_mreq);
485 mrep = md = rep->r_mrep;
486 FREE((caddr_t)rep, M_NFSREQ);
487 if (error)
488 return (error);
489
490 /*
491 * break down the rpc header and check if ok
492 */
493 dpos = mtod(md, caddr_t);
494 nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED);
495 p += 2;
496 if (*p++ == rpc_msgdenied) {
497 if (*p == rpc_mismatch)
498 error = EOPNOTSUPP;
499 else
500 error = EACCES;
501 m_freem(mrep);
502 return (error);
503 }
504 /*
505 * skip over the auth_verf, someday we may want to cache auth_short's
506 * for nfs_reqhead(), but for now just dump it
507 */
508 if (*++p != 0) {
509 len = nfsm_rndup(fxdr_unsigned(long, *p));
510 nfsm_adv(len);
511 }
512 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
513 /* 0 == ok */
514 if (*p == 0) {
515 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
516 if (*p != 0) {
517 error = fxdr_unsigned(int, *p);
518 m_freem(mrep);
519 return (error);
520 }
521 *mrp = mrep;
522 *mdp = md;
523 *dposp = dpos;
524 return (0);
525 }
526 m_freem(mrep);
527 return (EPROTONOSUPPORT);
528nfsmout:
529 return (error);
530}
531
532/*
533 * Get a request for the server main loop
534 * - receive a request via. nfs_soreceive()
535 * - verify it
536 * - fill in the cred struct.
537 */
538nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr)
539 struct socket *so;
540 u_long prog;
541 u_long vers;
542 int maxproc;
543 struct mbuf **nam;
544 struct mbuf **mrp;
545 struct mbuf **mdp;
546 caddr_t *dposp;
547 u_long *retxid;
548 u_long *proc;
549 register struct ucred *cr;
550{
551 register int i;
0bd503ad
KM
552 register u_long *p;
553 register long t1;
554 caddr_t dpos, cp2;
555 int error = 0;
556 struct mbuf *mrep, *md;
557 int len;
a2907882
KM
558
559 if (error = nfs_udpreceive(so, nam, &mrep))
560 return (error);
561 md = mrep;
562 dpos = mtod(mrep, caddr_t);
563 nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED);
564 *retxid = *p++;
565 if (*p++ != rpc_call) {
566 m_freem(mrep);
567 return (ERPCMISMATCH);
568 }
569 if (*p++ != rpc_vers) {
570 m_freem(mrep);
571 return (ERPCMISMATCH);
572 }
573 if (*p++ != prog) {
574 m_freem(mrep);
575 return (EPROGUNAVAIL);
576 }
577 if (*p++ != vers) {
578 m_freem(mrep);
579 return (EPROGMISMATCH);
580 }
581 *proc = fxdr_unsigned(u_long, *p++);
582 if (*proc == NFSPROC_NULL) {
583 *mrp = mrep;
584 return (0);
585 }
586 if (*proc > maxproc || *p++ != rpc_auth_unix) {
587 m_freem(mrep);
588 return (EPROCUNAVAIL);
589 }
0bd503ad
KM
590 (void) fxdr_unsigned(int, *p++);
591 len = fxdr_unsigned(int, *++p);
592 nfsm_adv(nfsm_rndup(len));
a2907882
KM
593 nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED);
594 cr->cr_uid = fxdr_unsigned(uid_t, *p++);
595 cr->cr_gid = fxdr_unsigned(gid_t, *p++);
0bd503ad
KM
596 len = fxdr_unsigned(int, *p);
597 if (len > 10) {
a2907882
KM
598 m_freem(mrep);
599 return (EBADRPC);
600 }
0bd503ad
KM
601 nfsm_disect(p, u_long *, (len + 2)*NFSX_UNSIGNED);
602 for (i = 1; i <= len; i++)
a2907882 603 cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++);
0bd503ad 604 cr->cr_ngroups = len + 1;
a2907882
KM
605 /*
606 * Do we have any use for the verifier.
607 * According to the "Remote Procedure Call Protocol Spec." it
608 * should be AUTH_NULL, but some clients make it AUTH_UNIX?
609 * For now, just skip over it
610 */
0bd503ad
KM
611 len = fxdr_unsigned(int, *++p);
612 if (len > 0)
613 nfsm_adv(nfsm_rndup(len));
a2907882
KM
614 *mrp = mrep;
615 *mdp = md;
616 *dposp = dpos;
617 return (0);
618nfsmout:
619 return (error);
620}
621
622/*
623 * Generate the rpc reply header
624 * siz arg. is used to decide if adding a cluster is worthwhile
625 */
626nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
627 int siz;
628 u_long retxid;
629 int err;
630 struct mbuf **mrq;
631 struct mbuf **mbp;
632 caddr_t *bposp;
633{
0bd503ad
KM
634 register u_long *p;
635 register long t1;
636 caddr_t bpos;
637 struct mbuf *mreq, *mb, *mb2;
a2907882
KM
638
639 NFSMGETHDR(mreq);
640 mb = mreq;
641 if ((siz+RPC_REPLYSIZ) > MHLEN)
642 NFSMCLGET(mreq, M_WAIT);
643 p = mtod(mreq, u_long *);
644 mreq->m_len = 6*NFSX_UNSIGNED;
645 bpos = ((caddr_t)p)+mreq->m_len;
646 *p++ = retxid;
647 *p++ = rpc_reply;
648 if (err == ERPCMISMATCH) {
649 *p++ = rpc_msgdenied;
650 *p++ = rpc_mismatch;
651 *p++ = txdr_unsigned(2);
652 *p = txdr_unsigned(2);
653 } else {
654 *p++ = rpc_msgaccepted;
655 *p++ = 0;
656 *p++ = 0;
657 switch (err) {
658 case EPROGUNAVAIL:
659 *p = txdr_unsigned(RPC_PROGUNAVAIL);
660 break;
661 case EPROGMISMATCH:
662 *p = txdr_unsigned(RPC_PROGMISMATCH);
663 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
664 *p++ = txdr_unsigned(2);
665 *p = txdr_unsigned(2); /* someday 3 */
666 break;
667 case EPROCUNAVAIL:
668 *p = txdr_unsigned(RPC_PROCUNAVAIL);
669 break;
670 default:
671 *p = 0;
672 if (err != VNOVAL) {
673 nfsm_build(p, u_long *, NFSX_UNSIGNED);
674 *p = txdr_unsigned(err);
675 }
676 break;
677 };
678 }
679 *mrq = mreq;
680 *mbp = mb;
681 *bposp = bpos;
682 if (err != 0 && err != VNOVAL)
683 nfsstats.srvrpc_errs++;
684 return (0);
685}
686
687/*
688 * Nfs timer routine
689 * Scan the nfsreq list and retranmit any requests that have timed out
690 * To avoid retransmission attempts on STREAM sockets (in the future) make
691 * sure to set the r_retry field to 0.
692 */
693nfs_timer()
694{
695 register struct nfsreq *rep;
696 register struct mbuf *m;
697 register struct socket *so;
0bd503ad 698 int s;
a2907882
KM
699
700 s = splnet();
701 rep = nfsreqh.r_next;
ffe6f482 702 while (rep && rep != &nfsreqh) {
a2907882
KM
703 if (rep->r_timer > 0)
704 rep->r_timer--;
705 else if (rep->r_mrep == NULL && rep->r_retry > 0) {
706 so = rep->r_mntp->nm_so;
707 if ((so->so_state & SS_CANTSENDMORE) == 0 &&
708 !so->so_error &&
709 sbspace(&so->so_snd) >= rep->r_msiz) {
710 m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT);
711 if (m != NULL) {
712 nfsstats.rpcretries++;
36c3043b
KM
713 rep->r_timeout <<= 2; /* x4 backoff */
714 if (rep->r_timeout > NFS_MAXTIMEO)
715 rep->r_timeout = NFS_MAXTIMEO;
a2907882
KM
716 rep->r_timer = rep->r_timeout;
717 if (rep->r_retry != VNOVAL)
718 rep->r_retry--;
719#ifdef MGETHDR
720 m->m_pkthdr.len = rep->r_msiz;
721#endif
722 (*so->so_proto->pr_usrreq)(so, PRU_SEND,
723 m, (caddr_t)0, (struct mbuf *)0,
724 (struct mbuf *)0);
725 }
726 }
727 }
728 rep = rep->r_next;
729 }
730 splx(s);
36c3043b 731 timeout(nfs_timer, (caddr_t)0, hz/10);
a2907882
KM
732}
733
734/*
735 * nfs_sbwait() is simply sbwait() but at a negative priority so that it
736 * can not be interrupted by a signal.
737 */
738nfs_sbwait(sb)
739 struct sockbuf *sb;
740{
741 sb->sb_flags |= SB_WAIT;
ffe6f482 742 sleep((caddr_t)&sb->sb_cc, PZERO-2);
a2907882 743}