Print this page
6742 Freed and reused idm_conn_t buffer leads to system panic.
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Steve Ping <steve.ping@nexenta.com>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/idm/idm_conn_sm.c
          +++ new/usr/src/uts/common/io/idm/idm_conn_sm.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2013 by Delphix. All rights reserved.
       25 + * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25   26   */
  26   27  
  27   28  #include <sys/cpuvar.h>
  28   29  #include <sys/ddi.h>
  29   30  #include <sys/sunddi.h>
  30   31  #include <sys/modctl.h>
  31   32  #include <sys/socket.h>
  32   33  #include <sys/strsubr.h>
  33   34  #include <sys/note.h>
  34   35  #include <sys/sdt.h>
↓ open down ↓ 128 lines elided ↑ open up ↑
 163  164  
 164  165          taskq_destroy(ic->ic_state_taskq);
 165  166  
 166  167          cv_destroy(&ic->ic_state_cv);
 167  168          /*
 168  169           * The thread that generated the event that got us here may still
 169  170           * hold the ic_state_mutex. Once it is released we can safely
 170  171           * destroy it since there is no way to locate the object now.
 171  172           */
 172  173          mutex_enter(&ic->ic_state_mutex);
      174 +        IDM_SM_TIMER_CLEAR(ic);
 173  175          mutex_destroy(&ic->ic_state_mutex);
 174  176  }
 175  177  
 176  178  void
 177  179  idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)
 178  180  {
 179  181          mutex_enter(&ic->ic_state_mutex);
 180  182          idm_conn_event_locked(ic, event, event_info, CT_NONE);
 181  183          mutex_exit(&ic->ic_state_mutex);
 182  184  }
