*** kern/uipc_socket.c.orig Mon Nov 1 15:18:06 2004 --- kern/uipc_socket.c Mon Nov 1 16:40:59 2004 *************** *** 72,77 **** --- 72,81 ---- static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt); #endif + static int sosend_nolock(struct socket *so, struct sockaddr *addr, + struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, + struct thread *td); + static void filt_sordetach(struct knote *kn); static int filt_soread(struct knote *kn, long hint); static void filt_sowdetach(struct knote *kn); *************** *** 593,598 **** --- 597,865 ---- #endif /*ZERO_COPY_SOCKETS*/ int + sosend2(so, addr, uio, top, control, flags, td) + struct socket *so; + struct sockaddr *addr; + struct uio *uio; + struct mbuf *top; + struct mbuf *control; + int flags; + struct thread *td; + { + if ((so->so_options & SO_FAST1) != 0) + return (sosend(so, addr, uio, top, control, flags, td)); + else + return (sosend_nolock(so, addr, uio, top, control, flags, td)); + } + + static int + sosend_nolock(so, addr, uio, top, control, flags, td) + struct socket *so; + struct sockaddr *addr; + struct uio *uio; + struct mbuf *top; + struct mbuf *control; + int flags; + struct thread *td; + { + struct mbuf **mp; + struct mbuf *m; + long space, len = 0, resid; + int clen = 0, error, dontroute; + int atomic = sosendallatonce(so) || top; + #ifdef ZERO_COPY_SOCKETS + int cow_send; + #endif /* ZERO_COPY_SOCKETS */ + + if (uio != NULL) + resid = uio->uio_resid; + else + resid = top->m_pkthdr.len; + /* + * In theory resid should be unsigned. + * However, space must be signed, as it might be less than 0 + * if we over-committed, and we must use a signed comparison + * of space and resid. On the other hand, a negative resid + * causes us to loop sending 0-length segments to the protocol. + * + * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM + * type sockets since that's an error. + */ + if (resid < 0 || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) { + error = EINVAL; + goto out; + } + + dontroute = + (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && + (so->so_proto->pr_flags & PR_ATOMIC); + if (td != NULL) + td->td_proc->p_stats->p_ru.ru_msgsnd++; + if (control != NULL) + clen = control->m_len; + #define snderr(errno) { error = (errno); goto release; } + + restart: + do { + if (so->so_snd.sb_state & SBS_CANTSENDMORE) + snderr(EPIPE); + if (so->so_error) { + error = so->so_error; + so->so_error = 0; + goto release; + } + if ((so->so_state & SS_ISCONNECTED) == 0) { + /* + * `sendto' and `sendmsg' is allowed on a connection- + * based socket if it supports implied connect. + * Return ENOTCONN if not connected and no address is + * supplied. + */ + if ((so->so_proto->pr_flags & PR_CONNREQUIRED) && + (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) { + if ((so->so_state & SS_ISCONFIRMING) == 0 && + !(resid == 0 && clen != 0)) + snderr(ENOTCONN); + } else if (addr == NULL) + snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? + ENOTCONN : EDESTADDRREQ); + } + space = sbspace(&so->so_snd); + if (flags & MSG_OOB) + space += 1024; + if ((atomic && resid > so->so_snd.sb_hiwat) || + clen > so->so_snd.sb_hiwat) + snderr(EMSGSIZE); + if (space < resid + clen && + (atomic || space < so->so_snd.sb_lowat || space < clen)) { + if ((so->so_state & SS_NBIO) || (flags & MSG_NBIO)) + snderr(EWOULDBLOCK); + error = sbwait(&so->so_snd); + if (error) + goto out_locked; + goto restart; + } + mp = ⊤ + space -= clen; + do { + if (uio == NULL) { + /* + * Data is prepackaged in "top". + */ + resid = 0; + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + } else do { + #ifdef ZERO_COPY_SOCKETS + cow_send = 0; + #endif /* ZERO_COPY_SOCKETS */ + if (resid >= MINCLSIZE) { + #ifdef ZERO_COPY_SOCKETS + if (top == NULL) { + MGETHDR(m, M_TRYWAIT, MT_DATA); + if (m == NULL) { + error = ENOBUFS; + goto release; + } + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *)0; + } else { + MGET(m, M_TRYWAIT, MT_DATA); + if (m == NULL) { + error = ENOBUFS; + goto release; + } + } + if (so_zero_copy_send && + resid>=PAGE_SIZE && + space>=PAGE_SIZE && + uio->uio_iov->iov_len>=PAGE_SIZE) { + so_zerocp_stats.size_ok++; + if (!((vm_offset_t) + uio->uio_iov->iov_base & PAGE_MASK)){ + so_zerocp_stats.align_ok++; + cow_send = socow_setup(m, uio); + } + } + if (!cow_send) { + MCLGET(m, M_TRYWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + m = NULL; + } else { + len = min(min(MCLBYTES, resid), space); + } + } else + len = PAGE_SIZE; + #else /* ZERO_COPY_SOCKETS */ + if (top == NULL) { + m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *)0; + } else + m = m_getcl(M_TRYWAIT, MT_DATA, 0); + len = min(min(MCLBYTES, resid), space); + #endif /* ZERO_COPY_SOCKETS */ + } else { + if (top == NULL) { + m = m_gethdr(M_TRYWAIT, MT_DATA); + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *)0; + + len = min(min(MHLEN, resid), space); + /* + * For datagram protocols, leave room + * for protocol headers in first mbuf. + */ + if (atomic && m && len < MHLEN) + MH_ALIGN(m, len); + } else { + m = m_get(M_TRYWAIT, MT_DATA); + len = min(min(MLEN, resid), space); + } + } + if (m == NULL) { + error = ENOBUFS; + goto release; + } + + space -= len; + #ifdef ZERO_COPY_SOCKETS + if (cow_send) + error = 0; + else + #endif /* ZERO_COPY_SOCKETS */ + error = uiomove(mtod(m, void *), (int)len, uio); + resid = uio->uio_resid; + m->m_len = len; + *mp = m; + top->m_pkthdr.len += len; + if (error) { + goto release; + } + mp = &m->m_next; + if (resid <= 0) { + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + break; + } + } while (space > 0 && atomic); + if (dontroute) { + SOCK_LOCK(so); + so->so_options |= SO_DONTROUTE; + SOCK_UNLOCK(so); + } + /* + * XXX all the SBS_CANTSENDMORE checks previously + * done could be out of date. We could have recieved + * a reset packet in an interrupt or maybe we slept + * while doing page faults in uiomove() etc. We could + * probably recheck again inside the locking protection + * here, but there are probably other places that this + * also happens. We must rethink this. + */ + error = (*so->so_proto->pr_usrreqs->pru_send)(so, + (flags & MSG_OOB) ? PRUS_OOB : + /* + * If the user set MSG_EOF, the protocol + * understands this flag and nothing left to + * send then use PRU_SEND_EOF instead of PRU_SEND. + */ + ((flags & MSG_EOF) && + (so->so_proto->pr_flags & PR_IMPLOPCL) && + (resid <= 0)) ? + PRUS_EOF : + /* If there is more to send set PRUS_MORETOCOME */ + (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0, + top, addr, control, td); + + if (dontroute) { + SOCK_LOCK(so); + so->so_options &= ~SO_DONTROUTE; + SOCK_UNLOCK(so); + } + clen = 0; + control = NULL; + top = NULL; + mp = ⊤ + if (error) { + goto release; + } + } while (resid && space > 0); + } while (resid); + + release: + out_locked: + + out: + if (top != NULL) + m_freem(top); + if (control != NULL) + m_freem(control); + return (error); + } + + int sosend(so, addr, uio, top, control, flags, td) struct socket *so; struct sockaddr *addr; *************** *** 1681,1686 **** --- 1948,1954 ---- case SO_TIMESTAMP: case SO_BINTIME: case SO_NOSIGPIPE: + case SO_FAST1: error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) *** netinet/udp_usrreq.c.orig Mon Nov 1 15:18:29 2004 --- netinet/udp_usrreq.c Mon Nov 1 15:18:52 2004 *************** *** 1142,1146 **** pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, pru_listen_notsupp, udp_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, ! udp_sockaddr, sosend, soreceive, sopoll, in_pcbsosetlabel }; --- 1142,1146 ---- pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, pru_listen_notsupp, udp_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, ! udp_sockaddr, sosend2, soreceive, sopoll, in_pcbsosetlabel }; *** sys/socket.h.orig Mon Nov 1 15:18:14 2004 --- sys/socket.h Mon Nov 1 15:19:31 2004 *************** *** 119,124 **** --- 119,126 ---- #define SO_BINTIME 0x2000 /* timestamp received dgram traffic */ #endif + #define SO_FAST1 0x8000 + /* * Additional options, not kept in so_options. */ *** sys/socketvar.h.orig Mon Nov 1 15:18:20 2004 --- sys/socketvar.h Mon Nov 1 15:19:43 2004 *************** *** 523,528 **** --- 523,531 ---- int sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, struct thread *td); + int sosend2(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, + struct thread *td); int sosetopt(struct socket *so, struct sockopt *sopt); int soshutdown(struct socket *so, int how); void sotoxsocket(struct socket *so, struct xsocket *xso);