unix/stream: refactor sendfile(2) logic to work without M_BLOCKER flag

This flag was initially an INVARIANT thing back in 2014, but we got
stuck with it until today.  A bug with sendfile(2) headers/trailers
fixed as a side effect of refactoring.
This commit is contained in:
Gleb Smirnoff
2025-05-23 14:55:56 -07:00
parent 46c6446201
commit 51ac5ee0d5
+19 -15
View File
@@ -1008,10 +1008,10 @@ uipc_stream_sbcheck(struct sockbuf *sb)
dacc = dccc = dctl = dmbcnt = 0; dacc = dccc = dctl = dmbcnt = 0;
STAILQ_FOREACH(d, &sb->uxst_mbq, m_stailq) { STAILQ_FOREACH(d, &sb->uxst_mbq, m_stailq) {
if (d == sb->uxst_fnrdy) if (d == sb->uxst_fnrdy) {
MPASS(d->m_flags & M_NOTREADY);
notready = true; notready = true;
if (notready) }
MPASS(d->m_flags & (M_NOTREADY|M_BLOCKED));
if (d->m_type == MT_CONTROL) if (d->m_type == MT_CONTROL)
dctl += d->m_len; dctl += d->m_len;
else if (d->m_type == MT_DATA) { else if (d->m_type == MT_DATA) {
@@ -2471,15 +2471,21 @@ uipc_sendfile(struct socket *so, int flags, struct mbuf *m,
sb->sb_mbcnt += mc.mc_mlen; sb->sb_mbcnt += mc.mc_mlen;
if (sb->uxst_fnrdy == NULL) { if (sb->uxst_fnrdy == NULL) {
if (notready) { if (notready) {
sb->uxst_fnrdy = STAILQ_FIRST(&mc.mc_q);
wakeup = false; wakeup = false;
STAILQ_FOREACH(m, &mc.mc_q, m_stailq) {
if (m->m_flags & M_NOTREADY) {
sb->uxst_fnrdy = m;
break;
} else { } else {
sb->sb_acc += mc.mc_len; sb->sb_acc += m->m_len;
wakeup = true; wakeup = true;
} }
}
} else {
wakeup = true;
sb->sb_acc += mc.mc_len;
}
} else { } else {
STAILQ_FOREACH(m, &mc.mc_q, m_stailq)
m->m_flags |= M_BLOCKED;
wakeup = false; wakeup = false;
} }
STAILQ_CONCAT(&sb->uxst_mbq, &mc.mc_q); STAILQ_CONCAT(&sb->uxst_mbq, &mc.mc_q);
@@ -2504,24 +2510,22 @@ uipc_sendfile(struct socket *so, int flags, struct mbuf *m,
static int static int
uipc_sbready(struct sockbuf *sb, struct mbuf *m, int count) uipc_sbready(struct sockbuf *sb, struct mbuf *m, int count)
{ {
u_int blocker; bool blocker;
/* assert locked */ /* assert locked */
blocker = (sb->uxst_fnrdy == m) ? M_BLOCKED : 0; blocker = (sb->uxst_fnrdy == m);
STAILQ_FOREACH_FROM(m, &sb->uxst_mbq, m_stailq) { STAILQ_FOREACH_FROM(m, &sb->uxst_mbq, m_stailq) {
if (count > 0) { if (count > 0) {
MPASS(m->m_flags & M_NOTREADY); MPASS(m->m_flags & M_NOTREADY);
m->m_flags &= ~(M_NOTREADY | blocker); m->m_flags &= ~M_NOTREADY;
if (blocker) if (blocker)
sb->sb_acc += m->m_len; sb->sb_acc += m->m_len;
count--; count--;
} else if (blocker && !(m->m_flags & M_NOTREADY)) { } else if (m->m_flags & M_NOTREADY)
MPASS(m->m_flags & M_BLOCKED);
m->m_flags &= ~M_BLOCKED;
sb->sb_acc += m->m_len;
} else
break; break;
else if (blocker)
sb->sb_acc += m->m_len;
} }
if (blocker) { if (blocker) {
sb->uxst_fnrdy = m; sb->uxst_fnrdy = m;