diff options
author | avos <avos@FreeBSD.org> | 2018-03-31 17:28:30 +0000 |
---|---|---|
committer | avos <avos@FreeBSD.org> | 2018-03-31 17:28:30 +0000 |
commit | db82dd0a6a9de84e8678be871ebd8821c9802628 (patch) | |
tree | c65bad4b2605ee841a1601664e0031ea459d576f /sys/kern | |
parent | 67843375d3eb84dcb779a957ef89bed98a45a823 (diff) | |
download | FreeBSD-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.c | 57 |
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); } |