summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_sockbuf.c
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2007-03-19 18:35:13 +0000
committerandre <andre@FreeBSD.org>2007-03-19 18:35:13 +0000
commit515a501549ecde68391cfcda8fa7589d3be40b09 (patch)
tree2990be3a6e9bba0c00c062b7e5afbdc1fb30ba4f /sys/kern/uipc_sockbuf.c
parent52a90d88fa8297a87f870f937e67657a45d52f71 (diff)
downloadFreeBSD-src-515a501549ecde68391cfcda8fa7589d3be40b09.zip
FreeBSD-src-515a501549ecde68391cfcda8fa7589d3be40b09.tar.gz
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
Diffstat (limited to 'sys/kern/uipc_sockbuf.c')
-rw-r--r--sys/kern/uipc_sockbuf.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index f34df44..638f485 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -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.
OpenPOWER on IntegriCloud