diff options
author | Andriy Voskoboinyk <avos@FreeBSD.org> | 2017-10-16 21:46:11 +0000 |
---|---|---|
committer | Andriy Voskoboinyk <avos@FreeBSD.org> | 2017-10-16 21:46:11 +0000 |
commit | 6623429867e0a48c72ccbe6c8c240a85e6b88b86 (patch) | |
tree | ab7a3c3c20cd9fe9bae40b9c4d34351a2d9863a9 /sys | |
parent | c64c1f95a791046f4bd15e1d69b7c0de63e4cd83 (diff) | |
download | src-6623429867e0a48c72ccbe6c8c240a85e6b88b86.tar.gz src-6623429867e0a48c72ccbe6c8c240a85e6b88b86.zip |
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 constants out of the loop.
Was previously tested with D4077.
Differential Revision: https://reviews.freebsd.org/D4090
Notes
Notes:
svn path=/head/; revision=324673
Diffstat (limited to 'sys')
-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 a8a0391eae5c..6fe5f7630c58 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -1449,62 +1449,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); } |