From owner-p4-projects@FreeBSD.ORG Sun Oct 30 14:11:22 2005 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B368316A421; Sun, 30 Oct 2005 14:11:21 +0000 (GMT) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 807BC16A41F for ; Sun, 30 Oct 2005 14:11:21 +0000 (GMT) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3181B43D46 for ; Sun, 30 Oct 2005 14:11:21 +0000 (GMT) (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j9UEBKhx042726 for ; Sun, 30 Oct 2005 14:11:21 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j9UEBK2f042723 for perforce@freebsd.org; Sun, 30 Oct 2005 14:11:20 GMT (envelope-from bb+lists.freebsd.perforce@cyrus.watson.org) Date: Sun, 30 Oct 2005 14:11:20 GMT Message-Id: <200510301411.j9UEBK2f042723@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to bb+lists.freebsd.perforce@cyrus.watson.org using -f From: Robert Watson To: Perforce Change Reviews Cc: Subject: PERFORCE change 86068 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 30 Oct 2005 14:11:22 -0000 http://perforce.freebsd.org/chv.cgi?CH=86068 Change 86068 by rwatson@rwatson_zoo on 2005/10/30 14:10:56 First cut at breaking out mbuf copyin/etc code from sosend() into sosend_copyin(). Compiles. Affected files ... .. //depot/projects/netsmp/src/sys/kern/uipc_socket.c#14 edit Differences ... ==== //depot/projects/netsmp/src/sys/kern/uipc_socket.c#14 (text+ko) ==== @@ -569,6 +569,131 @@ return (error); } +/* + * sosend_copyin() accepts a uio and prepares an mbuf chain holding part or + * all of the data referenced by the uio. If desired, it uses zero-copy. + * *space will be updated to reflect data copied in. + * + * NB: If atomic I/O is requested, the caller must already have checked that + * space can hold resid bytes. + * + * NB: In the event of an error, the caller may need to free the partial + * chain pointed to by *mpp. The contents of both *uio and *space may be + * modified even in the case of an error. + */ +static int +sosend_copyin(struct uio *uio, struct mbuf **retmp, int atomic, long *space, + int flags) +{ + struct mbuf *m, **mp, *top; + long len, resid; + int error; +#ifdef ZERO_COPY_SOCKETS + int cow_send; +#endif + + *retmp = top = NULL; + mp = ⊤ + len = 0; + resid = uio->uio_resid; + error = 0; + 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 out; + } + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = NULL; + } else { + MGET(m, M_TRYWAIT, MT_DATA); + if (m == NULL) { + error = ENOBUFS; + goto out; + } + } + if (so_zero_copy_send && + resid>=PAGE_SIZE && + *space>=PAGE_SIZE && + uio->uio_iov->iov_len>=PAGE_SIZE) { + so_zerocp_stats.size_ok++; + so_zerocp_stats.align_ok++; + cow_send = socow_setup(m, uio); + len = cow_send; + } + 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 /* ZERO_COPY_SOCKETS */ + if (top == NULL) { + m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = NULL; + } 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 = NULL; + + 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 out; + } + + *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 out; + mp = &m->m_next; + if (resid <= 0) { + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + break; + } + } while (*space > 0 && atomic); +out: + *retmp = top; + return (error); +} + #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) /* * Send on a socket. @@ -613,9 +738,7 @@ int flags; struct thread *td; { - struct mbuf **mp; - struct mbuf *m; - long space, len = 0, resid; + long space, resid; int clen = 0, error, dontroute; int atomic = sosendallatonce(so) || top; #ifdef ZERO_COPY_SOCKETS @@ -682,6 +805,7 @@ snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? ENOTCONN : EDESTADDRREQ); } + space = sbspace(&so->so_snd); if (flags & MSG_OOB) space += 1024; @@ -699,153 +823,61 @@ goto restart; } SOCKBUF_UNLOCK(&so->so_snd); - 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; - SOCKBUF_LOCK(&so->so_snd); - goto release; - } - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = NULL; - } else { - MGET(m, M_TRYWAIT, MT_DATA); - if (m == NULL) { - error = ENOBUFS; - SOCKBUF_LOCK(&so->so_snd); - 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++; - so_zerocp_stats.align_ok++; - cow_send = socow_setup(m, uio); - len = cow_send; - } - 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 /* ZERO_COPY_SOCKETS */ - if (top == NULL) { - m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = NULL; - } else - m = m_getcl(M_TRYWAIT, MT_DATA, 0); - len = min(min(MCLBYTES, resid), space); -#endif /* ZERO_COPY_SOCKETS */ + if (uio == NULL) { + resid = 0; + if (flags & MSG_EOR) + top->m_flags |= M_EOR; } else { - if (top == NULL) { - m = m_gethdr(M_TRYWAIT, MT_DATA); - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = NULL; - - 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); + error = sosend_copyin(uio, &top, atomic, + &space, flags); + if (error != 0) { + SOCKBUF_LOCK(&so->so_snd); + goto release; } + resid = uio->uio_resid; } - if (m == NULL) { - error = ENOBUFS; - SOCKBUF_LOCK(&so->so_snd); - goto release; + if (dontroute) { + SOCK_LOCK(so); + so->so_options |= SO_DONTROUTE; + SOCK_UNLOCK(so); } - - 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) { - SOCKBUF_LOCK(&so->so_snd); - 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 : + /* + * 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)) ? + ((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) { - SOCKBUF_LOCK(&so->so_snd); - goto release; - } + (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; + if (error) { + SOCKBUF_LOCK(&so->so_snd); + goto release; + } } while (resid && space > 0); SOCKBUF_LOCK(&so->so_snd); } while (resid);