↓ open down ↓ 301 lines elided ↑ open up ↑
 484  486                  /*NOTREACHED*/
 485  487          }
 486  488  }
 487  489  
 488  490  
 489  491  static void
 490  492  idm_login_timeout(void *arg)
 491  493  {
 492  494          idm_conn_t *ic = arg;
 493  495  
      496 +        ic->ic_state_timeout = 0;
 494  497          idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
 495  498  }
 496  499  
 497  500  static void
 498  501  idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
 499  502  {
 500  503          switch (event_ctx->iec_event) {
 501  504          case CE_LOGIN_RCV:
 502  505                  /* T4 */
      506 +                /* Keep login timeout active through S3 and into S4 */
 503  507                  idm_initial_login_actions(ic, event_ctx);
 504  508                  idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
 505  509                  break;
 506  510          case CE_LOGIN_TIMEOUT:
 507  511                  /*
 508  512                   * Don't need to cancel login timer since the timer is
 509  513                   * presumed to be the source of this event.
 510  514                   */
 511  515                  (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
 512  516                  idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
 513  517                  break;
 514  518          case CE_CONNECT_REJECT:
 515  519                  /*
 516  520                   * Iscsit doesn't want to hear from us again in this case.
 517  521                   * Since it rejected the connection it doesn't have a
 518  522                   * connection context to handle additional notifications.
 519  523                   * IDM needs to just clean things up on its own.
 520  524                   */
 521      -                (void) untimeout(ic->ic_state_timeout);
      525 +                IDM_SM_TIMER_CLEAR(ic);
 522  526                  idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
 523  527                  break;
 524  528          case CE_CONNECT_FAIL:
 525  529          case CE_TRANSPORT_FAIL:
 526  530          case CE_LOGOUT_OTHER_CONN_SND:
 527  531                  /* T6 */
 528      -                (void) untimeout(ic->ic_state_timeout);
      532 +                IDM_SM_TIMER_CLEAR(ic);
 529  533                  (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
 530  534                  idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
 531  535                  break;
 532  536          case CE_TX_PROTOCOL_ERROR:
 533  537          case CE_RX_PROTOCOL_ERROR:
 534  538                  /* Don't care */
 535  539                  break;
 536  540          default:
 537  541                  ASSERT(0);
 538  542                  /*NOTREACHED*/
↓ open down ↓ 7 lines elided ↑ open up ↑
 546  550  
 547  551          /*
 548  552           * Login timer should no longer be active after leaving this
 549  553           * state.
 550  554           */
 551  555          switch (event_ctx->iec_event) {
 552  556          case CE_LOGIN_SUCCESS_RCV:
 553  557          case CE_LOGIN_SUCCESS_SND:
 554  558                  ASSERT(ic->ic_client_callback == NULL);
 555  559  
 556      -                (void) untimeout(ic->ic_state_timeout);
      560 +                IDM_SM_TIMER_CLEAR(ic);
 557  561                  idm_login_success_actions(ic, event_ctx);
 558  562                  if (ic->ic_rdma_extensions) {
 559  563                          /* T19 */
 560  564                          idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
 561  565                  } else {
 562  566                          /* T5 */
 563  567                          idm_update_state(ic, CS_S5_LOGGED_IN, event_ctx);
 564  568                  }
 565  569                  break;
 566  570          case CE_LOGIN_TIMEOUT:
 567  571                  /* T7 */
 568  572                  (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
 569  573                  idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
 570  574                  break;
 571  575          case CE_LOGIN_FAIL_SND:
 572  576                  /*
 573  577                   * Allow the logout response pdu to be sent and defer
 574  578                   * the state machine cleanup until the completion callback.
 575  579                   * Only 1 level or callback interposition is allowed.
 576  580                   */
 577      -                (void) untimeout(ic->ic_state_timeout);
      581 +                IDM_SM_TIMER_CLEAR(ic);
 578  582                  pdu = (idm_pdu_t *)event_ctx->iec_info;
 579  583                  ASSERT(ic->ic_client_callback == NULL);
 580  584                  ic->ic_client_callback = pdu->isp_callback;
 581  585                  pdu->isp_callback =
 582  586                      idm_state_s9b_wait_snd_done_cb;
 583  587                  idm_update_state(ic, CS_S9B_WAIT_SND_DONE,
 584  588                      event_ctx);
 585  589                  break;
 586  590          case CE_LOGIN_FAIL_RCV:
 587  591                  ASSERT(ic->ic_client_callback == NULL);
↓ open down ↓ 3 lines elided ↑ open up ↑
 591  595                   * no longer be in an appropriate state.
 592  596                   */
 593  597                  event_ctx->iec_pdu_forwarded = B_TRUE;
 594  598                  pdu = (idm_pdu_t *)event_ctx->iec_info;
 595  599                  idm_pdu_rx_forward(ic, pdu);
 596  600                  /* FALLTHROUGH */
 597  601          case CE_TRANSPORT_FAIL:
 598  602          case CE_LOGOUT_OTHER_CONN_SND:
 599  603          case CE_LOGOUT_OTHER_CONN_RCV:
 600  604                  /* T7 */
 601      -                (void) untimeout(ic->ic_state_timeout);
      605 +                IDM_SM_TIMER_CLEAR(ic);
 602  606                  (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
 603  607                  idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
 604  608                  break;
 605  609          case CE_LOGOUT_SESSION_SUCCESS:
 606  610                  /*
 607  611                   * T8
 608  612                   * A session reinstatement request can be received while a
 609  613                   * session is active and a login is in process. The iSCSI
 610  614                   * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
 611  615                   * event sent from the session to the IDM layer.
 612  616                   */
 613      -                (void) untimeout(ic->ic_state_timeout);
      617 +                IDM_SM_TIMER_CLEAR(ic);
 614  618                  if (IDM_CONN_ISTGT(ic)) {
 615  619                          ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
 616  620                  } else {
 617  621                          ic->ic_transport_ops->it_ini_conn_disconnect(ic);
 618  622                  }
 619  623                  idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
 620  624                  break;
 621  625  
 622  626          case CE_LOGIN_SND:
 623  627                  ASSERT(ic->ic_client_callback == NULL);
↓ open down ↓ 195 lines elided ↑ open up ↑
 819  823                  ASSERT(0);
 820  824          }
 821  825  }
 822  826  
 823  827  
 824  828  static void
 825  829  idm_logout_req_timeout(void *arg)
 826  830  {
 827  831          idm_conn_t *ic = arg;
 828  832  
      833 +        ic->ic_state_timeout = 0;
 829  834          idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
 830  835  }
 831  836  
 832  837  static void
 833  838  idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
 834  839  {
 835  840          /* Must cancel logout timer before leaving this state */
 836  841          switch (event_ctx->iec_event) {
 837  842          case CE_LOGOUT_THIS_CONN_RCV:
 838  843          case CE_LOGOUT_THIS_CONN_SND:
 839  844          case CE_LOGOUT_OTHER_CONN_RCV:
 840  845          case CE_LOGOUT_OTHER_CONN_SND:
 841  846                  /* T10 */
 842  847                  if (IDM_CONN_ISTGT(ic)) {
 843      -                        (void) untimeout(ic->ic_state_timeout);
      848 +                        IDM_SM_TIMER_CLEAR(ic);
 844  849                  }
 845  850                  idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
 846  851                  idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
 847  852                  break;
 848  853          case CE_LOGOUT_SESSION_RCV:
 849  854          case CE_LOGOUT_SESSION_SND:
 850  855                  /* T10 */
 851  856                  if (IDM_CONN_ISTGT(ic)) {
 852      -                        (void) untimeout(ic->ic_state_timeout);
      857 +                        IDM_SM_TIMER_CLEAR(ic);
 853  858                  }
 854  859                  idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
 855  860                  idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
 856  861                  break;
 857  862          case CE_ASYNC_LOGOUT_RCV:
 858  863          case CE_ASYNC_LOGOUT_SND:
 859  864                  /* T12 Do nothing */
 860  865                  break;
 861  866          case CE_TRANSPORT_FAIL:
 862  867          case CE_ASYNC_DROP_CONN_RCV:
 863  868          case CE_ASYNC_DROP_CONN_SND:
 864  869          case CE_ASYNC_DROP_ALL_CONN_RCV:
 865  870          case CE_ASYNC_DROP_ALL_CONN_SND:
 866  871                  /* T16 */
 867  872                  if (IDM_CONN_ISTGT(ic)) {
 868      -                        (void) untimeout(ic->ic_state_timeout);
      873 +                        IDM_SM_TIMER_CLEAR(ic);
 869  874                  }
 870  875                  /* FALLTHROUGH */
 871  876          case CE_LOGOUT_TIMEOUT:
 872  877                  idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
 873  878                  idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
 874  879                  break;
 875  880          case CE_LOGOUT_SESSION_SUCCESS:
 876  881                  /* T18 */
 877  882                  if (IDM_CONN_ISTGT(ic)) {
 878      -                        (void) untimeout(ic->ic_state_timeout);
      883 +                        IDM_SM_TIMER_CLEAR(ic);
 879  884                  }
 880  885                  idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
 881  886  
 882  887                  /* Close connection (if it's not already closed) */
 883  888                  if (IDM_CONN_ISTGT(ic)) {
 884  889                          ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
 885  890                  } else {
 886  891                          ic->ic_transport_ops->it_ini_conn_disconnect(ic);
 887  892                  }
 888  893  
↓ open down ↓ 10 lines elided ↑ open up ↑
 899  904                  ASSERT(0);
 900  905          }
 901  906  }
 902  907  
 903  908  
 904  909  static void
 905  910  idm_cleanup_timeout(void *arg)
 906  911  {
 907  912          idm_conn_t *ic = arg;
 908  913  
      914 +        ic->ic_state_timeout = 0;
 909  915          idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
 910  916  }
 911  917  
 912  918  static void
 913  919  idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
 914  920  {
 915  921          idm_pdu_t *pdu;
 916  922  
 917  923          /*
 918  924           * Need to cancel the cleanup timeout before leaving this state
 919  925           * if it hasn't already fired.
 920  926           */
 921  927          switch (event_ctx->iec_event) {
 922  928          case CE_LOGOUT_SUCCESS_RCV:
 923  929          case CE_LOGOUT_SUCCESS_SND:
 924  930          case CE_LOGOUT_SESSION_SUCCESS:
 925      -                (void) untimeout(ic->ic_state_timeout);
      931 +                IDM_SM_TIMER_CLEAR(ic);
 926  932                  /*FALLTHROUGH*/
 927  933          case CE_CLEANUP_TIMEOUT:
 928  934                  /* M1 */
 929  935                  idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
 930  936                  break;
 931  937          case CE_LOGOUT_OTHER_CONN_RCV:
 932  938          case CE_LOGOUT_OTHER_CONN_SND:
 933  939                  /* M2 */
 934  940                  idm_update_state(ic, CS_S10_IN_CLEANUP, event_ctx);
 935  941                  break;
↓ open down ↓ 88 lines elided ↑ open up ↑
1024 1030           * if it hasn't already fired.
1025 1031           */
1026 1032          switch (event_ctx->iec_event) {
1027 1033          case CE_LOGOUT_FAIL_RCV:
1028 1034          case CE_LOGOUT_FAIL_SND:
1029 1035                  idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
1030 1036                  break;
1031 1037          case CE_LOGOUT_SUCCESS_SND:
1032 1038          case CE_LOGOUT_SUCCESS_RCV:
1033 1039          case CE_LOGOUT_SESSION_SUCCESS:
1034      -                (void) untimeout(ic->ic_state_timeout);
     1040 +                IDM_SM_TIMER_CLEAR(ic);
1035 1041                  /*FALLTHROUGH*/
1036 1042          case CE_CLEANUP_TIMEOUT:
1037 1043                  idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
1038 1044                  break;
1039 1045          case CE_LOGOUT_SUCCESS_SND_DONE:
1040 1046          case CE_LOGOUT_FAIL_SND_DONE:
1041 1047                  pdu = (idm_pdu_t *)event_ctx->iec_info;
1042 1048                  /* restore client callback */
1043 1049                  pdu->isp_callback =  ic->ic_client_callback;
1044 1050                  ic->ic_client_callback = NULL;
↓ open down ↓ 135 lines elided ↑ open up ↑
1180 1186                          default:
1181 1187                                  idm_conn_event(ic, CE_CONNECT_FAIL, NULL);
1182 1188                                  break;
1183 1189                          }
1184 1190                  }
1185 1191  
1186 1192                  /*
1187 1193                   * First login received will cause a transition to
1188 1194                   * CS_S4_IN_LOGIN.  Start login timer.
1189 1195                   */
     1196 +                IDM_SM_TIMER_CHECK(ic);
1190 1197                  ic->ic_state_timeout = timeout(idm_login_timeout, ic,
1191 1198                      drv_usectohz(IDM_LOGIN_SECONDS*1000000));
1192 1199                  break;
1193 1200          case CS_S4_IN_LOGIN:
1194 1201                  if (ic->ic_conn_type == CONN_TYPE_INI) {
1195 1202                          (void) idm_notify_client(ic, CN_READY_FOR_LOGIN, NULL);
1196 1203                          mutex_enter(&ic->ic_state_mutex);
1197 1204                          ic->ic_state_flags |= CF_LOGIN_READY;
1198 1205                          cv_signal(&ic->ic_state_cv);
1199 1206                          mutex_exit(&ic->ic_state_mutex);
↓ open down ↓ 15 lines elided ↑ open up ↑
1215 1222                          /* Connection reinstatement is complete */
1216 1223                          idm_conn_event(ic->ic_reinstate_conn,
1217 1224                              CE_CONN_REINSTATE_SUCCESS, NULL);
1218 1225                  }
1219 1226                  break;
1220 1227          case CS_S6_IN_LOGOUT:
1221 1228                  break;
1222 1229          case CS_S7_LOGOUT_REQ:
1223 1230                  /* Start logout timer for target connections */
1224 1231                  if (IDM_CONN_ISTGT(ic)) {
     1232 +                        IDM_SM_TIMER_CHECK(ic);
1225 1233                          ic->ic_state_timeout = timeout(idm_logout_req_timeout,
1226 1234                              ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
1227 1235                  }
1228 1236                  break;
1229 1237          case CS_S8_CLEANUP:
1230 1238                  /* Close connection (if it's not already closed) */
1231 1239                  if (IDM_CONN_ISTGT(ic)) {
1232 1240                          ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
1233 1241                  } else {
1234 1242                          ic->ic_transport_ops->it_ini_conn_disconnect(ic);
1235 1243                  }
1236 1244  
1237 1245                  /* Stop executing active tasks */
1238 1246                  idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
1239 1247  
1240 1248                  /* Start logout timer */
     1249 +                IDM_SM_TIMER_CHECK(ic);
1241 1250                  ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
1242 1251                      drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
1243 1252                  break;
1244 1253          case CS_S10_IN_CLEANUP:
1245 1254                  break;
1246 1255          case CS_S9A_REJECTED:
1247 1256                  /*
1248 1257                   * We never finished establishing the connection so no
1249 1258                   * disconnect.  No client notifications because the client
1250 1259                   * rejected the connection.
↓ open down ↓ 407 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX