git: 51ac5ee0d57f - main - unix/stream: refactor sendfile(2) logic to work without M_BLOCKER flag

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Fri, 23 May 2025 22:52:53 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=51ac5ee0d57f178882af4b40d36089e2069704e4

commit 51ac5ee0d57f178882af4b40d36089e2069704e4
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-05-23 21:55:56 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-05-23 22:04:39 +0000

    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.
---
 sys/kern/uipc_usrreq.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 0f730cf9424b..5b1b8443f8e6 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1008,10 +1008,10 @@ uipc_stream_sbcheck(struct sockbuf *sb)
 
 	dacc = dccc = dctl = dmbcnt = 0;
 	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;
-		if (notready)
-			MPASS(d->m_flags & (M_NOTREADY|M_BLOCKED));
+		}
 		if (d->m_type == MT_CONTROL)
 			dctl += d->m_len;
 		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;
 	if (sb->uxst_fnrdy == NULL) {
 		if (notready) {
-			sb->uxst_fnrdy = STAILQ_FIRST(&mc.mc_q);
 			wakeup = false;
+			STAILQ_FOREACH(m, &mc.mc_q, m_stailq) {
+				if (m->m_flags & M_NOTREADY) {
+					sb->uxst_fnrdy = m;
+					break;
+				} else {
+					sb->sb_acc += m->m_len;
+					wakeup = true;
+				}
+			}
 		} else {
-			sb->sb_acc += mc.mc_len;
 			wakeup = true;
+			sb->sb_acc += mc.mc_len;
 		}
 	} else {
-		STAILQ_FOREACH(m, &mc.mc_q, m_stailq)
-			m->m_flags |= M_BLOCKED;
 		wakeup = false;
 	}
 	STAILQ_CONCAT(&sb->uxst_mbq, &mc.mc_q);
@@ -2504,24 +2510,22 @@ out:
 static int
 uipc_sbready(struct sockbuf *sb, struct mbuf *m, int count)
 {
-	u_int blocker;
+	bool blocker;
 
 	/* assert locked */
 
-	blocker = (sb->uxst_fnrdy == m) ? M_BLOCKED : 0;
+	blocker = (sb->uxst_fnrdy == m);
 	STAILQ_FOREACH_FROM(m, &sb->uxst_mbq, m_stailq) {
 		if (count > 0) {
 			MPASS(m->m_flags & M_NOTREADY);
-			m->m_flags &= ~(M_NOTREADY | blocker);
+			m->m_flags &= ~M_NOTREADY;
 			if (blocker)
 				sb->sb_acc += m->m_len;
 			count--;
-		} else if (blocker && !(m->m_flags & M_NOTREADY)) {
-			MPASS(m->m_flags & M_BLOCKED);
-			m->m_flags &= ~M_BLOCKED;
-			sb->sb_acc += m->m_len;
-		} else
+		} else if (m->m_flags & M_NOTREADY)
 			break;
+		else if (blocker)
+			sb->sb_acc += m->m_len;
 	}
 	if (blocker) {
 		sb->uxst_fnrdy = m;