1*16973Skarels /* uipc_usrreq.c 6.7 84/08/20 */ 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" 1312760Ssam #include "../h/file.h" 14*16973Skarels #include "../h/stat.h" 158925Sroot 168925Sroot /* 178925Sroot * Unix communications domain. 1812760Ssam * 1912760Ssam * TODO: 2012760Ssam * SEQPACKET, RDM 2113119Ssam * rethink name space problems 2212760Ssam * need a proper out-of-band 238925Sroot */ 2413119Ssam struct sockaddr sun_noname = { AF_UNIX }; 258925Sroot 268925Sroot /*ARGSUSED*/ 2712760Ssam uipc_usrreq(so, req, m, nam, rights) 288925Sroot struct socket *so; 298925Sroot int req; 3012760Ssam struct mbuf *m, *nam, *rights; 318925Sroot { 328925Sroot struct unpcb *unp = sotounpcb(so); 338925Sroot register struct socket *so2; 348925Sroot int error = 0; 358925Sroot 3612760Ssam if (req != PRU_SEND && rights && rights->m_len) { 3712760Ssam error = EOPNOTSUPP; 3812760Ssam goto release; 3912760Ssam } 4012760Ssam if (unp == 0 && req != PRU_ATTACH) { 4112760Ssam error = EINVAL; 4212760Ssam goto release; 4312760Ssam } 448925Sroot switch (req) { 458925Sroot 468925Sroot case PRU_ATTACH: 478925Sroot if (unp) { 489169Ssam error = EISCONN; 498925Sroot break; 508925Sroot } 519028Sroot error = unp_attach(so); 528925Sroot break; 538925Sroot 548925Sroot case PRU_DETACH: 558925Sroot unp_detach(unp); 568925Sroot break; 578925Sroot 589169Ssam case PRU_BIND: 599169Ssam error = unp_bind(unp, nam); 609169Ssam break; 619169Ssam 629169Ssam case PRU_LISTEN: 639169Ssam if (unp->unp_inode == 0) 649169Ssam error = EINVAL; 659169Ssam break; 669169Ssam 678925Sroot case PRU_CONNECT: 689028Sroot error = unp_connect(so, nam); 698925Sroot break; 708925Sroot 7112760Ssam case PRU_CONNECT2: 7213115Ssam error = unp_connect2(so, (struct mbuf *)0, 7313115Ssam (struct socket *)nam); 7412760Ssam break; 7512760Ssam 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 */ 14212760Ssam if (rights) { 14312760Ssam error = unp_internalize(rights); 14412760Ssam if (error) 14512760Ssam break; 14612760Ssam } 14712760Ssam if (sbspace(&so2->so_rcv) > 0) { 14813119Ssam /* 14913119Ssam * There's no record of source socket's 15013119Ssam * name, so send null name for the moment. 15113119Ssam */ 1529169Ssam (void) sbappendaddr(&so2->so_rcv, 15313119Ssam &sun_noname, m, rights); 15412760Ssam sbwakeup(&so2->so_rcv); 15512760Ssam m = 0; 15612760Ssam } 1579169Ssam /* END XXX */ 1589028Sroot if (nam) 1599169Ssam unp_disconnect(unp); 1608925Sroot break; 1618925Sroot 1628925Sroot case SOCK_STREAM: 1638925Sroot #define rcv (&so2->so_rcv) 1648925Sroot #define snd (&so->so_snd) 16512760Ssam if (rights && rights->m_len) { 16612760Ssam error = EOPNOTSUPP; 16712760Ssam break; 16812760Ssam } 1698925Sroot if (unp->unp_conn == 0) 1708925Sroot panic("uipc 3"); 1718925Sroot so2 = unp->unp_conn->unp_socket; 1728925Sroot /* 1738925Sroot * Send to paired receive port, and then 1748925Sroot * give it enough resources to hold what it already has. 1758925Sroot * Wake up readers. 1768925Sroot */ 1778925Sroot sbappend(rcv, m); 1788925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1798925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1808925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1818925Sroot rcv->sb_hiwat = rcv->sb_cc; 1828925Sroot sbwakeup(rcv); 1838925Sroot #undef snd 1848925Sroot #undef rcv 1858925Sroot break; 1868925Sroot 1878925Sroot default: 1888925Sroot panic("uipc 4"); 1898925Sroot } 19012760Ssam m = 0; 1918925Sroot break; 1928925Sroot 1938925Sroot case PRU_ABORT: 1948925Sroot unp_drop(unp, ECONNABORTED); 1958925Sroot break; 1968925Sroot 1978925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 1988925Sroot case PRU_CONTROL: 19913050Ssam return (EOPNOTSUPP); 2008925Sroot 201*16973Skarels /* END UNIMPLEMENTED HOOKS */ 2028925Sroot case PRU_SENSE: 203*16973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 204*16973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 205*16973Skarels so2 = unp->unp_conn->unp_socket; 206*16973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 207*16973Skarels } 208*16973Skarels return (0); 2098925Sroot 2108925Sroot case PRU_RCVOOB: 21116774Sbloom return (EOPNOTSUPP); 2128925Sroot 2138925Sroot case PRU_SENDOOB: 2148925Sroot break; 2158925Sroot 2168925Sroot case PRU_SOCKADDR: 2178925Sroot break; 2188925Sroot 21914121Ssam case PRU_PEERADDR: 22014121Ssam break; 22114121Ssam 2228925Sroot case PRU_SLOWTIMO: 2238925Sroot break; 2248925Sroot 2258925Sroot default: 2268925Sroot panic("piusrreq"); 2278925Sroot } 22812760Ssam release: 22912760Ssam if (m) 23012760Ssam m_freem(m); 23111709Ssam return (error); 2328925Sroot } 2338925Sroot 234*16973Skarels /* 235*16973Skarels * We assign all buffering for stream sockets to the source, 236*16973Skarels * as that is where the flow control is implemented. 237*16973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 238*16973Skarels * and don't really want to reserve the sendspace. Their recvspace should 239*16973Skarels * be large enough for at least one max-size datagram plus address. 240*16973Skarels */ 241*16973Skarels #define PIPSIZ 4096 242*16973Skarels int unpst_sendspace = PIPSIZ; 243*16973Skarels int unpst_recvspace = 0; 244*16973Skarels int unpdg_sendspace = 2*1024; /* really max datagram size */ 245*16973Skarels int unpdg_recvspace = 4*1024; 2468925Sroot 2479169Ssam unp_attach(so) 2488925Sroot struct socket *so; 2498925Sroot { 2509169Ssam register struct mbuf *m; 2518925Sroot register struct unpcb *unp; 2528925Sroot int error; 2538925Sroot 254*16973Skarels switch (so->so_type) { 255*16973Skarels 256*16973Skarels case SOCK_STREAM: 257*16973Skarels error = soreserve(so, unpst_sendspace, unpst_recvspace); 258*16973Skarels break; 259*16973Skarels 260*16973Skarels case SOCK_DGRAM: 261*16973Skarels error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 262*16973Skarels break; 263*16973Skarels } 2648925Sroot if (error) 26510139Ssam return (error); 2669637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 26710139Ssam if (m == NULL) 26810139Ssam return (ENOBUFS); 2698925Sroot unp = mtod(m, struct unpcb *); 2708925Sroot so->so_pcb = (caddr_t)unp; 2718925Sroot unp->unp_socket = so; 2728925Sroot return (0); 2738925Sroot } 2748925Sroot 2758925Sroot unp_detach(unp) 2769169Ssam register struct unpcb *unp; 2778925Sroot { 2788925Sroot 2798925Sroot if (unp->unp_inode) { 2808925Sroot irele(unp->unp_inode); 2818925Sroot unp->unp_inode = 0; 2828925Sroot } 2838925Sroot if (unp->unp_conn) 2848925Sroot unp_disconnect(unp); 2858925Sroot while (unp->unp_refs) 2868925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2878925Sroot soisdisconnected(unp->unp_socket); 2888925Sroot unp->unp_socket->so_pcb = 0; 2899169Ssam m_freem(unp->unp_remaddr); 2909169Ssam (void) m_free(dtom(unp)); 2918925Sroot } 2928925Sroot 2939169Ssam unp_bind(unp, nam) 2948925Sroot struct unpcb *unp; 2959169Ssam struct mbuf *nam; 2968925Sroot { 2979169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2988925Sroot register struct inode *ip; 29916695Smckusick register struct nameidata *ndp = &u.u_nd; 3008925Sroot int error; 3018925Sroot 30216695Smckusick ndp->ni_dirp = soun->sun_path; 30312760Ssam if (nam->m_len == MLEN) 30412760Ssam return (EINVAL); 30512760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 30612760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 30716695Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 30816695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 30916695Smckusick ip = namei(ndp); 3108925Sroot if (ip) { 3118925Sroot iput(ip); 31210139Ssam return (EADDRINUSE); 3138925Sroot } 31411828Ssam if (error = u.u_error) { 31511828Ssam u.u_error = 0; /* XXX */ 31611828Ssam return (error); 31711828Ssam } 31816695Smckusick ip = maknode(IFSOCK | 0777, ndp); 3198925Sroot if (ip == NULL) { 3208925Sroot error = u.u_error; /* XXX */ 3218925Sroot u.u_error = 0; /* XXX */ 3228925Sroot return (error); 3238925Sroot } 3248925Sroot ip->i_socket = unp->unp_socket; 3258925Sroot unp->unp_inode = ip; 3268925Sroot iunlock(ip); /* but keep reference */ 3278925Sroot return (0); 3288925Sroot } 3298925Sroot 3309169Ssam unp_connect(so, nam) 3318925Sroot struct socket *so; 3329169Ssam struct mbuf *nam; 3338925Sroot { 3349169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3359169Ssam register struct inode *ip; 3368925Sroot int error; 33712760Ssam register struct socket *so2; 33816695Smckusick register struct nameidata *ndp = &u.u_nd; 3398925Sroot 34016695Smckusick ndp->ni_dirp = soun->sun_path; 34112760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 34212760Ssam return (EMSGSIZE); 34312760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 34416695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 34516695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 34616695Smckusick ip = namei(ndp); 3478925Sroot if (ip == 0) { 3488925Sroot error = u.u_error; 3498925Sroot u.u_error = 0; 35010139Ssam return (error); /* XXX */ 3518925Sroot } 3528925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3538925Sroot error = ENOTSOCK; 3548925Sroot goto bad; 3558925Sroot } 3568925Sroot so2 = ip->i_socket; 3578925Sroot if (so2 == 0) { 3588925Sroot error = ECONNREFUSED; 3598925Sroot goto bad; 3608925Sroot } 36113115Ssam if (so->so_type != so2->so_type) { 36213115Ssam error = EPROTOTYPE; 36313115Ssam goto bad; 36413115Ssam } 36513115Ssam if (so->so_proto->pr_flags & PR_CONNREQUIRED && 36613115Ssam ((so2->so_options&SO_ACCEPTCONN) == 0 || 36713115Ssam (so2 = sonewconn(so2)) == 0)) { 36813115Ssam error = ECONNREFUSED; 36913115Ssam goto bad; 37013115Ssam } 37112760Ssam error = unp_connect2(so, nam, so2); 37212760Ssam bad: 37312760Ssam iput(ip); 37412760Ssam return (error); 37512760Ssam } 37612760Ssam 37712760Ssam unp_connect2(so, sonam, so2) 37812760Ssam register struct socket *so; 37912760Ssam struct mbuf *sonam; 38012760Ssam register struct socket *so2; 38112760Ssam { 38212760Ssam register struct unpcb *unp = sotounpcb(so); 38312760Ssam register struct unpcb *unp2; 38412760Ssam 38512760Ssam if (so2->so_type != so->so_type) 38612760Ssam return (EPROTOTYPE); 38714049Ssam unp2 = sotounpcb(so2); 38814049Ssam unp->unp_conn = unp2; 3898925Sroot switch (so->so_type) { 3908925Sroot 3918925Sroot case SOCK_DGRAM: 3928925Sroot unp->unp_nextref = unp2->unp_refs; 3938925Sroot unp2->unp_refs = unp; 3948925Sroot break; 3958925Sroot 3968925Sroot case SOCK_STREAM: 3979169Ssam unp2->unp_conn = unp; 39812760Ssam if (sonam) 39912760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 40014049Ssam soisconnected(so2); 40114049Ssam soisconnected(so); 4028925Sroot break; 4038925Sroot 4048925Sroot default: 40512760Ssam panic("unp_connect2"); 4068925Sroot } 4078925Sroot return (0); 4088925Sroot } 4099169Ssam 4109169Ssam unp_disconnect(unp) 4119169Ssam struct unpcb *unp; 4129169Ssam { 4139169Ssam register struct unpcb *unp2 = unp->unp_conn; 4149169Ssam 4159169Ssam if (unp2 == 0) 4169169Ssam return; 4179169Ssam unp->unp_conn = 0; 4189169Ssam switch (unp->unp_socket->so_type) { 4199169Ssam 4209169Ssam case SOCK_DGRAM: 4219169Ssam if (unp2->unp_refs == unp) 4229169Ssam unp2->unp_refs = unp->unp_nextref; 4239169Ssam else { 4249169Ssam unp2 = unp2->unp_refs; 4259169Ssam for (;;) { 4269169Ssam if (unp2 == 0) 4279169Ssam panic("unp_disconnect"); 4289169Ssam if (unp2->unp_nextref == unp) 4299169Ssam break; 4309169Ssam unp2 = unp2->unp_nextref; 4319169Ssam } 4329169Ssam unp2->unp_nextref = unp->unp_nextref; 4339169Ssam } 4349169Ssam unp->unp_nextref = 0; 4359169Ssam break; 4369169Ssam 4379169Ssam case SOCK_STREAM: 43814049Ssam soisdisconnected(unp->unp_socket); 4399169Ssam unp2->unp_conn = 0; 4409169Ssam soisdisconnected(unp2->unp_socket); 4419169Ssam break; 4429169Ssam } 4439169Ssam } 4449169Ssam 44512760Ssam #ifdef notdef 4469169Ssam unp_abort(unp) 4479169Ssam struct unpcb *unp; 4489169Ssam { 4499169Ssam 4509169Ssam unp_detach(unp); 4519169Ssam } 45212760Ssam #endif 4539169Ssam 4549169Ssam /*ARGSUSED*/ 4559169Ssam unp_usrclosed(unp) 4569169Ssam struct unpcb *unp; 4579169Ssam { 4589169Ssam 4599169Ssam } 4609169Ssam 4619169Ssam unp_drop(unp, errno) 4629169Ssam struct unpcb *unp; 4639169Ssam int errno; 4649169Ssam { 46516054Skarels struct socket *so = unp->unp_socket; 4669169Ssam 46716054Skarels so->so_error = errno; 4689169Ssam unp_disconnect(unp); 46916054Skarels if (so->so_head) { 47016054Skarels so->so_pcb = (caddr_t) 0; 47116431Skarels m_freem(unp->unp_remaddr); 47216054Skarels (void) m_free(dtom(unp)); 47316054Skarels sofree(so); 47416054Skarels } 4759169Ssam } 4769169Ssam 47712760Ssam #ifdef notdef 4789169Ssam unp_drain() 4799169Ssam { 4809169Ssam 4819169Ssam } 48212760Ssam #endif 48312760Ssam 48412760Ssam unp_externalize(rights) 48512760Ssam struct mbuf *rights; 48612760Ssam { 48712760Ssam int newfds = rights->m_len / sizeof (int); 48812760Ssam register int i; 48912760Ssam register struct file **rp = mtod(rights, struct file **); 49012760Ssam register struct file *fp; 49112760Ssam int f; 49212760Ssam 49312760Ssam if (newfds > ufavail()) { 49412760Ssam for (i = 0; i < newfds; i++) { 49512760Ssam fp = *rp; 49612760Ssam unp_discard(fp); 49712760Ssam *rp++ = 0; 49812760Ssam } 49912760Ssam return (EMSGSIZE); 50012760Ssam } 50112760Ssam for (i = 0; i < newfds; i++) { 50212760Ssam f = ufalloc(0); 50312760Ssam if (f < 0) 50412760Ssam panic("unp_externalize"); 50512760Ssam fp = *rp; 50612760Ssam u.u_ofile[f] = fp; 50712760Ssam fp->f_msgcount--; 50814927Smckusick *(int *)rp++ = f; 50912760Ssam } 51012760Ssam return (0); 51112760Ssam } 51212760Ssam 51312760Ssam unp_internalize(rights) 51412760Ssam struct mbuf *rights; 51512760Ssam { 51612760Ssam register struct file **rp; 51712760Ssam int oldfds = rights->m_len / sizeof (int); 51812760Ssam register int i; 51912760Ssam register struct file *fp; 52012760Ssam 52112760Ssam rp = mtod(rights, struct file **); 52213084Ssam for (i = 0; i < oldfds; i++) 52312760Ssam if (getf(*(int *)rp++) == 0) 52412760Ssam return (EBADF); 52512760Ssam rp = mtod(rights, struct file **); 52613084Ssam for (i = 0; i < oldfds; i++) { 52712760Ssam fp = getf(*(int *)rp); 52812760Ssam *rp++ = fp; 52912760Ssam fp->f_count++; 53012760Ssam fp->f_msgcount++; 53112760Ssam } 53212760Ssam return (0); 53312760Ssam } 53412760Ssam 53512760Ssam int unp_defer, unp_gcing; 53612760Ssam int unp_mark(); 53712760Ssam 53812760Ssam unp_gc() 53912760Ssam { 54012760Ssam register struct file *fp; 54112760Ssam register struct socket *so; 54212760Ssam 54312760Ssam if (unp_gcing) 54412760Ssam return; 54512760Ssam unp_gcing = 1; 54612760Ssam restart: 54712760Ssam unp_defer = 0; 54812760Ssam for (fp = file; fp < fileNFILE; fp++) 54912760Ssam fp->f_flag &= ~(FMARK|FDEFER); 55012760Ssam do { 55112760Ssam for (fp = file; fp < fileNFILE; fp++) { 55212760Ssam if (fp->f_count == 0) 55312760Ssam continue; 55412760Ssam if (fp->f_flag & FDEFER) { 55512760Ssam fp->f_flag &= ~FDEFER; 55612760Ssam unp_defer--; 55712760Ssam } else { 55812760Ssam if (fp->f_flag & FMARK) 55912760Ssam continue; 56012760Ssam if (fp->f_count == fp->f_msgcount) 56112760Ssam continue; 56212760Ssam fp->f_flag |= FMARK; 56312760Ssam } 56412760Ssam if (fp->f_type != DTYPE_SOCKET) 56512760Ssam continue; 56612760Ssam so = (struct socket *)fp->f_data; 56712760Ssam if (so->so_proto->pr_family != AF_UNIX || 56812760Ssam (so->so_proto->pr_flags&PR_ADDR) == 0) 56912760Ssam continue; 57012760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 57112760Ssam sbwait(&so->so_rcv); 57212760Ssam goto restart; 57312760Ssam } 57412760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 57512760Ssam } 57612760Ssam } while (unp_defer); 57712760Ssam for (fp = file; fp < fileNFILE; fp++) { 57812760Ssam if (fp->f_count == 0) 57912760Ssam continue; 58012760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 58112760Ssam if (fp->f_type != DTYPE_SOCKET) 58212760Ssam panic("unp_gc"); 58312760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 58412760Ssam } 58512760Ssam } 58612760Ssam unp_gcing = 0; 58712760Ssam } 58812760Ssam 58912760Ssam unp_scan(m, op) 59012760Ssam register struct mbuf *m; 59112760Ssam int (*op)(); 59212760Ssam { 59312760Ssam register struct file **rp; 59412760Ssam register int i; 59512760Ssam int qfds; 59612760Ssam 59712760Ssam while (m) { 59812760Ssam m = m->m_next; 59912760Ssam if (m == 0) 60012760Ssam goto bad; 60112760Ssam if (m->m_len) { 60212760Ssam qfds = m->m_len / sizeof (struct file *); 60312760Ssam rp = mtod(m, struct file **); 60412760Ssam for (i = 0; i < qfds; i++) 60512760Ssam (*op)(*rp++); 60612760Ssam } 60712760Ssam do { 60812760Ssam m = m->m_next; 60912760Ssam if (m == 0) 61012760Ssam goto bad; 61112760Ssam } while (m->m_act == 0); 61212760Ssam m = m->m_next; 61312760Ssam } 61412760Ssam return; 61512760Ssam bad: 61612760Ssam panic("unp_gcscan"); 61712760Ssam } 61812760Ssam 61912760Ssam unp_mark(fp) 62012760Ssam struct file *fp; 62112760Ssam { 62212760Ssam 62312760Ssam if (fp->f_flag & FMARK) 62412760Ssam return; 62512760Ssam unp_defer++; 62612760Ssam fp->f_flag |= (FMARK|FDEFER); 62712760Ssam } 62812760Ssam 62912760Ssam unp_discard(fp) 63012760Ssam struct file *fp; 63112760Ssam { 63212760Ssam 63312760Ssam fp->f_msgcount--; 63413084Ssam closef(fp); 63512760Ssam } 636