summaryrefslogtreecommitdiff
path: root/sys/kern/uipc_socket.c
diff options
context:
space:
mode:
authorBruce M Simpson <bms@FreeBSD.org>2006-09-22 15:34:16 +0000
committerBruce M Simpson <bms@FreeBSD.org>2006-09-22 15:34:16 +0000
commit4a75dc25851fdd62c3e3779523672b1dcf01da20 (patch)
tree5162d04c3bd6dc1648577abc4bf465a0521acc3d /sys/kern/uipc_socket.c
parent2972ed120b1eb0be2e7f0ffa4cad25f9e90f4caf (diff)
Notes
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r--sys/kern/uipc_socket.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 480bde885600..2a273882d2ec 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1405,6 +1405,7 @@ soreceive_generic(so, psa, uio, mp0, controlp, flagsp)
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
int moff, type = 0;
+ int mbuf_removed = 0;
int orig_resid = uio->uio_resid;
mp = mp0;
@@ -1525,6 +1526,7 @@ dontblock:
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
+ mbuf_removed = 1;
so->so_rcv.sb_mb = m_free(m);
m = so->so_rcv.sb_mb;
sockbuf_pushsync(&so->so_rcv, nextrecord);
@@ -1550,6 +1552,7 @@ dontblock:
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
+ mbuf_removed = 1;
so->so_rcv.sb_mb = m->m_next;
m->m_next = NULL;
*cme = m;
@@ -1671,8 +1674,20 @@ dontblock:
#endif /* ZERO_COPY_SOCKETS */
error = uiomove(mtod(m, char *) + moff, (int)len, uio);
SOCKBUF_LOCK(&so->so_rcv);
- if (error)
+ if (error) {
+ /*
+ * If any part of the record has been removed
+ * (such as the MT_SONAME mbuf, which will
+ * happen when PR_ADDR, and thus also
+ * PR_ATOMIC, is set), then drop the entire
+ * record to maintain the atomicity of the
+ * receive operation.
+ */
+ if (m && mbuf_removed &&
+ (pr->pr_flags & PR_ATOMIC))
+ (void)sbdroprecord_locked(&so->so_rcv);
goto release;
+ }
} else
uio->uio_resid -= len;
SOCKBUF_LOCK_ASSERT(&so->so_rcv);