Print this page
OS-7088 cyclics corked on overlay socket with full queue
*** 205,214 ****
--- 205,275 ----
return (B_TRUE);
}
/*
+ * Kernel socket callback to indicate the socket itself is able to send
+ * data again. Check for devices on this mux that were send-blocked,
+ * and clear them.
+ */
+ /* ARGSUSED */
+ static void
+ overlay_mux_cansend_now(ksocket_t ksock, ksocket_callback_event_t event,
+ void *arg, uintptr_t ignore_me)
+ {
+ overlay_mux_t *mux = (overlay_mux_t *)arg;
+ overlay_dev_t *odd;
+ mac_handle_t *mhs_to_update, *current_mh;
+ size_t allocsize;
+
+ ASSERT3P(ksock, ==, mux->omux_ksock);
+ ASSERT3U(event, ==, KSOCKET_EV_CANSEND);
+
+ /* Traverse omux_devices and check for ones marked as send-blocked. */
+ mutex_enter(&mux->omux_lock);
+ if (mux->omux_count == 0) {
+ /* Nothing to wake up. */
+ mutex_exit(&mux->omux_lock);
+ return;
+ }
+ allocsize = sizeof (mac_handle_t) * mux->omux_count;
+ mhs_to_update = kmem_zalloc(allocsize, KM_NOSLEEP);
+ VERIFY(mhs_to_update != NULL); /* Failure should be rare. */
+ current_mh = mhs_to_update;
+
+ for (odd = avl_first(&mux->omux_devices); odd != NULL;
+ odd = AVL_NEXT(&mux->omux_devices, odd)) {
+ mac_handle_t odd_mh = NULL;
+
+ mutex_enter(&odd->odd_lock);
+ if ((odd->odd_flags & OVERLAY_F_TXSTOPPED) != 0) {
+ /* Get ready to tell MAC it can transmit again. */
+ odd->odd_flags &= ~OVERLAY_F_TXSTOPPED;
+ odd_mh = odd->odd_mh;
+ }
+ mutex_exit(&odd->odd_lock);
+ if (odd_mh != NULL) {
+ *current_mh = odd_mh;
+ current_mh++;
+ }
+ }
+ mutex_exit(&mux->omux_lock);
+
+ /*
+ * Yes, I'm using the value-then-decrement. "current_mh" is
+ * guaranteed to be at least one ahead of mhs_to_update if there are
+ * any mac handles that need updating. I also have to do this outside
+ * the omux lock because the tx_update may trigger immediate or
+ * concurrent packet transmission.
+ */
+ while (current_mh-- != mhs_to_update)
+ mac_tx_update(*current_mh);
+
+ kmem_free(mhs_to_update, allocsize);
+ }
+
+ /*
* Register a given device with a socket backend. If no such device socket
* exists, create a new one.
*/
overlay_mux_t *
overlay_mux_open(overlay_plugin_t *opp, int domain, int family, int protocol,
*** 215,224 ****
--- 276,286 ----
struct sockaddr *addr, socklen_t len, int *errp)
{
int err;
overlay_mux_t *mux;
ksocket_t ksock;
+ ksocket_callbacks_t ks_cb = { 0 };
if (errp == NULL)
errp = &err;
mutex_enter(&overlay_mux_lock);
*** 288,298 ****
--- 350,389 ----
mux->omux_count = 1;
avl_create(&mux->omux_devices, overlay_mux_comparator,
sizeof (overlay_dev_t), offsetof(overlay_dev_t, odd_muxnode));
mutex_init(&mux->omux_lock, NULL, MUTEX_DRIVER, NULL);
+ #if defined(OVERLAY_PINCH) || defined(OVERLAY_FC_TEST)
+ /* Set the xmit buf to a REALLY SMALL value, say 12k (1-3 packets) */
+ int bufsize = 12 * 1024;
+ if (ksocket_setsockopt(ksock, SOL_SOCKET, SO_SNDBUF,
+ (const void *)&bufsize, sizeof (bufsize), CRED()) != 0) {
+ ksocket_close(ksock, kcred);
+ mutex_destroy(&mux->omux_lock);
+ avl_destroy(&mux->omux_devices);
+ kmem_free(mux->omux_addr, len);
+ kmem_free(mux, sizeof (overlay_mux_t));
+ return (NULL);
+ }
+ #endif
+ /*
+ * Set a callback in case we hit socket flow control and need to know
+ * when it's ready to send again. See the aforementioned
+ * ksocket_socket() comments about the use of kcred vs. being
+ * zone-aware.
+ */
+ ks_cb.ksock_cb_cansend = overlay_mux_cansend_now;
+ if (ksocket_setcallbacks(ksock, &ks_cb, mux, kcred) != 0) {
+ ksocket_close(ksock, kcred);
+ mutex_destroy(&mux->omux_lock);
+ avl_destroy(&mux->omux_devices);
+ kmem_free(mux->omux_addr, len);
+ kmem_free(mux, sizeof (overlay_mux_t));
+ return (NULL);
+ }
+
/* Once this is called, we need to expect to rx data */
*errp = ksocket_krecv_set(ksock, overlay_mux_recv, mux);
if (*errp != 0) {
ksocket_close(ksock, kcred);
mutex_destroy(&mux->omux_lock);
*** 352,363 ****
int ret;
/*
* It'd be nice to be able to use MSG_MBLK_QUICKRELE, unfortunately,
* that isn't actually supported by UDP at this time.
*/
! ret = ksocket_sendmblk(mux->omux_ksock, hdr, 0, &mp, kcred);
if (ret != 0)
freemsg(mp);
return (ret);
}
--- 443,462 ----
int ret;
/*
* It'd be nice to be able to use MSG_MBLK_QUICKRELE, unfortunately,
* that isn't actually supported by UDP at this time.
+ *
+ * Send with MSG_DONTWAIT to indicate clogged UDP sockets upstack.
*/
! ret = ksocket_sendmblk(mux->omux_ksock, hdr, MSG_DONTWAIT, &mp, kcred);
! /*
! * NOTE: ksocket_sendmblk() may send partial packets downstack,
! * returning what's not sent in &mp (i.e. mp pre-call might be a
! * b_cont of mp post-call). We can't hold up this message (it's a
! * datagram), so we drop, and let the caller cope.
! */
if (ret != 0)
freemsg(mp);
return (ret);
}