summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authoravos <avos@FreeBSD.org>2018-03-31 17:28:30 +0000
committeravos <avos@FreeBSD.org>2018-03-31 17:28:30 +0000
commitdb82dd0a6a9de84e8678be871ebd8821c9802628 (patch)
treec65bad4b2605ee841a1601664e0031ea459d576f /sys/kern
parent67843375d3eb84dcb779a957ef89bed98a45a823 (diff)
downloadFreeBSD-src-db82dd0a6a9de84e8678be871ebd8821c9802628.zip
FreeBSD-src-db82dd0a6a9de84e8678be871ebd8821c9802628.tar.gz
MFC r324673:
mbuf(9): unbreak m_fragment() - Fix it by replacing m_cat() with m_prev->m_next = m_new (m_cat() will try to append data - as a result, there will be no fragmentation). - Move some checks out of the loop. Some variables were renamed (m_final -> m_first, m_new -> m_last) Was previously tested with D4077. Differential Revision: D4090
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_mbuf.c57
1 files changed, 27 insertions, 30 deletions
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index 5f103eb..de6c561 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -1439,62 +1439,59 @@ bad:
struct mbuf *
m_fragment(struct mbuf *m0, int how, int length)
{
- struct mbuf *m_new = NULL, *m_final = NULL;
- int progress = 0;
+ struct mbuf *m_first, *m_last;
+ int divisor = 255, progress = 0, fraglen;
if (!(m0->m_flags & M_PKTHDR))
return (m0);
- if ((length == 0) || (length < -2))
+ if (length == 0 || length < -2)
return (m0);
+ if (length > MCLBYTES)
+ length = MCLBYTES;
+ if (length < 0 && divisor > MCLBYTES)
+ divisor = MCLBYTES;
+ if (length == -1)
+ length = 1 + (arc4random() % divisor);
+ if (length > 0)
+ fraglen = length;
m_fixhdr(m0); /* Needed sanity check */
- m_final = m_getcl(how, MT_DATA, M_PKTHDR);
-
- if (m_final == NULL)
+ m_first = m_getcl(how, MT_DATA, M_PKTHDR);
+ if (m_first == NULL)
goto nospace;
- if (m_dup_pkthdr(m_final, m0, how) == 0)
+ if (m_dup_pkthdr(m_first, m0, how) == 0)
goto nospace;
- m_new = m_final;
-
- if (length == -1)
- length = 1 + (arc4random() & 255);
+ m_last = m_first;
while (progress < m0->m_pkthdr.len) {
- int fraglen;
-
- if (length > 0)
- fraglen = length;
- else
- fraglen = 1 + (arc4random() & 255);
+ if (length == -2)
+ fraglen = 1 + (arc4random() % divisor);
if (fraglen > m0->m_pkthdr.len - progress)
fraglen = m0->m_pkthdr.len - progress;
- if (fraglen > MCLBYTES)
- fraglen = MCLBYTES;
-
- if (m_new == NULL) {
- m_new = m_getcl(how, MT_DATA, 0);
+ if (progress != 0) {
+ struct mbuf *m_new = m_getcl(how, MT_DATA, 0);
if (m_new == NULL)
goto nospace;
+
+ m_last->m_next = m_new;
+ m_last = m_new;
}
- m_copydata(m0, progress, fraglen, mtod(m_new, caddr_t));
+ m_copydata(m0, progress, fraglen, mtod(m_last, caddr_t));
progress += fraglen;
- m_new->m_len = fraglen;
- if (m_new != m_final)
- m_cat(m_final, m_new);
- m_new = NULL;
+ m_last->m_len = fraglen;
}
m_freem(m0);
- m0 = m_final;
+ m0 = m_first;
return (m0);
nospace:
- if (m_final)
- m_freem(m_final);
+ if (m_first)
+ m_freem(m_first);
/* Return the original chain on failure */
return (m0);
}
OpenPOWER on IntegriCloud