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/sys/idm/idm_conn_sm.h
          +++ new/usr/src/uts/common/sys/idm/idm_conn_sm.h
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | 
      ↓ 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 2010 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
       25 + * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25   26   */
  26   27  #ifndef _IDM_CONN_SM_H_
  27   28  #define _IDM_CONN_SM_H_
  28   29  
  29   30  #ifdef  __cplusplus
  30   31  extern "C" {
  31   32  #endif
  32   33  
  33   34  
  34   35  /*
  35   36   * IDM connection state machine events.  Most events get generated internally
  36   37   * either by the state machine or by the IDM TX/RX code.  For example when IDM
  37   38   * receives a login request for a target connectionit will generate a
  38   39   * CE_LOGIN_RCV event.  Similarly when the target sends a successful login
  39   40   * response IDM generate a "CE_LOGIN_SUCCESS_SND" event.  The following
  40   41   * events are not detected on the TX/RX path and must be generated explicitly
  41   42   * by the client when appropriate:
  42   43   *
  43   44   * CE_LOGOUT_OTHER_CONN_RCV
  44   45   * CE_ASYNC_DROP_CONN_RCV   (Only because the message may be received on
  45   46   * a different connection from the connection being dropped)
  46   47   * CE_ASYNC_DROP_ALL_CONN_RCV
  47   48   * CE_LOGOUT_OTHER_CONN_SND
  48   49   * CE_ASYNC_DROP_ALL_CONN_SND
  49   50   *
  50   51   * The following events might occur in any state since they are driven
  51   52   * by the PDU's that IDM receives:
  52   53   *
  53   54   * CE_LOGIN_RCV
  54   55   * CE_LOGIN_SUCCESS_RCV
  55   56   * CE_LOGIN_FAIL_RCV
  56   57   * CE_LOGOUT_SUCCESS_RCV
  57   58   * CE_LOGOUT_FAIL_RCV
  58   59   * CE_ASYNC_LOGOUT_RCV
  59   60   * CE_MISC_RCV
  60   61   * CE_RX_PROTOCOL_ERROR
  61   62   */
  62   63  
  63   64  #define IDM_LOGIN_SECONDS       20
  64   65  #define IDM_LOGOUT_SECONDS      20
  65   66  #define IDM_CLEANUP_SECONDS     0
  66   67  
  67   68  /* Update idm_ce_name table whenever connection events are modified */
  68   69  typedef enum {
  69   70          CE_UNDEFINED = 0,
  70   71  
  71   72          /* Initiator events */
  72   73          CE_CONNECT_REQ,
  73   74          CE_CONNECT_FAIL,
  74   75          CE_CONNECT_SUCCESS,
  75   76          CE_LOGIN_SND,
  76   77          CE_LOGIN_SUCCESS_RCV,
  77   78          CE_LOGIN_FAIL_RCV,
  78   79          CE_LOGOUT_THIS_CONN_SND,
  79   80          CE_LOGOUT_OTHER_CONN_SND,
  80   81          CE_LOGOUT_SESSION_SND,
  81   82          CE_LOGOUT_SUCCESS_RCV,
  82   83          CE_LOGOUT_FAIL_RCV,
  83   84          CE_ASYNC_LOGOUT_RCV,
  84   85          CE_ASYNC_DROP_CONN_RCV,
  85   86          CE_ASYNC_DROP_ALL_CONN_RCV,
  86   87  
  87   88          /* Target events */
  88   89          CE_CONNECT_ACCEPT,
  89   90          CE_CONNECT_REJECT,
  90   91          CE_LOGIN_RCV,
  91   92          CE_LOGIN_TIMEOUT,
  92   93          CE_LOGIN_SUCCESS_SND,
  93   94          CE_LOGIN_FAIL_SND,
  94   95          CE_LOGIN_FAIL_SND_DONE,
  95   96          CE_LOGOUT_THIS_CONN_RCV,
  96   97          CE_LOGOUT_OTHER_CONN_RCV,
  97   98          CE_LOGOUT_SESSION_RCV,
  98   99          CE_LOGOUT_SUCCESS_SND,
  99  100          CE_LOGOUT_SUCCESS_SND_DONE,
 100  101          CE_LOGOUT_FAIL_SND,
 101  102          CE_LOGOUT_FAIL_SND_DONE,
 102  103          CE_CLEANUP_TIMEOUT,
 103  104          CE_ASYNC_LOGOUT_SND,
 104  105          CE_ASYNC_DROP_CONN_SND,
 105  106          CE_ASYNC_DROP_ALL_CONN_SND,
 106  107          CE_LOGOUT_TIMEOUT,
 107  108  
 108  109          /* Common events */
 109  110          CE_TRANSPORT_FAIL,
 110  111          CE_MISC_TX,
 111  112          CE_TX_PROTOCOL_ERROR,
 112  113          CE_MISC_RX,
 113  114          CE_RX_PROTOCOL_ERROR,
 114  115          CE_LOGOUT_SESSION_SUCCESS,
 115  116          CE_CONN_REINSTATE,
 116  117          CE_CONN_REINSTATE_SUCCESS,
 117  118          CE_CONN_REINSTATE_FAIL,
 118  119          CE_ENABLE_DM_SUCCESS,
 119  120          CE_ENABLE_DM_FAIL,
 120  121  
 121  122          /* Add new events above CE_MAX_EVENT */
 122  123          CE_MAX_EVENT
 123  124  } idm_conn_event_t;
 124  125  
 125  126  #ifdef IDM_CONN_SM_STRINGS
 126  127  /* An array of event text values, for use in logging events */
 127  128  static const char *idm_ce_name[CE_MAX_EVENT+1] = {
 128  129          "CE_UNDEFINED",
 129  130          "CE_CONNECT_REQ",
 130  131          "CE_CONNECT_FAIL",
 131  132          "CE_CONNECT_SUCCESS",
 132  133          "CE_LOGIN_SND",
 133  134          "CE_LOGIN_SUCCESS_RCV",
 134  135          "CE_LOGIN_FAIL_RCV",
 135  136          "CE_LOGOUT_THIS_CONN_SND",
 136  137          "CE_LOGOUT_OTHER_CONN_SND",
 137  138          "CE_LOGOUT_SESSION_SND",
 138  139          "CE_LOGOUT_SUCCESS_RCV",
 139  140          "CE_LOGOUT_FAIL_RCV",
 140  141          "CE_ASYNC_LOGOUT_RCV",
 141  142          "CE_ASYNC_DROP_CONN_RCV",
 142  143          "CE_ASYNC_DROP_ALL_CONN_RCV",
 143  144          "CE_CONNECT_ACCEPT",
 144  145          "CE_CONNECT_REJECT",
 145  146          "CE_LOGIN_RCV",
 146  147          "CE_LOGIN_TIMEOUT",
 147  148          "CE_LOGIN_SUCCESS_SND",
 148  149          "CE_LOGIN_FAIL_SND",
 149  150          "CE_LOGIN_FAIL_SND_DONE",
 150  151          "CE_LOGOUT_THIS_CONN_RCV",
 151  152          "CE_LOGOUT_OTHER_CONN_RCV",
 152  153          "CE_LOGOUT_SESSION_RCV",
 153  154          "CE_LOGOUT_SUCCESS_SND",
 154  155          "CE_LOGOUT_SUCCESS_SND_DONE",
 155  156          "CE_LOGOUT_FAIL_SND",
 156  157          "CE_LOGOUT_FAIL_SND_DONE",
 157  158          "CE_CLEANUP_TIMEOUT",
 158  159          "CE_ASYNC_LOGOUT_SND",
 159  160          "CE_ASYNC_DROP_CONN_SND",
 160  161          "CE_ASYNC_DROP_ALL_CONN_SND",
 161  162          "CE_LOGOUT_TIMEOUT",
 162  163          "CE_TRANSPORT_FAIL",
 163  164          "CE_MISC_TX",
 164  165          "CE_TX_PROTOCOL_ERROR",
 165  166          "CE_MISC_RX",
 166  167          "CE_RX_PROTOCOL_ERROR",
 167  168          "CE_LOGOUT_SESSION_SUCCESS",
 168  169          "CE_CONN_REINSTATE",
 169  170          "CE_CONN_REINSTATE_SUCCESS",
 170  171          "CE_CONN_REINSTATE_FAIL",
 171  172          "CE_ENABLE_DM_SUCCESS",
 172  173          "CE_ENABLE_DM_FAIL",
 173  174          "CE_MAX_EVENT"
 174  175  };
 175  176  #endif
 176  177  
 177  178  /* Update idm_cs_name table whenever connection states are modified */
 178  179  typedef enum {
 179  180          CS_S0_UNDEFINED = 0,
 180  181  
 181  182          CS_S1_FREE,
 182  183          CS_S2_XPT_WAIT,
 183  184          CS_S3_XPT_UP,
 184  185          CS_S4_IN_LOGIN,
 185  186          CS_S5_LOGGED_IN,
 186  187          CS_S6_IN_LOGOUT,
 187  188          CS_S7_LOGOUT_REQ,
 188  189          CS_S8_CLEANUP,
 189  190          CS_S9_INIT_ERROR,
 190  191          CS_S10_IN_CLEANUP,
 191  192          CS_S11_COMPLETE,
 192  193          CS_S12_ENABLE_DM,
 193  194          CS_S9A_REJECTED,
 194  195          CS_S9B_WAIT_SND_DONE,
 195  196  
 196  197          /* Add new connection states above CS_MAX_STATE */
 197  198          CS_MAX_STATE
 198  199  } idm_conn_state_t;
 199  200  
 200  201  #ifdef IDM_CONN_SM_STRINGS
 201  202  /* An array of state text values, for use in logging state transitions */
 202  203  static const char *idm_cs_name[CS_MAX_STATE+1] = {
 203  204          "CS_S0_UNDEFINED",
 204  205          "CS_S1_FREE",
 205  206          "CS_S2_XPT_WAIT",
 206  207          "CS_S3_XPT_UP",
 207  208          "CS_S4_IN_LOGIN",
 208  209          "CS_S5_LOGGED_IN",
 209  210          "CS_S6_IN_LOGOUT",
 210  211          "CS_S7_LOGOUT_REQ",
 211  212          "CS_S8_CLEANUP",
  
    | 
      ↓ open down ↓ | 
    177 lines elided | 
    
      ↑ open up ↑ | 
  
 212  213          "CS_S9_INIT_ERROR",
 213  214          "CS_S10_IN_CLEANUP",
 214  215          "CS_S11_COMPLETE",
 215  216          "CS_S12_ENABLE_DM",
 216  217          "CS_S9A_REJECTED",
 217  218          "CS_S9B_WAIT_SND_DONE",
 218  219          "CS_MAX_STATE"
 219  220  };
 220  221  #endif
 221  222  
      223 +/*
      224 + * Currently the state machine has a condition where idm_login_timeout() is
      225 + * left active after the connection has been closed. This causes the system
      226 + * to panic when idm_login_timeout() modifies the freed memory. In an attempt
      227 + * to isolate and find this issue special attention is being placed on
      228 + * the ic_state_timeout value. After each untimeout call the value will now
      229 + * be cleared. Just before the value is set the code will check for 0 and
      230 + * display an error. One final change is being done in idm_conn_sm_fini() which
      231 + * if ic_state_machine is not 0, an error message will be displayed and
      232 + * untimeout() called. That should prevent customer sites from seeing the
      233 + * panic. The code also calls ASSERT(0) which should cause a panic during
      234 + * system test.
      235 + */
      236 +#define IDM_SM_TIMER_CHECK(ic) \
      237 +        if (ic->ic_state_timeout) { \
      238 +                cmn_err(CE_WARN, "%s: existing timeout still set. " \
      239 +                    "state: %s, last: %s\n", __func__, \
      240 +                    idm_cs_name[ic->ic_state], \
      241 +                    idm_cs_name[ic->ic_last_state]); \
      242 +                ASSERT(0); \
      243 +        }
      244 +
      245 +#define IDM_SM_TIMER_CLEAR(ic) \
      246 +        (void) untimeout(ic->ic_state_timeout); \
      247 +        ic->ic_state_timeout = 0;
      248 +
 222  249  typedef enum {
 223  250          CT_NONE = 0,
 224  251          CT_RX_PDU,
 225  252          CT_TX_PDU
 226  253  } idm_pdu_event_type_t;
 227  254  
 228  255  typedef enum {
 229  256          CA_TX_PROTOCOL_ERROR,   /* Send "protocol error" to state machine */
 230  257          CA_RX_PROTOCOL_ERROR,   /* Send "protocol error" to state machine */
 231  258          CA_FORWARD,             /* State machine event and forward to client */
 232  259          CA_DROP                 /* Drop PDU */
 233  260  } idm_pdu_event_action_t;
 234  261  
 235  262  typedef struct {
 236  263          struct idm_conn_s       *iec_ic;
 237  264          idm_conn_event_t        iec_event;
 238  265          uintptr_t               iec_info;
 239  266          idm_pdu_event_type_t    iec_pdu_event_type;
 240  267          boolean_t               iec_pdu_forwarded;
 241  268  } idm_conn_event_ctx_t;
 242  269  
 243  270  idm_status_t
 244  271  idm_conn_sm_init(struct idm_conn_s *ic);
 245  272  
 246  273  void
 247  274  idm_conn_sm_fini(struct idm_conn_s *ic);
 248  275  
 249  276  idm_status_t
 250  277  idm_notify_client(struct idm_conn_s *ic, idm_client_notify_t cn,
 251  278      uintptr_t data);
 252  279  
 253  280  void
 254  281  idm_conn_event(struct idm_conn_s *ic, idm_conn_event_t event, uintptr_t data);
 255  282  
 256  283  void
 257  284  idm_conn_event(struct idm_conn_s *ic, idm_conn_event_t event, uintptr_t data);
 258  285  
 259  286  void
 260  287  idm_conn_event_locked(struct idm_conn_s *ic, idm_conn_event_t event,
 261  288      uintptr_t event_info, idm_pdu_event_type_t pdu_event_type);
 262  289  
 263  290  idm_status_t
 264  291  idm_conn_reinstate_event(struct idm_conn_s *old_ic, struct idm_conn_s *new_ic);
 265  292  
 266  293  void
 267  294  idm_conn_tx_pdu_event(struct idm_conn_s *ic, idm_conn_event_t event,
 268  295      uintptr_t data);
 269  296  
 270  297  void
 271  298  idm_conn_rx_pdu_event(struct idm_conn_s *ic, idm_conn_event_t event,
 272  299      uintptr_t data);
 273  300  
 274  301  char *
 275  302  idm_conn_state_str(struct idm_conn_s *ic);
 276  303  
 277  304  #ifdef  __cplusplus
 278  305  }
 279  306  #endif
 280  307  
 281  308  #endif /* _IDM_CONN_SM_H_ */
  
    | 
      ↓ open down ↓ | 
    50 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX