Print this page
OS-7088 cyclics corked on overlay socket with full queue

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/overlay/overlay_mux.c
          +++ new/usr/src/uts/common/io/overlay/overlay_mux.c
↓ open down ↓ 199 lines elided ↑ open up ↑
 200  200  
 201  201                  mutex_enter(&odd->odd_lock);
 202  202                  overlay_io_done(odd, OVERLAY_F_IN_RX);
 203  203                  mutex_exit(&odd->odd_lock);
 204  204          }
 205  205  
 206  206          return (B_TRUE);
 207  207  }
 208  208  
 209  209  /*
      210 + * Kernel socket callback to indicate the socket itself is able to send
      211 + * data again.  Check for devices on this mux that were send-blocked,
      212 + * and clear them.
      213 + */
      214 +/* ARGSUSED */
      215 +static void
      216 +overlay_mux_cansend_now(ksocket_t ksock, ksocket_callback_event_t event,
      217 +    void *arg, uintptr_t ignore_me)
      218 +{
      219 +        overlay_mux_t *mux = (overlay_mux_t *)arg;
      220 +        overlay_dev_t *odd;
      221 +        mac_handle_t *mhs_to_update, *current_mh;
      222 +        size_t allocsize;
      223 +
      224 +        ASSERT3P(ksock, ==, mux->omux_ksock);
      225 +        ASSERT3U(event, ==, KSOCKET_EV_CANSEND);
      226 +
      227 +        /* Traverse omux_devices and check for ones marked as send-blocked. */
      228 +        mutex_enter(&mux->omux_lock);
      229 +        if (mux->omux_count == 0) {
      230 +                /* Nothing to wake up. */
      231 +                mutex_exit(&mux->omux_lock);
      232 +                return;
      233 +        }
      234 +        allocsize = sizeof (mac_handle_t) * mux->omux_count;
      235 +        mhs_to_update = kmem_zalloc(allocsize, KM_NOSLEEP);
      236 +        VERIFY(mhs_to_update != NULL);  /* Failure should be rare. */
      237 +        current_mh = mhs_to_update;
      238 +
      239 +        for (odd = avl_first(&mux->omux_devices); odd != NULL;
      240 +            odd = AVL_NEXT(&mux->omux_devices, odd)) {
      241 +                mac_handle_t odd_mh = NULL;
      242 +
      243 +                mutex_enter(&odd->odd_lock);
      244 +                if ((odd->odd_flags & OVERLAY_F_TXSTOPPED) != 0) {
      245 +                        /* Get ready to tell MAC it can transmit again. */
      246 +                        odd->odd_flags &= ~OVERLAY_F_TXSTOPPED;
      247 +                        odd_mh = odd->odd_mh;
      248 +                }
      249 +                mutex_exit(&odd->odd_lock);
      250 +                if (odd_mh != NULL) {
      251 +                        *current_mh = odd_mh;
      252 +                        current_mh++;
      253 +                }
      254 +        }
      255 +        mutex_exit(&mux->omux_lock);
      256 +
      257 +        /*
      258 +         * Yes, I'm using the value-then-decrement.  "current_mh" is
      259 +         * guaranteed to be at least one ahead of mhs_to_update if there are
      260 +         * any mac handles that need updating.  I also have to do this outside
      261 +         * the omux lock because the tx_update may trigger immediate or
      262 +         * concurrent packet transmission.
      263 +         */
      264 +        while (current_mh-- != mhs_to_update)
      265 +                mac_tx_update(*current_mh);
      266 +
      267 +        kmem_free(mhs_to_update, allocsize);
      268 +}
      269 +
      270 +/*
 210  271   * Register a given device with a socket backend. If no such device socket
 211  272   * exists, create a new one.
 212  273   */
 213  274  overlay_mux_t *
 214  275  overlay_mux_open(overlay_plugin_t *opp, int domain, int family, int protocol,
 215  276      struct sockaddr *addr, socklen_t len, int *errp)
 216  277  {
 217  278          int err;
 218  279          overlay_mux_t *mux;
 219  280          ksocket_t ksock;
      281 +        ksocket_callbacks_t ks_cb = { 0 };
 220  282  
 221  283          if (errp == NULL)
 222  284                  errp = &err;
 223  285  
 224  286          mutex_enter(&overlay_mux_lock);
 225  287          for (mux = list_head(&overlay_mux_list); mux != NULL;
 226  288              mux = list_next(&overlay_mux_list, mux)) {
 227  289                  if (domain == mux->omux_domain &&
 228  290                      family == mux->omux_family &&
 229  291                      protocol == mux->omux_protocol &&
↓ open down ↓ 53 lines elided ↑ open up ↑
 283  345          mux->omux_family = family;
 284  346          mux->omux_protocol = protocol;
 285  347          mux->omux_addr = kmem_alloc(len, KM_SLEEP);
 286  348          bcopy(addr, mux->omux_addr, len);
 287  349          mux->omux_alen = len;
 288  350          mux->omux_count = 1;
 289  351          avl_create(&mux->omux_devices, overlay_mux_comparator,
 290  352              sizeof (overlay_dev_t), offsetof(overlay_dev_t, odd_muxnode));
 291  353          mutex_init(&mux->omux_lock, NULL, MUTEX_DRIVER, NULL);
 292  354  
      355 +#if defined(OVERLAY_PINCH) || defined(OVERLAY_FC_TEST)
      356 +        /* Set the xmit buf to a REALLY SMALL value, say 12k (1-3 packets) */
      357 +        int bufsize = 12 * 1024;
 293  358  
      359 +        if (ksocket_setsockopt(ksock, SOL_SOCKET, SO_SNDBUF,
      360 +                (const void *)&bufsize, sizeof (bufsize), CRED()) != 0) {
      361 +                ksocket_close(ksock, kcred);
      362 +                mutex_destroy(&mux->omux_lock);
      363 +                avl_destroy(&mux->omux_devices);
      364 +                kmem_free(mux->omux_addr, len);
      365 +                kmem_free(mux, sizeof (overlay_mux_t));
      366 +                return (NULL);
      367 +        }
      368 +#endif
      369 +        /*
      370 +         * Set a callback in case we hit socket flow control and need to know
      371 +         * when it's ready to send again.  See the aforementioned
      372 +         * ksocket_socket() comments about the use of kcred vs. being
      373 +         * zone-aware.
      374 +         */
      375 +        ks_cb.ksock_cb_cansend = overlay_mux_cansend_now;
      376 +        if (ksocket_setcallbacks(ksock, &ks_cb, mux, kcred) != 0) {
      377 +                ksocket_close(ksock, kcred);
      378 +                mutex_destroy(&mux->omux_lock);
      379 +                avl_destroy(&mux->omux_devices);
      380 +                kmem_free(mux->omux_addr, len);
      381 +                kmem_free(mux, sizeof (overlay_mux_t));
      382 +                return (NULL);
      383 +        }
      384 +
 294  385          /* Once this is called, we need to expect to rx data */
 295  386          *errp = ksocket_krecv_set(ksock, overlay_mux_recv, mux);
 296  387          if (*errp != 0) {
 297  388                  ksocket_close(ksock, kcred);
 298  389                  mutex_destroy(&mux->omux_lock);
 299  390                  avl_destroy(&mux->omux_devices);
 300  391                  kmem_free(mux->omux_addr, len);
 301  392                  kmem_free(mux, sizeof (overlay_mux_t));
 302  393                  return (NULL);
 303  394          }
↓ open down ↓ 43 lines elided ↑ open up ↑
 347  438  }
 348  439  
 349  440  int
 350  441  overlay_mux_tx(overlay_mux_t *mux, struct msghdr *hdr, mblk_t *mp)
 351  442  {
 352  443          int ret;
 353  444  
 354  445          /*
 355  446           * It'd be nice to be able to use MSG_MBLK_QUICKRELE, unfortunately,
 356  447           * that isn't actually supported by UDP at this time.
      448 +         *
      449 +         * Send with MSG_DONTWAIT to indicate clogged UDP sockets upstack.
 357  450           */
 358      -        ret = ksocket_sendmblk(mux->omux_ksock, hdr, 0, &mp, kcred);
      451 +        ret = ksocket_sendmblk(mux->omux_ksock, hdr, MSG_DONTWAIT, &mp, kcred);
      452 +        /*
      453 +         * NOTE: ksocket_sendmblk() may send partial packets downstack,
      454 +         * returning what's not sent in &mp (i.e. mp pre-call might be a
      455 +         * b_cont of mp post-call).  We can't hold up this message (it's a
      456 +         * datagram), so we drop, and let the caller cope.
      457 +         */
 359  458          if (ret != 0)
 360  459                  freemsg(mp);
 361  460  
 362  461          return (ret);
 363  462  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX