xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 12760)
1*12760Ssam /*	uipc_usrreq.c	1.10	83/05/27	*/
28925Sroot 
38925Sroot #include "../h/param.h"
48925Sroot #include "../h/dir.h"
58925Sroot #include "../h/user.h"
68925Sroot #include "../h/mbuf.h"
78925Sroot #include "../h/protosw.h"
88925Sroot #include "../h/socket.h"
98925Sroot #include "../h/socketvar.h"
108925Sroot #include "../h/unpcb.h"
118925Sroot #include "../h/un.h"
128925Sroot #include "../h/inode.h"
139169Ssam #include "../h/nami.h"
14*12760Ssam #include "../h/file.h"
158925Sroot 
168925Sroot /*
178925Sroot  * Unix communications domain.
18*12760Ssam  *
19*12760Ssam  * TODO:
20*12760Ssam  *	SEQPACKET, RDM
21*12760Ssam  *	change for names in file system
22*12760Ssam  *	need a proper out-of-band
238925Sroot  */
248925Sroot 
258925Sroot /*ARGSUSED*/
26*12760Ssam uipc_usrreq(so, req, m, nam, rights)
278925Sroot 	struct socket *so;
288925Sroot 	int req;
29*12760Ssam 	struct mbuf *m, *nam, *rights;
308925Sroot {
318925Sroot 	struct unpcb *unp = sotounpcb(so);
328925Sroot 	register struct socket *so2;
338925Sroot 	int error = 0;
348925Sroot 
35*12760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
36*12760Ssam 		error = EOPNOTSUPP;
37*12760Ssam 		goto release;
38*12760Ssam 	}
39*12760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
40*12760Ssam 		error = EINVAL;
41*12760Ssam 		goto release;
42*12760Ssam 	}
438925Sroot 	switch (req) {
448925Sroot 
458925Sroot 	case PRU_ATTACH:
468925Sroot 		if (unp) {
479169Ssam 			error = EISCONN;
488925Sroot 			break;
498925Sroot 		}
509028Sroot 		error = unp_attach(so);
518925Sroot 		break;
528925Sroot 
538925Sroot 	case PRU_DETACH:
548925Sroot 		unp_detach(unp);
558925Sroot 		break;
568925Sroot 
579169Ssam 	case PRU_BIND:
589169Ssam 		error = unp_bind(unp, nam);
599169Ssam 		break;
609169Ssam 
619169Ssam 	case PRU_LISTEN:
629169Ssam 		if (unp->unp_inode == 0)
639169Ssam 			error = EINVAL;
649169Ssam 		break;
659169Ssam 
668925Sroot 	case PRU_CONNECT:
679028Sroot 		error = unp_connect(so, nam);
688925Sroot 		break;
698925Sroot 
70*12760Ssam #ifdef notdef
71*12760Ssam 	case PRU_CONNECT2:
72*12760Ssam 		error = unp_connect2(so, (struct mbuf *)0, (struct socket *)nam);
73*12760Ssam 		break;
74*12760Ssam 
75*12760Ssam #endif
768925Sroot 	case PRU_DISCONNECT:
778925Sroot 		unp_disconnect(unp);
788925Sroot 		break;
798925Sroot 
809169Ssam 	case PRU_ACCEPT:
819169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
829169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
839169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
848925Sroot 		break;
858925Sroot 
868925Sroot 	case PRU_SHUTDOWN:
878925Sroot 		socantsendmore(so);
888925Sroot 		unp_usrclosed(unp);
898925Sroot 		break;
908925Sroot 
918925Sroot 	case PRU_RCVD:
928925Sroot 		switch (so->so_type) {
938925Sroot 
948925Sroot 		case SOCK_DGRAM:
958925Sroot 			panic("uipc 1");
9610139Ssam 			/*NOTREACHED*/
978925Sroot 
9810139Ssam 		case SOCK_STREAM:
998925Sroot #define	rcv (&so->so_rcv)
1008925Sroot #define snd (&so2->so_snd)
1018925Sroot 			if (unp->unp_conn == 0)
1028925Sroot 				break;
1038925Sroot 			so2 = unp->unp_conn->unp_socket;
1048925Sroot 			/*
1058925Sroot 			 * Transfer resources back to send port
1068925Sroot 			 * and wakeup any waiting to write.
1078925Sroot 			 */
1088925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1098925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1108925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1118925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1128925Sroot 			sbwakeup(snd);
1138925Sroot #undef snd
1148925Sroot #undef rcv
1158925Sroot 			break;
1168925Sroot 
1178925Sroot 		default:
1188925Sroot 			panic("uipc 2");
1198925Sroot 		}
1208925Sroot 		break;
1218925Sroot 
1228925Sroot 	case PRU_SEND:
1238925Sroot 		switch (so->so_type) {
1248925Sroot 
1258925Sroot 		case SOCK_DGRAM:
1269028Sroot 			if (nam) {
1278925Sroot 				if (unp->unp_conn) {
1288925Sroot 					error = EISCONN;
1298925Sroot 					break;
1308925Sroot 				}
1319028Sroot 				error = unp_connect(so, nam);
1328925Sroot 				if (error)
1338925Sroot 					break;
1348925Sroot 			} else {
1358925Sroot 				if (unp->unp_conn == 0) {
1368925Sroot 					error = ENOTCONN;
1378925Sroot 					break;
1388925Sroot 				}
1398925Sroot 			}
1408925Sroot 			so2 = unp->unp_conn->unp_socket;
1419169Ssam 			/* BEGIN XXX */
142*12760Ssam 			if (rights) {
143*12760Ssam 				error = unp_internalize(rights);
144*12760Ssam 				if (error)
145*12760Ssam 					break;
146*12760Ssam 			}
147*12760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
1489169Ssam 				(void) sbappendaddr(&so2->so_rcv,
149*12760Ssam 				    mtod(nam, struct sockaddr *), m,
150*12760Ssam 				    rights);
151*12760Ssam 				sbwakeup(&so2->so_rcv);
152*12760Ssam 				m = 0;
153*12760Ssam 			}
1549169Ssam 			/* END XXX */
1559028Sroot 			if (nam)
1569169Ssam 				unp_disconnect(unp);
1578925Sroot 			break;
1588925Sroot 
1598925Sroot 		case SOCK_STREAM:
1608925Sroot #define	rcv (&so2->so_rcv)
1618925Sroot #define	snd (&so->so_snd)
162*12760Ssam 			if (rights && rights->m_len) {
163*12760Ssam 				error = EOPNOTSUPP;
164*12760Ssam 				break;
165*12760Ssam 			}
1668925Sroot 			if (unp->unp_conn == 0)
1678925Sroot 				panic("uipc 3");
1688925Sroot 			so2 = unp->unp_conn->unp_socket;
1698925Sroot 			/*
1708925Sroot 			 * Send to paired receive port, and then
1718925Sroot 			 * give it enough resources to hold what it already has.
1728925Sroot 			 * Wake up readers.
1738925Sroot 			 */
1748925Sroot 			sbappend(rcv, m);
1758925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1768925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1778925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1788925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1798925Sroot 			sbwakeup(rcv);
1808925Sroot #undef snd
1818925Sroot #undef rcv
1828925Sroot 			break;
1838925Sroot 
1848925Sroot 		default:
1858925Sroot 			panic("uipc 4");
1868925Sroot 		}
187*12760Ssam 		m = 0;
1888925Sroot 		break;
1898925Sroot 
1908925Sroot 	case PRU_ABORT:
1918925Sroot 		unp_drop(unp, ECONNABORTED);
1928925Sroot 		break;
1938925Sroot 
1948925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
1958925Sroot 	case PRU_CONTROL:
1968925Sroot 		error = EOPNOTSUPP;
1978925Sroot 		break;
1988925Sroot 
1998925Sroot 	case PRU_SENSE:
2008925Sroot 		error = EOPNOTSUPP;
2018925Sroot 		break;
2028925Sroot /* END UNIMPLEMENTED HOOKS */
2038925Sroot 
2048925Sroot 	case PRU_RCVOOB:
2058925Sroot 		break;
2068925Sroot 
2078925Sroot 	case PRU_SENDOOB:
2088925Sroot 		break;
2098925Sroot 
2108925Sroot 	case PRU_SOCKADDR:
2118925Sroot 		break;
2128925Sroot 
2138925Sroot 	case PRU_SLOWTIMO:
2148925Sroot 		break;
2158925Sroot 
2168925Sroot 	default:
2178925Sroot 		panic("piusrreq");
2188925Sroot 	}
219*12760Ssam release:
220*12760Ssam 	if (m)
221*12760Ssam 		m_freem(m);
22211709Ssam 	return (error);
2238925Sroot }
2248925Sroot 
225*12760Ssam /* SHOULD BE PIPSIZ and 0 */
2268925Sroot int	unp_sendspace = 1024*2;
2278925Sroot int	unp_recvspace = 1024*2;
2288925Sroot 
2299169Ssam unp_attach(so)
2308925Sroot 	struct socket *so;
2318925Sroot {
2329169Ssam 	register struct mbuf *m;
2338925Sroot 	register struct unpcb *unp;
2348925Sroot 	int error;
2358925Sroot 
2368925Sroot 	error = soreserve(so, unp_sendspace, unp_recvspace);
2378925Sroot 	if (error)
23810139Ssam 		return (error);
2399637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
24010139Ssam 	if (m == NULL)
24110139Ssam 		return (ENOBUFS);
2428925Sroot 	unp = mtod(m, struct unpcb *);
2438925Sroot 	so->so_pcb = (caddr_t)unp;
2448925Sroot 	unp->unp_socket = so;
2458925Sroot 	return (0);
2468925Sroot }
2478925Sroot 
2488925Sroot unp_detach(unp)
2499169Ssam 	register struct unpcb *unp;
2508925Sroot {
2518925Sroot 
2528925Sroot 	if (unp->unp_inode) {
2538925Sroot 		irele(unp->unp_inode);
2548925Sroot 		unp->unp_inode = 0;
2558925Sroot 	}
2568925Sroot 	if (unp->unp_conn)
2578925Sroot 		unp_disconnect(unp);
2588925Sroot 	while (unp->unp_refs)
2598925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2608925Sroot 	soisdisconnected(unp->unp_socket);
2618925Sroot 	unp->unp_socket->so_pcb = 0;
2629169Ssam 	m_freem(unp->unp_remaddr);
2639169Ssam 	(void) m_free(dtom(unp));
2648925Sroot }
2658925Sroot 
2669169Ssam unp_bind(unp, nam)
2678925Sroot 	struct unpcb *unp;
2689169Ssam 	struct mbuf *nam;
2698925Sroot {
2709169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
2718925Sroot 	register struct inode *ip;
2729169Ssam 	extern schar();
2738925Sroot 	int error;
2748925Sroot 
2758925Sroot 	u.u_dirp = soun->sun_path;
276*12760Ssam 	if (nam->m_len == MLEN)
277*12760Ssam 		return (EINVAL);
278*12760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
279*12760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
2809169Ssam 	ip = namei(schar, CREATE, 1);
2818925Sroot 	if (ip) {
2828925Sroot 		iput(ip);
28310139Ssam 		return (EADDRINUSE);
2848925Sroot 	}
28511828Ssam 	if (error = u.u_error) {
28611828Ssam 		u.u_error = 0;			/* XXX */
28711828Ssam 		return (error);
28811828Ssam 	}
2898925Sroot 	ip = maknode(IFSOCK | 0777);
2908925Sroot 	if (ip == NULL) {
2918925Sroot 		error = u.u_error;		/* XXX */
2928925Sroot 		u.u_error = 0;			/* XXX */
2938925Sroot 		return (error);
2948925Sroot 	}
2958925Sroot 	ip->i_socket = unp->unp_socket;
2968925Sroot 	unp->unp_inode = ip;
2978925Sroot 	iunlock(ip);			/* but keep reference */
2988925Sroot 	return (0);
2998925Sroot }
3008925Sroot 
3019169Ssam unp_connect(so, nam)
3028925Sroot 	struct socket *so;
3039169Ssam 	struct mbuf *nam;
3048925Sroot {
3059169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3069169Ssam 	register struct inode *ip;
3078925Sroot 	int error;
308*12760Ssam 	register struct socket *so2;
3098925Sroot 
3108925Sroot 	u.u_dirp = soun->sun_path;
311*12760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
312*12760Ssam 		return (EMSGSIZE);
313*12760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
3149169Ssam 	ip = namei(schar, LOOKUP, 1);
3158925Sroot 	if (ip == 0) {
3168925Sroot 		error = u.u_error;
3178925Sroot 		u.u_error = 0;
31810139Ssam 		return (error);		/* XXX */
3198925Sroot 	}
3208925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3218925Sroot 		error = ENOTSOCK;
3228925Sroot 		goto bad;
3238925Sroot 	}
3248925Sroot 	so2 = ip->i_socket;
3258925Sroot 	if (so2 == 0) {
3268925Sroot 		error = ECONNREFUSED;
3278925Sroot 		goto bad;
3288925Sroot 	}
329*12760Ssam 	error = unp_connect2(so, nam, so2);
330*12760Ssam bad:
331*12760Ssam 	iput(ip);
332*12760Ssam 	return (error);
333*12760Ssam }
334*12760Ssam 
335*12760Ssam unp_connect2(so, sonam, so2)
336*12760Ssam 	register struct socket *so;
337*12760Ssam 	struct mbuf *sonam;
338*12760Ssam 	register struct socket *so2;
339*12760Ssam {
340*12760Ssam 	register struct unpcb *unp = sotounpcb(so);
341*12760Ssam 	register struct unpcb *unp2;
342*12760Ssam 
343*12760Ssam 	if (so2->so_type != so->so_type)
344*12760Ssam 		return (EPROTOTYPE);
3458925Sroot 	switch (so->so_type) {
3468925Sroot 
3478925Sroot 	case SOCK_DGRAM:
3488925Sroot 		unp2 = sotounpcb(so2);
349*12760Ssam 		unp->unp_conn = unp2;
3508925Sroot 		unp->unp_nextref = unp2->unp_refs;
3518925Sroot 		unp2->unp_refs = unp;
3528925Sroot 		break;
3538925Sroot 
3548925Sroot 	case SOCK_STREAM:
3558925Sroot 		if ((so2->so_options&SO_ACCEPTCONN) == 0 ||
356*12760Ssam 		    (so2 = sonewconn(so2)) == 0)
357*12760Ssam 			return (ECONNREFUSED);
3589169Ssam 		unp2 = sotounpcb(so2);
3599169Ssam 		unp->unp_conn = unp2;
3609169Ssam 		unp2->unp_conn = unp;
361*12760Ssam 		if (sonam)
362*12760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
3638925Sroot 		break;
3648925Sroot 
3658925Sroot 	default:
366*12760Ssam 		panic("unp_connect2");
3678925Sroot 	}
3689169Ssam 	soisconnected(so2);
3698925Sroot 	soisconnected(so);
3708925Sroot 	return (0);
3718925Sroot }
3729169Ssam 
3739169Ssam unp_disconnect(unp)
3749169Ssam 	struct unpcb *unp;
3759169Ssam {
3769169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
3779169Ssam 
3789169Ssam 	if (unp2 == 0)
3799169Ssam 		return;
3809169Ssam 	unp->unp_conn = 0;
3819169Ssam 	soisdisconnected(unp->unp_socket);
3829169Ssam 	switch (unp->unp_socket->so_type) {
3839169Ssam 
3849169Ssam 	case SOCK_DGRAM:
3859169Ssam 		if (unp2->unp_refs == unp)
3869169Ssam 			unp2->unp_refs = unp->unp_nextref;
3879169Ssam 		else {
3889169Ssam 			unp2 = unp2->unp_refs;
3899169Ssam 			for (;;) {
3909169Ssam 				if (unp2 == 0)
3919169Ssam 					panic("unp_disconnect");
3929169Ssam 				if (unp2->unp_nextref == unp)
3939169Ssam 					break;
3949169Ssam 				unp2 = unp2->unp_nextref;
3959169Ssam 			}
3969169Ssam 			unp2->unp_nextref = unp->unp_nextref;
3979169Ssam 		}
3989169Ssam 		unp->unp_nextref = 0;
3999169Ssam 		break;
4009169Ssam 
4019169Ssam 	case SOCK_STREAM:
4029169Ssam 		unp2->unp_conn = 0;
4039169Ssam 		soisdisconnected(unp2->unp_socket);
4049169Ssam 		break;
4059169Ssam 	}
4069169Ssam }
4079169Ssam 
408*12760Ssam #ifdef notdef
4099169Ssam unp_abort(unp)
4109169Ssam 	struct unpcb *unp;
4119169Ssam {
4129169Ssam 
4139169Ssam 	unp_detach(unp);
4149169Ssam }
415*12760Ssam #endif
4169169Ssam 
4179169Ssam /*ARGSUSED*/
4189169Ssam unp_usrclosed(unp)
4199169Ssam 	struct unpcb *unp;
4209169Ssam {
4219169Ssam 
4229169Ssam }
4239169Ssam 
4249169Ssam unp_drop(unp, errno)
4259169Ssam 	struct unpcb *unp;
4269169Ssam 	int errno;
4279169Ssam {
4289169Ssam 
4299169Ssam 	unp->unp_socket->so_error = errno;
4309169Ssam 	unp_disconnect(unp);
4319169Ssam }
4329169Ssam 
433*12760Ssam #ifdef notdef
4349169Ssam unp_drain()
4359169Ssam {
4369169Ssam 
4379169Ssam }
438*12760Ssam #endif
439*12760Ssam 
440*12760Ssam unp_externalize(rights)
441*12760Ssam 	struct mbuf *rights;
442*12760Ssam {
443*12760Ssam 	int newfds = rights->m_len / sizeof (int);
444*12760Ssam 	register int i;
445*12760Ssam 	register struct file **rp = mtod(rights, struct file **);
446*12760Ssam 	register struct file *fp;
447*12760Ssam 	int f;
448*12760Ssam 
449*12760Ssam 	if (newfds > ufavail()) {
450*12760Ssam 		for (i = 0; i < newfds; i++) {
451*12760Ssam 			fp = *rp;
452*12760Ssam 			unp_discard(fp);
453*12760Ssam 			*rp++ = 0;
454*12760Ssam 		}
455*12760Ssam 		return (EMSGSIZE);
456*12760Ssam 	}
457*12760Ssam 	for (i = 0; i < newfds; i++) {
458*12760Ssam 		f = ufalloc(0);
459*12760Ssam 		if (f < 0)
460*12760Ssam 			panic("unp_externalize");
461*12760Ssam 		fp = *rp;
462*12760Ssam 		u.u_ofile[f] = fp;
463*12760Ssam 		fp->f_msgcount--;
464*12760Ssam 		*(int *)rp = f;
465*12760Ssam 	}
466*12760Ssam 	return (0);
467*12760Ssam }
468*12760Ssam 
469*12760Ssam unp_internalize(rights)
470*12760Ssam 	struct mbuf *rights;
471*12760Ssam {
472*12760Ssam 	register struct file **rp;
473*12760Ssam 	int oldfds = rights->m_len / sizeof (int);
474*12760Ssam 	register int i;
475*12760Ssam 	register struct file *fp;
476*12760Ssam 
477*12760Ssam 	rp = mtod(rights, struct file **);
478*12760Ssam 	for (i = 0; i < oldfds; i++) {
479*12760Ssam 		if (getf(*(int *)rp++) == 0)
480*12760Ssam 			return (EBADF);
481*12760Ssam 	rp = mtod(rights, struct file **);
482*12760Ssam 	for (i = 0; i < oldfds; i++)
483*12760Ssam 		fp = getf(*(int *)rp);
484*12760Ssam 		*rp++ = fp;
485*12760Ssam 		fp->f_count++;
486*12760Ssam 		fp->f_msgcount++;
487*12760Ssam 	}
488*12760Ssam 	return (0);
489*12760Ssam }
490*12760Ssam 
491*12760Ssam int	unp_defer, unp_gcing;
492*12760Ssam int	unp_mark();
493*12760Ssam 
494*12760Ssam unp_gc()
495*12760Ssam {
496*12760Ssam 	register struct file *fp;
497*12760Ssam 	register struct socket *so;
498*12760Ssam 
499*12760Ssam 	if (unp_gcing)
500*12760Ssam 		return;
501*12760Ssam 	unp_gcing = 1;
502*12760Ssam restart:
503*12760Ssam 	unp_defer = 0;
504*12760Ssam 	for (fp = file; fp < fileNFILE; fp++)
505*12760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
506*12760Ssam 	do {
507*12760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
508*12760Ssam 			if (fp->f_count == 0)
509*12760Ssam 				continue;
510*12760Ssam 			if (fp->f_flag & FDEFER) {
511*12760Ssam 				fp->f_flag &= ~FDEFER;
512*12760Ssam 				unp_defer--;
513*12760Ssam 			} else {
514*12760Ssam 				if (fp->f_flag & FMARK)
515*12760Ssam 					continue;
516*12760Ssam 				if (fp->f_count == fp->f_msgcount)
517*12760Ssam 					continue;
518*12760Ssam 				fp->f_flag |= FMARK;
519*12760Ssam 			}
520*12760Ssam 			if (fp->f_type != DTYPE_SOCKET)
521*12760Ssam 				continue;
522*12760Ssam 			so = (struct socket *)fp->f_data;
523*12760Ssam 			if (so->so_proto->pr_family != AF_UNIX ||
524*12760Ssam 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
525*12760Ssam 				continue;
526*12760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
527*12760Ssam 				sbwait(&so->so_rcv);
528*12760Ssam 				goto restart;
529*12760Ssam 			}
530*12760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
531*12760Ssam 		}
532*12760Ssam 	} while (unp_defer);
533*12760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
534*12760Ssam 		if (fp->f_count == 0)
535*12760Ssam 			continue;
536*12760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
537*12760Ssam 			if (fp->f_type != DTYPE_SOCKET)
538*12760Ssam 				panic("unp_gc");
539*12760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
540*12760Ssam 		}
541*12760Ssam 	}
542*12760Ssam 	unp_gcing = 0;
543*12760Ssam }
544*12760Ssam 
545*12760Ssam unp_scan(m, op)
546*12760Ssam 	register struct mbuf *m;
547*12760Ssam 	int (*op)();
548*12760Ssam {
549*12760Ssam 	register struct file **rp;
550*12760Ssam 	register int i;
551*12760Ssam 	int qfds;
552*12760Ssam 
553*12760Ssam 	while (m) {
554*12760Ssam 		m = m->m_next;
555*12760Ssam 		if (m == 0)
556*12760Ssam 			goto bad;
557*12760Ssam 		if (m->m_len) {
558*12760Ssam 			qfds = m->m_len / sizeof (struct file *);
559*12760Ssam 			rp = mtod(m, struct file **);
560*12760Ssam 			for (i = 0; i < qfds; i++)
561*12760Ssam 				(*op)(*rp++);
562*12760Ssam 		}
563*12760Ssam 		do {
564*12760Ssam 			m = m->m_next;
565*12760Ssam 			if (m == 0)
566*12760Ssam 				goto bad;
567*12760Ssam 		} while (m->m_act == 0);
568*12760Ssam 		m = m->m_next;
569*12760Ssam 	}
570*12760Ssam 	return;
571*12760Ssam bad:
572*12760Ssam 	panic("unp_gcscan");
573*12760Ssam }
574*12760Ssam 
575*12760Ssam unp_mark(fp)
576*12760Ssam 	struct file *fp;
577*12760Ssam {
578*12760Ssam 
579*12760Ssam 	if (fp->f_flag & FMARK)
580*12760Ssam 		return;
581*12760Ssam 	unp_defer++;
582*12760Ssam 	fp->f_flag |= (FMARK|FDEFER);
583*12760Ssam }
584*12760Ssam 
585*12760Ssam unp_discard(fp)
586*12760Ssam 	struct file *fp;
587*12760Ssam {
588*12760Ssam 
589*12760Ssam 	fp->f_msgcount--;
590*12760Ssam 	closef(fp, 0);
591*12760Ssam }
592