Print this page
OS-7088 cyclics corked on overlay socket with full queue
        
@@ -8,11 +8,11 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2018 Joyent, Inc.
  */
 
 /*
  * Overlay Devices
  *
@@ -1052,10 +1052,11 @@
         int ret;
         ovep_encap_info_t einfo;
         struct msghdr hdr;
 
         mutex_enter(&odd->odd_lock);
+        ASSERT0(odd->odd_flags & OVERLAY_F_TXSTOPPED);
         if ((odd->odd_flags & OVERLAY_F_MDDROP) ||
             !(odd->odd_flags & OVERLAY_F_IN_MUX)) {
                 mutex_exit(&odd->odd_lock);
                 freemsgchain(mp_chain);
                 return (NULL);
@@ -1069,10 +1070,14 @@
         einfo.ovdi_id = odd->odd_vid;
         mp = mp_chain;
         while (mp != NULL) {
                 socklen_t slen;
                 struct sockaddr_storage storage;
+#ifdef OVERLAY_FC_TEST
+                /* Can deal with it being NULL later... */
+                mblk_t *save_mp = msgpullup(mp, -1);
+#endif
 
                 mp_chain = mp->b_next;
                 mp->b_next = NULL;
                 ep = NULL;
 
@@ -1080,34 +1085,75 @@
                     (struct sockaddr *)&storage, &slen);
                 if (ret != OVERLAY_TARGET_OK) {
                         if (ret == OVERLAY_TARGET_DROP)
                                 freemsg(mp);
                         mp = mp_chain;
+#ifdef OVERLAY_FC_TEST
+                        freemsg(save_mp);       /* Handles NULL and non-NULL */
+#endif
                         continue;
                 }
 
                 hdr.msg_name = &storage;
                 hdr.msg_namelen = slen;
 
                 ret = odd->odd_plugin->ovp_ops->ovpo_encap(odd->odd_mh, mp,
                     &einfo, &ep);
                 if (ret != 0 || ep == NULL) {
+#ifdef OVERLAY_FC_TEST
+                        freemsg(save_mp);       /* Handles NULL and non-NULL */
+#endif
                         freemsg(mp);
                         goto out;
                 }
 
                 ASSERT(ep->b_cont == mp || ep == mp);
                 ret = overlay_mux_tx(odd->odd_mux, &hdr, ep);
-                if (ret != 0)
+                if (ret != 0) {
+                        if (ret != EWOULDBLOCK) {
+                                /*
+                                 * Get rid of the packets, something ELSE is
+                                 * wrong with the socket, and we really should
+                                 * just drop the packets for now.
+                                 */
+#ifdef OVERLAY_FC_TEST
+                                freemsg(save_mp);
+                                save_mp = NULL;
+#endif
+                                freemsgchain(mp_chain);
+                                mp_chain = NULL;
+                        }
+#ifdef OVERLAY_FC_TEST
+                        if (save_mp != NULL) {
+                                /*
+                                 * Return the dropped mp here to see how
+                                 * upper-layer MAC reacts to it.
+                                 */
+                                save_mp->b_next = mp_chain;
+                                mp_chain = save_mp;
+                        }
+#endif
+                        /*
+                         * EWOULDBLOCK is a special case.  Return the rest of
+                         * the mp_chain to MAC and have this instance be
+                         * marked as unable to transmit.  Re-enable this
+                         * instance when the mux's socket is able to send data
+                         * again ("cansend" callback).
+                         */
                         goto out;
+                }
 
                 mp = mp_chain;
         }
 
 out:
         mutex_enter(&odd->odd_lock);
         overlay_io_done(odd, OVERLAY_F_IN_TX);
+        if (mp_chain != NULL) {
+                /* Note that we're returning an unsent chain to MAC. */
+                odd->odd_flags |= OVERLAY_F_TXSTOPPED;
+        }
         mutex_exit(&odd->odd_lock);
         return (mp_chain);
 }
 
 /* ARGSUSED */