async_rcvd: Fix possible deadlock
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 11 Mar 2013 01:50:05 +0000 (09:50 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 11 Mar 2013 01:50:05 +0000 (09:50 +0800)
It is possible when we try dropping the asynchronized rcvd message, the
message is not on the msgport yet, but sendmsg_stage1 is done, i.e.
MSG_DONE is cleared.  Originally we were waiting for the MSG_DONE to be
set, however, it will _never_ be set, since the message dropping is done
in the netisr and the MSG_DONE will only be turned on when the message
is dequeued and runs in the _same_ netisr.

Fixing this deadlock by keeping dropping the asynchronized rcvd message,
if the message's MSG_DONE flag is not set.

Reported-by: pavalos@
sys/kern/uipc_msg.c

index 7687761..8085d21 100644 (file)
@@ -621,6 +621,7 @@ so_async_rcvd_drop(struct socket *so)
 {
        lwkt_msg_t lmsg = &so->so_rcvd_msg.base.lmsg;
 
+again:
        /*
         * Spinlock safe, reply runs to degenerate lwkt_spin_dropmsg()
         */
@@ -631,8 +632,7 @@ so_async_rcvd_drop(struct socket *so)
        spin_unlock(&so->so_rcvd_spin);
        if ((lmsg->ms_flags & MSGF_DONE) == 0) {
                kprintf("Warning: tcp: so_async_rcvd_drop() raced message\n");
-               while ((lmsg->ms_flags & MSGF_DONE) == 0) {
-                       tsleep(so, 0, "soadrop", 1);
-               }
+               tsleep(so, 0, "soadrop", 1);
+               goto again;
        }
 }