summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/uipc_socket.c')
-rw-r--r--sys/kern/uipc_socket.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index b1415d7..80699b0 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -348,9 +348,15 @@ sofree(so)
SOCKBUF_LOCK(&so->so_snd);
so->so_snd.sb_flags |= SB_NOINTR;
(void)sblock(&so->so_snd, M_WAITOK);
- socantsendmore(so);
+ /*
+ * socantsendmore_locked() drops the socket buffer mutex so that it
+ * can safely perform wakeups. Re-acquire the mutex before
+ * continuing.
+ */
+ socantsendmore_locked(so);
+ SOCKBUF_LOCK(&so->so_snd);
sbunlock(&so->so_snd);
- sbrelease(&so->so_snd, so);
+ sbrelease_locked(&so->so_snd, so);
SOCKBUF_UNLOCK(&so->so_snd);
sorflush(so);
sodealloc(so);
@@ -1202,7 +1208,7 @@ dontblock:
flags |= MSG_TRUNC;
if ((flags & MSG_PEEK) == 0) {
SOCKBUF_LOCK_ASSERT(&so->so_rcv);
- (void) sbdroprecord(&so->so_rcv);
+ (void) sbdroprecord_locked(&so->so_rcv);
}
}
if ((flags & MSG_PEEK) == 0) {
@@ -1271,23 +1277,41 @@ sorflush(so)
struct protosw *pr = so->so_proto;
struct sockbuf asb;
+ /*
+ * XXXRW: This is quite ugly. The existing code made a copy of the
+ * socket buffer, then zero'd the original to clear the buffer
+ * fields. However, with mutexes in the socket buffer, this causes
+ * problems. We only clear the zeroable bits of the original;
+ * however, we have to initialize and destroy the mutex in the copy
+ * so that dom_dispose() and sbrelease() can lock t as needed.
+ */
SOCKBUF_LOCK(sb);
sb->sb_flags |= SB_NOINTR;
(void) sblock(sb, M_WAITOK);
- socantrcvmore(so);
+ /*
+ * socantrcvmore_locked() drops the socket buffer mutex so that it
+ * can safely perform wakeups. Re-acquire the mutex before
+ * continuing.
+ */
+ socantrcvmore_locked(so);
+ SOCKBUF_LOCK(sb);
sbunlock(sb);
- asb = *sb;
/*
- * Invalidate/clear most of the sockbuf structure, but keep
- * its selinfo structure valid.
+ * Invalidate/clear most of the sockbuf structure, but leave
+ * selinfo and mutex data unchanged.
*/
+ bzero(&asb, offsetof(struct sockbuf, sb_startzero));
+ bcopy(&sb->sb_startzero, &asb.sb_startzero,
+ sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
bzero(&sb->sb_startzero,
sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
SOCKBUF_UNLOCK(sb);
+ SOCKBUF_LOCK_INIT(&asb, "so_rcv");
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL)
(*pr->pr_domain->dom_dispose)(asb.sb_mb);
sbrelease(&asb, so);
+ SOCKBUF_LOCK_DESTROY(&asb);
}
#ifdef INET
OpenPOWER on IntegriCloud