Skip to content

Commit

Permalink
Maintain a pointer and offset pair into the socket buffer mbuf chain to
Browse files Browse the repository at this point in the history
avoid traversal of the entire socket buffer for larger offsets on stream
sockets.

Adjust tcp_output() make use of it.

Tested by:	gallatin
  • Loading branch information
andreoppermann committed Mar 19, 2007
1 parent 52a90d8 commit 515a501
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
41 changes: 41 additions & 0 deletions sys/kern/uipc_sockbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,8 @@ sbdrop_internal(struct sockbuf *sb, int len)
m->m_len -= len;
m->m_data += len;
sb->sb_cc -= len;
if (sb->sb_sndptroff != 0)
sb->sb_sndptroff -= len;
if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
sb->sb_ctl -= len;
break;
Expand Down Expand Up @@ -903,6 +905,45 @@ sbdrop(struct sockbuf *sb, int len)
SOCKBUF_UNLOCK(sb);
}


/*
* Maintain a pointer and offset pair into the socket buffer mbuf chain to
* avoid traversal of the entire socket buffer for larger offsets.
*/
struct mbuf *
sbsndptr(struct sockbuf *sb, u_int off, u_int len, u_int *moff)
{
struct mbuf *m, *ret;

KASSERT(sb->sb_mb != NULL, ("%s: sb_mb is NULL", __func__));
KASSERT(off + len <= sb->sb_cc, ("%s: beyond sb", __func__));
KASSERT(sb->sb_sndptroff <= sb->sb_cc, ("%s: sndptroff broken", __func__));

/*
* Is off below stored offset? Happens on retransmits.
* Just return, we can't help here.
*/
if (sb->sb_sndptroff > off) {
*moff = off;
return (sb->sb_mb);
}

/* Return closest mbuf in chain for current offset. */
*moff = off - sb->sb_sndptroff;
m = ret = sb->sb_sndptr ? sb->sb_sndptr : sb->sb_mb;

/* Advance by len to be as close as possible for the next transmit. */
for (off = off - sb->sb_sndptroff + len - 1;
off > 0 && off >= m->m_len;
m = m->m_next) {
sb->sb_sndptroff += m->m_len;
off -= m->m_len;
}
sb->sb_sndptr = m;

return (ret);
}

/*
* Drop a record off the front of a sockbuf and move the next record to the
* front.
Expand Down
16 changes: 13 additions & 3 deletions sys/netinet/tcp_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,9 @@ tcp_output(struct tcpcb *tp)
* the template for sends on this connection.
*/
if (len) {
struct mbuf *mb;
u_int moff;

if ((tp->t_flags & TF_FORCEDATA) && len == 1)
tcpstat.tcps_sndprobe++;
else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
Expand Down Expand Up @@ -785,13 +788,20 @@ tcp_output(struct tcpcb *tp)
#endif
m->m_data += max_linkhdr;
m->m_len = hdrlen;

/*
* Start the m_copy functions from the closest mbuf
* to the offset in the socket buffer chain.
*/
mb = sbsndptr(&so->so_snd, off, len, &moff);

if (len <= MHLEN - hdrlen - max_linkhdr) {
m_copydata(so->so_snd.sb_mb, off, (int)len,
m_copydata(mb, moff, (int)len,
mtod(m, caddr_t) + hdrlen);
m->m_len += len;
} else {
m->m_next = m_copy(so->so_snd.sb_mb, off, (int)len);
if (m->m_next == 0) {
m->m_next = m_copy(mb, moff, (int)len);
if (m->m_next == NULL) {
SOCKBUF_UNLOCK(&so->so_snd);
(void) m_free(m);
error = ENOBUFS;
Expand Down
10 changes: 10 additions & 0 deletions sys/sys/socketvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ struct socket {
struct mbuf *sb_mbtail; /* (c/d) the last mbuf in the chain */
struct mbuf *sb_lastrecord; /* (c/d) first mbuf of last
* record in socket buffer */
struct mbuf *sb_sndptr; /* (c/d) pointer into mbuf chain */
u_int sb_sndptroff; /* (c/d) byte offset of ptr into chain */
u_int sb_cc; /* (c/d) actual chars in buffer */
u_int sb_hiwat; /* (c/d) max actual char count */
u_int sb_mbcnt; /* (c/d) chars of mbufs used */
Expand Down Expand Up @@ -321,6 +323,12 @@ struct xsocket {
(sb)->sb_mbcnt -= MSIZE; \
if ((m)->m_flags & M_EXT) \
(sb)->sb_mbcnt -= (m)->m_ext.ext_size; \
if ((sb)->sb_sndptr == (m)) { \
(sb)->sb_sndptr = NULL; \
(sb)->sb_sndptroff = 0; \
} \
if ((sb)->sb_sndptroff != 0) \
(sb)->sb_sndptroff -= (m)->m_len; \
}

/*
Expand Down Expand Up @@ -491,6 +499,8 @@ int sbreserve(struct sockbuf *sb, u_long cc, struct socket *so,
struct thread *td);
int sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so,
struct thread *td);
struct mbuf *
sbsndptr(struct sockbuf *sb, u_int off, u_int len, u_int *moff);
void sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb);
int sbwait(struct sockbuf *sb);
int sb_lock(struct sockbuf *sb);
Expand Down

0 comments on commit 515a501

Please sign in to comment.