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
This commit is contained in:
parent
c64c1f95a7
commit
6623429867
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=324673
@ -1449,62 +1449,59 @@ m_collapse(struct mbuf *m0, int how, int maxfrags)
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user