|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)uipc_usrreq.c 7.26 (Berkeley) 6/3/91
34: */
35:
36: #include "param.h"
37: #include "proc.h"
38: #include "filedesc.h"
39: #include "domain.h"
40: #include "protosw.h"
41: #include "socket.h"
42: #include "socketvar.h"
43: #include "unpcb.h"
44: #include "un.h"
45: #include "namei.h"
46: #include "vnode.h"
47: #include "file.h"
48: #include "stat.h"
49: #include "mbuf.h"
50:
51: /*
52: * Unix communications domain.
53: *
54: * TODO:
55: * SEQPACKET, RDM
56: * rethink name space problems
57: * need a proper out-of-band
58: */
59: struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
60: ino_t unp_ino; /* prototype for fake inode numbers */
61:
62: /*ARGSUSED*/
63: uipc_usrreq(so, req, m, nam, control)
64: struct socket *so;
65: int req;
66: struct mbuf *m, *nam, *control;
67: {
68: struct unpcb *unp = sotounpcb(so);
69: register struct socket *so2;
70: register int error = 0;
71: struct proc *p = curproc; /* XXX */
72:
73: if (req == PRU_CONTROL)
74: return (EOPNOTSUPP);
75: if (req != PRU_SEND && control && control->m_len) {
76: error = EOPNOTSUPP;
77: goto release;
78: }
79: if (unp == 0 && req != PRU_ATTACH) {
80: error = EINVAL;
81: goto release;
82: }
83: switch (req) {
84:
85: case PRU_ATTACH:
86: if (unp) {
87: error = EISCONN;
88: break;
89: }
90: error = unp_attach(so);
91: break;
92:
93: case PRU_DETACH:
94: unp_detach(unp);
95: break;
96:
97: case PRU_BIND:
98: error = unp_bind(unp, nam, p);
99: break;
100:
101: case PRU_LISTEN:
102: if (unp->unp_vnode == 0)
103: error = EINVAL;
104: break;
105:
106: case PRU_CONNECT:
107: error = unp_connect(so, nam, p);
108: break;
109:
110: case PRU_CONNECT2:
111: error = unp_connect2(so, (struct socket *)nam);
112: break;
113:
114: case PRU_DISCONNECT:
115: unp_disconnect(unp);
116: break;
117:
118: case PRU_ACCEPT:
119: /*
120: * Pass back name of connected socket,
121: * if it was bound and we are still connected
122: * (our peer may have closed already!).
123: */
124: if (unp->unp_conn && unp->unp_conn->unp_addr) {
125: nam->m_len = unp->unp_conn->unp_addr->m_len;
126: bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
127: mtod(nam, caddr_t), (unsigned)nam->m_len);
128: } else {
129: nam->m_len = sizeof(sun_noname);
130: *(mtod(nam, struct sockaddr *)) = sun_noname;
131: }
132: break;
133:
134: case PRU_SHUTDOWN:
135: socantsendmore(so);
136: unp_shutdown(unp);
137: break;
138:
139: case PRU_RCVD:
140: switch (so->so_type) {
141:
142: case SOCK_DGRAM:
143: panic("uipc 1");
144: /*NOTREACHED*/
145:
146: case SOCK_STREAM:
147: #define rcv (&so->so_rcv)
148: #define snd (&so2->so_snd)
149: if (unp->unp_conn == 0)
150: break;
151: so2 = unp->unp_conn->unp_socket;
152: /*
153: * Adjust backpressure on sender
154: * and wakeup any waiting to write.
155: */
156: snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
157: unp->unp_mbcnt = rcv->sb_mbcnt;
158: snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
159: unp->unp_cc = rcv->sb_cc;
160: sowwakeup(so2);
161: #undef snd
162: #undef rcv
163: break;
164:
165: default:
166: panic("uipc 2");
167: }
168: break;
169:
170: case PRU_SEND:
171: if (control && (error = unp_internalize(control, p)))
172: break;
173: switch (so->so_type) {
174:
175: case SOCK_DGRAM: {
176: struct sockaddr *from;
177:
178: if (nam) {
179: if (unp->unp_conn) {
180: error = EISCONN;
181: break;
182: }
183: error = unp_connect(so, nam, p);
184: if (error)
185: break;
186: } else {
187: if (unp->unp_conn == 0) {
188: error = ENOTCONN;
189: break;
190: }
191: }
192: so2 = unp->unp_conn->unp_socket;
193: if (unp->unp_addr)
194: from = mtod(unp->unp_addr, struct sockaddr *);
195: else
196: from = &sun_noname;
197: if (sbappendaddr(&so2->so_rcv, from, m, control)) {
198: sorwakeup(so2);
199: m = 0;
200: control = 0;
201: } else
202: error = ENOBUFS;
203: if (nam)
204: unp_disconnect(unp);
205: break;
206: }
207:
208: case SOCK_STREAM:
209: #define rcv (&so2->so_rcv)
210: #define snd (&so->so_snd)
211: if (so->so_state & SS_CANTSENDMORE) {
212: error = EPIPE;
213: break;
214: }
215: if (unp->unp_conn == 0)
216: panic("uipc 3");
217: so2 = unp->unp_conn->unp_socket;
218: /*
219: * Send to paired receive port, and then reduce
220: * send buffer hiwater marks to maintain backpressure.
221: * Wake up readers.
222: */
223: if (control) {
224: if (sbappendcontrol(rcv, m, control))
225: control = 0;
226: } else
227: sbappend(rcv, m);
228: snd->sb_mbmax -=
229: rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
230: unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
231: snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
232: unp->unp_conn->unp_cc = rcv->sb_cc;
233: sorwakeup(so2);
234: m = 0;
235: #undef snd
236: #undef rcv
237: break;
238:
239: default:
240: panic("uipc 4");
241: }
242: break;
243:
244: case PRU_ABORT:
245: unp_drop(unp, ECONNABORTED);
246: break;
247:
248: case PRU_SENSE:
249: ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
250: if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
251: so2 = unp->unp_conn->unp_socket;
252: ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
253: }
254: ((struct stat *) m)->st_dev = NODEV;
255: if (unp->unp_ino == 0)
256: unp->unp_ino = unp_ino++;
257: ((struct stat *) m)->st_ino = unp->unp_ino;
258: return (0);
259:
260: case PRU_RCVOOB:
261: return (EOPNOTSUPP);
262:
263: case PRU_SENDOOB:
264: error = EOPNOTSUPP;
265: break;
266:
267: case PRU_SOCKADDR:
268: if (unp->unp_addr) {
269: nam->m_len = unp->unp_addr->m_len;
270: bcopy(mtod(unp->unp_addr, caddr_t),
271: mtod(nam, caddr_t), (unsigned)nam->m_len);
272: } else
273: nam->m_len = 0;
274: break;
275:
276: case PRU_PEERADDR:
277: if (unp->unp_conn && unp->unp_conn->unp_addr) {
278: nam->m_len = unp->unp_conn->unp_addr->m_len;
279: bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
280: mtod(nam, caddr_t), (unsigned)nam->m_len);
281: } else
282: nam->m_len = 0;
283: break;
284:
285: case PRU_SLOWTIMO:
286: break;
287:
288: default:
289: panic("piusrreq");
290: }
291: release:
292: if (control)
293: m_freem(control);
294: if (m)
295: m_freem(m);
296: return (error);
297: }
298:
299: /*
300: * Both send and receive buffers are allocated PIPSIZ bytes of buffering
301: * for stream sockets, although the total for sender and receiver is
302: * actually only PIPSIZ.
303: * Datagram sockets really use the sendspace as the maximum datagram size,
304: * and don't really want to reserve the sendspace. Their recvspace should
305: * be large enough for at least one max-size datagram plus address.
306: */
307: #define PIPSIZ 4096
308: u_long unpst_sendspace = PIPSIZ;
309: u_long unpst_recvspace = PIPSIZ;
310: u_long unpdg_sendspace = 2*1024; /* really max datagram size */
311: u_long unpdg_recvspace = 4*1024;
312:
313: int unp_rights; /* file descriptors in flight */
314:
315: unp_attach(so)
316: struct socket *so;
317: {
318: register struct mbuf *m;
319: register struct unpcb *unp;
320: int error;
321:
322: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
323: switch (so->so_type) {
324:
325: case SOCK_STREAM:
326: error = soreserve(so, unpst_sendspace, unpst_recvspace);
327: break;
328:
329: case SOCK_DGRAM:
330: error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
331: break;
332: }
333: if (error)
334: return (error);
335: }
336: m = m_getclr(M_DONTWAIT, MT_PCB);
337: if (m == NULL)
338: return (ENOBUFS);
339: unp = mtod(m, struct unpcb *);
340: so->so_pcb = (caddr_t)unp;
341: unp->unp_socket = so;
342: return (0);
343: }
344:
345: unp_detach(unp)
346: register struct unpcb *unp;
347: {
348:
349: if (unp->unp_vnode) {
350: unp->unp_vnode->v_socket = 0;
351: vrele(unp->unp_vnode);
352: unp->unp_vnode = 0;
353: }
354: if (unp->unp_conn)
355: unp_disconnect(unp);
356: while (unp->unp_refs)
357: unp_drop(unp->unp_refs, ECONNRESET);
358: soisdisconnected(unp->unp_socket);
359: unp->unp_socket->so_pcb = 0;
360: m_freem(unp->unp_addr);
361: (void) m_free(dtom(unp));
362: if (unp_rights)
363: unp_gc();
364: }
365:
366: unp_bind(unp, nam, p)
367: struct unpcb *unp;
368: struct mbuf *nam;
369: struct proc *p;
370: {
371: struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
372: register struct vnode *vp;
373: register struct nameidata *ndp;
374: struct vattr vattr;
375: int error;
376: struct nameidata nd;
377:
378: ndp = &nd;
379: ndp->ni_dirp = soun->sun_path;
380: if (unp->unp_vnode != NULL)
381: return (EINVAL);
382: if (nam->m_len == MLEN) {
383: if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
384: return (EINVAL);
385: } else
386: *(mtod(nam, caddr_t) + nam->m_len) = 0;
387: /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
388: ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
389: ndp->ni_segflg = UIO_SYSSPACE;
390: if (error = namei(ndp, p))
391: return (error);
392: vp = ndp->ni_vp;
393: if (vp != NULL) {
394: VOP_ABORTOP(ndp);
395: if (ndp->ni_dvp == vp)
396: vrele(ndp->ni_dvp);
397: else
398: vput(ndp->ni_dvp);
399: vrele(vp);
400: return (EADDRINUSE);
401: }
402: VATTR_NULL(&vattr);
403: vattr.va_type = VSOCK;
404: vattr.va_mode = 0777;
405: if (error = VOP_CREATE(ndp, &vattr, p))
406: return (error);
407: vp = ndp->ni_vp;
408: vp->v_socket = unp->unp_socket;
409: unp->unp_vnode = vp;
410: unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
411: VOP_UNLOCK(vp);
412: return (0);
413: }
414:
415: unp_connect(so, nam, p)
416: struct socket *so;
417: struct mbuf *nam;
418: struct proc *p;
419: {
420: register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
421: register struct vnode *vp;
422: register struct socket *so2, *so3;
423: register struct nameidata *ndp;
424: struct unpcb *unp2, *unp3;
425: int error;
426: struct nameidata nd;
427:
428: ndp = &nd;
429: ndp->ni_dirp = soun->sun_path;
430: if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */
431: if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
432: return (EMSGSIZE);
433: } else
434: *(mtod(nam, caddr_t) + nam->m_len) = 0;
435: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
436: ndp->ni_segflg = UIO_SYSSPACE;
437: if (error = namei(ndp, p))
438: return (error);
439: vp = ndp->ni_vp;
440: if (vp->v_type != VSOCK) {
441: error = ENOTSOCK;
442: goto bad;
443: }
444: if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
445: goto bad;
446: so2 = vp->v_socket;
447: if (so2 == 0) {
448: error = ECONNREFUSED;
449: goto bad;
450: }
451: if (so->so_type != so2->so_type) {
452: error = EPROTOTYPE;
453: goto bad;
454: }
455: if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
456: if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
457: (so3 = sonewconn(so2, 0)) == 0) {
458: error = ECONNREFUSED;
459: goto bad;
460: }
461: unp2 = sotounpcb(so2);
462: unp3 = sotounpcb(so3);
463: if (unp2->unp_addr)
464: unp3->unp_addr =
465: m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
466: so2 = so3;
467: }
468: error = unp_connect2(so, so2);
469: bad:
470: vput(vp);
471: return (error);
472: }
473:
474: unp_connect2(so, so2)
475: register struct socket *so;
476: register struct socket *so2;
477: {
478: register struct unpcb *unp = sotounpcb(so);
479: register struct unpcb *unp2;
480:
481: if (so2->so_type != so->so_type)
482: return (EPROTOTYPE);
483: unp2 = sotounpcb(so2);
484: unp->unp_conn = unp2;
485: switch (so->so_type) {
486:
487: case SOCK_DGRAM:
488: unp->unp_nextref = unp2->unp_refs;
489: unp2->unp_refs = unp;
490: soisconnected(so);
491: break;
492:
493: case SOCK_STREAM:
494: unp2->unp_conn = unp;
495: soisconnected(so);
496: soisconnected(so2);
497: break;
498:
499: default:
500: panic("unp_connect2");
501: }
502: return (0);
503: }
504:
505: unp_disconnect(unp)
506: struct unpcb *unp;
507: {
508: register struct unpcb *unp2 = unp->unp_conn;
509:
510: if (unp2 == 0)
511: return;
512: unp->unp_conn = 0;
513: switch (unp->unp_socket->so_type) {
514:
515: case SOCK_DGRAM:
516: if (unp2->unp_refs == unp)
517: unp2->unp_refs = unp->unp_nextref;
518: else {
519: unp2 = unp2->unp_refs;
520: for (;;) {
521: if (unp2 == 0)
522: panic("unp_disconnect");
523: if (unp2->unp_nextref == unp)
524: break;
525: unp2 = unp2->unp_nextref;
526: }
527: unp2->unp_nextref = unp->unp_nextref;
528: }
529: unp->unp_nextref = 0;
530: unp->unp_socket->so_state &= ~SS_ISCONNECTED;
531: break;
532:
533: case SOCK_STREAM:
534: soisdisconnected(unp->unp_socket);
535: unp2->unp_conn = 0;
536: soisdisconnected(unp2->unp_socket);
537: break;
538: }
539: }
540:
541: #ifdef notdef
542: unp_abort(unp)
543: struct unpcb *unp;
544: {
545:
546: unp_detach(unp);
547: }
548: #endif
549:
550: unp_shutdown(unp)
551: struct unpcb *unp;
552: {
553: struct socket *so;
554:
555: if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
556: (so = unp->unp_conn->unp_socket))
557: socantrcvmore(so);
558: }
559:
560: unp_drop(unp, errno)
561: struct unpcb *unp;
562: int errno;
563: {
564: struct socket *so = unp->unp_socket;
565:
566: so->so_error = errno;
567: unp_disconnect(unp);
568: if (so->so_head) {
569: so->so_pcb = (caddr_t) 0;
570: m_freem(unp->unp_addr);
571: (void) m_free(dtom(unp));
572: sofree(so);
573: }
574: }
575:
576: #ifdef notdef
577: unp_drain()
578: {
579:
580: }
581: #endif
582:
583: unp_externalize(rights)
584: struct mbuf *rights;
585: {
586: struct proc *p = curproc; /* XXX */
587: register int i;
588: register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
589: register struct file **rp = (struct file **)(cm + 1);
590: register struct file *fp;
591: int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
592: int f;
593:
594: if (fdavail(p, newfds)) {
595: for (i = 0; i < newfds; i++) {
596: fp = *rp;
597: unp_discard(fp);
598: *rp++ = 0;
599: }
600: return (EMSGSIZE);
601: }
602: for (i = 0; i < newfds; i++) {
603: if (fdalloc(p, 0, &f))
604: panic("unp_externalize");
605: fp = *rp;
606: p->p_fd->fd_ofiles[f] = fp;
607: fp->f_msgcount--;
608: unp_rights--;
609: *(int *)rp++ = f;
610: }
611: return (0);
612: }
613:
614: unp_internalize(control, p)
615: struct mbuf *control;
616: struct proc *p;
617: {
618: struct filedesc *fdp = p->p_fd;
619: register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
620: register struct file **rp;
621: register struct file *fp;
622: register int i, fd;
623: int oldfds;
624:
625: if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
626: cm->cmsg_len != control->m_len)
627: return (EINVAL);
628: oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
629: rp = (struct file **)(cm + 1);
630: for (i = 0; i < oldfds; i++) {
631: fd = *(int *)rp++;
632: if ((unsigned)fd >= fdp->fd_nfiles ||
633: fdp->fd_ofiles[fd] == NULL)
634: return (EBADF);
635: }
636: rp = (struct file **)(cm + 1);
637: for (i = 0; i < oldfds; i++) {
638: fp = fdp->fd_ofiles[*(int *)rp];
639: *rp++ = fp;
640: fp->f_count++;
641: fp->f_msgcount++;
642: unp_rights++;
643: }
644: return (0);
645: }
646:
647: int unp_defer, unp_gcing;
648: int unp_mark();
649: extern struct domain unixdomain;
650:
651: unp_gc()
652: {
653: register struct file *fp;
654: register struct socket *so;
655:
656: if (unp_gcing)
657: return;
658: unp_gcing = 1;
659: restart:
660: unp_defer = 0;
661: for (fp = filehead; fp; fp = fp->f_filef)
662: fp->f_flag &= ~(FMARK|FDEFER);
663: do {
664: for (fp = filehead; fp; fp = fp->f_filef) {
665: if (fp->f_count == 0)
666: continue;
667: if (fp->f_flag & FDEFER) {
668: fp->f_flag &= ~FDEFER;
669: unp_defer--;
670: } else {
671: if (fp->f_flag & FMARK)
672: continue;
673: if (fp->f_count == fp->f_msgcount)
674: continue;
675: fp->f_flag |= FMARK;
676: }
677: if (fp->f_type != DTYPE_SOCKET ||
678: (so = (struct socket *)fp->f_data) == 0)
679: continue;
680: if (so->so_proto->pr_domain != &unixdomain ||
681: (so->so_proto->pr_flags&PR_RIGHTS) == 0)
682: continue;
683: #ifdef notdef
684: if (so->so_rcv.sb_flags & SB_LOCK) {
685: /*
686: * This is problematical; it's not clear
687: * we need to wait for the sockbuf to be
688: * unlocked (on a uniprocessor, at least),
689: * and it's also not clear what to do
690: * if sbwait returns an error due to receipt
691: * of a signal. If sbwait does return
692: * an error, we'll go into an infinite
693: * loop. Delete all of this for now.
694: */
695: (void) sbwait(&so->so_rcv);
696: goto restart;
697: }
698: #endif
699: unp_scan(so->so_rcv.sb_mb, unp_mark);
700: }
701: } while (unp_defer);
702: for (fp = filehead; fp; fp = fp->f_filef) {
703: if (fp->f_count == 0)
704: continue;
705: if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
706: while (fp->f_msgcount)
707: unp_discard(fp);
708: }
709: unp_gcing = 0;
710: }
711:
712: unp_dispose(m)
713: struct mbuf *m;
714: {
715: int unp_discard();
716:
717: if (m)
718: unp_scan(m, unp_discard);
719: }
720:
721: unp_scan(m0, op)
722: register struct mbuf *m0;
723: int (*op)();
724: {
725: register struct mbuf *m;
726: register struct file **rp;
727: register struct cmsghdr *cm;
728: register int i;
729: int qfds;
730:
731: while (m0) {
732: for (m = m0; m; m = m->m_next)
733: if (m->m_type == MT_CONTROL &&
734: m->m_len >= sizeof(*cm)) {
735: cm = mtod(m, struct cmsghdr *);
736: if (cm->cmsg_level != SOL_SOCKET ||
737: cm->cmsg_type != SCM_RIGHTS)
738: continue;
739: qfds = (cm->cmsg_len - sizeof *cm)
740: / sizeof (struct file *);
741: rp = (struct file **)(cm + 1);
742: for (i = 0; i < qfds; i++)
743: (*op)(*rp++);
744: break; /* XXX, but saves time */
745: }
746: m0 = m0->m_act;
747: }
748: }
749:
750: unp_mark(fp)
751: struct file *fp;
752: {
753:
754: if (fp->f_flag & FMARK)
755: return;
756: unp_defer++;
757: fp->f_flag |= (FMARK|FDEFER);
758: }
759:
760: unp_discard(fp)
761: struct file *fp;
762: {
763:
764: fp->f_msgcount--;
765: unp_rights--;
1.1.1.2 ! root 766: (void) closef(fp, curproc);
1.1 root 767: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.