1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

Maintain a pointer and offset pair into the socket buffer mbuf chain to

avoid traversal of the entire socket buffer for larger offsets on stream
sockets.

Adjust tcp_output() make use of it.

Tested by:	gallatin
This commit is contained in:
Andre Oppermann 2007-03-19 18:35:13 +00:00
parent c53fb74f0e
commit 4e02375908
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167715
3 changed files with 64 additions and 3 deletions

View File

@ -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;
@ -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.

View File

@ -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)) {
@ -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;

View File

@ -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 */
@ -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; \
}
/*
@ -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);