"Fossies" - the Fresh Open Source Software Archive

Member "opensaf-5.21.09/src/imm/agent/imma_om_api.cc" (14 Sep 2021, 331650 Bytes) of package /linux/misc/opensaf-5.21.09.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imma_om_api.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.21.06_vs_5.21.09.

    1 /*      -*- OpenSAF  -*-
    2  *
    3  * (C) Copyright 2008 The OpenSAF Foundation
    4  * Copyright Ericsson AB 2009, 2017 - All Rights Reserved.
    5  * Copyright (C) 2017, Oracle and/or its affiliates. All rights reserved.
    6  *
    7  * This program is distributed in the hope that it will be useful, but
    8  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    9  * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
   10  * under the GNU Lesser General Public License Version 2.1, February 1999.
   11  * The complete license can be accessed from the following location:
   12  * http://opensource.org/licenses/lgpl-license.php
   13  * See the Copying file included with the OpenSAF distribution for full
   14  * licensing terms.
   15  *
   16  * Author(s): Ericsson AB
   17  *
   18  */
   19 
   20 /*****************************************************************************
   21   DESCRIPTION:
   22 
   23   This file contains the IMMSv SAF API definitions.
   24 
   25  TRACE GUIDE:
   26  Policy is to not use logging/syslog from library code.
   27  Only the trace part of logtrace is used from library.
   28 
   29  It is possible to turn on trace for the IMMA library used
   30  by an application process. This is done by the application
   31  defining the environment variable: IMMA_TRACE_PATHNAME.
   32  The trace will end up in the file defined by that variable.
   33 
   34  TRACE   debug traces                 - aproximates DEBUG
   35  TRACE_1 normal but important events  - aproximates INFO.
   36  TRACE_2 user errors with return code - aproximates NOTICE.
   37  TRACE_3 unusual or strange events    - aproximates WARNING
   38  TRACE_4 library errors ERR_LIBRARY   - aproximates ERROR
   39 *****************************************************************************/
   40 
   41 #include <string.h>
   42 #include <stdlib.h>
   43 
   44 #include "imma.h"
   45 #include "imm/common/immsv_api.h"
   46 #include <saAis.h>
   47 #include "base/osaf_extended_name.h"
   48 
   49 static const char *immLoaderName = IMMSV_LOADERNAME; /*Defined in immsv_evt.h */
   50 
   51 /* TODO: ABT move these to cb ? OR stop using the cb*/
   52 static SaInt32T immInvocations = 0;
   53 static bool immOmIsLoader = false;
   54 
   55 static const char *sysaClName = SA_IMM_ATTR_CLASS_NAME;
   56 static const char *sysaAdmName = SA_IMM_ATTR_ADMIN_OWNER_NAME;
   57 static const char *sysaImplName = SA_IMM_ATTR_IMPLEMENTER_NAME;
   58 
   59 static int imma_om_resurrect(IMMA_CB *cb, IMMA_CLIENT_NODE *cl_node,
   60                              bool *locked);
   61 static SaAisErrorT imma_finalizeCcb(SaImmCcbHandleT ccbHandle,
   62                                     bool keepCcbHandleOpen);
   63 static SaAisErrorT imma_applyCcb(SaImmCcbHandleT ccbHandle, bool onlyValidate);
   64 
   65 /****************************************************************************
   66   Name          :  SaImmOmInitialize
   67 
   68   Description   :  This function initializes the ImmOm Service for the
   69                    invoking process and registers the callback functions.
   70                    The handle 'immHandle' is returned as the reference to this
   71                    association between the process and  the ImmOm Service.
   72 
   73 
   74   Arguments     :  immHandle -  A pointer to the handle designating this
   75                                 particular initialization of the IMM OM
   76                                 service that is to be returned by the
   77                                 ImmOm Service.
   78                    immCallbacks  - Pointer to a SaImmCallbacksT structure,
   79                                 containing the callback functions of the
   80                                 process that the ImmOm Service may invoke.
   81                    version    - Is a pointer to the version of the Imm
   82                                 Service that the invoking process is using.
   83 
   84 
   85 
   86   Return Values :  Refer to SAI-AIS specification for various return values.
   87 
   88   Notes         :
   89 ******************************************************************************/
   90 static SaAisErrorT initialize_common(SaImmHandleT *immHandle,
   91                                      IMMA_CLIENT_NODE *cl_node,
   92                                      SaVersionT *version);
   93 
   94 SaAisErrorT saImmOmInitialize_o2(SaImmHandleT *immHandle,
   95                                  const SaImmCallbacksT_o2 *immCallbacks,
   96                                  SaVersionT *inout_version) {
   97   IMMA_CLIENT_NODE *cl_node = NULL;
   98   SaAisErrorT rc = SA_AIS_OK;
   99   SaVersionT requested_version;
  100 
  101   TRACE_ENTER();
  102   if ((!immHandle) || (!inout_version)) {
  103     TRACE_2("ERR_INVALID_PARAM: immHandle is NULL or version is NULL");
  104     return SA_AIS_ERR_INVALID_PARAM;
  105   }
  106 
  107   requested_version = *inout_version;
  108 
  109   if ((requested_version.releaseCode != 'A') ||
  110       (requested_version.majorVersion != 0x02) ||
  111       (requested_version.minorVersion < 11)) {
  112     TRACE_2(
  113         "ERR_VERSION: THIS SHOULD BE A VERSION A.2.11 initialize but claims to be"
  114         "%c %u %u",
  115         requested_version.releaseCode, requested_version.majorVersion,
  116         requested_version.minorVersion);
  117     imma_version_validate(inout_version);
  118     return SA_AIS_ERR_VERSION;
  119   }
  120 
  121   /* Draft Validations : Version */
  122   rc = imma_version_validate(inout_version);
  123   if (rc != SA_AIS_OK) {
  124     TRACE_2("ERR_VERSION: Version validation failed");
  125     return rc;
  126   }
  127 
  128   /* Alloc the client info data structure */
  129   cl_node = new IMMA_CLIENT_NODE{};
  130 
  131   if (cl_node == NULL) {
  132     TRACE_4("ERR_NO_MEMORY: IMMA_CLIENT_NODE alloc failed");
  133     return SA_AIS_ERR_NO_MEMORY;
  134   }
  135 
  136   cl_node->isImmA2b = true;
  137 
  138   if (requested_version.minorVersion >= 0x0d) {
  139     cl_node->isImmA2d = true;
  140     if (requested_version.minorVersion >= 0x0e) {
  141       cl_node->isImmA2e = true;
  142       if (requested_version.minorVersion >= 0x0f) {
  143         cl_node->isImmA2f = true;
  144         if (requested_version.minorVersion >= 0x10) {
  145           cl_node->isImmA2x10 = true;
  146           if (requested_version.minorVersion >= 0x11) {
  147             cl_node->isImmA2x11 = true;
  148             if (requested_version.minorVersion >= 0x12) {
  149               cl_node->isImmA2x12 = true;
  150             }
  151           }
  152         }
  153       }
  154     }
  155   }
  156 
  157   /* Store the callback functions, if set */
  158   if (immCallbacks) {
  159     cl_node->o.mCallbkA2b = *immCallbacks;
  160     cl_node->isImmA2bCbk = true;
  161   }
  162 
  163   return initialize_common(immHandle, cl_node, &requested_version);
  164 }
  165 
  166 SaAisErrorT saImmOmInitialize(SaImmHandleT *immHandle,
  167                               const SaImmCallbacksT *immCallbacks,
  168                               SaVersionT *inout_version) {
  169   IMMA_CLIENT_NODE *cl_node = NULL;
  170   SaAisErrorT rc = SA_AIS_OK;
  171   SaVersionT requested_version;
  172   TRACE_ENTER();
  173 
  174   if ((!immHandle) || (!inout_version)) {
  175     TRACE_2("ERR_INVALID_PARAM: immHandle is NULL or version is NULL");
  176     return SA_AIS_ERR_INVALID_PARAM;
  177   }
  178 
  179   requested_version = *inout_version;
  180 
  181   /* Draft Validations : Version */
  182   rc = imma_version_validate(inout_version);
  183   if (rc != SA_AIS_OK) {
  184     TRACE_2("ERR_VERSION: Version validation failed");
  185     return rc;
  186   }
  187 
  188   /* Alloc the client info data structure */
  189   cl_node = new IMMA_CLIENT_NODE{};
  190 
  191   if (cl_node == NULL) {
  192     TRACE_4("ERR_NO_MEMORY: IMMA_CLIENT_NODE alloc failed");
  193     return SA_AIS_ERR_NO_MEMORY;
  194   }
  195 
  196   if ((requested_version.releaseCode == 'A') &&
  197       (requested_version.majorVersion == 0x02)) {
  198     TRACE("OM client version A.2.%u", requested_version.minorVersion);
  199     if (requested_version.minorVersion >= 0x0b) {
  200       cl_node->isImmA2b = true;
  201       if (requested_version.minorVersion >= 0x0d) {
  202         cl_node->isImmA2d = true;
  203         if (requested_version.minorVersion >= 0x0e) {
  204           cl_node->isImmA2e = true;
  205           if (requested_version.minorVersion >= 0x0f) {
  206             cl_node->isImmA2f = true;
  207             if (requested_version.minorVersion >= 0x10) {
  208               cl_node->isImmA2x10 = true;
  209               if (requested_version.minorVersion >= 0x11) {
  210                 cl_node->isImmA2x11 = true;
  211                 if (requested_version.minorVersion >= 0x12) {
  212                   cl_node->isImmA2x12 = true;
  213                 }
  214               }
  215             }
  216           }
  217         }
  218       }
  219     }
  220   }
  221 
  222   /* Store the callback functions, if set */
  223   cl_node->isImmA2bCbk = false; /* redundant */
  224   if (immCallbacks) {
  225     cl_node->o.mCallbk = *immCallbacks;
  226   }
  227 
  228   rc = initialize_common(immHandle, cl_node, &requested_version);
  229   TRACE_LEAVE();
  230   return rc;
  231 }
  232 
  233 static SaAisErrorT initialize_common(SaImmHandleT *immHandle,
  234                                      IMMA_CLIENT_NODE *cl_node,
  235                                      SaVersionT *version) {
  236   IMMA_CB *cb = &imma_cb;
  237   SaAisErrorT rc = SA_AIS_OK;
  238   IMMSV_EVT init_evt;
  239   IMMSV_EVT *out_evt = NULL;
  240   bool locked = true;
  241   char *value;
  242   TRACE_ENTER();
  243   osafassert(immHandle && cl_node);
  244 
  245   uint32_t proc_rc = imma_startup(NCSMDS_SVC_ID_IMMA_OM);
  246   if (NCSCC_RC_SUCCESS != proc_rc) {
  247     TRACE_4("ERR_LIBRARY: imma startup failed:%u", proc_rc);
  248     rc = SA_AIS_ERR_LIBRARY;
  249     goto end;
  250   }
  251 
  252   if (false == cb->is_immnd_up) {
  253     TRACE_2("ERR_TRY_AGAIN: IMMND is DOWN");
  254     rc = SA_AIS_ERR_TRY_AGAIN;
  255     goto end;
  256   }
  257 
  258   if (cl_node->isImmA2x12 && !cb->clmMemberNode) {
  259     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
  260     rc = SA_AIS_ERR_UNAVAILABLE;
  261     goto clm_left;
  262   }
  263 
  264   cl_node->syncr_timeout = imma_getSyncrTimeout();
  265   TRACE_2("IMMA library syncronous timeout set to:%lld",
  266           cl_node->syncr_timeout);
  267 
  268   *immHandle = 0;
  269 
  270   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  271     TRACE_4("ERR_LIBRARY: Lock failed");
  272     rc = SA_AIS_ERR_LIBRARY;
  273     goto end;
  274   }
  275   /* locked == true already */
  276 
  277   /* Put the client info data structure in the Pat tree */
  278 
  279   if ((cl_node->isImmA2bCbk &&
  280        cl_node->o.mCallbkA2b.saImmOmAdminOperationInvokeCallback) ||
  281       (!(cl_node->isImmA2bCbk) &&
  282        cl_node->o.mCallbk.saImmOmAdminOperationInvokeCallback)) {
  283     proc_rc = imma_callback_ipc_init(cl_node);
  284     if (proc_rc != NCSCC_RC_SUCCESS) {
  285       rc = SA_AIS_ERR_LIBRARY;
  286       /* ALready log'ed by imma_callback_ipc_init */
  287       goto ipc_init_fail;
  288     }
  289   }
  290 
  291   /* populate the EVT structure */
  292   memset(&init_evt, 0, sizeof(IMMSV_EVT));
  293   init_evt.type = IMMSV_EVT_TYPE_IMMND;
  294   init_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_INIT;
  295   init_evt.info.immnd.info.initReq.version = *version;
  296   init_evt.info.immnd.info.initReq.client_pid = getpid();
  297 
  298   /* Release the CB lock Before MDS Send */
  299   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  300   locked = false;
  301   /* cl_node has not been added to tree in cb yet so safe to access
  302      without cb-lock.
  303    */
  304 
  305   if (false == cb->is_immnd_up) {
  306     rc = SA_AIS_ERR_TRY_AGAIN;
  307     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
  308     goto mds_fail;
  309   }
  310 
  311   /* send the request to the IMMND */
  312   proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &cb->immnd_mds_dest,
  313                                    &init_evt, &out_evt, cl_node->syncr_timeout);
  314 
  315   /* Error Handling */
  316   switch (proc_rc) {
  317     case NCSCC_RC_SUCCESS:
  318       break;
  319     case NCSCC_RC_REQ_TIMOUT:
  320       rc = SA_AIS_ERR_TIMEOUT;
  321       goto mds_fail;
  322     default:
  323       TRACE_4("ERR_LIBRARY: Mds returned unexpected error code: %u", proc_rc);
  324       rc = SA_AIS_ERR_LIBRARY;
  325       goto mds_fail;
  326   }
  327 
  328   if (out_evt) {
  329     rc = out_evt->info.imma.info.initRsp.error;
  330     if (rc == SA_AIS_ERR_UNAVAILABLE && cl_node->isImmA2x12) {
  331       cb->clmMemberNode = false;
  332       TRACE(" Node left the CLM membership");
  333       goto rsp_not_ok;
  334     }
  335 
  336     if (rc != SA_AIS_OK) {
  337       goto rsp_not_ok;
  338     }
  339 
  340     /* Take the CB lock after MDS Send */
  341     if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  342       TRACE_4("ERR_LIBRARY: Lock failed");
  343       rc = SA_AIS_ERR_LIBRARY;
  344       goto lock_fail1;
  345     }
  346 
  347     locked = true;
  348 
  349     if (false == cb->is_immnd_up) {
  350       /*IMMND went down during THIS call! */
  351       rc = SA_AIS_ERR_TRY_AGAIN;
  352       TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
  353       goto rsp_not_ok;
  354     }
  355 
  356     cl_node->handle = out_evt->info.imma.info.initRsp.immHandle;
  357     cl_node->isOm = true;
  358     SaTimeT timeout = out_evt->info.imma.info.initRsp.syncrTimeout;
  359     if (timeout >= NCS_SAF_MIN_ACCEPT_TIME) {
  360       cl_node->syncr_timeout = timeout;
  361       TRACE_2("IMMA library syncronous timeout set to:%lld",
  362               cl_node->syncr_timeout);
  363     }
  364 
  365     cl_node->maxSearchHandles = 100;
  366     if ((value = getenv("IMMA_MAX_OPEN_SEARCHES_PER_HANDLE"))) {
  367       char *endptr;
  368       uint32_t n = (uint32_t)strtol(value, &endptr, 10);
  369       if (*value && !*endptr)
  370         cl_node->maxSearchHandles = n;
  371       else
  372         LOG_WA(
  373             "IMMA_MAX_OPEN_SEARCHES_PER_HANDLE contains non-valid number value. Set default value (100)");
  374     }
  375     cl_node->searchHandleSize = 0;
  376 
  377     TRACE_1("Trying to add OM client id:%u node:%x",
  378             m_IMMSV_UNPACK_HANDLE_HIGH(cl_node->handle),
  379             m_IMMSV_UNPACK_HANDLE_LOW(cl_node->handle));
  380     proc_rc = imma_client_node_add(&cb->client_tree, cl_node);
  381     if (proc_rc != NCSCC_RC_SUCCESS) {
  382       IMMA_CLIENT_NODE *stale_node = NULL;
  383       imma_client_node_get(&cb->client_tree, &(cl_node->handle), &stale_node);
  384 
  385       if ((stale_node != NULL) && stale_node->stale) {
  386         TRACE_1("Removing stale client");
  387         imma_finalize_client(cb, stale_node);
  388         proc_rc = imma_shutdown(NCSMDS_SVC_ID_IMMA_OM);
  389         if (proc_rc != NCSCC_RC_SUCCESS) {
  390           TRACE_4("ERR_LIBRARY: Call to imma_shutdown FAILED");
  391           rc = SA_AIS_ERR_LIBRARY;
  392           goto node_add_fail;
  393         }
  394 
  395         TRACE_1("Retrying add of client node");
  396         proc_rc = imma_client_node_add(&cb->client_tree, cl_node);
  397       }
  398 
  399       if (proc_rc != NCSCC_RC_SUCCESS) {
  400         rc = SA_AIS_ERR_LIBRARY;
  401         TRACE_4("ERR_LIBRARY: client_node_add failed");
  402         goto node_add_fail;
  403       }
  404     }
  405   } else {
  406     TRACE_4("ERR_LIBRARY: Empty reply received");
  407     rc = SA_AIS_ERR_LIBRARY;
  408   }
  409 
  410 /*Error handling */
  411 node_add_fail:
  412 lock_fail1:
  413   if (rc != SA_AIS_OK) {
  414     IMMSV_EVT finalize_evt, *out_evt1;
  415 
  416     out_evt1 = NULL;
  417     memset(&finalize_evt, 0, sizeof(IMMSV_EVT));
  418     finalize_evt.type = IMMSV_EVT_TYPE_IMMND;
  419     finalize_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FINALIZE;
  420     finalize_evt.info.immnd.info.finReq.client_hdl = cl_node->handle;
  421 
  422     if (locked) {
  423       m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  424       locked = false;
  425     }
  426 
  427     /* send the request to the IMMND */
  428     proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
  429                                      &finalize_evt, &out_evt1,
  430                                      cl_node->syncr_timeout);
  431 
  432     if (out_evt1) {
  433       free(out_evt1);
  434       out_evt1 = NULL;
  435     }
  436   }
  437   TRACE("OM client version A.2.%u", version->minorVersion);
  438 
  439 rsp_not_ok:
  440 mds_fail:
  441 
  442   /* Free the IPC initialized for this client */
  443   if (rc != SA_AIS_OK) imma_callback_ipc_destroy(cl_node);
  444 
  445 ipc_init_fail:
  446   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  447 
  448   if (out_evt) {
  449     free(out_evt);
  450     out_evt = NULL;
  451   }
  452 
  453   if (rc == SA_AIS_OK) {
  454     /* Went well, return immHandle to the application */
  455     *immHandle = cl_node->handle;
  456   }
  457 
  458 clm_left:
  459 end:
  460   if (rc != SA_AIS_OK) {
  461     if (NCSCC_RC_SUCCESS != imma_shutdown(NCSMDS_SVC_ID_IMMA_OM)) {
  462       /* Oh boy. Failure in imma_shutdown when we already have
  463          some other problem. */
  464       TRACE_4("ERR_LIBRARY: Call to imma_shutdown failed, prior error %u", rc);
  465 
  466       rc = SA_AIS_ERR_LIBRARY;
  467     }
  468 
  469     delete cl_node;
  470   }
  471 
  472   TRACE_LEAVE();
  473   return rc;
  474 }
  475 
  476 /****************************************************************************
  477   Name          :  saImmOmSelectionObjectGet
  478 
  479   Description   :  This function returns the operating system handle
  480                    associated with the immHandle.
  481 
  482   Arguments     :  immHandle - Imm OM service handle.
  483                    selectionObject - Pointer to the operating system handle.
  484 
  485   Return Values :  Refer to SAI-AIS specification for various return values.
  486 
  487   Notes         :
  488 ******************************************************************************/
  489 SaAisErrorT saImmOmSelectionObjectGet(SaImmHandleT immHandle,
  490                                       SaSelectionObjectT *selectionObject) {
  491   SaAisErrorT rc = SA_AIS_OK;
  492   IMMA_CB *cb = &imma_cb;
  493   IMMA_CLIENT_NODE *cl_node = 0;
  494   bool locked = true;
  495   TRACE_ENTER();
  496 
  497   if (!selectionObject) return SA_AIS_ERR_INVALID_PARAM;
  498 
  499   if (cb->sv_id == 0) {
  500     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
  501     return SA_AIS_ERR_BAD_HANDLE;
  502   }
  503 
  504   if (cb->is_immnd_up == false) {
  505     /* Normally this call will not go remote. But if IMMND is down,
  506        then it is highly likely that immOiHandle is stale marked.
  507        The reactive resurrect will fail as long as IMMND is down.
  508     */
  509     TRACE_3("ERR_TRY_AGAIN: IMMND_DOWN");
  510     return SA_AIS_ERR_TRY_AGAIN;
  511   }
  512 
  513   *selectionObject = (-1); /* Ensure non valid descriptor in case of failure. */
  514 
  515   /* Take the CB lock */
  516   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  517     TRACE_4("ERR_LIBRARY: Lock failed");
  518     rc = SA_AIS_ERR_LIBRARY;
  519     goto lock_fail;
  520   }
  521   /* locked == true already */
  522 
  523   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
  524 
  525   if (!(cl_node && cl_node->isOm)) {
  526     TRACE_2("ERR_BAD_HANDLE: Bad handle %llx", immHandle);
  527     rc = SA_AIS_ERR_BAD_HANDLE;
  528     goto node_not_found;
  529   }
  530 
  531   if (cl_node->isImmA2bCbk) { /* cl_node->isImmA2bCbk is true only if there is
  532                                  an A.2.11 callback */
  533     if (cl_node->o.mCallbkA2b.saImmOmAdminOperationInvokeCallback == NULL) {
  534       TRACE_2(
  535           "ERR_INVALID_PARAM: saImmOmSelectionObjectGet not allowed "
  536           "when saImmOmAdminOperationInvokeCallback is NULL");
  537       rc = SA_AIS_ERR_INVALID_PARAM;
  538       goto no_callback;
  539     }
  540   } else {
  541     if (cl_node->o.mCallbk.saImmOmAdminOperationInvokeCallback == NULL) {
  542       TRACE_2(
  543           "ERR_INVALID_PARAM: saImmOmSelectionObjectGet not allowed "
  544           "when saImmOmAdminOperationInvokeCallback is NULL");
  545       rc = SA_AIS_ERR_INVALID_PARAM;
  546       goto no_callback;
  547     }
  548   }
  549   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
  550     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
  551     rc = SA_AIS_ERR_UNAVAILABLE;
  552     goto clm_left;
  553   }
  554 
  555   if (cl_node->stale) {
  556     TRACE_1("Handle %llx is stale", immHandle);
  557     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
  558 
  559     if (!locked &&
  560         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  561       TRACE_4("ERR_LIBRARY: LOCK failed");
  562       rc = SA_AIS_ERR_LIBRARY;
  563       goto lock_fail;
  564     }
  565     locked = true;
  566 
  567     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
  568 
  569     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
  570       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
  571               immHandle);
  572       if (cl_node && cl_node->stale) {
  573         cl_node->exposed = true;
  574       }
  575       rc = SA_AIS_ERR_BAD_HANDLE;
  576       goto stale_handle;
  577     }
  578 
  579     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
  580   }
  581 
  582   *selectionObject = (SaSelectionObjectT)m_GET_FD_FROM_SEL_OBJ(
  583       m_NCS_IPC_GET_SEL_OBJ(&cl_node->callbk_mbx));
  584 
  585   cl_node->selObjUsable = true;
  586 
  587 clm_left:
  588 no_callback:
  589 stale_handle:
  590 node_not_found:
  591   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  592 
  593 lock_fail:
  594   TRACE_LEAVE();
  595   return rc;
  596 }
  597 
  598 /****************************************************************************
  599   Name          :  saImmOmDispatch
  600 
  601   Description   :  This function invokes, in the context of the calling
  602                    thread. pending callbacks for the handle immHandle in a
  603                    way that is specified by the dispatchFlags parameter.
  604 
  605   Arguments     :  immHandle - IMM OM Service handle
  606                    dispatchFlags - Flags that specify the callback execution
  607                                    behaviour of this function.
  608 
  609   Return Values :  Refer to SAI-AIS specification for various return values.
  610 
  611   Notes         :
  612 ******************************************************************************/
  613 SaAisErrorT saImmOmDispatch(SaImmHandleT immHandle,
  614                             SaDispatchFlagsT dispatchFlags) {
  615   SaAisErrorT rc = SA_AIS_OK;
  616   IMMA_CB *cb = &imma_cb;
  617   IMMA_CLIENT_NODE *cl_node = 0;
  618   bool locked = false;
  619   uint32_t pend_fin = 0;
  620   uint32_t pend_dis = 0;
  621   TRACE_ENTER();
  622 
  623   if (cb->sv_id == 0) {
  624     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
  625     rc = SA_AIS_ERR_BAD_HANDLE;
  626     goto fail;
  627   }
  628 
  629   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  630     TRACE_4("ERR_LIBRARY: Lock failed");
  631     rc = SA_AIS_ERR_LIBRARY;
  632     goto fail;
  633   }
  634   locked = true;
  635 
  636   /* get the client_info */
  637   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
  638   if (!(cl_node && cl_node->isOm)) {
  639     TRACE_2("ERR_BAD_HANDLE: client-node_get failed");
  640     rc = SA_AIS_ERR_BAD_HANDLE;
  641     goto fail;
  642   }
  643   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
  644     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
  645     rc = SA_AIS_ERR_UNAVAILABLE;
  646     goto clm_left;
  647   }
  648 
  649   if (cl_node->stale) {
  650     TRACE_1("Handle %llx is stale, trying to resurrect it.", immHandle);
  651 
  652     if (cb->dispatch_clients_to_resurrect == 0) {
  653       rc = SA_AIS_ERR_BAD_HANDLE;
  654       cl_node->exposed = true;
  655       goto fail;
  656     }
  657 
  658     --(cb->dispatch_clients_to_resurrect);
  659     TRACE_1("Remaining clients to actively resurrect: %d",
  660             cb->dispatch_clients_to_resurrect);
  661 
  662     if (!imma_om_resurrect(cb, cl_node, &locked)) {
  663       TRACE_3(
  664           "ERR_BAD_HANDLE: Failed to resurrect stale OM handle <c:%u, n:%x>",
  665           m_IMMSV_UNPACK_HANDLE_HIGH(immHandle),
  666           m_IMMSV_UNPACK_HANDLE_LOW(immHandle));
  667       rc = SA_AIS_ERR_BAD_HANDLE;
  668       goto fail;
  669     }
  670 
  671     TRACE_1("Successfully resurrected OM handle <c:%u, n:%x>",
  672             m_IMMSV_UNPACK_HANDLE_HIGH(immHandle),
  673             m_IMMSV_UNPACK_HANDLE_LOW(immHandle));
  674 
  675     if (!locked &&
  676         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  677       TRACE_4("ERR_LIBRARY: Lock failure");
  678       rc = SA_AIS_ERR_LIBRARY;
  679       goto fail;
  680     }
  681     locked = true;
  682 
  683     /* get the client again. */
  684     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
  685     if (!(cl_node && cl_node->isOm)) {
  686       TRACE_3(
  687           "ERR_BAD_HANDLE: client_node_get failed AFTER successful resurrect!");
  688       rc = SA_AIS_ERR_BAD_HANDLE;
  689       goto fail;
  690     }
  691 
  692     if (cl_node->stale) {
  693       TRACE_3(
  694           "ERR_BAD_HANDLE: client became stale AGAIN after successful resurrect!");
  695       cl_node->exposed = true;
  696       rc = SA_AIS_ERR_BAD_HANDLE;
  697       goto fail;
  698     }
  699 
  700     cl_node->selObjUsable = true; /* success */
  701   }
  702 
  703   /* Back to normal case of non stale (possibly resurrected) handle. */
  704   /* Unlock & do the dispatch to avoid deadlock in arrival callback. */
  705   if (locked) {
  706     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  707     locked = false;
  708   }
  709   cl_node = NULL; /* Prevent unsafe use.*/
  710   /* unlocked */
  711 
  712   /* Increment Dispatch usgae count */
  713   cb->pend_dis++;
  714 
  715   switch (dispatchFlags) {
  716     case SA_DISPATCH_ONE:
  717       rc = imma_hdl_callbk_dispatch_one(cb, immHandle);
  718       break;
  719 
  720     case SA_DISPATCH_ALL:
  721       rc = imma_hdl_callbk_dispatch_all(cb, immHandle);
  722       break;
  723 
  724     case SA_DISPATCH_BLOCKING:
  725       rc = imma_hdl_callbk_dispatch_block(cb, immHandle);
  726       break;
  727 
  728     default:
  729       rc = SA_AIS_ERR_INVALID_PARAM;
  730       break;
  731   } /* switch */
  732 
  733   /* Decrement Dispatch usage count */
  734   cb->pend_dis--;
  735 
  736   /* can't use cb after we do agent shutdown, so copy all counts */
  737   pend_dis = cb->pend_dis;
  738   pend_fin = cb->pend_fin;
  739 
  740 clm_left:
  741 fail:
  742   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  743 
  744   /* see if we are still in any dispact context */
  745   if (pend_dis == 0) {
  746     while (pend_fin != 0) {
  747       /* call agent shutdown,for each finalize done before */
  748       cb->pend_fin--;
  749       imma_shutdown(NCSMDS_SVC_ID_IMMA_OM);
  750       pend_fin--;
  751     }
  752   }
  753 
  754   TRACE_LEAVE();
  755   return rc;
  756 }
  757 
  758 /****************************************************************************
  759   Name          :  saImmOmFinalize
  760 
  761   Description   :  This function closes the association, represented by
  762                    immHandle, between the invoking process and the IMM OM
  763                    Service.
  764 
  765   Arguments     :  immHandle - IMM OM Service handle.
  766 
  767   Return Values :  Refer to SAI-AIS specification for various return values.
  768 
  769   Notes         :
  770 ******************************************************************************/
  771 SaAisErrorT saImmOmFinalize(SaImmHandleT immHandle) {
  772   SaAisErrorT rc = SA_AIS_OK;
  773   IMMA_CB *cb = &imma_cb;
  774   IMMSV_EVT finalize_evt;
  775   IMMSV_EVT *out_evt = NULL;
  776   IMMA_CLIENT_NODE *cl_node = 0;
  777   uint32_t proc_rc = NCSCC_RC_SUCCESS;
  778   bool locked = true;
  779   bool agent_flag = false; /* flag = false, we should not call agent shutdown */
  780   SaTimeT timeout = 0;
  781   TRACE_ENTER();
  782 
  783   if (cb->sv_id == 0) {
  784     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
  785     return SA_AIS_ERR_BAD_HANDLE;
  786   }
  787 
  788   /* No check for immnd_up here because this is finalize, see below. */
  789 
  790   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  791     TRACE_4("ERR_LIBRARY: Lock failed");
  792     rc = SA_AIS_ERR_LIBRARY;
  793     goto lock_fail;
  794   }
  795   /* locked == true already */
  796 
  797   /* get the client_info */
  798   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
  799   if (!(cl_node && cl_node->isOm)) {
  800     rc = SA_AIS_ERR_BAD_HANDLE;
  801     TRACE_2("ERR_BAD_HANDLE: client_node_get failed");
  802     goto node_not_found;
  803   }
  804 
  805   /*Increment before stale check to get uniform stale handling
  806     before and after send (see stale_handle:)
  807   */
  808   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
  809     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
  810     goto bad_sync;
  811   }
  812 
  813   if (cl_node->stale) {
  814     TRACE_1("Handle %llx is stale", immHandle);
  815     rc = SA_AIS_OK; /*Dont punish the client for closing stale handle */
  816     /* Dont try to resurrect since this is finalize. */
  817     cl_node->exposed =
  818         true; /* But dont allow anyone else to resurrect it either */
  819     goto stale_handle;
  820   }
  821 
  822   /* populate the structure */
  823   memset(&finalize_evt, 0, sizeof(IMMSV_EVT));
  824   finalize_evt.type = IMMSV_EVT_TYPE_IMMND;
  825   finalize_evt.info.immnd.type = IMMND_EVT_A2ND_IMM_FINALIZE;
  826   finalize_evt.info.immnd.info.finReq.client_hdl = cl_node->handle;
  827 
  828   timeout = cl_node->syncr_timeout;
  829   /* Unlock before MDS Send */
  830   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  831   locked = false;
  832   cl_node = NULL; /* avoid unsafe use */
  833 
  834   if (cb->is_immnd_up == false) {
  835     TRACE_3("IMMND is DOWN");
  836     /* IF IMMND IS DOWN then we know handle is stale.
  837        Since this is a handle finalize, we simply discard the handle.
  838        No error return!
  839      */
  840     goto stale_handle;
  841   }
  842 
  843   /* send the request to the IMMND */
  844   proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
  845                                    &finalize_evt, &out_evt, timeout);
  846 
  847   /* MDS error handling */
  848   switch (proc_rc) {
  849     case NCSCC_RC_SUCCESS:
  850       break;
  851     case NCSCC_RC_REQ_TIMOUT:
  852       TRACE_3("Got ERR_TIMEOUT in saImmOmFinalize - ignoring");
  853       /* Yes could be a stale handle, but this is handle finalize.
  854          Dont cause unnecessary problems by returnign an error code.
  855          If this is a true timeout caused by an unusually sluggish but
  856          up IMMND, then this connection at the IMMND side may linger,
  857          but on this IMMA side we will drop it.
  858       */
  859       goto stale_handle;
  860 
  861     default:
  862       TRACE_4("ERR_LIBRARY: Mds returned unexpected error code: %u", proc_rc);
  863       rc = SA_AIS_ERR_LIBRARY;
  864       /* We lose the pending reply count in this case but ERR_LIBRARY dominates.
  865        */
  866       goto mds_send_fail;
  867   }
  868 
  869   /* Read the received error (if any)  */
  870   if (out_evt) {
  871     rc = out_evt->info.imma.info.errRsp.error;
  872     free(out_evt);
  873     out_evt = NULL;
  874 
  875     if (rc == SA_AIS_ERR_BAD_HANDLE) {
  876       rc = SA_AIS_OK;
  877       /* Client was already gone in local immnd server, but client node
  878          still present in the imma library. This can happen as a result
  879          of timeout on syncronous downcall. Continue the finalize here
  880          in the library to deallocate the client-node in the library.
  881          No need to disturb the client doing this finalize, return OK.
  882       */
  883     }
  884   } else {
  885     /* rc = SA_AIS_ERR_LIBRARY;
  886        This is a finalize, no point in disturbing the user with
  887        a communication error.
  888     */
  889     TRACE_3("Received empty reply from server");
  890   }
  891 
  892 stale_handle:
  893   /* Do the finalize processing at IMMA */
  894   if (rc == SA_AIS_OK) {
  895     /* Take the CB lock  */
  896     if (!locked &&
  897         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
  898       rc = SA_AIS_ERR_LIBRARY;
  899       /* Losing track of the pending reply count, but ERR_LIBRARY dominates*/
  900       TRACE_4("ERR_LIBRARY: Lock failed");
  901       goto lock_fail1;
  902     }
  903 
  904     locked = true;
  905 
  906     /* get the client_info */
  907     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
  908     if (!(cl_node && cl_node->isOm)) {
  909       /*rc = SA_AIS_ERR_BAD_HANDLE; This is finalize.*/
  910       TRACE_3("client_node_get failed");
  911       goto node_not_found;
  912     }
  913 
  914     if (cl_node->stale) {
  915       TRACE_3("Handle %llx is stale", immHandle);
  916       /*Dont punish the client for closing stale handle rc == SA_AIS_OK */
  917 
  918       cl_node->exposed = true; /* But dont resurrect it either */
  919     }
  920 
  921     imma_proc_decrement_pending_reply(cl_node, true);
  922     imma_finalize_client(cb, cl_node);
  923     /* Finalize the environment */
  924     if (cb->pend_dis == 0) {
  925       agent_flag = true;
  926     } else if (cb->pend_dis > 0) {
  927       cb->pend_fin++;
  928     }
  929   }
  930 
  931 lock_fail1:
  932 mds_send_fail:
  933 node_not_found:
  934 bad_sync:
  935   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
  936 
  937 lock_fail:
  938   /* we are not in any dispatch context, we can do agent shutdown */
  939   if ((agent_flag == true) && (rc == SA_AIS_OK) &&
  940       (NCSCC_RC_SUCCESS != imma_shutdown(NCSMDS_SVC_ID_IMMA_OM))) {
  941     TRACE_4("ERR_LIBRARY: Call to imma_shutdown failed");
  942     rc = SA_AIS_ERR_LIBRARY;
  943   }
  944   TRACE_LEAVE();
  945   return rc;
  946 }
  947 
  948 /****************************************************************************
  949   Name          :  saImmOmAdminOwnerInitialize
  950 
  951   Description   :  Initialize an admin owner handle.
  952                    This a blocking syncronous call.
  953 
  954 
  955   Arguments     :  immHandle - IMM OM handle
  956                    adminOwnerName - The name of the admin owner.
  957                    releaseOwnershipOnFinalize - se the IMM spec.
  958                    adminOwnerHandle - The handle that is returned.
  959 
  960   Return Values :  Refer to SAI-AIS specification for various return values.
  961 
  962   Notes         :
  963 ******************************************************************************/
  964 SaAisErrorT saImmOmAdminOwnerInitialize(
  965     SaImmHandleT immHandle, const SaImmAdminOwnerNameT adminOwnerName,
  966     SaBoolT releaseOwnershipOnFinalize,
  967     SaImmAdminOwnerHandleT *adminOwnerHandle) {
  968   SaAisErrorT rc = SA_AIS_OK;
  969   IMMA_CB *cb = &imma_cb;
  970   IMMSV_EVT evt;
  971   IMMSV_EVT *out_evt = NULL;
  972   IMMA_CLIENT_NODE *cl_node = NULL;
  973   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
  974   SaUint32T proc_rc = NCSCC_RC_SUCCESS;
  975   bool locked = true;
  976   bool isLoaderName = false;
  977   SaUint32T nameLen = 0;
  978   SaTimeT timeout = 0;
  979   TRACE_ENTER();
  980 
  981   if (cb->sv_id == 0) {
  982     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
  983     return SA_AIS_ERR_BAD_HANDLE;
  984   }
  985 
  986   if ((adminOwnerHandle == NULL) || (adminOwnerName == NULL) ||
  987       ((nameLen = strlen(adminOwnerName)) == 0)) {
  988     TRACE_2(
  989         "ERR_INVALID_PARAM: 'adminOwnerHandle is NULL, or adminOwnerName is NULL, or adminOwnerName "
  990         "has zero length");
  991     return SA_AIS_ERR_INVALID_PARAM;
  992   }
  993 
  994   if (releaseOwnershipOnFinalize && (releaseOwnershipOnFinalize != 1)) {
  995     TRACE_2("ERR_INVALID_PARAM: releaseOwnershipOnFinalize must be 1 or 0");
  996     return SA_AIS_ERR_INVALID_PARAM;
  997   }
  998 
  999   if (nameLen >= IMMSV_MAX_ADMO_NAME_LENGTH) {
 1000     TRACE_2("ERR_INVALID_PARAM: Admin owner name too long, size: %u max:%u",
 1001             nameLen, IMMSV_MAX_ADMO_NAME_LENGTH - 1);
 1002     return SA_AIS_ERR_INVALID_PARAM;
 1003   }
 1004 
 1005   if (cb->is_immnd_up == false) {
 1006     TRACE_2("ERR_TRY_AGAIN: IMMND is DOWN");
 1007     return SA_AIS_ERR_TRY_AGAIN;
 1008   }
 1009 
 1010   *adminOwnerHandle = 0;
 1011   isLoaderName = (memcmp(adminOwnerName, immLoaderName, nameLen) == 0);
 1012 
 1013   /* get the CB Lock */
 1014   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1015     rc = SA_AIS_ERR_LIBRARY;
 1016     TRACE_4("ERR_LIBRARY: Lock failed");
 1017     goto lock_fail;
 1018   }
 1019 
 1020   /*locked == true already */
 1021 
 1022   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1023   if (!(cl_node && cl_node->isOm)) {
 1024     rc = SA_AIS_ERR_BAD_HANDLE;
 1025     TRACE_2("ERR_BAD_HANDLE: client_node_get failed");
 1026     goto bad_handle;
 1027   }
 1028   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 1029     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 1030     rc = SA_AIS_ERR_UNAVAILABLE;
 1031     goto clm_left;
 1032   }
 1033 
 1034   if (cl_node->stale) {
 1035     TRACE_1("Handle %llx is stale", immHandle);
 1036     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 1037 
 1038     if (!locked &&
 1039         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1040       TRACE_4("ERR_LIBRARY: LOCK failed");
 1041       rc = SA_AIS_ERR_LIBRARY;
 1042       goto lock_fail;
 1043     }
 1044     locked = true;
 1045 
 1046     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1047 
 1048     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 1049       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 1050               immHandle);
 1051       if (cl_node && cl_node->stale) {
 1052         cl_node->exposed = true;
 1053       }
 1054       rc = SA_AIS_ERR_BAD_HANDLE;
 1055       goto bad_handle;
 1056     }
 1057 
 1058     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 1059   }
 1060 
 1061   /* Allocate the IMMA_ADMIN_OWNER_NODE & Populate */
 1062   ao_node = (IMMA_ADMIN_OWNER_NODE *)calloc(1, sizeof(IMMA_ADMIN_OWNER_NODE));
 1063   if (ao_node == NULL) {
 1064     rc = SA_AIS_ERR_NO_MEMORY;
 1065     TRACE_4("ERR_MEMORY: Memory allocation error");
 1066     goto ao_node_alloc_fail;
 1067   }
 1068 
 1069   ao_node->admin_owner_hdl = (SaImmAdminOwnerHandleT)m_NCS_GET_TIME_NS;
 1070   /*This is the external handle that the application uses.
 1071     Internally we use the gloablId provided by the director. */
 1072 
 1073   ao_node->mImmHandle = immHandle;
 1074 
 1075   /* Populate & Send the Event to IMMND */
 1076   memset(&evt, 0, sizeof(IMMSV_EVT));
 1077   evt.type = IMMSV_EVT_TYPE_IMMND;
 1078   evt.info.immnd.type = IMMND_EVT_A2ND_IMM_ADMINIT;
 1079   evt.info.immnd.info.adminitReq.client_hdl = immHandle;
 1080   osaf_extended_name_alloc(adminOwnerName,
 1081                            &evt.info.immnd.info.adminitReq.i.adminOwnerName);
 1082   if (releaseOwnershipOnFinalize) {
 1083     evt.info.immnd.info.adminitReq.i.releaseOwnershipOnFinalize = true;
 1084     /* Release on finalize can not be undone in case of IMMND crash.
 1085        The om-handle can then not be resurrected unless this admin-owner
 1086        has been finalized before the IMMND crash.
 1087     */
 1088     ao_node->mReleaseOnFinalize = true;
 1089   }
 1090 
 1091   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 1092     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 1093     goto admin_owner_node_free;
 1094   }
 1095   timeout = cl_node->syncr_timeout;
 1096 
 1097   /* Unlock before MDS Send */
 1098   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1099   locked = false;
 1100   cl_node = NULL; /* Prevent unsafe use. */
 1101 
 1102   if (cb->is_immnd_up == false) {
 1103     rc = SA_AIS_ERR_TRY_AGAIN;
 1104     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 1105     goto mds_send_fail;
 1106   }
 1107 
 1108   /* Send the evt to IMMND */
 1109   proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 1110                                    &evt, &out_evt, timeout);
 1111   /* Generate rc from proc_rc */
 1112   switch (proc_rc) {
 1113     case NCSCC_RC_SUCCESS:
 1114       break;
 1115     case NCSCC_RC_REQ_TIMOUT:
 1116       rc = imma_proc_check_stale(cb, immHandle, SA_AIS_ERR_TIMEOUT);
 1117       break; /* i.e. goto mds_send_fail */
 1118     default:
 1119       rc = SA_AIS_ERR_LIBRARY;
 1120       TRACE_4("ERR_LIBRARY: MDS returned unexpected error code %u", proc_rc);
 1121       /* Losing track of the pending reply count, but ERR_LIBRARY dominates*/
 1122       goto admin_owner_node_free;
 1123   }
 1124 
 1125 mds_send_fail:
 1126   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1127     rc = SA_AIS_ERR_LIBRARY;
 1128     TRACE_4("ERR_LIBRARY: Lock failed");
 1129     /* Losing track of the pending reply count, but ERR_LIBRARY dominates*/
 1130     goto admin_owner_node_free;
 1131   }
 1132   locked = true;
 1133 
 1134   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1135   if (!(cl_node && cl_node->isOm)) {
 1136     rc = SA_AIS_ERR_BAD_HANDLE;
 1137     TRACE_3("ERR_BAD_HANDLE: client_node_get failed after down-call");
 1138     goto admin_owner_node_free;
 1139   }
 1140 
 1141   imma_proc_decrement_pending_reply(cl_node, true);
 1142 
 1143   if (cl_node->stale) {
 1144     if (isExposed(cb, cl_node)) {
 1145       TRACE_3("ERR_BAD_HANDLE: Handle %llx became stale and exposed",
 1146               immHandle);
 1147       rc = SA_AIS_ERR_BAD_HANDLE;
 1148     } else {
 1149       TRACE_3(
 1150           "ERR_TRY_AGAIN: Handle %llx became stale but possible to resurrect",
 1151           immHandle);
 1152       /* Can override BAD_HANDLE/TIMEOUT set by check_stale */
 1153       rc = SA_AIS_ERR_TRY_AGAIN;
 1154     }
 1155     goto admin_owner_node_free;
 1156   }
 1157 
 1158   if (rc != SA_AIS_OK) {
 1159     TRACE_2("Error already set %u", rc);
 1160     goto admin_owner_node_free;
 1161   }
 1162 
 1163   if (out_evt) {
 1164     /* Process the received Event */
 1165     rc = out_evt->info.imma.info.admInitRsp.error;
 1166     if (rc == SA_AIS_OK) {
 1167       ao_node->mAdminOwnerId = out_evt->info.imma.info.admInitRsp.ownerId;
 1168       ao_node->mAdminOwnerName = (char *)calloc(1, nameLen + 1);
 1169       strncpy(ao_node->mAdminOwnerName, adminOwnerName, nameLen + 1);
 1170     } else {
 1171       goto admin_owner_node_free;
 1172     }
 1173   } else {
 1174     TRACE_4("ERR_LIBRARY: Empty reply message for AdminOwnerInitialize");
 1175     rc = SA_AIS_ERR_LIBRARY;
 1176     goto admin_owner_node_free;
 1177   }
 1178 
 1179   do {
 1180     proc_rc = imma_admin_owner_node_add(&cb->admin_owner_tree, ao_node);
 1181 
 1182     if (proc_rc != NCSCC_RC_SUCCESS) {
 1183       IMMA_ADMIN_OWNER_NODE *ao_node_tmp = NULL;
 1184       imma_admin_owner_node_get(&cb->admin_owner_tree,
 1185                                 &(ao_node->admin_owner_hdl), &ao_node_tmp);
 1186       if (!ao_node_tmp) {
 1187         LOG_NO("Failed to add node to the admin owner tree - aborting");
 1188         abort();
 1189       }
 1190       ao_node->admin_owner_hdl++;
 1191       TRACE_4(
 1192           "Duplicate admin owner handle %llu (poor clock resolution) adjusting it to %llu",
 1193           ao_node_tmp->admin_owner_hdl, ao_node->admin_owner_hdl);
 1194     }
 1195   } while (proc_rc != NCSCC_RC_SUCCESS);
 1196 
 1197   *adminOwnerHandle = ao_node->admin_owner_hdl;
 1198 
 1199   if (isLoaderName) {
 1200     TRACE_1("This appears to be a LOADER client");
 1201     immOmIsLoader = true;
 1202   }
 1203 
 1204   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1205 
 1206   free(out_evt);
 1207   out_evt = NULL;
 1208 
 1209   TRACE_1("Admin owner init successful");
 1210   TRACE_LEAVE();
 1211   return SA_AIS_OK;
 1212 
 1213 /* Error Handling */
 1214 
 1215 admin_owner_node_free:
 1216   if (ao_node != NULL) {
 1217     free(ao_node);
 1218     ao_node = NULL;
 1219   }
 1220 
 1221 ao_node_alloc_fail:
 1222 /* Do Nothing */
 1223 
 1224 clm_left:
 1225 bad_handle:
 1226   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1227 
 1228 lock_fail:
 1229   if (out_evt) free(out_evt);
 1230   TRACE_1("Returning with FAILURE:%u", rc);
 1231   TRACE_LEAVE();
 1232   return rc;
 1233 }
 1234 
 1235 /*******************************************************************
 1236  * imma_newCcbId internal function
 1237  *
 1238  * NOTE: The CB must be LOCKED on entry of this function!!
 1239  *       It will normally be locked on exit, as reflected in the 'locked'
 1240  *       in/out parameter. If SA_AIS_OK is returned, then ccb_node
 1241  *       is still valid and locked is true.
 1242  *       The ccb_node must be in state mApplied == true, that is it must
 1243  *       either be a pristine ccb_node or an old ccb_node where the previous
 1244  *       CCB was successfully applied. If the previous CCB was aborted
 1245  *       by the system (ERR_FAILED_OPERATION), then ccb-chaining is no
 1246  *       longer possible with the same ccb_node/ccbHandle.
 1247  *******************************************************************/
 1248 static SaAisErrorT imma_newCcbId(IMMA_CB *cb, IMMA_CCB_NODE *ccb_node,
 1249                                  SaUint32T adminOwnerId, bool *locked,
 1250                                  SaTimeT timeout) {
 1251   SaAisErrorT rc = SA_AIS_OK;
 1252   SaUint32T proc_rc = NCSCC_RC_SUCCESS;
 1253   IMMSV_EVT evt;
 1254   IMMSV_EVT *out_evt = NULL;
 1255   IMMA_CCB_NODE *old_ccb_node = NULL;
 1256   SaImmHandleT immHandle = ccb_node->mImmHandle;
 1257   SaImmCcbHandleT ccbHandle = ccb_node->ccb_hdl;
 1258   SaUint32T ccbId = 0;
 1259 
 1260   TRACE_ENTER();
 1261   TRACE("imma_newCcbId:create new ccb id with admoId:%u", adminOwnerId);
 1262 
 1263   osafassert(locked && *locked);
 1264 
 1265   if (ccb_node->mAborted) {
 1266     rc = SA_AIS_ERR_FAILED_OPERATION;
 1267     goto fail;
 1268   }
 1269 
 1270   if (ccb_node->mAugCcb) {
 1271     rc = SA_AIS_ERR_BAD_OPERATION;
 1272     goto fail;
 1273   }
 1274 
 1275   osafassert(ccb_node->mApplied);
 1276   ccb_node->mCcbId = 0;
 1277 
 1278   /* Guard against race with ourselves. */
 1279   if (ccb_node->mExclusive) {
 1280     rc = SA_AIS_ERR_TRY_AGAIN;
 1281     goto fail;
 1282   }
 1283   ccb_node->mExclusive = true;
 1284 
 1285   /* Populate & Send the Open Event to IMMND */
 1286   memset(&evt, 0, sizeof(IMMSV_EVT));
 1287   evt.type = IMMSV_EVT_TYPE_IMMND;
 1288   evt.info.immnd.type = IMMND_EVT_A2ND_CCBINIT;
 1289   evt.info.immnd.info.ccbinitReq.client_hdl = immHandle;
 1290   evt.info.immnd.info.ccbinitReq.adminOwnerId = adminOwnerId;
 1291   evt.info.immnd.info.ccbinitReq.ccbFlags = ccb_node->mCcbFlags;
 1292 
 1293   TRACE("Sending request for new ccbid with admin OwnerId:%u", adminOwnerId);
 1294 
 1295   /* Unlock before MDS Send */
 1296   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1297   *locked = false;
 1298   old_ccb_node = ccb_node;
 1299   ccb_node = NULL; /* avoid unsafe use */
 1300 
 1301   /* IMMND GOES DOWN */
 1302   if (cb->is_immnd_up == false) {
 1303     rc = SA_AIS_ERR_NO_RESOURCES;
 1304     TRACE_3("ERR_NO_RESOURCES: IMMND is DOWN");
 1305     goto mds_send_fail;
 1306   }
 1307 
 1308   /* Send the evt to IMMND */
 1309   proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &(cb->immnd_mds_dest),
 1310                                    &evt, &out_evt, timeout);
 1311   /* Generate rc from proc_rc */
 1312   switch (proc_rc) {
 1313     case NCSCC_RC_SUCCESS:
 1314       break;
 1315     case NCSCC_RC_REQ_TIMOUT:
 1316       rc = imma_proc_check_stale(cb, immHandle, SA_AIS_ERR_TIMEOUT);
 1317       goto mds_send_fail;
 1318     default:
 1319       rc = SA_AIS_ERR_LIBRARY;
 1320       TRACE_4("ERR_LIBRARY: MDS returned unexpected error code %u", proc_rc);
 1321       goto mds_send_fail;
 1322   }
 1323 
 1324   osafassert(out_evt);
 1325   /* Process the received Event */
 1326   osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 1327   osafassert(out_evt->info.imma.type == IMMA_EVT_ND2A_CCBINIT_RSP);
 1328   rc = out_evt->info.imma.info.ccbInitRsp.error;
 1329   ccbId = out_evt->info.imma.info.ccbInitRsp.ccbId;
 1330   /* Free the out event */
 1331   free(out_evt);
 1332   out_evt = NULL;
 1333 
 1334 mds_send_fail:
 1335   /* Take the CB lock */
 1336   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1337     rc = SA_AIS_ERR_LIBRARY;
 1338     TRACE_4("ERR_LIBRARY: Lock failed");
 1339     if (out_evt) {
 1340       free(out_evt);
 1341       out_evt = NULL;
 1342     }
 1343     goto fail;
 1344   }
 1345   *locked = true;
 1346 
 1347   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 1348   if (!ccb_node) {
 1349     TRACE_4(
 1350         "ERR_LIBRARY: Ccb node gone, ccb_node->mExclusive not respected by "
 1351         "another thread ?");
 1352     rc = SA_AIS_ERR_LIBRARY;
 1353     goto fail;
 1354   }
 1355 
 1356   /* It should not be possible that the ccb_node was replaced. */
 1357   osafassert(ccb_node == old_ccb_node);
 1358 
 1359   ccb_node->mExclusive = false;
 1360 
 1361   if (rc == SA_AIS_OK) {
 1362     ccb_node->mApplied = false;
 1363     ccb_node->mCcbId = ccbId;
 1364     TRACE("CcbId:%u admin ownerId:%u\n", ccb_node->mCcbId, adminOwnerId);
 1365   }
 1366 
 1367 fail:
 1368   TRACE_LEAVE();
 1369   return rc;
 1370 }
 1371 
 1372 /****************************************************************************
 1373   Name          :  saImmOmCcbInitialize
 1374 
 1375   Description   :  Initialize an admin owner handle.
 1376                    This a blocking syncronous call.
 1377 
 1378 
 1379   Arguments     :  adminOwnerHandle - The handle for the admin owner to
 1380                                       which the Ccb will be associated.
 1381                    ccbFlags         - Refer to the SA_AIS_IMM specification
 1382                                       for explanation.
 1383                    ccbHandle        - The address of a Ccb handle which
 1384                                       will be initialized.
 1385 
 1386   Return Values :  Refer to SAI-AIS specification for various return values.
 1387 
 1388   Notes         :
 1389 ******************************************************************************/
 1390 SaAisErrorT saImmOmCcbInitialize(SaImmAdminOwnerHandleT adminOwnerHandle,
 1391                                  SaImmCcbFlagsT ccbFlags,
 1392                                  SaImmCcbHandleT *ccbHandle) {
 1393   SaAisErrorT rc = SA_AIS_OK;
 1394   SaUint32T proc_rc = NCSCC_RC_SUCCESS;
 1395   IMMA_CB *cb = &imma_cb;
 1396   IMMA_CLIENT_NODE *cl_node = NULL;
 1397   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 1398   IMMA_CCB_NODE *ccb_node = NULL;
 1399   bool locked = false;
 1400   SaImmHandleT immHandle = 0LL;
 1401   SaUint32T adminOwnerId = 0;
 1402   TRACE_ENTER();
 1403 
 1404   if (cb->sv_id == 0) {
 1405     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 1406     return SA_AIS_ERR_BAD_HANDLE;
 1407   }
 1408 
 1409   if (ccbHandle == NULL) {
 1410     return SA_AIS_ERR_INVALID_PARAM;
 1411   }
 1412 
 1413   *ccbHandle = 0LL; /* User may have forgotten to initialize to zero */
 1414 
 1415   if (cb->is_immnd_up == false) {
 1416     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 1417     return SA_AIS_ERR_TRY_AGAIN;
 1418   }
 1419 
 1420   /* get the CB Lock */
 1421   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1422     rc = SA_AIS_ERR_LIBRARY;
 1423     TRACE_4("ERR_LIBRARY: Lock failed");
 1424     goto done;
 1425   }
 1426   locked = true;
 1427 
 1428   imma_admin_owner_node_get(&cb->admin_owner_tree, &adminOwnerHandle, &ao_node);
 1429   if (!ao_node) {
 1430     TRACE_2("ERR_BAD_HANDLE: Admin owner handle not valid");
 1431     rc = SA_AIS_ERR_BAD_HANDLE;
 1432     goto done;
 1433   }
 1434 
 1435   immHandle = ao_node->mImmHandle;
 1436   adminOwnerId = ao_node->mAdminOwnerId;
 1437   /* Dont trust adminOwnerId just yet, resurrect possible. See *** below */
 1438   ao_node = NULL;
 1439 
 1440   /* Look up client node also to verify that the client handle is still active.
 1441    */
 1442   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1443   if (!(cl_node && cl_node->isOm)) {
 1444     rc = SA_AIS_ERR_LIBRARY;
 1445     TRACE_4("ERR_LIBRARY: No client associated with Admin Owner");
 1446     goto done;
 1447   }
 1448 
 1449   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 1450     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 1451     rc = SA_AIS_ERR_UNAVAILABLE;
 1452     goto clm_left;
 1453   }
 1454 
 1455   if (cl_node->stale) {
 1456     TRACE_1("IMM Handle %llx is stale", immHandle);
 1457     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 1458     cl_node = NULL;
 1459 
 1460     if (!locked &&
 1461         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1462       TRACE_4("ERR_LIBRARY: LOCK failed");
 1463       rc = SA_AIS_ERR_LIBRARY;
 1464       goto done;
 1465     }
 1466     locked = true;
 1467 
 1468     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1469 
 1470     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 1471       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 1472               immHandle);
 1473       if (cl_node && cl_node->stale) {
 1474         cl_node->exposed = true;
 1475       }
 1476       rc = SA_AIS_ERR_BAD_HANDLE;
 1477       goto done;
 1478     }
 1479 
 1480     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 1481 
 1482     /* Look up admin owner again since successful resurrect implies
 1483        new admin-owner-id ! */
 1484     imma_admin_owner_node_get(&cb->admin_owner_tree, &adminOwnerHandle,
 1485                               &ao_node);
 1486     if (!ao_node) {
 1487       TRACE_3("ERR_LIBRARY: Admin owner node dissapeared during resurrect");
 1488       rc = SA_AIS_ERR_LIBRARY;
 1489       /* Very strange case, resurrect succeeded yet admin owner node is gone. */
 1490       goto done;
 1491     }
 1492     TRACE_1("Admin-owner-id should have changed(?) Before: %u After: %u",
 1493             adminOwnerId, ao_node->mAdminOwnerId);
 1494     adminOwnerId = ao_node->mAdminOwnerId; /* *** */
 1495     ao_node = NULL;
 1496   }
 1497 
 1498   if (ccbFlags) {
 1499     SaImmCcbFlagsT ccbFlagsTmp = ccbFlags;
 1500 
 1501     if (ccbFlagsTmp & SA_IMM_CCB_REGISTERED_OI) {
 1502       TRACE("SA_IMM_CCB_REGISTERED_OI is set");
 1503       ccbFlagsTmp &= ~SA_IMM_CCB_REGISTERED_OI;
 1504       if (ccbFlagsTmp & SA_IMM_CCB_ALLOW_NULL_OI) {
 1505         TRACE("SA_IMM_CCB_ALLOW_NULL_OI is set");
 1506         if (!(cl_node->isImmA2b)) {
 1507           TRACE(
 1508               "ERR_VERSION: SA_IMM_CCB_ALLOW_NULL_OI"
 1509               "requires IMM version A.02.11");
 1510           rc = SA_AIS_ERR_VERSION;
 1511           goto done;
 1512         }
 1513 
 1514         ccbFlagsTmp &= ~SA_IMM_CCB_ALLOW_NULL_OI;
 1515       }
 1516     }
 1517 
 1518     if (ccbFlagsTmp) {
 1519       TRACE("ERR_INVALID_PARAM: Unknon flags in ccbFlags: 0x%llx", ccbFlags);
 1520       rc = SA_AIS_ERR_INVALID_PARAM;
 1521       goto done;
 1522     }
 1523   }
 1524 
 1525   /* Allocate the IMMA_CCB_NODE & Populate */
 1526 
 1527   ccb_node = (IMMA_CCB_NODE *)calloc(1, sizeof(IMMA_CCB_NODE));
 1528   if (ccb_node == NULL) {
 1529     rc = SA_AIS_ERR_NO_MEMORY;
 1530     TRACE_4("ERR_NO_MEMORY: Memory allocation failure");
 1531     goto done;
 1532   }
 1533 
 1534   ccb_node->ccb_hdl = (SaImmCcbHandleT)m_NCS_GET_TIME_NS;
 1535   /*This is the external handle that the application uses.
 1536      Internally we use the gloablId provided by the Director. */
 1537 
 1538   do {
 1539     proc_rc = imma_ccb_node_add(&cb->ccb_tree, ccb_node);
 1540 
 1541     if (proc_rc != NCSCC_RC_SUCCESS) {
 1542       IMMA_CCB_NODE *ccb_node_tmp = NULL;
 1543       imma_ccb_node_get(&cb->ccb_tree, &(ccb_node->ccb_hdl), &ccb_node_tmp);
 1544       if (!ccb_node_tmp) {
 1545         LOG_NO("Failed to add ccb-node to ccb-tree - aborting");
 1546         abort();
 1547       }
 1548       ccb_node->ccb_hdl++;
 1549       TRACE_4(
 1550           "Duplicate ccb handle %llu (poor clock resolution) adjusting it to %llu",
 1551           ccb_node_tmp->ccb_hdl, ccb_node->ccb_hdl);
 1552     }
 1553   } while (proc_rc != NCSCC_RC_SUCCESS);
 1554 
 1555   ccb_node->mCcbFlags = ccbFlags; /*Save flags in client for repeated init */
 1556   ccb_node->mImmHandle = immHandle;
 1557   ccb_node->mAdminOwnerHdl = adminOwnerHandle;
 1558   ccb_node->mApplied = true;
 1559 
 1560   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 1561     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 1562     goto remove_ccb_node;
 1563   }
 1564 
 1565   rc = imma_newCcbId(cb, ccb_node, adminOwnerId, &locked,
 1566                      cl_node->syncr_timeout);
 1567   cl_node = NULL;
 1568   /* ccb_node still valid if rc == SA_AIS_OK. */
 1569   if (rc == SA_AIS_OK) {
 1570     osafassert(!(ccb_node->mExclusive));
 1571     osafassert(locked);
 1572   }
 1573 
 1574   if (!locked) {
 1575     if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1576       rc = SA_AIS_ERR_LIBRARY;
 1577       /* Loses track of pending reply count, but ERR_LIBRARY dominates */
 1578       TRACE_4("ERR_LIBRARY: Lock failed");
 1579       goto done;
 1580     }
 1581     locked = true;
 1582   }
 1583 
 1584   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1585   if (!(cl_node && cl_node->isOm)) {
 1586     rc = SA_AIS_ERR_BAD_HANDLE;
 1587     TRACE_3("ERR_BAD_HANDLE: Client node not found after down call");
 1588     goto remove_ccb_node;
 1589   }
 1590 
 1591   imma_proc_decrement_pending_reply(cl_node, true);
 1592   if (rc == SA_AIS_ERR_LIBRARY) {
 1593     goto done;
 1594   }
 1595 
 1596   if (cl_node->stale) {
 1597     if (isExposed(cb, cl_node)) {
 1598       TRACE_3("ERR_BAD_HANDLE: IMM Handle %llx became stale during down-call",
 1599               immHandle);
 1600       rc = SA_AIS_ERR_BAD_HANDLE;
 1601     } else {
 1602       TRACE_3(
 1603           "ERR_TRY_AGAIN: Handle %llx became stale but possible to resurrect",
 1604           immHandle);
 1605       /* Can override BAD_HANDLE/TIMEOUT set in check_stale
 1606          A retry attempt may succeed in resurrecting immhandle/adminowner
 1607          and obtain a fresh ccb-id.
 1608       */
 1609       rc = SA_AIS_ERR_TRY_AGAIN;
 1610     }
 1611   }
 1612 
 1613 remove_ccb_node:
 1614   if (rc == SA_AIS_OK) {
 1615     *ccbHandle = ccb_node->ccb_hdl;
 1616   } else {
 1617     osafassert(rc != SA_AIS_ERR_LIBRARY);
 1618     imma_ccb_node_delete(cb, ccb_node); /*Remove node from tree and free it. */
 1619     ccb_node = NULL;
 1620   }
 1621 
 1622 clm_left:
 1623 done:
 1624   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 1625 
 1626   TRACE_LEAVE();
 1627   return rc;
 1628 }
 1629 
 1630 /****************************************************************************
 1631   Name          :  saImmOmCcbObjectCreate/_2
 1632 
 1633   Description   :  Creates a config object in the IMM.
 1634                    This a blocking syncronous call.
 1635 
 1636 
 1637   Arguments     :  ccbHandle - Ccb Handle
 1638                    className - A pointer to the name of the class of the object
 1639                    parentName - A pointer to the name of the parent.
 1640                    attrValues - Initial values for some attributes.
 1641 
 1642   Return Values :  Refer to SAI-AIS specification for various return values.
 1643 ******************************************************************************/
 1644 static SaAisErrorT ccb_object_create_common(
 1645     SaImmCcbHandleT ccbHandle, const SaImmClassNameT className,
 1646     const SaNameT *parentName, const SaConstStringT objectName,
 1647     const SaImmAttrValuesT_2 **attrValues);
 1648 
 1649 SaAisErrorT saImmOmCcbObjectCreate_2(SaImmCcbHandleT ccbHandle,
 1650                                      const SaImmClassNameT className,
 1651                                      const SaNameT *parentName,
 1652                                      const SaImmAttrValuesT_2 **attrValues) {
 1653   if (attrValues == NULL) {
 1654     TRACE_2("ERR_INVALID_PARAM: attrValues is NULL");
 1655     return SA_AIS_ERR_INVALID_PARAM;
 1656   }
 1657 
 1658   return ccb_object_create_common(ccbHandle, className, parentName, NULL,
 1659                                   attrValues);
 1660 }
 1661 
 1662 SaAisErrorT saImmOmCcbObjectCreate_o3(SaImmCcbHandleT ccbHandle,
 1663                                       const SaImmClassNameT className,
 1664                                       const SaConstStringT objectName,
 1665                                       const SaImmAttrValuesT_2 **attrValues) {
 1666   if (objectName == NULL) {
 1667     TRACE_2("ERR_INVALID_PARAM: objectName is NULL");
 1668     return SA_AIS_ERR_INVALID_PARAM;
 1669   }
 1670 
 1671   return ccb_object_create_common(ccbHandle, className, NULL, objectName,
 1672                                   attrValues);
 1673 }
 1674 
 1675 static SaAisErrorT ccb_object_create_common(
 1676     SaImmCcbHandleT ccbHandle, const SaImmClassNameT className,
 1677     const SaNameT *parentName, const SaConstStringT objectName,
 1678     const SaImmAttrValuesT_2 **attrValues) {
 1679   SaAisErrorT rc = SA_AIS_OK;
 1680   IMMA_CB *cb = &imma_cb;
 1681   IMMSV_EVT evt;
 1682   IMMSV_EVT *out_evt = NULL;
 1683   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 1684   IMMA_CLIENT_NODE *cl_node = NULL;
 1685   IMMA_CCB_NODE *ccb_node = NULL;
 1686   bool locked = false;
 1687   SaImmHandleT immHandle = 0LL;
 1688   SaUint32T adminOwnerId = 0;
 1689   SaStringT *newErrorStrings = NULL;
 1690   size_t parentNameLength = 0;
 1691   TRACE_ENTER();
 1692 
 1693   if (cb->sv_id == 0) {
 1694     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 1695     return SA_AIS_ERR_BAD_HANDLE;
 1696   }
 1697 
 1698   if (className == NULL) {
 1699     TRACE_2("ERR_INVALID_PARAM: classname is NULL");
 1700     TRACE_LEAVE();
 1701     return SA_AIS_ERR_INVALID_PARAM;
 1702   }
 1703 
 1704   if (objectName && !objectName[0]) {
 1705     TRACE_2("ERR_INVALID_PARAM: Object name cannot be empty string");
 1706     TRACE_LEAVE();
 1707     return SA_AIS_ERR_INVALID_PARAM;
 1708   }
 1709 
 1710   if (cb->is_immnd_up == false) {
 1711     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 1712     /* ##1## Any on going ccb has been aborted and this will be detected
 1713        in resurrect processing. But this could be the first operation
 1714        attempted for a new ccb-id, i.e. there is no on-going ccb-id.
 1715        In that case resurrection may succeed.
 1716        (A ccb-handle is associated with a chain of actual ccb-ids).
 1717     */
 1718     return SA_AIS_ERR_TRY_AGAIN;
 1719   }
 1720 
 1721   /* get the CB Lock */
 1722   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1723     rc = SA_AIS_ERR_LIBRARY;
 1724     TRACE_4("ERR_LIBRARY: Lock failed");
 1725     goto lock_fail;
 1726   }
 1727   locked = true;
 1728 
 1729   /* Get the CCB info */
 1730   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 1731   if (!ccb_node) {
 1732     rc = SA_AIS_ERR_BAD_HANDLE;
 1733     TRACE_2("ERR_BAD_HANDLE: Ccb handle not valid");
 1734     goto done;
 1735   }
 1736 
 1737   if (ccb_node->mExclusive) {
 1738     rc = SA_AIS_ERR_TRY_AGAIN;
 1739     TRACE_3(
 1740         "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, in another thread",
 1741         ccb_node->mCcbId);
 1742     goto done;
 1743   }
 1744 
 1745   if (ccb_node->mAborted) {
 1746     TRACE_2("ERR_FAILED_OPERATION: CCB %u has already been aborted",
 1747             ccb_node->mCcbId);
 1748     rc = SA_AIS_ERR_FAILED_OPERATION;
 1749     goto done;
 1750   }
 1751 
 1752   immHandle = ccb_node->mImmHandle;
 1753 
 1754   /* Free string from previous ccb-op */
 1755   imma_free_errorStrings(ccb_node->mErrorStrings);
 1756   ccb_node->mErrorStrings = NULL;
 1757 
 1758   /*Look up client node also, to verify that the client handle
 1759      is still active. */
 1760   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1761   if (!(cl_node && cl_node->isOm)) {
 1762     rc = SA_AIS_ERR_LIBRARY;
 1763     TRACE_4("ERR_LIBRARY: SaImmHandleT associated with Ccb is not valid");
 1764     goto done;
 1765   }
 1766 
 1767   if (objectName && !cl_node->isImmA2f) {
 1768     rc = SA_AIS_ERR_VERSION;
 1769     TRACE_2(
 1770         "ERR_VERSION: saImmOmCcbObjectCreate_o3 only supported for "
 1771         "A.02.15 and above");
 1772     goto done;
 1773   }
 1774   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 1775     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 1776     rc = SA_AIS_ERR_UNAVAILABLE;
 1777     goto clm_left;
 1778   }
 1779 
 1780   if (cl_node->stale) {
 1781     TRACE_1("IMM Handle %llx is stale", immHandle);
 1782 
 1783     /* Why do we bother trying resurrect? See ##1## above. */
 1784 
 1785     if (!(ccb_node->mApplied)) {
 1786       TRACE_3(
 1787           "ERR_FAILED_OPERATION: IMMND DOWN discards ccb "
 1788           "in active but non-critical state");
 1789       ccb_node->mAborted = true;
 1790       rc = SA_AIS_ERR_FAILED_OPERATION;
 1791       /* We drop the resurrect task since this ccb is doomed. */
 1792       goto done;
 1793     }
 1794 
 1795     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 1796     cl_node = NULL;
 1797     ccb_node = NULL;
 1798 
 1799     if (!locked &&
 1800         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1801       TRACE_4("ERR_LIBRARY: LOCK failed");
 1802       rc = SA_AIS_ERR_LIBRARY;
 1803       goto done;
 1804     }
 1805     locked = true;
 1806 
 1807     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1808 
 1809     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 1810       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 1811               immHandle);
 1812       if (cl_node && cl_node->stale) {
 1813         cl_node->exposed = true;
 1814       }
 1815       rc = SA_AIS_ERR_BAD_HANDLE;
 1816       goto done;
 1817     }
 1818 
 1819     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 1820 
 1821     /* Look up ccb_node again */
 1822     imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 1823     if (!ccb_node) {
 1824       rc = SA_AIS_ERR_BAD_HANDLE;
 1825       TRACE_3(
 1826           "ERR_BAD_HANDLE: Ccb handle not valid after successful resurrect - "
 1827           "ccb closed in some other thread?");
 1828       goto done;
 1829     }
 1830 
 1831     if (ccb_node->mExclusive) {
 1832       rc = SA_AIS_ERR_TRY_AGAIN;
 1833       TRACE_3(
 1834           "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, in another thread",
 1835           ccb_node->mCcbId);
 1836       goto done;
 1837     }
 1838 
 1839     if (ccb_node->mAborted) {
 1840       TRACE_3("ERR_FAILED_OPERATION: Ccb-id %u aborted in another thread?",
 1841               ccb_node->mCcbId);
 1842       rc = SA_AIS_ERR_FAILED_OPERATION;
 1843       goto done;
 1844     }
 1845   }
 1846 
 1847   /* Get the Admin Owner info  */
 1848   imma_admin_owner_node_get(&cb->admin_owner_tree, &(ccb_node->mAdminOwnerHdl),
 1849                             &ao_node);
 1850   if (!ao_node) {
 1851     rc = SA_AIS_ERR_LIBRARY;
 1852     TRACE_4("ERR_LIBRARY: No Amin-Owner associated with Ccb");
 1853     goto done;
 1854   }
 1855 
 1856   osafassert(ccb_node->mImmHandle == ao_node->mImmHandle);
 1857   adminOwnerId = ao_node->mAdminOwnerId;
 1858   ao_node = NULL;
 1859 
 1860   if (ccb_node->mApplied) { /* Current ccb-id is closed, get a new one.*/
 1861     if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 1862       TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 1863       goto done;
 1864     }
 1865     rc = imma_newCcbId(cb, ccb_node, adminOwnerId, &locked,
 1866                        cl_node->syncr_timeout);
 1867     cl_node = NULL;
 1868     /* ccb_node still valid if rc == SA_AIS_OK. */
 1869     if (rc == SA_AIS_OK) {
 1870       osafassert(!(ccb_node->mExclusive));
 1871       osafassert(locked);
 1872     }
 1873 
 1874     if (!locked) {
 1875       if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 1876         rc = SA_AIS_ERR_LIBRARY;
 1877         TRACE_4("ERR_LIBRARY: Lock failed");
 1878         goto done;
 1879       }
 1880       locked = true;
 1881     }
 1882 
 1883     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 1884     if (!(cl_node && cl_node->isOm)) {
 1885       rc = SA_AIS_ERR_LIBRARY;
 1886       TRACE_4("ERR_LIBRARY: No client associated with Admin Owner");
 1887       goto done;
 1888     }
 1889 
 1890     imma_proc_decrement_pending_reply(cl_node, true);
 1891 
 1892     if (rc != SA_AIS_OK) {
 1893       goto done;
 1894     }
 1895 
 1896     /* successfully obtained new ccb-id */
 1897 
 1898     if (cl_node->stale) {
 1899       /* Became stale AFTER we successfully obtained new ccb-id ! */
 1900       TRACE_3("ERR_FAILED_OPERATION: IMM Handle %llx became stale", immHandle);
 1901 
 1902       rc = SA_AIS_ERR_FAILED_OPERATION;
 1903       /* The above is safe because we know the ccb WAS terminated*/
 1904       ccb_node->mCcbId = 0;
 1905       ccb_node->mAborted = true;
 1906       goto done;
 1907     }
 1908   }
 1909 
 1910   osafassert(locked);
 1911   osafassert(cl_node);
 1912   osafassert(ccb_node);
 1913 
 1914   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 1915     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 1916     goto done;
 1917   }
 1918 
 1919   /* Populate the Object-Create event */
 1920   memset(&evt, 0, sizeof(IMMSV_EVT));
 1921   evt.type = IMMSV_EVT_TYPE_IMMND;
 1922   if (objectName) {
 1923     evt.info.immnd.type = IMMND_EVT_A2ND_OBJ_CREATE_2;
 1924   } else {
 1925     evt.info.immnd.type = IMMND_EVT_A2ND_OBJ_CREATE;
 1926   }
 1927 
 1928   evt.info.immnd.info.objCreate.adminOwnerId = adminOwnerId;
 1929   evt.info.immnd.info.objCreate.ccbId = ccb_node->mCcbId;
 1930 
 1931   evt.info.immnd.info.objCreate.className.size = strlen(className) + 1;
 1932 
 1933   /*alloc-1 */
 1934   evt.info.immnd.info.objCreate.className.buf =
 1935       (char *)malloc(evt.info.immnd.info.objCreate.className.size);
 1936   if (evt.info.immnd.info.objCreate.className.buf == NULL) {
 1937     rc = SA_AIS_ERR_NO_MEMORY;
 1938     goto mds_send_fail;
 1939   }
 1940   strcpy(evt.info.immnd.info.objCreate.className.buf, className);
 1941 
 1942   if (parentName) {
 1943     if (!osaf_is_extended_name_valid(parentName)) {
 1944       rc = SA_AIS_ERR_INVALID_PARAM;
 1945       TRACE_2("ERR_INVALID_PARAM: Parent name invalid");
 1946       goto mds_send_fail;
 1947     }
 1948 
 1949     parentNameLength = osaf_extended_name_length(parentName);
 1950   }
 1951 
 1952   if (parentNameLength > 0) {
 1953     evt.info.immnd.info.objCreate.parentOrObjectDn.size = parentNameLength + 1;
 1954     evt.info.immnd.info.objCreate.parentOrObjectDn.buf =
 1955         (char *)malloc((parentNameLength + 1) * sizeof(char));
 1956     if (!evt.info.immnd.info.objCreate.parentOrObjectDn.buf) {
 1957       rc = SA_AIS_ERR_NO_MEMORY;
 1958       goto mds_send_fail;
 1959     }
 1960     memcpy(evt.info.immnd.info.objCreate.parentOrObjectDn.buf,
 1961            osaf_extended_name_borrow(parentName), parentNameLength);
 1962     evt.info.immnd.info.objCreate.parentOrObjectDn.buf[parentNameLength] = '\0';
 1963   } else if (objectName) {
 1964     size_t objectNameLength = strlen(objectName);
 1965     if (!osaf_is_extended_names_enabled() &&
 1966         objectNameLength >= SA_MAX_UNEXTENDED_NAME_LENGTH) {
 1967       rc = SA_AIS_ERR_INVALID_PARAM;
 1968       TRACE_2("ERR_INVALID_PARAM: Object name is invalid");
 1969       goto mds_send_fail;
 1970     }
 1971 
 1972     evt.info.immnd.info.objCreate.parentOrObjectDn.size = objectNameLength + 1;
 1973     evt.info.immnd.info.objCreate.parentOrObjectDn.buf = (char *)objectName;
 1974   } else {
 1975     evt.info.immnd.info.objCreate.parentOrObjectDn.size = 0;
 1976     evt.info.immnd.info.objCreate.parentOrObjectDn.buf = NULL;
 1977   }
 1978 
 1979   osafassert(evt.info.immnd.info.objCreate.attrValues == NULL);
 1980   if (attrValues) {
 1981     const SaImmAttrValuesT_2 *attr;
 1982     int i;
 1983     for (i = 0; attrValues[i]; ++i) {
 1984       attr = attrValues[i];
 1985       TRACE("attr:%s \n", attr->attrName);
 1986 
 1987       /* Prevent duplicate attribute assignments */
 1988       IMMSV_ATTR_VALUES_LIST *p = evt.info.immnd.info.objCreate.attrValues;
 1989       while (p != NULL) {
 1990         if (strcmp(attr->attrName, p->n.attrName.buf) == 0) {
 1991           rc = SA_AIS_ERR_INVALID_PARAM;
 1992           TRACE_2(
 1993               "ERR_INVALID_PARAM: Attribute %s occurs multiple times "
 1994               "in attrValues parameter",
 1995               attr->attrName);
 1996           goto mds_send_fail;
 1997         }
 1998         p = p->next;
 1999       }
 2000 
 2001       /*Check that the user does not set value for System attributes. */
 2002 
 2003       if (strcmp(attr->attrName, sysaClName) == 0) {
 2004         if (immOmIsLoader) {
 2005           /*I am loader => will allow the classname attribute to be defaulted */
 2006           continue;
 2007         }
 2008         /*Non loaders are not allowed to explicitly assign className attribute
 2009          */
 2010         rc = SA_AIS_ERR_INVALID_PARAM;
 2011         TRACE_2("ERR_INVALID_PARAM: Not allowed to set attribute %s ",
 2012                 sysaClName);
 2013         goto mds_send_fail;
 2014       } else if (strcmp(attr->attrName, sysaAdmName) == 0) {
 2015         if (immOmIsLoader) {
 2016           /*Loader => clear admName attribute, not others */
 2017           /*This is controversial! The standard is not explicit on this. */
 2018           /* Removing curent admin owner name allows the imm to set IMMLOADER */
 2019           continue;
 2020         }
 2021         rc = SA_AIS_ERR_INVALID_PARAM;
 2022         TRACE_2("ERR_INVALID_PARAM: Not allowed to set attribute %s",
 2023                 sysaAdmName);
 2024         goto mds_send_fail;
 2025       } else if ((strcmp(attr->attrName, sysaImplName) == 0) &&
 2026                  (!immOmIsLoader)) {
 2027         /*Loader allowed to explicitly assign implName attribute, not others
 2028            The only point of allowing this is that a class/object implementer
 2029            set with identical implementer name may be faster after cluster
 2030            restart because ImmAttrValue::setValueC_st checks for equality
 2031            before overwrite.
 2032          */
 2033 
 2034         rc = SA_AIS_ERR_INVALID_PARAM;
 2035         TRACE_2("ERR_INVALID_PARAM: Not allowed to set attribute %s",
 2036                 sysaImplName);
 2037         goto mds_send_fail;
 2038       } else if (attr->attrValuesNumber == 0 && !immOmIsLoader) {
 2039         TRACE("CcbObjectCreate ignoring attribute %s with no values",
 2040               attr->attrName);
 2041         continue;
 2042       }
 2043 
 2044       /*alloc-3 */
 2045       p = (IMMSV_ATTR_VALUES_LIST *)calloc(1, sizeof(IMMSV_ATTR_VALUES_LIST));
 2046 
 2047       p->n.attrName.size = strlen(attr->attrName) + 1;
 2048       if (p->n.attrName.size >= IMMSV_MAX_ATTR_NAME_LENGTH) {
 2049         TRACE_2("ERR_INVALID_PARAM: Attribute name too long");
 2050         rc = SA_AIS_ERR_INVALID_PARAM;
 2051         free(p);
 2052         p = NULL;
 2053         goto mds_send_fail;
 2054       }
 2055 
 2056       /*alloc-4 */
 2057       p->n.attrName.buf = (char *)malloc(p->n.attrName.size);
 2058       strncpy(p->n.attrName.buf, attr->attrName, p->n.attrName.size);
 2059       p->n.attrName.buf[p->n.attrName.size-1] = 0;
 2060 
 2061       p->n.attrValuesNumber = attr->attrValuesNumber;
 2062       p->n.attrValueType = attr->attrValueType;
 2063 
 2064       const SaImmAttrValueT *avarr = attr->attrValues;
 2065       /*alloc-5 */
 2066       if (attr->attrValuesNumber > 0) {
 2067         imma_copyAttrValue(&(p->n.attrValue), attr->attrValueType, avarr[0]);
 2068       }
 2069 
 2070       if (attr->attrValuesNumber > 1) {
 2071         unsigned int numAdded = attr->attrValuesNumber - 1;
 2072         unsigned int i;
 2073         for (i = 1; i <= numAdded; ++i) {
 2074           /*alloc-6 */
 2075           IMMSV_EDU_ATTR_VAL_LIST *al = (IMMSV_EDU_ATTR_VAL_LIST *)calloc(
 2076               1, sizeof(IMMSV_EDU_ATTR_VAL_LIST));
 2077 
 2078           /*alloc-7 */
 2079           imma_copyAttrValue(&(al->n), attr->attrValueType, avarr[i]);
 2080           al->next = p->n.attrMoreValues;
 2081           p->n.attrMoreValues = al;
 2082         }
 2083       }
 2084 
 2085       p->next = evt.info.immnd.info.objCreate.attrValues; /*NULL initially. */
 2086       evt.info.immnd.info.objCreate.attrValues = p;
 2087     }
 2088   }
 2089 
 2090 
 2091   rc = imma_evt_fake_evs(cb, &evt, &out_evt, cl_node->syncr_timeout,
 2092                          cl_node->handle, &locked, false);
 2093   cl_node = NULL;
 2094   ccb_node = NULL;
 2095 
 2096   TRACE("objectCreate send RETURNED:%u", rc);
 2097 
 2098   if (out_evt) {
 2099     /* Process the outcome, note this is after a blocking call. */
 2100     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 2101     osafassert((out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR) ||
 2102                (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2));
 2103     if (rc == SA_AIS_OK) {
 2104       rc = out_evt->info.imma.info.errRsp.error;
 2105       if (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2) {
 2106         newErrorStrings =
 2107             imma_getErrorStrings(&(out_evt->info.imma.info.errRsp));
 2108       }
 2109     }
 2110     /* Free the out event */
 2111     /*Will free the root event only, not any pointer structures. */
 2112     free(out_evt);
 2113     out_evt = NULL;
 2114   }
 2115 
 2116 mds_send_fail:
 2117   /*We may be un-locked here but this should not matter. */
 2118 
 2119   if (evt.info.immnd.info.objCreate.className.buf) { /*free-1 */
 2120     free(evt.info.immnd.info.objCreate.className.buf);
 2121     evt.info.immnd.info.objCreate.className.buf = NULL;
 2122   }
 2123 
 2124   if (parentName && evt.info.immnd.info.objCreate.parentOrObjectDn.buf) {
 2125     free(evt.info.immnd.info.objCreate.parentOrObjectDn.buf);
 2126     evt.info.immnd.info.objCreate.parentOrObjectDn.buf = NULL;
 2127   }
 2128 
 2129   while (evt.info.immnd.info.objCreate.attrValues) {
 2130     IMMSV_ATTR_VALUES_LIST *p = evt.info.immnd.info.objCreate.attrValues;
 2131     evt.info.immnd.info.objCreate.attrValues = p->next;
 2132     p->next = NULL;
 2133     if (p->n.attrName.buf) { /*free-4 */
 2134       free(p->n.attrName.buf);
 2135       p->n.attrName.buf = NULL;
 2136     }
 2137 
 2138     immsv_evt_free_att_val(&(p->n.attrValue),
 2139                            (SaImmValueTypeT)p->n.attrValueType); /*free-5 */
 2140 
 2141     while (p->n.attrMoreValues) {
 2142       IMMSV_EDU_ATTR_VAL_LIST *al = p->n.attrMoreValues;
 2143       p->n.attrMoreValues = al->next;
 2144       al->next = NULL;
 2145       immsv_evt_free_att_val(&(al->n),
 2146                              (SaImmValueTypeT)p->n.attrValueType); /*free-7 */
 2147       free(al);                                                    /*free-6 */
 2148     }
 2149 
 2150     p->next = NULL;
 2151     free(p); /*free-3 */
 2152     p = NULL;
 2153   }
 2154 
 2155   if (!locked && m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2156     TRACE_4("ERR_LIBRARY: Lock failed");
 2157     rc = SA_AIS_ERR_LIBRARY;
 2158     goto lock_fail;
 2159   }
 2160   locked = true;
 2161 
 2162   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2163   if (!(cl_node && cl_node->isOm)) {
 2164     if (rc == SA_AIS_OK) {
 2165       TRACE_3("ERR_BAD_HANDLE: client_node gone on return from down-call");
 2166       rc = SA_AIS_ERR_BAD_HANDLE;
 2167     }
 2168     goto done;
 2169   }
 2170 
 2171   imma_proc_decrement_pending_reply(cl_node, true);
 2172 
 2173   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 2174   if (!ccb_node) {
 2175     TRACE_3("ERR_BAD_HANDLE: ccb-node gone on return from down call");
 2176     /* BAD_HANDLE overrides any other return code already assigned. */
 2177     rc = SA_AIS_ERR_BAD_HANDLE;
 2178     goto done;
 2179   }
 2180 
 2181   osafassert(ccb_node->mErrorStrings == NULL);
 2182   ccb_node->mErrorStrings = newErrorStrings;
 2183   newErrorStrings = NULL; /* Dont free the strings on exit from this func */
 2184 
 2185   if (rc == SA_AIS_OK) {
 2186     if (cl_node->stale) {
 2187       /* Became stale during the blocked call yet the call
 2188          succeeded! This should be very rare.
 2189          We know the ccb is aborted. So we dont need to expose
 2190          the stale handle.
 2191       */
 2192 
 2193       TRACE_3(
 2194           "ERR_FAILED_OPERATION: Handle %llx became stale "
 2195           "during the down-call",
 2196           immHandle);
 2197       ccb_node->mAborted = true;
 2198       rc = SA_AIS_ERR_FAILED_OPERATION;
 2199     }
 2200 
 2201     if (ccb_node->mAugCcb) {
 2202       /* This is an OI augmented ccb.
 2203          Successfull object create added by OI to root CCB =>
 2204          this aug-ccb must be applied (confirmed by the OI)
 2205          or the imm will interpret the missing confirmation
 2206          as abort and abort the entire root ccb.
 2207        */
 2208       ccb_node->mAugIsTainted = true;
 2209     }
 2210   } else if (rc == SA_AIS_ERR_TRY_AGAIN && (cb->is_immnd_up == false)) {
 2211     /*
 2212        We lost contact with the IMMND which means we KNOW the current
 2213        ccb-id associated with this ccb-handle was aborted in non-critical
 2214        phase. Better then to handle this as FAILED_OPERATION, since this
 2215        can avoid exposing the immHandle as BAD_HANDLE.
 2216      */
 2217     TRACE_3(
 2218         "ERR_FAILED_OPERATION: Converting TRY_AGAIN to "
 2219         "FAILED_OPERATION in ccbObjectCreate in IMMA");
 2220     rc = SA_AIS_ERR_FAILED_OPERATION;
 2221     ccb_node->mAborted = true;
 2222   } else if (rc == SA_AIS_ERR_FAILED_OPERATION) {
 2223     ccb_node->mAborted = true;
 2224   }
 2225 
 2226 clm_left:
 2227 done:
 2228   imma_free_errorStrings(
 2229       newErrorStrings); /* In case of failed resurrect only */
 2230 
 2231   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 2232 
 2233 lock_fail:
 2234 
 2235   TRACE_LEAVE();
 2236   return rc;
 2237 }
 2238 
 2239 /****************************************************************************
 2240   Name          :  saImmOmCcbObjectModify/_2
 2241 
 2242   Description   :  Modifies a config object in the IMM.
 2243                    This a blocking syncronous call.
 2244 
 2245 
 2246   Arguments     :  ccbHandle - Ccb Handle
 2247                    objectName - A pointer to the name of the object.
 2248                    attrMods - The attribute modifications (see the standard)
 2249 
 2250   Return Values :  Refer to SAI-AIS specification for various return values.
 2251 ******************************************************************************/
 2252 static SaAisErrorT ccb_object_modify_common(
 2253     SaImmCcbHandleT ccbHandle, SaConstStringT objectName,
 2254     const SaImmAttrModificationT_2 **attrMods, bool bUseString);
 2255 
 2256 SaAisErrorT saImmOmCcbObjectModify_2(
 2257     SaImmCcbHandleT ccbHandle, const SaNameT *objectName,
 2258     const SaImmAttrModificationT_2 **attrMods) {
 2259   bool freeMemory = false;
 2260   SaStringT objectNameStr = NULL;
 2261   SaAisErrorT rc;
 2262 
 2263   if (objectName) {
 2264     if (!osaf_is_extended_name_valid(objectName)) {
 2265       TRACE_2("ERR_INVALID_PARAM: Object name is invalid");
 2266       return SA_AIS_ERR_INVALID_PARAM;
 2267     }
 2268 
 2269     size_t len = osaf_extended_name_length(objectName);
 2270     if (len < SA_MAX_UNEXTENDED_NAME_LENGTH) {
 2271       objectNameStr = (SaStringT)malloc(len + 1);
 2272       memcpy(objectNameStr, osaf_extended_name_borrow(objectName), len);
 2273       objectNameStr[len] = 0;
 2274       freeMemory = true;
 2275     } else {
 2276       objectNameStr = (SaStringT)osaf_extended_name_borrow(objectName);
 2277     }
 2278   }
 2279 
 2280   rc = ccb_object_modify_common(ccbHandle, objectNameStr, attrMods, false);
 2281 
 2282   if (freeMemory) {
 2283     free(objectNameStr);
 2284   }
 2285 
 2286   return rc;
 2287 }
 2288 
 2289 SaAisErrorT saImmOmCcbObjectModify_o3(
 2290     SaImmCcbHandleT ccbHandle, SaConstStringT objectName,
 2291     const SaImmAttrModificationT_2 **attrMods) {
 2292   return ccb_object_modify_common(ccbHandle, objectName, attrMods, true);
 2293 }
 2294 
 2295 static SaAisErrorT ccb_object_modify_common(
 2296     SaImmCcbHandleT ccbHandle, SaConstStringT objectName,
 2297     const SaImmAttrModificationT_2 **attrMods, bool bUseString) {
 2298   SaAisErrorT rc = SA_AIS_OK;
 2299   IMMA_CB *cb = &imma_cb;
 2300   IMMSV_EVT evt;
 2301   IMMSV_EVT *out_evt = NULL;
 2302   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 2303   IMMA_CLIENT_NODE *cl_node = NULL;
 2304   IMMA_CCB_NODE *ccb_node = NULL;
 2305   bool locked = false;
 2306   SaImmHandleT immHandle = 0LL;
 2307   SaUint32T adminOwnerId = 0;
 2308   SaStringT *newErrorStrings = NULL;
 2309   TRACE_ENTER();
 2310 
 2311   if (cb->sv_id == 0) {
 2312     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 2313     return SA_AIS_ERR_BAD_HANDLE;
 2314   }
 2315 
 2316   if (objectName == NULL) {
 2317     TRACE_2("ERR_INVALID_PARAM: objectName is NULL");
 2318     TRACE_LEAVE();
 2319     return SA_AIS_ERR_INVALID_PARAM;
 2320   }
 2321 
 2322   if (!objectName[0]) {
 2323     TRACE_2("ERR_INVALID_PARAM: objectName is empty");
 2324     TRACE_LEAVE();
 2325     return SA_AIS_ERR_INVALID_PARAM;
 2326   }
 2327 
 2328   if (attrMods == NULL) {
 2329     TRACE_2("ERR_INVALID_PARAM: attrMods is NULL");
 2330     TRACE_LEAVE();
 2331     return SA_AIS_ERR_INVALID_PARAM;
 2332   }
 2333 
 2334   if (cb->is_immnd_up == false) {
 2335     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 2336     /* ##1## Any on going ccb has been aborted and this will be detected
 2337        in resurrect processing. But this could be the first operation
 2338        attempted for a new ccb-id, i.e. there is no on-going ccb-id,
 2339        (remember that a ccb-handle is associated with a chain of actual
 2340        ccb-ids). In that case resurrection may succeed.
 2341     */
 2342     return SA_AIS_ERR_TRY_AGAIN;
 2343   }
 2344 
 2345   /* get the CB Lock */
 2346   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2347     rc = SA_AIS_ERR_LIBRARY;
 2348     TRACE_4("ERR_LIBRARY: Lock failed");
 2349     goto lock_fail;
 2350   }
 2351   locked = true;
 2352 
 2353   /* Get the CCB info */
 2354   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 2355   if (!ccb_node) {
 2356     rc = SA_AIS_ERR_BAD_HANDLE;
 2357     TRACE_2("ERR_BAD_HANDLE: Ccb handle not valid");
 2358     goto done;
 2359   }
 2360 
 2361   if (ccb_node->mExclusive) {
 2362     rc = SA_AIS_ERR_TRY_AGAIN;
 2363     TRACE_3(
 2364         "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, in another thread",
 2365         ccb_node->mCcbId);
 2366     goto done;
 2367   }
 2368 
 2369   if (ccb_node->mAborted) {
 2370     TRACE_2("ERR_FAILED_OPERATION: CCB %u has already been aborted",
 2371             ccb_node->mCcbId);
 2372     rc = SA_AIS_ERR_FAILED_OPERATION;
 2373     goto done;
 2374   }
 2375 
 2376   immHandle = ccb_node->mImmHandle;
 2377 
 2378   /* Free string from previous ccb-op */
 2379   imma_free_errorStrings(ccb_node->mErrorStrings);
 2380   ccb_node->mErrorStrings = NULL;
 2381 
 2382   /*Look up client node also, to verify that the client handle
 2383      is still active. */
 2384   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2385   if (!(cl_node && cl_node->isOm)) {
 2386     rc = SA_AIS_ERR_LIBRARY;
 2387     TRACE_4("ERR_LIBRARY: No valid SaImmHandleT associated with Ccb");
 2388     goto done;
 2389   }
 2390 
 2391   if (bUseString && !cl_node->isImmA2f) {
 2392     rc = SA_AIS_ERR_VERSION;
 2393     TRACE_2(
 2394         "ERR_VERSION: saImmOmCcbObjectModify_o3 only supported for "
 2395         "A.02.15 and above");
 2396     goto done;
 2397   }
 2398   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 2399     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 2400     rc = SA_AIS_ERR_UNAVAILABLE;
 2401     goto clm_left;
 2402   }
 2403 
 2404   if (cl_node->stale) {
 2405     TRACE_1("IMM Handle %llx is stale", immHandle);
 2406 
 2407     if (!(ccb_node->mApplied)) {
 2408       TRACE_3(
 2409           "ERR_FAILED_OPERATION: IMMND DOWN discards ccb "
 2410           "in active but non-critical state");
 2411       ccb_node->mAborted = true;
 2412       rc = SA_AIS_ERR_FAILED_OPERATION;
 2413       /* We drop the resurrect task since this ccb is doomed. */
 2414       goto done;
 2415     }
 2416 
 2417     /* Why do we bother trying resurrect? See ##1## above. */
 2418 
 2419     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 2420     cl_node = NULL;
 2421     ccb_node = NULL;
 2422 
 2423     if (!locked &&
 2424         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2425       TRACE_4("ERR_LIBRARY: Lock failed");
 2426       rc = SA_AIS_ERR_LIBRARY;
 2427       goto done;
 2428     }
 2429     locked = true;
 2430 
 2431     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2432 
 2433     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 2434       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 2435               immHandle);
 2436       if (cl_node && cl_node->stale) {
 2437         cl_node->exposed = true;
 2438       }
 2439       rc = SA_AIS_ERR_BAD_HANDLE;
 2440       goto done;
 2441     }
 2442 
 2443     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 2444 
 2445     /* Look up ccb_node again */
 2446     imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 2447     if (!ccb_node) {
 2448       rc = SA_AIS_ERR_BAD_HANDLE;
 2449       TRACE_3(
 2450           "ERR_BAD_HANDLE: Ccb handle not valid after successful resurrect");
 2451       goto done;
 2452     }
 2453 
 2454     if (ccb_node->mExclusive) {
 2455       rc = SA_AIS_ERR_TRY_AGAIN;
 2456       TRACE_3(
 2457           "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, "
 2458           "in another thread",
 2459           ccb_node->mCcbId);
 2460       goto done;
 2461     }
 2462 
 2463     if (ccb_node->mAborted) {
 2464       TRACE_3("ERR_FAILED_OPERATION: Ccb-id %u was aborted", ccb_node->mCcbId);
 2465       rc = SA_AIS_ERR_FAILED_OPERATION;
 2466       goto done;
 2467     }
 2468   }
 2469 
 2470   /* Get the Admin Owner info  */
 2471   imma_admin_owner_node_get(&cb->admin_owner_tree, &(ccb_node->mAdminOwnerHdl),
 2472                             &ao_node);
 2473   if (!ao_node) {
 2474     rc = SA_AIS_ERR_LIBRARY;
 2475     TRACE_4("ERR_LIBRARY: No Amin-Owner associated with Ccb");
 2476     goto done;
 2477   }
 2478 
 2479   osafassert(ccb_node->mImmHandle == ao_node->mImmHandle);
 2480   adminOwnerId = ao_node->mAdminOwnerId;
 2481   ao_node = NULL;
 2482 
 2483   if (ccb_node->mApplied) { /* Current ccb-id is closed, get a new one.*/
 2484     if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 2485       TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 2486       goto done;
 2487     }
 2488     rc = imma_newCcbId(cb, ccb_node, adminOwnerId, &locked,
 2489                        cl_node->syncr_timeout);
 2490     cl_node = NULL;
 2491     /* ccb_node still valid if rc == SA_AIS_OK. */
 2492     if (rc == SA_AIS_OK) {
 2493       osafassert(!(ccb_node->mExclusive));
 2494       osafassert(locked);
 2495     }
 2496 
 2497     if (!locked) {
 2498       if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2499         rc = SA_AIS_ERR_LIBRARY;
 2500         TRACE_4("ERR_LIBRARY: Lock failed");
 2501         goto done;
 2502       }
 2503       locked = true;
 2504     }
 2505 
 2506     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2507     if (!(cl_node && cl_node->isOm)) {
 2508       rc = SA_AIS_ERR_LIBRARY;
 2509       TRACE_4("ERR_LIBRARY: No client associated with Admin Owner");
 2510       goto done;
 2511     }
 2512 
 2513     imma_proc_decrement_pending_reply(cl_node, true);
 2514 
 2515     if (rc != SA_AIS_OK) {
 2516       goto done;
 2517     }
 2518 
 2519     /* successfully obtained new ccb-id */
 2520 
 2521     if (cl_node->stale) {
 2522       /* Became stale AFTER we successfully obtained new ccb-id ! */
 2523       TRACE_3("ERR_FAILED_OPERATION: IMM Handle %llx became stale", immHandle);
 2524 
 2525       rc = SA_AIS_ERR_FAILED_OPERATION;
 2526       /* We know the ccb WAS terminated*/
 2527       ccb_node->mCcbId = 0;
 2528       ccb_node->mAborted = true;
 2529       goto done;
 2530     }
 2531   }
 2532 
 2533   osafassert(locked);
 2534   osafassert(cl_node);
 2535   osafassert(ccb_node);
 2536 
 2537   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 2538     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 2539     goto done;
 2540   }
 2541 
 2542   /* Populate the Object-Modify event */
 2543   memset(&evt, 0, sizeof(IMMSV_EVT));
 2544   evt.type = IMMSV_EVT_TYPE_IMMND;
 2545   evt.info.immnd.type = IMMND_EVT_A2ND_OBJ_MODIFY;
 2546 
 2547   evt.info.immnd.info.objModify.adminOwnerId = adminOwnerId;
 2548   evt.info.immnd.info.objModify.ccbId = ccb_node->mCcbId;
 2549 
 2550   evt.info.immnd.info.objModify.objectName.size = strlen(objectName) + 1;
 2551   if (evt.info.immnd.info.objModify.objectName.size != 1) {
 2552     /*alloc-1 */
 2553     evt.info.immnd.info.objModify.objectName.buf = (char *)objectName;
 2554   } else {
 2555     evt.info.immnd.info.objModify.objectName.size = 0;
 2556     evt.info.immnd.info.objModify.objectName.buf = NULL;
 2557   }
 2558 
 2559   osafassert(evt.info.immnd.info.objModify.attrMods == NULL);
 2560 
 2561   const SaImmAttrModificationT_2 *attrMod;
 2562   int i;
 2563   for (i = 0; attrMods[i]; ++i) {
 2564     attrMod = attrMods[i];
 2565 
 2566     /*NOTE: Check that user does not set values for System attributes. */
 2567 
 2568     IMMSV_ATTR_MODS_LIST *p = evt.info.immnd.info.objModify.attrMods;
 2569     while (p != NULL) {
 2570       if (strcmp(attrMod->modAttr.attrName, p->attrValue.attrName.buf) == 0) {
 2571         rc = SA_AIS_ERR_INVALID_PARAM;
 2572         TRACE_2(
 2573             "ERR_INVALID_PARAM: Attribute %s occurs multiple times "
 2574             "in attrMods parameter",
 2575             attrMod->modAttr.attrName);
 2576         goto mds_send_fail;
 2577       }
 2578 
 2579       p = p->next;
 2580     }
 2581 
 2582     /*alloc-2 */
 2583     p = (IMMSV_ATTR_MODS_LIST *)calloc(1, sizeof(IMMSV_ATTR_MODS_LIST));
 2584     p->attrModType = attrMod->modType;
 2585     p->attrValue.attrName.size = strlen(attrMod->modAttr.attrName) + 1;
 2586 
 2587     /* alloc 3 */
 2588     p->attrValue.attrName.buf = (char *)malloc(p->attrValue.attrName.size);
 2589     strncpy(p->attrValue.attrName.buf, attrMod->modAttr.attrName,
 2590             p->attrValue.attrName.size);
 2591     p->attrValue.attrName.buf[p->attrValue.attrName.size-1] = 0;
 2592 
 2593     p->attrValue.attrValuesNumber = attrMod->modAttr.attrValuesNumber;
 2594     p->attrValue.attrValueType = attrMod->modAttr.attrValueType;
 2595 
 2596     if (attrMod->modAttr.attrValuesNumber) { /*At least one value */
 2597       const SaImmAttrValueT *avarr = attrMod->modAttr.attrValues;
 2598       /*alloc-4 */
 2599       imma_copyAttrValue(&(p->attrValue.attrValue),
 2600                          attrMod->modAttr.attrValueType, avarr[0]);
 2601 
 2602       if (attrMod->modAttr.attrValuesNumber > 1) { /*Multiple values */
 2603         unsigned int numAdded = attrMod->modAttr.attrValuesNumber - 1;
 2604         unsigned int i;
 2605         for (i = 1; i <= numAdded; ++i) {
 2606           /*alloc-5 */
 2607           IMMSV_EDU_ATTR_VAL_LIST *al = (IMMSV_EDU_ATTR_VAL_LIST *)calloc(
 2608               1, sizeof(IMMSV_EDU_ATTR_VAL_LIST));
 2609           /*alloc-6 */
 2610           imma_copyAttrValue(&(al->n), attrMod->modAttr.attrValueType,
 2611                              avarr[i]);
 2612           al->next = p->attrValue.attrMoreValues; /*NULL initially */
 2613           p->attrValue.attrMoreValues = al;
 2614         } /*for */
 2615       }   /*Multiple values */
 2616     }
 2617     /*At least one value */
 2618     p->next = evt.info.immnd.info.objModify.attrMods; /*NULL initially. */
 2619     evt.info.immnd.info.objModify.attrMods = p;
 2620   }
 2621 
 2622   rc = imma_evt_fake_evs(cb, &evt, &out_evt, cl_node->syncr_timeout,
 2623                          cl_node->handle, &locked, false);
 2624   cl_node = NULL;
 2625   ccb_node = NULL;
 2626 
 2627   TRACE("objectModify send RETURNED:%u", rc);
 2628 
 2629   if (out_evt) {
 2630     /* Process the outcome, note this is after a blocking call. */
 2631     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 2632     osafassert((out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR) ||
 2633                (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2));
 2634     if (rc == SA_AIS_OK) {
 2635       rc = out_evt->info.imma.info.errRsp.error;
 2636       if (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2) {
 2637         newErrorStrings =
 2638             imma_getErrorStrings(&(out_evt->info.imma.info.errRsp));
 2639       }
 2640     }
 2641     free(out_evt);
 2642     out_evt = NULL;
 2643   }
 2644 
 2645 mds_send_fail:
 2646   /*We may be un-locked here but this should not matter. */
 2647 
 2648   while (evt.info.immnd.info.objModify.attrMods) {
 2649     IMMSV_ATTR_MODS_LIST *p = evt.info.immnd.info.objModify.attrMods;
 2650     evt.info.immnd.info.objModify.attrMods = p->next;
 2651     p->next = NULL;
 2652 
 2653     if (p->attrValue.attrName.buf) {
 2654       free(p->attrValue.attrName.buf); /*free-3 */
 2655       p->attrValue.attrName.buf = NULL;
 2656     }
 2657 
 2658     if (p->attrValue.attrValuesNumber) {
 2659       immsv_evt_free_att_val(&(p->attrValue.attrValue), /*free-4 */
 2660                              (SaImmValueTypeT)p->attrValue.attrValueType);
 2661 
 2662       while (p->attrValue.attrMoreValues) {
 2663         IMMSV_EDU_ATTR_VAL_LIST *al = p->attrValue.attrMoreValues;
 2664         p->attrValue.attrMoreValues = al->next;
 2665         al->next = NULL;
 2666         immsv_evt_free_att_val(
 2667             &(al->n), (SaImmValueTypeT)p->attrValue.attrValueType); /*free-6 */
 2668         free(al);                                                   /*free-5 */
 2669       }
 2670     }
 2671 
 2672     free(p); /*free-2 */
 2673   }
 2674 
 2675   if (!locked && m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2676     TRACE_4("ERR_LIBRARY: Lock failed");
 2677     rc = SA_AIS_ERR_LIBRARY;
 2678     goto lock_fail;
 2679   }
 2680   locked = true;
 2681 
 2682   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2683   if (!(cl_node && cl_node->isOm)) {
 2684     if (rc == SA_AIS_OK) {
 2685       TRACE_3("ERR_BAD_HANDLE: client_node gone on return from down-call");
 2686       rc = SA_AIS_ERR_BAD_HANDLE;
 2687     }
 2688     goto done;
 2689   }
 2690 
 2691   imma_proc_decrement_pending_reply(cl_node, true);
 2692 
 2693   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 2694   if (!ccb_node) {
 2695     TRACE_3("ERR_BAD_HANDLE: ccb-node gone on return from down-call");
 2696     /* BAD_HANDLE overrides any other return code already assigned. */
 2697     rc = SA_AIS_ERR_BAD_HANDLE;
 2698     goto done;
 2699   }
 2700 
 2701   osafassert(ccb_node->mErrorStrings == NULL);
 2702   ccb_node->mErrorStrings = newErrorStrings;
 2703   newErrorStrings = NULL; /* Dont free the strings on exit from this func */
 2704 
 2705   if (rc == SA_AIS_OK) {
 2706     if (cl_node->stale) {
 2707       /* Became stale during the blocked call yet the call
 2708          succeeded! This should be very rare.
 2709          We know the ccb is aborted. So we dont need to expose
 2710          the stale handle.
 2711       */
 2712 
 2713       TRACE_3(
 2714           "ERR_FAILED_OPERATION: Handle %llx became stale "
 2715           "during the down-call",
 2716           immHandle);
 2717       ccb_node->mAborted = true;
 2718       rc = SA_AIS_ERR_FAILED_OPERATION;
 2719     }
 2720 
 2721     if (ccb_node->mAugCcb) {
 2722       /* This is an OI augmented ccb.
 2723          Successfull object modify added by OI to root CCB =>
 2724          this aug-ccb must be applied (confirmed by the OI)
 2725          or the imm will interpret the missing confirmation
 2726          as abort and abort the entire root ccb.
 2727        */
 2728       ccb_node->mAugIsTainted = true;
 2729     }
 2730   } else if (rc == SA_AIS_ERR_TRY_AGAIN && (cb->is_immnd_up == false)) {
 2731     /*
 2732        We lost contact with the IMMND which means we KNOW the current
 2733        ccb-id associated with this ccb-handle was aborted in non-critical
 2734        phase. Better then to handle this as FAILED_OPERATION, since this
 2735        can avoid exposing the immHandle as BAD_HANDLE.
 2736      */
 2737     TRACE_3(
 2738         "ERR_FAILED_OPERATION: Converting TRY_AGAIN to "
 2739         "FAILED_OPERATION in ccbObjectModify in IMMA");
 2740     rc = SA_AIS_ERR_FAILED_OPERATION;
 2741     ccb_node->mAborted = true;
 2742   } else if (rc == SA_AIS_ERR_FAILED_OPERATION) {
 2743     ccb_node->mAborted = true;
 2744   }
 2745 
 2746 clm_left:
 2747 done:
 2748   imma_free_errorStrings(
 2749       newErrorStrings); /* In case of failed resurrect only */
 2750 
 2751   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 2752 
 2753 lock_fail:
 2754 
 2755   TRACE("objectModify really RETURNING:%u", rc);
 2756   TRACE_LEAVE();
 2757   return rc;
 2758 }
 2759 
 2760 /****************************************************************************
 2761   Name          :  saImmOmCcbObjectDelete
 2762 
 2763   Description   :  Deletes a config object in the IMM.
 2764                    This a blocking syncronous call.
 2765 
 2766 
 2767   Arguments     :  ccbHandle - Ccb Handle
 2768                    objectName - A pointer to the name of the object where
 2769                                 delete starts from.
 2770 
 2771   Return Values :  Refer to SAI-AIS specification for various return values.
 2772 ******************************************************************************/
 2773 static SaAisErrorT ccb_object_delete_common(SaImmCcbHandleT ccbHandle,
 2774                                             SaConstStringT objectName,
 2775                                             bool bUseString);
 2776 
 2777 SaAisErrorT saImmOmCcbObjectDelete(SaImmCcbHandleT ccbHandle,
 2778                                    const SaNameT *objectName) {
 2779   bool freeMemory = false;
 2780   SaStringT objectNameStr = NULL;
 2781   SaAisErrorT rc;
 2782 
 2783   if (objectName) {
 2784     if (!osaf_is_extended_name_valid(objectName)) {
 2785       TRACE_2("ERR_INVALID_PARAM: Object name is invalid");
 2786       return SA_AIS_ERR_INVALID_PARAM;
 2787     }
 2788 
 2789     size_t len = osaf_extended_name_length(objectName);
 2790     if (len < SA_MAX_UNEXTENDED_NAME_LENGTH) {
 2791       objectNameStr = (SaStringT)malloc(len + 1);
 2792       memcpy(objectNameStr, osaf_extended_name_borrow(objectName), len);
 2793       objectNameStr[len] = 0;
 2794       freeMemory = true;
 2795     } else {
 2796       objectNameStr = (SaStringT)osaf_extended_name_borrow(objectName);
 2797     }
 2798   }
 2799 
 2800   rc = ccb_object_delete_common(ccbHandle, objectNameStr, false);
 2801 
 2802   if (freeMemory) {
 2803     free(objectNameStr);
 2804   }
 2805 
 2806   return rc;
 2807 }
 2808 
 2809 SaAisErrorT saImmOmCcbObjectDelete_o3(SaImmCcbHandleT ccbHandle,
 2810                                       SaConstStringT objectName) {
 2811   return ccb_object_delete_common(ccbHandle, objectName, true);
 2812 }
 2813 
 2814 static SaAisErrorT ccb_object_delete_common(SaImmCcbHandleT ccbHandle,
 2815                                             SaConstStringT objectName,
 2816                                             bool bUseString) {
 2817   SaAisErrorT rc = SA_AIS_OK;
 2818   IMMA_CB *cb = &imma_cb;
 2819   IMMSV_EVT evt;
 2820   IMMSV_EVT *out_evt = NULL;
 2821   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 2822   IMMA_CLIENT_NODE *cl_node = NULL;
 2823   IMMA_CCB_NODE *ccb_node = NULL;
 2824   bool locked = false;
 2825   SaImmHandleT immHandle = 0LL;
 2826   SaUint32T adminOwnerId = 0;
 2827   SaStringT *newErrorStrings = NULL;
 2828   TRACE_ENTER();
 2829 
 2830   if (cb->sv_id == 0) {
 2831     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 2832     return SA_AIS_ERR_BAD_HANDLE;
 2833   }
 2834 
 2835   if (!objectName || !objectName[0]) {
 2836     TRACE_2("ERR_INVALID_PARAM: Empty object-name");
 2837     return SA_AIS_ERR_INVALID_PARAM;
 2838   }
 2839 
 2840   if (cb->is_immnd_up == false) {
 2841     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 2842     /* ##1## Any on going ccb has been aborted and this will be detected
 2843        in resurrect processing. But this could be the first operation
 2844        attempted for a new ccb-id, i.e. there is no on-going ccb-id,
 2845        (remember that a ccb-handle is associated with a chain of actual
 2846        ccbs). In that case resurrection may succeed.
 2847     */
 2848     return SA_AIS_ERR_TRY_AGAIN;
 2849   }
 2850 
 2851   /* get the CB Lock */
 2852   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2853     rc = SA_AIS_ERR_LIBRARY;
 2854     TRACE_4("ERR_LIBRARY: Lock failed");
 2855     goto lock_fail;
 2856   }
 2857   locked = true;
 2858 
 2859   /*Get the CCB info */
 2860   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 2861   if (!ccb_node) {
 2862     rc = SA_AIS_ERR_BAD_HANDLE;
 2863     TRACE_2("ERR_BAD_HANDLE: Ccb handle not valid");
 2864     goto done;
 2865   }
 2866 
 2867   if (ccb_node->mExclusive) {
 2868     rc = SA_AIS_ERR_TRY_AGAIN;
 2869     TRACE_3(
 2870         "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, in another thread",
 2871         ccb_node->mCcbId);
 2872     goto done;
 2873   }
 2874 
 2875   if (ccb_node->mAborted) {
 2876     TRACE_2("ERR_FAILED_OPERATION: CCB %u already aborted", ccb_node->mCcbId);
 2877     rc = SA_AIS_ERR_FAILED_OPERATION;
 2878     goto done;
 2879   }
 2880 
 2881   immHandle = ccb_node->mImmHandle;
 2882 
 2883   /* Free string from previous ccb-op */
 2884   imma_free_errorStrings(ccb_node->mErrorStrings);
 2885   ccb_node->mErrorStrings = NULL;
 2886 
 2887   /*Look up client node also, to verify that the client handle
 2888      is still active. */
 2889   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2890   if (!(cl_node && cl_node->isOm)) {
 2891     rc = SA_AIS_ERR_LIBRARY;
 2892     TRACE_4("ERR_LIBRARY: No valid SaImmHandleT associated with Ccb");
 2893     goto done;
 2894   }
 2895 
 2896   if (bUseString && !cl_node->isImmA2f) {
 2897     rc = SA_AIS_ERR_VERSION;
 2898     TRACE_2(
 2899         "ERR_VERSION: saImmOmCcbObjectDelete_o3 only supported for "
 2900         "A.02.15 and above");
 2901     goto done;
 2902   }
 2903   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 2904     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 2905     rc = SA_AIS_ERR_UNAVAILABLE;
 2906     goto clm_left;
 2907   }
 2908 
 2909   if (cl_node->stale) {
 2910     TRACE_1("IMM Handle %llx is stale exposed?:%u", immHandle,
 2911             cl_node->exposed);
 2912 
 2913     if (!(ccb_node->mApplied)) {
 2914       TRACE_3(
 2915           "ERR_FAILED_OPERATION: IMMND DOWN discards ccb "
 2916           "in active but non-critical state");
 2917       ccb_node->mAborted = true;
 2918       rc = SA_AIS_ERR_FAILED_OPERATION;
 2919       /* We drop the resurrect task since this ccb is doomed. */
 2920       goto done;
 2921     }
 2922 
 2923     /* Why do we bother trying resurrect? See ##1## above. */
 2924 
 2925     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 2926     cl_node = NULL;
 2927     ccb_node = NULL;
 2928 
 2929     if (!locked &&
 2930         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 2931       TRACE_4("ERR_LIBRARY: Lock failed");
 2932       rc = SA_AIS_ERR_LIBRARY;
 2933       goto done;
 2934     }
 2935     locked = true;
 2936 
 2937     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 2938 
 2939     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 2940       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 2941               immHandle);
 2942       if (cl_node && cl_node->stale) {
 2943         cl_node->exposed = true;
 2944       }
 2945       rc = SA_AIS_ERR_BAD_HANDLE;
 2946       goto done;
 2947     }
 2948 
 2949     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 2950 
 2951     /* Look up ccb_node again */
 2952     imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 2953     if (!ccb_node) {
 2954       rc = SA_AIS_ERR_BAD_HANDLE;
 2955       TRACE_3(
 2956           "ERR_BAD_HANDLE: Ccb handle not valid after successful resurrect");
 2957       goto done;
 2958     }
 2959 
 2960     if (ccb_node->mExclusive) {
 2961       rc = SA_AIS_ERR_TRY_AGAIN;
 2962       TRACE_3(
 2963           "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, "
 2964           "in another thread",
 2965           ccb_node->mCcbId);
 2966       goto done;
 2967     }
 2968 
 2969     if (ccb_node->mAborted) {
 2970       rc = SA_AIS_ERR_FAILED_OPERATION;
 2971       TRACE_3("ERR_FAILED_OPERATION: Ccb-id %u was already aborted",
 2972               ccb_node->mCcbId);
 2973       goto done;
 2974     }
 2975   }
 2976 
 2977   /*Get the Admin Owner info  */
 2978   imma_admin_owner_node_get(&cb->admin_owner_tree, &(ccb_node->mAdminOwnerHdl),
 2979                             &ao_node);
 2980   if (!ao_node) {
 2981     rc = SA_AIS_ERR_LIBRARY;
 2982     TRACE_4("ERR_LIBRARY: No Amin-Owner associated with Ccb");
 2983     goto done;
 2984   }
 2985 
 2986   osafassert(ccb_node->mImmHandle == ao_node->mImmHandle);
 2987   adminOwnerId = ao_node->mAdminOwnerId;
 2988   ao_node = NULL;
 2989 
 2990   if (ccb_node->mApplied) { /* Current ccb-id is closed, get a new one.*/
 2991     if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 2992       TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 2993       goto done;
 2994     }
 2995     rc = imma_newCcbId(cb, ccb_node, adminOwnerId, &locked,
 2996                        cl_node->syncr_timeout);
 2997     cl_node = NULL;
 2998     /* ccb_node still valid if rc == SA_AIS_OK. */
 2999     if (rc == SA_AIS_OK) {
 3000       osafassert(!(ccb_node->mExclusive));
 3001       osafassert(locked);
 3002     }
 3003 
 3004     if (!locked) {
 3005       if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3006         rc = SA_AIS_ERR_LIBRARY;
 3007         TRACE_4("ERR_LIBRARY: Lock failed");
 3008         goto done;
 3009       }
 3010       locked = true;
 3011     }
 3012 
 3013     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3014     if (!(cl_node && cl_node->isOm)) {
 3015       rc = SA_AIS_ERR_LIBRARY;
 3016       TRACE_4("ERR_LIBRARY: No client associated with Admin Owner");
 3017       goto done;
 3018     }
 3019 
 3020     imma_proc_decrement_pending_reply(cl_node, true);
 3021 
 3022     if (rc != SA_AIS_OK) {
 3023       goto done;
 3024     }
 3025 
 3026     /* successfully obtained new ccb-id */
 3027 
 3028     if (cl_node->stale) {
 3029       /* Became stale AFTER we successfully obtained new ccb-id ! */
 3030       TRACE_3("ERR_FAILED_OPERATION: IMM Handle %llx became stale", immHandle);
 3031 
 3032       rc = SA_AIS_ERR_FAILED_OPERATION;
 3033       /* We know the ccb WAS terminated*/
 3034       ccb_node->mCcbId = 0;
 3035       ccb_node->mAborted = true;
 3036       goto done;
 3037     }
 3038   }
 3039 
 3040   osafassert(locked);
 3041   osafassert(cl_node);
 3042   osafassert(ccb_node);
 3043 
 3044   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 3045     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 3046     goto done;
 3047   }
 3048 
 3049   /* Populate the Object-Delete event */
 3050   memset(&evt, 0, sizeof(IMMSV_EVT));
 3051   evt.type = IMMSV_EVT_TYPE_IMMND;
 3052   evt.info.immnd.type = IMMND_EVT_A2ND_OBJ_DELETE;
 3053 
 3054   evt.info.immnd.info.objDelete.adminOwnerId = adminOwnerId;
 3055   evt.info.immnd.info.objDelete.ccbId = ccb_node->mCcbId;
 3056 
 3057   evt.info.immnd.info.objDelete.objectName.size = strlen(objectName) + 1;
 3058   evt.info.immnd.info.objDelete.objectName.buf = (char *)objectName;
 3059 
 3060   rc = imma_evt_fake_evs(cb, &evt, &out_evt, cl_node->syncr_timeout,
 3061                          cl_node->handle, &locked, false);
 3062   cl_node = NULL;
 3063   ccb_node = NULL;
 3064 
 3065   TRACE("objectDelete send RETURNED:%u", rc);
 3066 
 3067   if (out_evt) {
 3068     /* Process the outcome, note this is after a blocking call. */
 3069     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 3070     osafassert((out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR) ||
 3071                (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2));
 3072     if (rc == SA_AIS_OK) {
 3073       rc = out_evt->info.imma.info.errRsp.error;
 3074       if (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2) {
 3075         newErrorStrings =
 3076             imma_getErrorStrings(&(out_evt->info.imma.info.errRsp));
 3077       }
 3078     }
 3079     free(out_evt);
 3080     out_evt = NULL;
 3081   }
 3082 
 3083   /*We may be un-locked here but this should not matter. */
 3084 
 3085   if (!locked && m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3086     TRACE_4("ERR_LIBRARY: Lock failed");
 3087     rc = SA_AIS_ERR_LIBRARY;
 3088     goto lock_fail;
 3089   }
 3090   locked = true;
 3091 
 3092   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3093   if (!(cl_node && cl_node->isOm)) {
 3094     if (rc == SA_AIS_OK) {
 3095       TRACE_3("ERR_BAD_HANDLE: client_node gone on return from down-call");
 3096       rc = SA_AIS_ERR_BAD_HANDLE;
 3097     }
 3098     goto done;
 3099   }
 3100 
 3101   imma_proc_decrement_pending_reply(cl_node, true);
 3102 
 3103   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 3104   if (!ccb_node) {
 3105     TRACE_3("ERR_BAD_HANDLE: ccb-node gone on return from down-call");
 3106     /* BAD_HANDLE overrides any other return code already assigned. */
 3107     rc = SA_AIS_ERR_BAD_HANDLE;
 3108     goto done;
 3109   }
 3110 
 3111   osafassert(ccb_node->mErrorStrings == NULL);
 3112   ccb_node->mErrorStrings = newErrorStrings;
 3113   newErrorStrings = NULL; /* Dont free the strings on exit from this func */
 3114 
 3115   if (rc == SA_AIS_OK) {
 3116     if (cl_node->stale) {
 3117       /* Became stale during the blocked call yet the call
 3118          succeeded! This should be very rare.
 3119          We know the ccb is aborted. So we dont need to expose
 3120          the stale handle.
 3121       */
 3122       TRACE_3(
 3123           "ERR_FAILED_OPERATION: Handle %llx became stale "
 3124           "during the down-call",
 3125           immHandle);
 3126       ccb_node->mAborted = true;
 3127       rc = SA_AIS_ERR_FAILED_OPERATION;
 3128     }
 3129     if (ccb_node->mAugCcb) {
 3130       /* This is an OI augmented ccb.
 3131          Successfull object delete added by OI to root CCB =>
 3132          this aug-ccb must be applied (confirmed by the OI)
 3133          or the imm will interpret the missing confirmation
 3134          as abort and abort the entire root ccb.
 3135        */
 3136       ccb_node->mAugIsTainted = true;
 3137     }
 3138   } else if (rc == SA_AIS_ERR_TRY_AGAIN && (cb->is_immnd_up == false)) {
 3139     /*
 3140        We lost contact with the IMMND which means we KNOW the current
 3141        ccb-id associated with this ccb-handle was aborted in non-critical
 3142        phase. Better then to handle this as FAILED_OPERATION, since this
 3143        can avoid exposing the immHandle as BAD_HANDLE.
 3144      */
 3145     TRACE_3(
 3146         "ERR_FAILED_OPERATION: Converting TRY_AGAIN to FAILED_OPERATION "
 3147         "in ccbObjectDelete in IMMA");
 3148     rc = SA_AIS_ERR_FAILED_OPERATION;
 3149     ccb_node->mAborted = true;
 3150   } else if (rc == SA_AIS_ERR_FAILED_OPERATION) {
 3151     ccb_node->mAborted = true;
 3152   }
 3153 
 3154 clm_left:
 3155 done:
 3156   imma_free_errorStrings(
 3157       newErrorStrings); /* In case of failed resurrect only */
 3158 
 3159   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 3160 
 3161 lock_fail:
 3162   TRACE("objectDelete really RETURNING:%u", rc);
 3163   TRACE_LEAVE();
 3164   return rc;
 3165 }
 3166 
 3167 /****************************************************************************
 3168   Name          :  saImmOmCcbApply
 3169 
 3170   Description   :  Applies (commits) a CCB.
 3171                    This a blocking syncronous call.
 3172 
 3173 
 3174   Arguments     :  ccbHandle - Ccb Handle
 3175 
 3176   Return Values :  Refer to SAI-AIS specification for various return values.
 3177 
 3178 ******************************************************************************/
 3179 SaAisErrorT saImmOmCcbApply(SaImmCcbHandleT ccbHandle) {
 3180   return imma_applyCcb(ccbHandle, false);
 3181 }
 3182 
 3183 SaAisErrorT imma_applyCcb(SaImmCcbHandleT ccbHandle, bool onlyValidate) {
 3184   SaAisErrorT rc = SA_AIS_OK;
 3185   IMMA_CB *cb = &imma_cb;
 3186   IMMSV_EVT evt;
 3187   IMMSV_EVT *out_evt = NULL;
 3188   IMMA_CLIENT_NODE *cl_node = NULL;
 3189   IMMA_CCB_NODE *ccb_node = NULL;
 3190   bool locked = false;
 3191   SaImmHandleT immHandle = 0LL;
 3192   SaUint32T ccbId = 0;
 3193   SaStringT *newErrorStrings = NULL;
 3194   TRACE_ENTER();
 3195 
 3196   if (cb->sv_id == 0) {
 3197     TRACE_2("ERR_BAD_HANDLE :No initialized handle exists!");
 3198     return SA_AIS_ERR_BAD_HANDLE;
 3199   }
 3200 
 3201   /* No point in checking for cb->is_immnd_up here because there
 3202      is no point in giving ERR_RETRY on a CcbApply.
 3203      An apply would not be the first op for a ccb-id.
 3204    */
 3205 
 3206   /* get the CB Lock */
 3207   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3208     rc = SA_AIS_ERR_LIBRARY;
 3209     TRACE_4("ERR_LIBRARY: Lock failed");
 3210     goto lock_fail;
 3211   }
 3212   locked = true;
 3213 
 3214   /*Get the CCB info */
 3215   imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 3216   if (!ccb_node) {
 3217     rc = SA_AIS_ERR_BAD_HANDLE;
 3218     TRACE_2("ERR_BAD_HANDLE: Ccb handle not valid");
 3219     goto done;
 3220   }
 3221   TRACE("CCb node found for ccbhandle %llx ccbid:%u", ccbHandle,
 3222         ccb_node->mCcbId);
 3223 
 3224   if (ccb_node->mExclusive) {
 3225     rc = SA_AIS_ERR_TRY_AGAIN;
 3226     TRACE_3(
 3227         "ERR_TRY_AGAIN: Ccb-id %u being created or in critical phase, in another thread",
 3228         ccb_node->mCcbId);
 3229     goto done;
 3230   }
 3231 
 3232   if (ccb_node->mAborted) {
 3233     /* mApplied must only be set to true when the current
 3234        ccb-id has been EXPLICITLY applied by the user.
 3235        This can only be done by a successful explicit
 3236        saImmOmCcbApply. A ccb-handle with an aborted ccb-id
 3237        can only be used again after an explcit saImmOmCcbAbort() has been
 3238        invoked on the handle. Otherwise only finalize is allowed on
 3239        the handle.
 3240 
 3241        Setting mApplied to true opens for the IMPLICIT
 3242        start of a new ccb-id with the current and same SaImmCcbHandleT value.
 3243        Because start of ccb-id can be implicit, we insist that
 3244        termination of ccb-id is explicit from the user.
 3245        The user could otherwise miss seeing the current ccb-id aborted
 3246        and think the ccb was simply a continuation of the same
 3247        (actually aborted) ccb with its operations.
 3248     */
 3249     rc = SA_AIS_ERR_FAILED_OPERATION;
 3250     TRACE_2("ERR_FAILED_OPERATION: Ccb %u has already been aborted",
 3251             ccb_node->mCcbId);
 3252     goto done;
 3253   }
 3254 
 3255   if (ccb_node->mApplied) {
 3256     ccb_node->mApplied = false;
 3257     ccb_node->mAborted = true;
 3258     rc = SA_AIS_ERR_FAILED_OPERATION;
 3259     TRACE_2("ERR_FAILED_OPERATION: Ccb %u has already been applied",
 3260             ccb_node->mCcbId);
 3261     goto done;
 3262   }
 3263 
 3264   if (ccb_node->mValidated && onlyValidate) {
 3265     rc = SA_AIS_OK; /* Validation is idempotent on clientr side */
 3266     goto done;
 3267   }
 3268 
 3269   immHandle = ccb_node->mImmHandle;
 3270 
 3271   /* Free string from previous ccb-op */
 3272   imma_free_errorStrings(ccb_node->mErrorStrings);
 3273   ccb_node->mErrorStrings = NULL;
 3274 
 3275   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3276   if (!(cl_node && cl_node->isOm)) {
 3277     rc = SA_AIS_ERR_LIBRARY;
 3278     TRACE_4("ERR_LIBRARY: SaImmHandleT associated with Ccb %u is not valid",
 3279             ccb_node->mCcbId);
 3280     goto done;
 3281   }
 3282   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 3283     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 3284     rc = SA_AIS_ERR_UNAVAILABLE;
 3285     goto clm_left;
 3286   }
 3287 
 3288   if (cl_node->stale || !(cb->is_immnd_up)) {
 3289     TRACE_3(
 3290         "ERR_FAILED_OPERATION: IMMND DOWN and/or IMM Handle %llx "
 3291         "is stale - Ccb %u has to be aborted.",
 3292         ccb_node->mImmHandle, ccb_node->mCcbId);
 3293     /* No point in resurrecting here since we know the ccb-id failed.
 3294        But we can avoid exposing with BAD_HANDLE because the ccb-id
 3295        failed in non critical phase. Instead discard the ccb-id and
 3296        force the user to refresh the ccb-id.
 3297     */
 3298     ccb_node->mAborted = true;
 3299     rc = SA_AIS_ERR_FAILED_OPERATION;
 3300     goto done;
 3301   }
 3302 
 3303   if (ccb_node->mAugCcb) {
 3304     if (onlyValidate) {
 3305       LOG_IN(
 3306           "ERR_BAD_OPERATION: saImmOmCcbValidate() not allowed on augmented ccbs");
 3307       rc = SA_AIS_ERR_BAD_OPERATION;
 3308     } else {
 3309       TRACE("Apply for augmentation for CcbId %u", ccb_node->mCcbId);
 3310       ccb_node->mApplied = true;
 3311     }
 3312     goto done;
 3313   }
 3314 
 3315   /* Skip checking Admin Owner info  */
 3316 
 3317   /* Populate the CcbApply event */
 3318   memset(&evt, 0, sizeof(IMMSV_EVT));
 3319   evt.type = IMMSV_EVT_TYPE_IMMND;
 3320   evt.info.immnd.type =
 3321       (onlyValidate) ? IMMND_EVT_A2ND_CCB_VALIDATE : IMMND_EVT_A2ND_CCB_APPLY;
 3322   evt.info.immnd.info.ccbId = ccb_node->mCcbId;
 3323 
 3324   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 3325     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 3326     goto done;
 3327   }
 3328 
 3329   ccb_node->mExclusive = true;
 3330   ccb_node->mApplying = !onlyValidate;
 3331   ccbId = ccb_node->mCcbId;
 3332 
 3333   rc = imma_evt_fake_evs(cb, &evt, &out_evt, cl_node->syncr_timeout,
 3334                          cl_node->handle, &locked, false);
 3335   cl_node = NULL;
 3336   ccb_node = NULL;
 3337 
 3338   TRACE("fake_evs for ccb-apply returned %u", rc);
 3339 
 3340   if (out_evt) {
 3341     /* Process the outcome, note this is after a blocking call. */
 3342     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 3343     osafassert((out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR) ||
 3344                (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2));
 3345     if (rc != SA_AIS_OK) {
 3346       TRACE_4(
 3347           "CCB-APPLY - Error return from fevs!:%u, "
 3348           "yet reply message also received (?) with error %u",
 3349           rc, out_evt->info.imma.info.errRsp.error);
 3350       osafassert(out_evt->info.imma.info.errRsp.error != SA_AIS_OK);
 3351     } else {
 3352       rc = out_evt->info.imma.info.errRsp.error;
 3353       TRACE_1("CCB APPLY - reply received from IMMND rc:%u", rc);
 3354       if (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR_2) {
 3355         newErrorStrings =
 3356             imma_getErrorStrings(&(out_evt->info.imma.info.errRsp));
 3357       }
 3358     }
 3359 
 3360     free(out_evt);
 3361     out_evt = NULL;
 3362   } else if (rc == SA_AIS_OK) {
 3363     TRACE_4(
 3364         "CCB_APPLY - ERR_TIMEOUT: Got OK from fake_evs but no "
 3365         "reply message!, from IMMND. Raising ERR_TIMEOUT "
 3366         "to convey the unknown result from cb-apply!");
 3367     rc = SA_AIS_ERR_TIMEOUT;
 3368   }
 3369 
 3370   if (!locked && m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3371     TRACE_4("CCB APPLY - ERR_LIBRARY: Lock failed");
 3372     /* Error library overrides any existing rc including OK!*/
 3373     rc = SA_AIS_ERR_LIBRARY;
 3374     goto lock_fail;
 3375   }
 3376   locked = true;
 3377 
 3378   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3379   if (!(cl_node && cl_node->isOm)) {
 3380     TRACE_3("CCB APPLY - client node gone on return from IMMND!");
 3381     /* Client node removed during the blocked call. */
 3382     if (rc == SA_AIS_OK) {
 3383       /* yet the call succeeded! This should be very rare.
 3384          OK reply from ccbApply is precious.
 3385          Ignore the nonexistent client_node for now.
 3386       */
 3387       TRACE_3(
 3388           "CCB APPLY - OK reply from IMMND on ccb-apply, but "
 3389           "immHandle was closed on return. OK on CCB overrides "
 3390           "immHandle problem.");
 3391     }
 3392   } else {
 3393     /* Normal case, cl_node still exists. */
 3394     imma_proc_decrement_pending_reply(cl_node, true);
 3395     if (cl_node->stale) {
 3396       TRACE_3("CCB APPLY - Handle %llx is stale on return, exposed:%u",
 3397               immHandle, cl_node->exposed);
 3398       /* Became stale during the blocked call */
 3399       if (rc == SA_AIS_OK) {
 3400         /* yet the call succeeded! This should be very rare.
 3401            OK reply from ccbApply is precious.
 3402            Ignore the stale handle for now.
 3403            It may get resurrected since there will be no active ccb-id
 3404            associated with the ccb-handle.
 3405         */
 3406         TRACE_3(
 3407             "CCB APPLY - Ok reply from IMMND overrides"
 3408             "stale handle");
 3409       } else if ((rc != SA_AIS_ERR_TIMEOUT) && (rc != SA_AIS_ERR_BAD_HANDLE)) {
 3410         TRACE_3("CCB APPLY - ERR_BAD_HANDLE(%u) overrides rc %u",
 3411                 SA_AIS_ERR_BAD_HANDLE, rc);
 3412         rc = SA_AIS_ERR_BAD_HANDLE;
 3413         /* is converted to ERR_TIMEOUT below */
 3414         /* Dont set exposed just yet */
 3415       }
 3416     }
 3417 
 3418     imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 3419     if (ccb_node) {
 3420       ccb_node->mExclusive = false;
 3421       ccb_node->mApplying = false;
 3422       osafassert(ccb_node->mErrorStrings == NULL);
 3423       if (rc == SA_AIS_OK) {
 3424         ccb_node->mValidated = true;
 3425         ccb_node->mApplied = !onlyValidate;
 3426         TRACE_1("CCB APPLY - Successful Apply for ccb id %u", ccb_node->mCcbId);
 3427       } else {
 3428         ccb_node->mErrorStrings = newErrorStrings;
 3429         newErrorStrings = NULL; /* Dont free strings on exit */
 3430       }
 3431     } else {
 3432       /*This branch should not be possible if ccb_node->mExclusive is respected.
 3433        */
 3434       TRACE_4(
 3435           "CCB APPLY - Ccb-handle closed on return from "
 3436           "ccb-apply down-call. Should not be possible!");
 3437       if (rc == SA_AIS_OK) {
 3438         TRACE_3(
 3439             "CCB APPLY - Ok reply from server on ccb-apply, "
 3440             "but ccbHandle was closed on return. OK on CCB "
 3441             "overrides ccbHandle problem.");
 3442       } else {
 3443         TRACE_3(
 3444             "CCB APPLY - CcbHandle no longer valid on "
 3445             "return, Error %u already set",
 3446             rc);
 3447       }
 3448     }
 3449   }
 3450 
 3451   if (rc == SA_AIS_OK) {
 3452     goto done;
 3453   }
 3454 
 3455   /* Now do some special conversion of error codes particular for ccb-apply */
 3456 
 3457   if (rc == SA_AIS_ERR_TRY_AGAIN) {
 3458     TRACE_3(
 3459         "CCB APPLY: Error in send/receive of ccb-apply message! "
 3460         "converting ERR_TRY_AGAIN to ...");
 3461     /* No point in returning TRY_AGAIN for ccb-apply.
 3462        We KNOW the ccb is aborted.
 3463        TRY_AGAIN could only have come from imma_evt_fake_evs
 3464        detecting IMMND DOWN *before* sending the request.
 3465        There is no TRY_AGAIN case from server side ccbApply.
 3466        Convert ERR_TRY_AGAIN to FAILED_OPERATION !
 3467        Handle will also be stale, but that is taken care of later.
 3468     */
 3469 
 3470     if (ccb_node) {
 3471       osafassert(!(ccb_node->mApplied));
 3472       ccb_node->mAborted = true;
 3473       rc = SA_AIS_ERR_FAILED_OPERATION;
 3474       TRACE_3("CCB APPLY - .... ERR_FAILED_OPERATION");
 3475     } else {
 3476       rc = SA_AIS_ERR_LIBRARY;
 3477       TRACE_4(
 3478           "CCB APPLY - .... ERR_LIBRARY: ccb-node removed during ccb-apply, "
 3479           "ccb_node->mExclusive violated");
 3480     }
 3481   }
 3482 
 3483   if (rc == SA_AIS_ERR_BAD_HANDLE) {
 3484     TRACE_3(
 3485         "CCB APPLY - ERR_TIMEOUT: Error during execution of "
 3486         "ccb-apply! converting ERR_BAD_HANDLE to ERR_TIMEOUT");
 3487     /* For the special case of ccb-apply we convert ERR_BAD_HANDLE to
 3488        ERR_TIMEOUT. This to converge all error handling for UNKNOWN OUTCOME of a
 3489        ccb to a single error code. Unknown result for a ccb is what the user
 3490        least of all wants to deal with from apply, but it can happen.
 3491 
 3492        ERR_BAD_HANDLE >>here<< means either IMMND went down during
 3493        processing of the apply down call, OR that the client-node or
 3494        ccb-node was removed by another thread in this client during
 3495        the down call.
 3496 
 3497        There is a small risk that the ccb managed to be applied
 3498        just before an IMMND crash. This is particularly the case for
 3499        CCBs that do not invovle implementers, since they commit
 3500        independently at all IMMNDs.
 3501        ERR_TIMEOUT is in fact converted *to* ERR_BAD_HANDLE by
 3502        fevs/imma_proc_check_stale. This is preferred for most other calls,
 3503        but not for ccb-apply!.
 3504 
 3505        For the case of client_node or ccb_node removed the CCB
 3506        outcome should definitely be that the CCB was not applied.
 3507        But for simplicity we converge also these cases of ERR_BAD_HANDLE
 3508        to ERR_TIMEOUT.
 3509 
 3510        The typical client would interpret ERR_BAD_HANDLE from
 3511        ccb-apply as if the CCB has not applied, but that could
 3512        be wrong.
 3513 
 3514        Therefore we convert ERR_BAD_HANDLE back ERR_TIMEOUT here,
 3515        to convey the honest uncertatinty of the ccb result towards
 3516        the client.
 3517 
 3518        Recovery of the ccb outcome may in turn be attempted next.
 3519     */
 3520 
 3521     rc = SA_AIS_ERR_TIMEOUT;
 3522   }
 3523 
 3524   if (rc == SA_AIS_ERR_TIMEOUT) {
 3525     /* Try to contact IMMND when up again and recover the result
 3526       of the ccb. If we fail here also then remove the ccb-node since
 3527       we dont want it to indicate aborted, nor applied, nor active.
 3528     */
 3529     TRACE_3("client_node %p exposed :%u", cl_node,
 3530             cl_node ? (cl_node->exposed) : 0);
 3531     if (onlyValidate) {
 3532       /* Let ERR_TIMEOUT reach the user when only validation was attempted.
 3533          This means the user does not know if validation succeeded or not.
 3534          They can choose to try to apply/commit the ccb which could succeed if
 3535          validation did succeed. But if validation failed then the apply/commit
 3536          will fail.
 3537 
 3538          If the validation is still on-going when the attempt to apply/commit
 3539          reaches the immsv, then the user should get TRY_AGAIN from local IMMND.
 3540        */
 3541       goto done;
 3542     }
 3543 
 3544     /* Reset the ccb_node flags back to indicate apply is in progress. */
 3545     if (ccb_node) {
 3546       ccb_node->mExclusive = true;
 3547       ccb_node->mApplying = true;
 3548     }
 3549 
 3550     /* Release the CB lock Before MDS Send */
 3551     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 3552     locked = false;
 3553 
 3554     rc = imma_proc_recover_ccb_result(cb, ccbId);
 3555 
 3556     if (ccb_node) {
 3557       /* ccb_node existed before recover_ccb_outcome downcall, try to
 3558          obtain it again.
 3559       */
 3560       if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3561         TRACE_4("CCB APPLY - ERR_LIBRARY: Lock failed");
 3562         /* Error library overrides any existing rc including OK!*/
 3563         rc = SA_AIS_ERR_LIBRARY;
 3564         goto lock_fail;
 3565       }
 3566       locked = true;
 3567 
 3568       ccb_node = NULL;
 3569       imma_ccb_node_get(&cb->ccb_tree, &ccbHandle, &ccb_node);
 3570       if (ccb_node) {
 3571         ccb_node->mExclusive = false;
 3572         ccb_node->mApplying = false;
 3573       }
 3574     }
 3575 
 3576     if (rc == SA_AIS_OK) {
 3577       TRACE_3(
 3578           "CCB APPLY - SA_AIS_OK: CCB result recovery SUCCEEDED - "
 3579           "Apply/Commit for ccb id %u result was OK",
 3580           ccbId);
 3581       if (ccb_node) {
 3582         ccb_node->mApplied = true;
 3583       }
 3584       goto done;
 3585     }
 3586 
 3587     if (rc == SA_AIS_ERR_TIMEOUT) {
 3588       TRACE_4(
 3589           "CCB APPLY: CCB result recovery FAILED for "
 3590           "ccb id %u returning ERR_TIMEOUT",
 3591           ccbId);
 3592       if (ccb_node) {
 3593         ccb_node->mExclusive = true;
 3594         imma_ccb_node_delete(cb, ccb_node);
 3595         ccb_node = NULL;
 3596       }
 3597       goto done;
 3598     }
 3599 
 3600     osafassert(rc == SA_AIS_ERR_FAILED_OPERATION);
 3601     TRACE_3(
 3602         "CCB APPLY: CCB result recovery SUCCEEDED - "
 3603         "ABORT for ccb id %u",
 3604         ccbId);
 3605 
 3606   } /*if(rc == SA_AIS_ERR_TIMEOUT)*/
 3607 
 3608   if (rc == SA_AIS_ERR_NO_RESOURCES) {
 3609     /* NO_RESOUCES from server is in the ccbApply case to be interpreted
 3610        as the PBE having too much backlog. */
 3611     rc = SA_AIS_ERR_TRY_AGAIN;
 3612     goto done;
 3613   }
 3614 
 3615   if (ccb_node) {
 3616     ccb_node->mAborted = true;
 3617   }
 3618 
 3619 clm_left:
 3620 done:
 3621   imma_free_errorStrings(
 3622       newErrorStrings); /* In case of failed resurrect only */
 3623 
 3624   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 3625 
 3626 lock_fail:
 3627   TRACE_LEAVE();
 3628   return rc;
 3629 }
 3630 
 3631 /****************************************************************************
 3632   Name          :  saImmOmCcbAbort
 3633 
 3634   Description   :  Aborts a CCB(id) without finalizing the ccb-handle.
 3635                    Discards any ccb operations currently associated with the
 3636 ccb-handle. Also resetts a ccbHandle that has previously received the abort
 3637                    return code SA_AIS_ERR_FAILED_OPERATION.
 3638 
 3639                    Previously it was only possible to explicitly abort an active
 3640 ccb by invoking saImOmCcbFinalize() which also closes the ccb-handle.
 3641 
 3642                    Previously it was also not possible to reset a ccbHandle that
 3643 had received the ccb-aborted return code: SA_AIS_ERR_FAILED_OPERATION.
 3644 
 3645                    If SA_AIS_OK is returned then ccb-handle can continue to be
 3646 used and is in the same empty state as if it had just been initialized.
 3647 
 3648                    This a blocking syncronous call.
 3649 
 3650 
 3651   Arguments     :  ccbHandle - Ccb Handle
 3652 
 3653   Return Values :  SA_AIS_OK; - Means the ccb contents has been discarded.
 3654                                 and involved Ois receive abort callback.
 3655                                 Ccb handle is still valid.
 3656 
 3657                    SA_AIS_ERR_VERSION - Not allowed for IMM API version below
 3658 A.2.14. SA_AIS_ERR_BAD_OPERATION - saImmOmCcbAbort not allowed in ccb
 3659                                               augmentation
 3660 
 3661                    Remaining returncodes identical to saImmOmFinalize.
 3662 
 3663 
 3664 ******************************************************************************/
 3665 SaAisErrorT saImmOmCcbAbort(SaImmCcbHandleT ccbHandle) {
 3666   return imma_finalizeCcb(ccbHandle, true);
 3667 }
 3668 
 3669 /****************************************************************************
 3670   Name          :  saImmOmCcbValidate
 3671 
 3672   Description   :  Performs the validation part of ccb-apply for the CCB in its
 3673                    current active state. If validation succeeds, then no
 3674 additional ccb-operations can be added to the ccb until the current set of
 3675                    operations have been applied or aborted. An apply of a
 3676 successfully validated ccb is highly likely to succeed, but still not guaranteed
 3677                    to succeed. If an apply of a validated ccb fails, it will
 3678 obviously not be due to any failure in validation, but for "physical" reasons,
 3679                    such as some problem with the PBE (persistent back end), or a
 3680 crash of some vital IMM process.
 3681 
 3682                    Thus after a successfull saImmOmCcbValidate, the ccb is in a
 3683 state that only accepts one of:
 3684 
 3685                       - saImmOmCcbApply(ccbHandle);  - Only applicable if
 3686 saImmOmCcbValidate returned SA_AIS_OK, SA_AIS_ERR_TIMEOUT, or
 3687 SA_AIS_ERR_TRY_AGAIN (validation not done).
 3688 
 3689                       - saImmOmCcbAbort(ccbHandle);    - Always applicable if
 3690 handle is valid. - saImmOmCcbFinalize(ccbHandle); - Always applicable if handle
 3691 is valid.
 3692 
 3693   Arguments     :  ccbHandle - Ccb Handle
 3694 
 3695   Return Values :  Same return values as saImmOmCcbApply with the following
 3696 adjustment: SA_AIS_OK - Validation succeeded. Ccb has not been
 3697 committed/applied. This ccb can now be aborted or an attempt may be made to
 3698                                apply/commit.
 3699 
 3700                    Refer to SAI-AIS IMM A.2.1 specification for the other return
 3701 values and to the OpenSAF_IMMSv_PR (programmers reference) for implementation
 3702                    specific details.
 3703 
 3704                    Note that just as for regular saImm*OmCcbApply an abort is
 3705 signalled by: SA_AIS_ERR_FAILED_OPERATION - Ccb is aborted possibly due to
 3706 failed validation.
 3707 
 3708 
 3709 
 3710 
 3711 ******************************************************************************/
 3712 SaAisErrorT saImmOmCcbValidate(SaImmCcbHandleT ccbHandle) {
 3713   return imma_applyCcb(ccbHandle, true);
 3714 }
 3715 
 3716 /****************************************************************************
 3717   Name          :  saImmOmAdminOperationInvoke_2/_o2/_o3
 3718 
 3719   Description   :  Invoke an Administrative Operation on an object in the IMM.
 3720                    This a blocking syncronous call.
 3721 
 3722 
 3723   Arguments     :  ownerHandle - AdminOwner handle.
 3724                    objectName - A pointer to the name of the object
 3725                            on which the operation is to be invoked.
 3726                    operationId - An id identifying the operation.
 3727                    params - Parameters to be supplied to the operation.
 3728                    operationReturnValue - The return value from implementer.
 3729                    timeout - Invocation is considered to be failed if this
 3730                              function does not complete by the time specified.
 3731 
 3732   Return Values :  Refer to SAI-AIS specification for various return values.
 3733 
 3734   Notes         : Note the TWO return values!
 3735 ******************************************************************************/
 3736 static SaAisErrorT admin_op_invoke_common(
 3737     SaImmAdminOwnerHandleT ownerHandle, SaConstStringT objectName,
 3738     SaImmContinuationIdT continuationId, SaImmAdminOperationIdT operationId,
 3739     const SaImmAdminOperationParamsT_2 **params,
 3740     SaAisErrorT *operationReturnValue, SaTimeT timeout,
 3741     SaImmAdminOperationParamsT_2 ***returnParams, bool isA2bCall,
 3742     bool bUseString);
 3743 
 3744 SaAisErrorT saImmOmAdminOperationInvoke_2(
 3745     SaImmAdminOwnerHandleT ownerHandle, const SaNameT *objectName,
 3746     SaImmContinuationIdT continuationId, SaImmAdminOperationIdT operationId,
 3747     const SaImmAdminOperationParamsT_2 **params,
 3748     SaAisErrorT *operationReturnValue, SaTimeT timeout) {
 3749   bool freeMemory = false;
 3750   SaStringT objectNameStr = NULL;
 3751   SaAisErrorT rc;
 3752 
 3753   if (objectName) {
 3754     if (!osaf_is_extended_name_valid(objectName)) {
 3755       TRACE_2("ERR_INVALID_PARAM: Object name is invalid");
 3756       return SA_AIS_ERR_INVALID_PARAM;
 3757     }
 3758 
 3759     size_t len = osaf_extended_name_length(objectName);
 3760     if (len < SA_MAX_UNEXTENDED_NAME_LENGTH) {
 3761       objectNameStr = (SaStringT)malloc(len + 1);
 3762       memcpy(objectNameStr, osaf_extended_name_borrow(objectName), len);
 3763       objectNameStr[len] = 0;
 3764       freeMemory = true;
 3765     } else {
 3766       objectNameStr = (SaStringT)osaf_extended_name_borrow(objectName);
 3767     }
 3768   }
 3769 
 3770   rc = admin_op_invoke_common(ownerHandle, objectNameStr, continuationId,
 3771                               operationId, params, operationReturnValue,
 3772                               timeout, NULL, false, false);
 3773 
 3774   if (freeMemory) {
 3775     free(objectNameStr);
 3776   }
 3777 
 3778   return rc;
 3779 }
 3780 
 3781 SaAisErrorT saImmOmAdminOperationInvoke_o2(
 3782     SaImmAdminOwnerHandleT ownerHandle, const SaNameT *objectName,
 3783     SaImmContinuationIdT continuationId, SaImmAdminOperationIdT operationId,
 3784     const SaImmAdminOperationParamsT_2 **params,
 3785     SaAisErrorT *operationReturnValue, SaTimeT timeout,
 3786     SaImmAdminOperationParamsT_2 ***returnParams) {
 3787   bool freeMemory = false;
 3788   SaStringT objectNameStr = NULL;
 3789   SaAisErrorT rc;
 3790 
 3791   if (objectName) {
 3792     if (!osaf_is_extended_name_valid(objectName)) {
 3793       TRACE_2("ERR_INVALID_PARAM: Object name is invalid");
 3794       return SA_AIS_ERR_INVALID_PARAM;
 3795     }
 3796 
 3797     size_t len = osaf_extended_name_length(objectName);
 3798     if (len < SA_MAX_UNEXTENDED_NAME_LENGTH) {
 3799       objectNameStr = (SaStringT)malloc(len + 1);
 3800       memcpy(objectNameStr, osaf_extended_name_borrow(objectName), len);
 3801       objectNameStr[len] = 0;
 3802       freeMemory = true;
 3803     } else {
 3804       objectNameStr = (SaStringT)osaf_extended_name_borrow(objectName);
 3805     }
 3806   }
 3807 
 3808   rc = admin_op_invoke_common(ownerHandle, objectNameStr, continuationId,
 3809                               operationId, params, operationReturnValue,
 3810                               timeout, returnParams, true, false);
 3811 
 3812   if (freeMemory) {
 3813     free(objectNameStr);
 3814   }
 3815 
 3816   return rc;
 3817 }
 3818 
 3819 SaAisErrorT saImmOmAdminOperationInvoke_o3(
 3820     SaImmAdminOwnerHandleT ownerHandle, SaConstStringT objectName,
 3821     SaImmContinuationIdT continuationId, SaImmAdminOperationIdT operationId,
 3822     const SaImmAdminOperationParamsT_2 **params,
 3823     SaAisErrorT *operationReturnValue, SaTimeT timeout,
 3824     SaImmAdminOperationParamsT_2 ***returnParams) {
 3825   return admin_op_invoke_common(ownerHandle, objectName, continuationId,
 3826                                 operationId, params, operationReturnValue,
 3827                                 timeout, returnParams, true, true);
 3828 }
 3829 
 3830 static SaAisErrorT admin_op_invoke_common(
 3831     SaImmAdminOwnerHandleT ownerHandle, SaConstStringT objectName,
 3832     SaImmContinuationIdT continuationId, SaImmAdminOperationIdT operationId,
 3833     const SaImmAdminOperationParamsT_2 **params,
 3834     SaAisErrorT *operationReturnValue, SaTimeT timeout,
 3835     SaImmAdminOperationParamsT_2 ***returnParams, bool isA2bCall,
 3836     bool bUseString) {
 3837   SaAisErrorT rc = SA_AIS_OK;
 3838   IMMA_CB *cb = &imma_cb;
 3839   IMMSV_EVT evt;
 3840   IMMSV_EVT *out_evt = NULL;
 3841   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 3842   IMMA_CLIENT_NODE *cl_node = NULL;
 3843   bool locked = true;
 3844   SaImmHandleT immHandle = 0LL;
 3845   SaUint32T adminOwnerId = 0;
 3846   bool opIdEsc = (operationId >= SA_IMM_PARAM_ADMOP_ID_ESC);
 3847   bool opNamePar = false;
 3848   TRACE_ENTER();
 3849 
 3850   if (timeout < 0) {
 3851     TRACE_4(
 3852         "saImmOmAdminOperationInvoke: failed invalid timeout return value:%d,immHandle:%llx",
 3853         SA_AIS_ERR_INVALID_PARAM, immHandle);
 3854     rc = SA_AIS_ERR_INVALID_PARAM;
 3855     goto done;
 3856   } else if (timeout >
 3857              (SA_TIME_ONE_MILLISECOND * MDS_MAX_TIMEOUT_MILLISECOND)) {
 3858     TRACE_4(
 3859         "saImmOmAdminOperationInvoke: timeout>MDS_MAX_TIMEOUT setting to max :%lld, immHandle:%llx",
 3860         (SA_TIME_ONE_MILLISECOND * MDS_MAX_TIMEOUT_MILLISECOND), immHandle);
 3861     timeout = (SA_TIME_ONE_MILLISECOND * MDS_MAX_TIMEOUT_MILLISECOND);
 3862   }
 3863 
 3864   if (cb->sv_id == 0) {
 3865     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 3866     return SA_AIS_ERR_BAD_HANDLE;
 3867   }
 3868 
 3869   if ((objectName == NULL) || (operationReturnValue == NULL) ||
 3870       (!objectName[0]) ||
 3871       !(osaf_is_extended_names_enabled() ||
 3872         strlen(objectName) < SA_MAX_UNEXTENDED_NAME_LENGTH) ||
 3873       (params == NULL)) {
 3874     rc = SA_AIS_ERR_INVALID_PARAM;
 3875     goto done;
 3876   }
 3877 
 3878   if (!imma_proc_is_adminop_params_valid(params)) {
 3879     rc = SA_AIS_ERR_INVALID_PARAM;
 3880     goto done;
 3881   }
 3882 
 3883   if (returnParams) {
 3884     /* Detach from any old lingering result. */
 3885     *returnParams = NULL;
 3886   }
 3887 
 3888   if (cb->is_immnd_up == false) {
 3889     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 3890     return SA_AIS_ERR_TRY_AGAIN;
 3891   }
 3892 
 3893   /*Overwrite any old/uninitialized value. */
 3894   *operationReturnValue =
 3895       SA_AIS_ERR_NO_SECTIONS; /* Set to bad value to prevent user mistakes. */
 3896 
 3897   /* get the CB Lock */
 3898   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3899     rc = SA_AIS_ERR_LIBRARY;
 3900     TRACE_4("ERR_LIBRARY: Lock failed");
 3901     goto lock_fail;
 3902   }
 3903   /*locked == true already */
 3904 
 3905   /* Get the Admin Owner info  */
 3906   imma_admin_owner_node_get(&cb->admin_owner_tree, &ownerHandle, &ao_node);
 3907   if (!ao_node) {
 3908     TRACE_2(
 3909         "ERR_BAD_HANDLE: No admin owner associated with admin owner handle!");
 3910     rc = SA_AIS_ERR_BAD_HANDLE;
 3911     goto ao_not_found;
 3912   }
 3913 
 3914   if (ao_node->mAugCcb) {
 3915     TRACE_2(
 3916         "ERR_NO_RESOURCES: Augmented CCB AdminOwner handle not allowed here");
 3917     rc = SA_AIS_ERR_NO_RESOURCES;
 3918     goto ao_not_found;
 3919   }
 3920 
 3921   immHandle = ao_node->mImmHandle;
 3922 
 3923   /* Look up client node also, to verify that the client handle
 3924      is still active. */
 3925 
 3926   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3927   if (!(cl_node && cl_node->isOm)) {
 3928     rc = SA_AIS_ERR_LIBRARY;
 3929     TRACE_4("ERR_LIBRARY: No valid SaImmHandleT associated with Admin owner");
 3930     goto client_not_found;
 3931   }
 3932 
 3933   if (bUseString && !cl_node->isImmA2f) {
 3934     rc = SA_AIS_ERR_VERSION;
 3935     TRACE_2(
 3936         "ERR_VERSION: saImmOmAdminOperationInvoke_o3 only supported for "
 3937         "A.02.15 and above");
 3938     goto client_not_found;
 3939   }
 3940   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 3941     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 3942     rc = SA_AIS_ERR_UNAVAILABLE;
 3943     goto clm_left;
 3944   }
 3945 
 3946   if (cl_node->stale) {
 3947     TRACE_1("IMM Handle %llx is stale", immHandle);
 3948     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 3949     cl_node = NULL;
 3950 
 3951     if (!locked &&
 3952         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 3953       TRACE_4("ERR_LIBRARY: Lock failed");
 3954       rc = SA_AIS_ERR_LIBRARY;
 3955       goto lock_fail;
 3956     }
 3957     locked = true;
 3958 
 3959     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 3960     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 3961       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 3962               immHandle);
 3963       if (cl_node && cl_node->stale) {
 3964         cl_node->exposed = true;
 3965       }
 3966       rc = SA_AIS_ERR_BAD_HANDLE;
 3967       goto stale_handle;
 3968     }
 3969 
 3970     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 3971   }
 3972 
 3973   adminOwnerId = ao_node->mAdminOwnerId;
 3974   ao_node = NULL;
 3975 
 3976   if (isA2bCall && !(cl_node->isImmA2b)) {
 3977     rc = SA_AIS_ERR_VERSION;
 3978     TRACE_2(
 3979         "ERR_VERSION: saImmOmAdminOperationInvoke_o2 only supported for "
 3980         "A.02.11 and above");
 3981     goto stale_handle;
 3982   }
 3983 
 3984   /* convert the timeout to 10 ms value and add it to the sync send
 3985      timeout */
 3986   timeout = m_IMMSV_CONVERT_SATIME_TEN_MILLI_SEC(timeout);
 3987 
 3988   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 3989     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 3990     goto bad_sync;
 3991   }
 3992 
 3993   /* Populate the Admin-op event */
 3994   memset(&evt, 0, sizeof(IMMSV_EVT));
 3995   evt.type = IMMSV_EVT_TYPE_IMMND;
 3996   evt.info.immnd.type = IMMND_EVT_A2ND_IMM_ADMOP;
 3997 
 3998   evt.info.immnd.info.admOpReq.adminOwnerId = adminOwnerId;
 3999   evt.info.immnd.info.admOpReq.operationId = operationId;
 4000   evt.info.immnd.info.admOpReq.continuationId = continuationId; /*New API */
 4001 
 4002   /* The timeout is packed here and goes over fevs, need to
 4003      consider how the timing of FEVS itself should be subtracted.
 4004      The timeout is also set up in the FEVS call so it IS handled
 4005      on the agent side. Not sure why we need it on the server, other than
 4006      as a "leniency indicator". That is if timeout is large we may need to
 4007      increase the wait time in the server above some default. */
 4008   evt.info.immnd.info.admOpReq.timeout = timeout;
 4009 
 4010   if ((immInvocations < 0) || (immInvocations == 0x7fffffff)) {
 4011     immInvocations = 0;
 4012   }
 4013   TRACE("immInvocations:%i", immInvocations);
 4014   evt.info.immnd.info.admOpReq.invocation = ++immInvocations;
 4015 
 4016   evt.info.immnd.info.admOpReq.objectName.size = strlen(objectName) + 1;
 4017   evt.info.immnd.info.admOpReq.objectName.buf = (char *)objectName;
 4018 
 4019   osafassert(evt.info.immnd.info.admOpReq.params == NULL);
 4020   int i;
 4021   for (i = 0; params[i]; ++i) {
 4022     const SaImmAdminOperationParamsT_2 *param = params[i];
 4023     /*alloc-2 */
 4024     IMMSV_ADMIN_OPERATION_PARAM *p = (IMMSV_ADMIN_OPERATION_PARAM *)malloc(
 4025         sizeof(IMMSV_ADMIN_OPERATION_PARAM));
 4026     memset(p, 0, sizeof(IMMSV_ADMIN_OPERATION_PARAM));
 4027     TRACE("PARAM:%s \n", param->paramName);
 4028 
 4029     if (!opNamePar) {
 4030       opNamePar =
 4031           opIdEsc && (strcmp(param->paramName, SA_IMM_PARAM_ADMOP_NAME) == 0);
 4032       if (opNamePar && (param->paramType != SA_IMM_ATTR_SASTRINGT)) {
 4033         TRACE_2("ERR_INVALID_PARAM: Param %s must be of type SaStringT",
 4034                 SA_IMM_PARAM_ADMOP_NAME);
 4035         rc = SA_AIS_ERR_INVALID_PARAM;
 4036         free(p);
 4037         p = NULL;
 4038         goto mds_send_fail;
 4039       }
 4040     }
 4041 
 4042     p->paramName.size = strlen(param->paramName) + 1;
 4043     if (p->paramName.size >= IMMSV_MAX_PARAM_NAME_LENGTH) {
 4044       TRACE_2("ERR_INVALID_PARAM: Param name too long");
 4045       rc = SA_AIS_ERR_INVALID_PARAM;
 4046       free(p);
 4047       p = NULL;
 4048       goto mds_send_fail;
 4049     }
 4050     /*alloc-3 */
 4051     p->paramName.buf = (char *)malloc(p->paramName.size);
 4052     strncpy(p->paramName.buf, param->paramName, p->paramName.size);
 4053     p->paramName.buf[p->paramName.size-1] = 0;
 4054 
 4055     p->paramType = param->paramType;
 4056     /*alloc-4 */
 4057     imma_copyAttrValue(&(p->paramBuffer), param->paramType, param->paramBuffer);
 4058 
 4059     p->next = evt.info.immnd.info.admOpReq.params; /*NULL initially. */
 4060     evt.info.immnd.info.admOpReq.params = p;
 4061   }
 4062 
 4063   if (opIdEsc && !opNamePar && cl_node->isImmA2b) {
 4064     TRACE_2("ERR_INVALID_PARAM: Op-id > %llx requires param %s",
 4065             (long long unsigned int)SA_IMM_PARAM_ADMOP_ID_ESC,
 4066             SA_IMM_PARAM_ADMOP_NAME);
 4067     rc = SA_AIS_ERR_INVALID_PARAM;
 4068     goto mds_send_fail;
 4069   }
 4070 
 4071   /* NOTE: Re-implement to send ND->ND instead of using FEVS,
 4072      less resources used and probably faster.  But we need to
 4073      uphold exclusiveness relative to ccbs .. see ERR_BUSY
 4074   */
 4075 
 4076   rc = imma_evt_fake_evs(cb, &evt, &out_evt, timeout, cl_node->handle, &locked,
 4077                          false);
 4078   cl_node = NULL;
 4079 
 4080   TRACE("Fevs send RETURNED:%u", rc);
 4081 
 4082   if (rc != SA_AIS_OK) {
 4083     goto mds_send_fail;
 4084   }
 4085 
 4086   if (out_evt) {
 4087     /* Process the outcome, note this is after a blocking call. */
 4088     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 4089     if (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR) {
 4090       rc = out_evt->info.imma.info.errRsp.error;
 4091       TRACE("ERROR returned:%u", rc);
 4092       osafassert(rc != SA_AIS_OK);
 4093       *operationReturnValue = (SaAisErrorT)
 4094           IMMSV_IMPOSSIBLE_ERROR;  // Bogus result since error is set.
 4095     } else {
 4096       TRACE("Normal return");
 4097       osafassert((out_evt->info.imma.type == IMMA_EVT_ND2A_ADMOP_RSP) ||
 4098                  (out_evt->info.imma.type == IMMA_EVT_ND2A_ADMOP_RSP_2));
 4099       *operationReturnValue = out_evt->info.imma.info.admOpRsp.result;
 4100       if ((*operationReturnValue) == IMMSV_IMPOSSIBLE_ERROR) {
 4101         rc = SA_AIS_ERR_FAILED_OPERATION;
 4102       }
 4103       if ((out_evt->info.imma.type == IMMA_EVT_ND2A_ADMOP_RSP_2) &&
 4104           (out_evt->info.imma.info.admOpRsp.parms)) {
 4105         TRACE("Decoding return params");
 4106         if (returnParams) {
 4107           *returnParams =
 4108               imma_proc_get_params(out_evt->info.imma.info.admOpRsp.parms);
 4109           // imma_proc_free_pointers(cb, &(out_evt->info.imma)); ABT: Crashes,
 4110           // figure out why!
 4111 
 4112           /* Check SaNameT values if the client side does not support extended
 4113            * names. In this case if everything is ok, but the client does not
 4114            * support extended names, operationReturnValue should be set to
 4115            * SA_AIS_ERR_NAME_TOO_LONG, and SaNameT values should be cleared */
 4116           if (!osaf_is_extended_names_enabled()) {
 4117             i = 0;
 4118             while ((*returnParams)[i]) {
 4119               if ((*returnParams)[i]->paramType == SA_IMM_ATTR_SANAMET &&
 4120                   !osaf_is_extended_name_valid(
 4121                       (SaNameT *)(*returnParams)[i]->paramBuffer)) {
 4122                 if (*operationReturnValue == SA_AIS_OK) {
 4123                   *operationReturnValue = SA_AIS_ERR_NAME_TOO_LONG;
 4124                 }
 4125                 osaf_extended_name_free(
 4126                     (SaNameT *)(*returnParams)[i]->paramBuffer);
 4127                 osaf_extended_name_clear(
 4128                     (SaNameT *)(*returnParams)[i]->paramBuffer);
 4129               }
 4130               i++;
 4131             }
 4132           }
 4133         } else {
 4134           imma_proc_free_pointers(cb, &(out_evt->info.imma));
 4135         }
 4136       }
 4137     }
 4138 
 4139     free(out_evt);
 4140     out_evt = NULL;
 4141   }
 4142 
 4143 mds_send_fail:
 4144   /*We may be un-locked here but this should not matter.
 4145      We are freing heap objects that should only be vissible from this
 4146      thread. */
 4147 
 4148   /*TODO 12345 The code below should be moved to common ?
 4149      This to allow re-use by all allocators of this event type.
 4150      At least it needs to be duplicated in immnd_evt.c/immnd_evt_destroy */
 4151 
 4152   while (evt.info.immnd.info.admOpReq.params) {
 4153     IMMSV_ADMIN_OPERATION_PARAM *p = evt.info.immnd.info.admOpReq.params;
 4154     evt.info.immnd.info.admOpReq.params = p->next;
 4155 
 4156     if (p->paramName.buf) { /*free-3 */
 4157       free(p->paramName.buf);
 4158       p->paramName.buf = NULL;
 4159     }
 4160     immsv_evt_free_att_val(&(p->paramBuffer),
 4161                            (SaImmValueTypeT)p->paramType); /*free-4 */
 4162     p->next = NULL;
 4163     free(p); /*free-2 */
 4164   }
 4165 
 4166   if (!locked && m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4167     TRACE_4("ERR_LIBRARY: Lock failed");
 4168     rc = SA_AIS_ERR_LIBRARY;
 4169     goto lock_fail1;
 4170   }
 4171   locked = true;
 4172 
 4173   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 4174   if (cl_node && cl_node->isOm) {
 4175     imma_proc_decrement_pending_reply(cl_node, true);
 4176   } else {
 4177     /*rc = SA_AIS_ERR_BAD_HANDLE;*/
 4178     TRACE_3("client_node_get failed. Handle closed during admop call");
 4179     /* Ignore the lost client node. The admop as such has
 4180        completed anyway, with or without error.
 4181        Any attempt to use the same immHandle later will discover the problem.
 4182     */
 4183   }
 4184 
 4185   if (rc == SA_AIS_ERR_BAD_HANDLE && cl_node && cl_node->stale) {
 4186     /* This ERR_BAD_HANDLE would have come from imma_fake_evs
 4187        and check_stale_handle (immnd crash => timeout => bad_handle) if IMMND
 4188        crashed during the down call.
 4189        We can not convert this to TRY_AGAIN because the admin-op may actually
 4190        have been performed at some other IMMND where the receiving OI resides.
 4191        But we can convert it back to TIMEOUT, which could allow a resurrect.
 4192      */
 4193     TRACE_3("Client became stale during down call");
 4194 
 4195     if (!cl_node->exposed) {
 4196       TRACE_3("ADMIN_OP - ERR_TIMEOUT: converting BAD_HANDLE to TIMEOUT");
 4197       rc = SA_AIS_ERR_TIMEOUT;
 4198     }
 4199   }
 4200 
 4201 clm_left:
 4202 ao_not_found:
 4203 client_not_found:
 4204 stale_handle:
 4205 bad_sync:
 4206   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 4207 
 4208 lock_fail1:
 4209   if (out_evt && rc == SA_AIS_ERR_LIBRARY && returnParams &&
 4210       *returnParams != NULL) {
 4211     SaImmAdminOperationParamsT_2 **Params = *returnParams;
 4212     SaImmAdminOperationParamsT_2 *q = NULL;
 4213     unsigned int ix = 0;
 4214     while (Params[ix]) {
 4215       q = Params[ix];
 4216       imma_freeAttrValue3(q->paramBuffer, q->paramType);
 4217       free(q->paramName);
 4218       q->paramName = NULL;
 4219       free(q);
 4220       ++ix;
 4221     }
 4222 
 4223     free(Params);
 4224   }
 4225 
 4226 lock_fail:
 4227 
 4228 done:
 4229   TRACE_LEAVE();
 4230   return rc;
 4231 }
 4232 
 4233 SaAisErrorT saImmOmAdminOperationMemoryFree(
 4234     SaImmAdminOwnerHandleT ownerHandle,
 4235     SaImmAdminOperationParamsT_2 **returnParams) {
 4236   IMMA_CB *cb = &imma_cb;
 4237   IMMA_CLIENT_NODE *cl_node = NULL;
 4238   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 4239   SaImmHandleT immHandle = 0LL;
 4240   bool locked = true;
 4241   SaAisErrorT rc = SA_AIS_OK;
 4242   TRACE_ENTER();
 4243 
 4244   if (cb->sv_id == 0) {
 4245     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 4246     return SA_AIS_ERR_BAD_HANDLE;
 4247   }
 4248 
 4249   /* get the CB Lock */
 4250   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4251     TRACE_4("ERR_LIBRARY: Lock failed");
 4252     TRACE_LEAVE();
 4253     return SA_AIS_ERR_LIBRARY;
 4254   }
 4255   /*locked == true already */
 4256 
 4257   imma_admin_owner_node_get(&cb->admin_owner_tree, &ownerHandle, &ao_node);
 4258   if (!ao_node) {
 4259     TRACE_2(
 4260         "ERR_BAD_HANDLE: No admin owner associated with admin owner handle!");
 4261     rc = SA_AIS_ERR_BAD_HANDLE;
 4262     goto done;
 4263   }
 4264   immHandle = ao_node->mImmHandle;
 4265 
 4266   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 4267   if (!(cl_node && cl_node->isOm)) {
 4268     TRACE_2("ERR_BAD_HANDLE: Client not found");
 4269     rc = SA_AIS_ERR_BAD_HANDLE;
 4270     goto done;
 4271   }
 4272   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 4273     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 4274     rc = SA_AIS_ERR_UNAVAILABLE;
 4275     goto clm_left;
 4276   }
 4277 
 4278   if (cl_node->stale) {
 4279     TRACE_1("IMM Handle %llx is stale - ignoring", immHandle);
 4280     /*return SA_AIS_ERR_BAD_HANDLE;*/
 4281     /* Dont let a stale handle prevent the deallocation. */
 4282   }
 4283 
 4284   if (!(cl_node->isImmA2b)) {
 4285     rc = SA_AIS_ERR_VERSION;
 4286     TRACE_2(
 4287         "ERR_VERSION: saImmOmAdminOperationMemoryFree only supported for "
 4288         "A.02.11 and above");
 4289     rc = SA_AIS_ERR_VERSION;
 4290     goto done;
 4291   }
 4292 
 4293   if (returnParams != NULL) {
 4294     SaImmAdminOperationParamsT_2 *q = NULL;
 4295     unsigned int ix = 0;
 4296     while (returnParams[ix]) {
 4297       q = returnParams[ix];
 4298       imma_freeAttrValue3(q->paramBuffer, q->paramType);
 4299       free(q->paramName);
 4300       q->paramName = NULL;
 4301       free(q);
 4302       ++ix;
 4303     }
 4304 
 4305     free(returnParams);
 4306   }
 4307 
 4308 clm_left:
 4309 done:
 4310   if (locked) {
 4311     m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 4312     locked = false;
 4313   }
 4314 
 4315   TRACE_LEAVE();
 4316   return rc;
 4317 }
 4318 
 4319 static int push_async_adm_op_continuation(IMMA_CB *cb,              // in
 4320                                           SaInt32T invocation,      // in
 4321                                           SaImmHandleT immHandle,   // in
 4322                                           SaInvocationT userInvoc)  // in
 4323 {
 4324   /* popAsyncAdmOpContinuation is in imma_proc.c */
 4325 
 4326   IMMA_CONTINUATION_RECORD *cr = cb->imma_continuations;
 4327 
 4328   TRACE("PUSH %i %llx %llx", invocation, immHandle, userInvoc);
 4329 
 4330   /* Check that there is not already a continuation with the same */
 4331   /* user invocation id. */
 4332 
 4333   while (cr) {
 4334     if (cr->userInvoc == userInvoc) {
 4335       return 0;
 4336     }
 4337     cr = cr->next;
 4338   }
 4339 
 4340   /* Ok add the new continuation. */
 4341   cr = (IMMA_CONTINUATION_RECORD *)malloc(sizeof(IMMA_CONTINUATION_RECORD));
 4342   cr->invocation = invocation;
 4343   cr->userInvoc = userInvoc;
 4344   cr->immHandle = immHandle;
 4345   cr->next = cb->imma_continuations;
 4346   cb->imma_continuations = cr;
 4347   return 1;
 4348 }
 4349 
 4350 /****************************************************************************
 4351   Name          :  saImmOmAdminOperationInvokeAsync/_2/_o3
 4352 
 4353   Description   :  Invoke an Administrative Operation on an object in the IMM.
 4354                    This an asynchronous non-blocking call.
 4355 
 4356   Arguments     :  ownerHandle - AdminOwner handle.
 4357                    userInvocation - An invocation id allowing the user
 4358                         to match the asynchronous return with the call.
 4359                    objectName - A pointer to the name of the object
 4360                            on which the operation is to be invoked.
 4361                    operationId - An id identifying the operation.
 4362                    params - Parameters to be supplied to the operation.
 4363 
 4364   Return Values :  Refer to SAI-AIS specification for various return values.
 4365 
 4366   Notes         :
 4367 ******************************************************************************/
 4368 static SaAisErrorT admin_op_invoke_async_common(
 4369     SaImmAdminOwnerHandleT ownerHandle, SaInvocationT userInvocation,
 4370     SaConstStringT objectName, SaImmContinuationIdT continuationId,
 4371     SaImmAdminOperationIdT operationId,
 4372     const SaImmAdminOperationParamsT_2 **params, bool bUseString);
 4373 
 4374 SaAisErrorT saImmOmAdminOperationInvokeAsync_2(
 4375     SaImmAdminOwnerHandleT ownerHandle, SaInvocationT userInvocation,
 4376     const SaNameT *objectName, SaImmContinuationIdT continuationId,
 4377     SaImmAdminOperationIdT operationId,
 4378     const SaImmAdminOperationParamsT_2 **params) {
 4379   bool freeMemory = false;
 4380   SaStringT objectNameStr = NULL;
 4381   SaAisErrorT rc;
 4382 
 4383   if (objectName) {
 4384     if (!osaf_is_extended_name_valid(objectName)) {
 4385       TRACE_2("ERR_INVALID_PARAM: Object name is invalid");
 4386       return SA_AIS_ERR_INVALID_PARAM;
 4387     }
 4388 
 4389     size_t len = osaf_extended_name_length(objectName);
 4390     if (len < SA_MAX_UNEXTENDED_NAME_LENGTH) {
 4391       objectNameStr = (SaStringT)malloc(len + 1);
 4392       memcpy(objectNameStr, osaf_extended_name_borrow(objectName), len);
 4393       objectNameStr[len] = 0;
 4394       freeMemory = true;
 4395     } else {
 4396       objectNameStr = (SaStringT)osaf_extended_name_borrow(objectName);
 4397     }
 4398   }
 4399 
 4400   rc = admin_op_invoke_async_common(ownerHandle, userInvocation, objectNameStr,
 4401                                     continuationId, operationId, params, false);
 4402 
 4403   if (freeMemory) {
 4404     free(objectNameStr);
 4405   }
 4406 
 4407   return rc;
 4408 }
 4409 
 4410 SaAisErrorT saImmOmAdminOperationInvokeAsync_o3(
 4411     SaImmAdminOwnerHandleT ownerHandle, SaInvocationT userInvocation,
 4412     SaConstStringT objectName, SaImmContinuationIdT continuationId,
 4413     SaImmAdminOperationIdT operationId,
 4414     const SaImmAdminOperationParamsT_2 **params) {
 4415   return admin_op_invoke_async_common(ownerHandle, userInvocation, objectName,
 4416                                       continuationId, operationId, params,
 4417                                       true);
 4418 }
 4419 
 4420 static SaAisErrorT admin_op_invoke_async_common(
 4421     SaImmAdminOwnerHandleT ownerHandle, SaInvocationT userInvocation,
 4422     SaConstStringT objectName, SaImmContinuationIdT continuationId,
 4423     SaImmAdminOperationIdT operationId,
 4424     const SaImmAdminOperationParamsT_2 **params, bool bUseString) {
 4425   SaAisErrorT rc = SA_AIS_OK;
 4426   IMMA_CB *cb = &imma_cb;
 4427   IMMSV_EVT evt;
 4428   IMMA_ADMIN_OWNER_NODE *ao_node = NULL;
 4429   IMMA_CLIENT_NODE *cl_node = NULL;
 4430   bool locked = true;
 4431   SaImmHandleT immHandle = 0LL;
 4432   SaUint32T adminOwnerId = 0;
 4433   bool opIdEsc = (operationId & SA_IMM_PARAM_ADMOP_ID_ESC);
 4434   bool opNamePar = false;
 4435   TRACE_ENTER();
 4436 
 4437   if (cb->sv_id == 0) {
 4438     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 4439     return SA_AIS_ERR_BAD_HANDLE;
 4440   }
 4441 
 4442   if ((objectName == NULL) || (!objectName[0]) ||
 4443       !(osaf_is_extended_names_enabled() ||
 4444         strlen(objectName) < SA_MAX_UNEXTENDED_NAME_LENGTH) ||
 4445       (params == NULL)) {
 4446     rc = SA_AIS_ERR_INVALID_PARAM;
 4447     goto done;
 4448   }
 4449 
 4450   if (!imma_proc_is_adminop_params_valid(params)) {
 4451     rc = SA_AIS_ERR_INVALID_PARAM;
 4452     goto done;
 4453   }
 4454 
 4455   if (cb->is_immnd_up == false) {
 4456     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 4457     return SA_AIS_ERR_TRY_AGAIN;
 4458   }
 4459 
 4460   /* get the CB Lock */
 4461   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4462     rc = SA_AIS_ERR_LIBRARY;
 4463     TRACE_4("ERR_LIBRARY: Lock failed");
 4464     goto lock_fail;
 4465   }
 4466   /*locked == true already */
 4467 
 4468   /* Get the Admin Owner info  */
 4469   imma_admin_owner_node_get(&cb->admin_owner_tree, &ownerHandle, &ao_node);
 4470   if (!ao_node) {
 4471     TRACE_2(
 4472         "ERR_BAD_HANDLE: No admin owner associated with admin owner handle!");
 4473     rc = SA_AIS_ERR_BAD_HANDLE;
 4474     goto ao_not_found;
 4475   }
 4476 
 4477   if (ao_node->mAugCcb) {
 4478     TRACE_2(
 4479         "ERR_NO_RESOURCES: Augmented CCB AdminOwner handle not allowed here");
 4480     rc = SA_AIS_ERR_NO_RESOURCES;
 4481     goto ao_not_found;
 4482   }
 4483 
 4484   immHandle = ao_node->mImmHandle;
 4485   adminOwnerId = ao_node->mAdminOwnerId;
 4486   ao_node = NULL;
 4487 
 4488   /* Look up client node also, to verify that the client handle
 4489      is still active. */
 4490 
 4491   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 4492   if (!(cl_node && cl_node->isOm)) {
 4493     rc = SA_AIS_ERR_LIBRARY;
 4494     TRACE_4("ERR_LIBRARY: No valid SaImmHandleT associated with Admin owner");
 4495     goto client_not_found;
 4496   }
 4497 
 4498   if (bUseString && !cl_node->isImmA2f) {
 4499     rc = SA_AIS_ERR_VERSION;
 4500     TRACE_2(
 4501         "ERR_VERSION: saImmOmAdminOperationInvokeAsync_o3 only supported for "
 4502         "A.02.15 and above");
 4503     goto client_not_found;
 4504   }
 4505   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 4506     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 4507     rc = SA_AIS_ERR_UNAVAILABLE;
 4508     goto clm_left;
 4509   }
 4510 
 4511   if (cl_node->stale) {
 4512     TRACE_1("IMM Handle %llx is stale", immHandle);
 4513     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 4514     cl_node = NULL;
 4515 
 4516     if (!locked &&
 4517         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4518       TRACE_4("ERR_LIBRARY: Lock failed");
 4519       rc = SA_AIS_ERR_LIBRARY;
 4520       goto lock_fail;
 4521     }
 4522     locked = true;
 4523 
 4524     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 4525     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 4526       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 4527               immHandle);
 4528       if (cl_node && cl_node->stale) {
 4529         cl_node->exposed = true;
 4530       }
 4531       rc = SA_AIS_ERR_BAD_HANDLE;
 4532       goto stale_handle;
 4533     }
 4534 
 4535     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 4536   }
 4537 
 4538   /* TODO: Should the timeout value be set to any sensible value ? */
 4539 
 4540   if (cl_node->isImmA2bCbk) { /* cl_node->isImmA2bCbk is true only if there is
 4541                                  an A.2.11 callback */
 4542     if (cl_node->o.mCallbkA2b.saImmOmAdminOperationInvokeCallback == NULL) {
 4543       rc = SA_AIS_ERR_INIT;
 4544       TRACE_2(
 4545           "ERR_INIT: The SaImmOmAdminOperationInvokeCallbackT_o2 "
 4546           "function was not set in the initialization of the handle "
 4547           "=> saImmOmAdminOperationInvokeAsync can not reply");
 4548       goto no_callback;
 4549     }
 4550   } else {
 4551     if (cl_node->o.mCallbk.saImmOmAdminOperationInvokeCallback == NULL) {
 4552       rc = SA_AIS_ERR_INIT;
 4553       TRACE_2(
 4554           "ERR_INIT: The SaImmOmAdminOperationInvokeCallbackT "
 4555           "function was not set in the initialization of the handle "
 4556           "=> saImmOmAdminOperationInvokeAsync can not reply");
 4557       goto no_callback;
 4558     }
 4559   }
 4560 
 4561   /* Populate & Send the Open Event to IMMND */
 4562   memset(&evt, 0, sizeof(IMMSV_EVT));
 4563 
 4564   evt.type = IMMSV_EVT_TYPE_IMMND;
 4565   evt.info.immnd.type = IMMND_EVT_A2ND_IMM_ADMOP_ASYNC;
 4566 
 4567   evt.info.immnd.info.admOpReq.adminOwnerId = adminOwnerId;
 4568   evt.info.immnd.info.admOpReq.operationId = operationId;
 4569   evt.info.immnd.info.admOpReq.continuationId = continuationId; /*New API */
 4570   evt.info.immnd.info.admOpReq.timeout = 0; /* or IMMSV_WAIT_TIME? */
 4571   if ((immInvocations < 0) || (immInvocations == 0x7fffffff)) {
 4572     immInvocations = 0;
 4573   }
 4574   TRACE("immInvocations:%i", immInvocations);
 4575 
 4576   evt.info.immnd.info.admOpReq.invocation = -(++immInvocations);
 4577   /*Negate invoc to encode async */
 4578 
 4579   evt.info.immnd.info.admOpReq.objectName.size = strlen(objectName) + 1;
 4580   evt.info.immnd.info.admOpReq.objectName.buf = (char *)objectName;
 4581 
 4582   osafassert(evt.info.immnd.info.admOpReq.params == NULL);
 4583 
 4584   const SaImmAdminOperationParamsT_2 *param;
 4585   int i;
 4586   for (i = 0; params[i]; ++i) {
 4587     param = params[i];
 4588     /*alloc-2 */
 4589     IMMSV_ADMIN_OPERATION_PARAM *p = (IMMSV_ADMIN_OPERATION_PARAM *)malloc(
 4590         sizeof(IMMSV_ADMIN_OPERATION_PARAM));
 4591     memset(p, 0, sizeof(IMMSV_ADMIN_OPERATION_PARAM));
 4592     TRACE("PARAM:%s ", param->paramName);
 4593 
 4594     if (!opNamePar) {
 4595       opNamePar =
 4596           opIdEsc && (strcmp(param->paramName, SA_IMM_PARAM_ADMOP_NAME) == 0);
 4597       if (opNamePar && (param->paramType != SA_IMM_ATTR_SASTRINGT)) {
 4598         TRACE_2("ERR_INVALID_PARAM: Param %s must be of type SaStringT",
 4599                 SA_IMM_PARAM_ADMOP_NAME);
 4600         rc = SA_AIS_ERR_INVALID_PARAM;
 4601         free(p);
 4602         p = NULL;
 4603         goto mds_send_fail;
 4604       }
 4605     }
 4606 
 4607     p->paramName.size = strlen(param->paramName) + 1;
 4608     if (p->paramName.size >= IMMSV_MAX_PARAM_NAME_LENGTH) {
 4609       TRACE_2("ERR_INVALID_PARAM: Param name too long");
 4610       rc = SA_AIS_ERR_INVALID_PARAM;
 4611       free(p);
 4612       p = NULL;
 4613       goto mds_send_fail;
 4614     }
 4615 
 4616     /*alloc-3 */
 4617     p->paramName.buf = (char *)malloc(p->paramName.size);
 4618     strncpy(p->paramName.buf, param->paramName, p->paramName.size);
 4619 
 4620     p->paramType = param->paramType;
 4621     /*alloc-4 */
 4622     imma_copyAttrValue(&(p->paramBuffer), param->paramType, param->paramBuffer);
 4623 
 4624     p->next = evt.info.immnd.info.admOpReq.params; /*NULL initially. */
 4625     evt.info.immnd.info.admOpReq.params = p;
 4626   }
 4627 
 4628   if (opIdEsc && !opNamePar) {
 4629     TRACE_2("ERR_INVALID_PARAM: Op-id > %llx requires param %s",
 4630             (long long unsigned int)SA_IMM_PARAM_ADMOP_ID_ESC,
 4631             SA_IMM_PARAM_ADMOP_NAME);
 4632     rc = SA_AIS_ERR_INVALID_PARAM;
 4633     goto mds_send_fail;
 4634   }
 4635 
 4636   if (!push_async_adm_op_continuation(cb,
 4637                                       evt.info.immnd.info.admOpReq.invocation,
 4638                                       immHandle, userInvocation)) {
 4639     TRACE_2(
 4640         "ERR_INVALID_PARAM: Provided invocation id (%llx) "
 4641         "is not unique, not even in this client instance",
 4642         userInvocation);
 4643     rc = SA_AIS_ERR_INVALID_PARAM;
 4644     goto mds_send_fail;
 4645   }
 4646 
 4647   /* NOTE: Re-implement to send ND->ND instead of using FEVS,
 4648      less resources used and probably faster. */
 4649 
 4650   /* Even though this is an asyncronous down call, we increment pending-reply,
 4651      because a crash of the local IMMND before the asyncronous reply of this
 4652      call is received will mean a lost reply, i.e. broken contract with the
 4653      OM application, i.e. exposed handle. In fact we need to increment
 4654      pending-reply to *prevent* a reactive resurrect of the OM handle from
 4655      succeeding. The OM application *should* instead exit the dispatch loop
 4656      with BAD_HANDLE so that it is made aware of the broken contract.
 4657    */
 4658   imma_proc_increment_pending_reply(cl_node, false);
 4659 
 4660   /* out_evt is NULL => fevs is async */
 4661   rc = imma_evt_fake_evs(cb, &evt, NULL, 0, cl_node->handle, &locked, false);
 4662   TRACE("Fevs send RETURNED:%u", rc);
 4663 
 4664   if (rc != SA_AIS_OK) {
 4665     if (!locked) {
 4666       if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4667         rc = SA_AIS_ERR_LIBRARY;
 4668         TRACE_4("ERR_LIBRARY: Lock failed");
 4669         goto mds_send_fail;
 4670       } else {
 4671         locked = true;
 4672       }
 4673     }
 4674     if (!imma_popAsyncAdmOpContinuation(cb,
 4675                                         evt.info.immnd.info.admOpReq.invocation,
 4676                                         &immHandle, &userInvocation)) {
 4677       TRACE_3(
 4678           "Missmatch on continuation for saImmOmAdminOperationInvokeAsync_2");
 4679     }
 4680   }
 4681 
 4682 mds_send_fail:
 4683   /*We may be un-locked here but this should not matter.
 4684      We are freing heap objects that should only be vissible from this
 4685      thread. */
 4686 
 4687   /* NOTE: 12345 The code below should be moved to common ?
 4688      This to allow re-use by all allocators of this event type.
 4689      At least it needs to be duplicated in immnd_evt.c/immnd_evt_destroy */
 4690   while (evt.info.immnd.info.admOpReq.params) {
 4691     IMMSV_ADMIN_OPERATION_PARAM *p = evt.info.immnd.info.admOpReq.params;
 4692     evt.info.immnd.info.admOpReq.params = p->next;
 4693 
 4694     if (p->paramName.buf) { /*free-3 */
 4695       free(p->paramName.buf);
 4696       p->paramName.buf = NULL;
 4697     }
 4698     immsv_evt_free_att_val(&(p->paramBuffer),
 4699                            (SaImmValueTypeT)p->paramType); /*free-4 */
 4700     p->next = NULL;
 4701     free(p); /*free-2 */
 4702     p = NULL;
 4703   }
 4704 
 4705 /* Note the imma_proc_decrement_pending_reply is done in the OM upcall
 4706    with the reply for the asyncronous operation.
 4707  */
 4708 clm_left:
 4709 ao_not_found:
 4710 client_not_found:
 4711 stale_handle:
 4712 no_callback:
 4713   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 4714 
 4715 lock_fail:
 4716 done:
 4717   TRACE_LEAVE();
 4718   return rc;
 4719 }
 4720 
 4721 /****************************************************************************
 4722   Name          :  saImmOmAdminOperationContinue
 4723 
 4724   Description   :  Allows a process to take over the continuation of an
 4725                    administrative operation that was initiated with a
 4726                    admin owner handle that has been finalized before the
 4727                    reply was received.
 4728 
 4729 
 4730   Arguments     :  ownerHandle - AdminOwner handle.
 4731                    userInvocation - An invocation id allowing the user
 4732                         to match the asynchronous return with the call.
 4733                    objectName - A pointer to the name of the object
 4734                            on which the operation is to be invoked.
 4735                            Actually redundant information.
 4736                    continuationId - identifies the corresponding pervious
 4737                    invocation.
 4738 
 4739   Return Values :  Refer to SAI-AIS specification for various return values.
 4740 
 4741   Notes         :
 4742 ******************************************************************************/
 4743 
 4744 SaAisErrorT saImmOmAdminOperationContinue(SaImmAdminOwnerHandleT ownerHandle,
 4745                                           const SaNameT *objectName,
 4746                                           SaImmContinuationIdT continuationId,
 4747                                           SaAisErrorT *operationReturnValue) {
 4748   TRACE_2(
 4749       "saImmOmAdminOperationContinue not implemented use saImmOmAdminOperationContinueAsync instead");
 4750   return SA_AIS_ERR_NOT_SUPPORTED;
 4751 }
 4752 
 4753 SaAisErrorT saImmOmAdminOperationContinue_o2(
 4754     SaImmAdminOwnerHandleT ownerHandle, const SaNameT *objectName,
 4755     SaImmContinuationIdT continuationId, SaAisErrorT *operationReturnValue,
 4756     SaImmAdminOperationParamsT_2 ***returnParams) {
 4757   TRACE_2(
 4758       "saImmOmAdminOperationContinue_o2 not implemented use "
 4759       "saImmOmAdminOperationContinueAsync instead");
 4760   return SA_AIS_ERR_NOT_SUPPORTED;
 4761 }
 4762 
 4763 SaAisErrorT saImmOmAdminOperationContinue_o3(
 4764     SaImmAdminOwnerHandleT ownerHandle, SaConstStringT objectName,
 4765     SaImmContinuationIdT continuationId, SaAisErrorT *operationReturnValue,
 4766     SaImmAdminOperationParamsT_2 ***returnParams) {
 4767   TRACE_2(
 4768       "saImmOmAdminOperationContinue_o3 not implemented use "
 4769       "saImmOmAdminOperationContinueAsync instead");
 4770   return SA_AIS_ERR_NOT_SUPPORTED;
 4771 }
 4772 
 4773 SaAisErrorT saImmOmAdminOperationContinueAsync(
 4774     SaImmAdminOwnerHandleT ownerHandle, SaInvocationT invocation,
 4775     const SaNameT *objectName, SaImmContinuationIdT continuationId) {
 4776   TRACE_2("saImmOmAdminOperationContinueAsync not yet implemented");
 4777   return SA_AIS_ERR_NOT_SUPPORTED;
 4778 }
 4779 
 4780 SaAisErrorT saImmOmAdminOperationContinueAsync_o3(
 4781     SaImmAdminOwnerHandleT ownerHandle, SaInvocationT invocation,
 4782     SaConstStringT objectName, SaImmContinuationIdT continuationId) {
 4783   TRACE_2("saImmOmAdminOperationContinueAsync_o3 not yet implemented");
 4784   return SA_AIS_ERR_NOT_SUPPORTED;
 4785 }
 4786 
 4787 SaAisErrorT saImmOmAdminOperationContinuationClear(
 4788     SaImmAdminOwnerHandleT ownerHandle, const SaNameT *objectName,
 4789     SaImmContinuationIdT continuationId) {
 4790   TRACE_2("saImmOmAdminOperationContinuationClear not yet implemented");
 4791   return SA_AIS_ERR_NOT_SUPPORTED;
 4792 }
 4793 
 4794 SaAisErrorT saImmOmAdminOperationContinuationClear_o3(
 4795     SaImmAdminOwnerHandleT ownerHandle, SaConstStringT objectName,
 4796     SaImmContinuationIdT continuationId) {
 4797   TRACE_2("saImmOmAdminOperationContinuationClear_o3 not yet implemented");
 4798   return SA_AIS_ERR_NOT_SUPPORTED;
 4799 }
 4800 
 4801 SaAisErrorT saImmOmClassCreate_2(
 4802     SaImmHandleT immHandle, const SaImmClassNameT className,
 4803     SaImmClassCategoryT classCategory,
 4804     const SaImmAttrDefinitionT_2 **attrDefinitions) {
 4805   SaAisErrorT rc = SA_AIS_OK;
 4806   bool locked = true;
 4807   IMMA_CB *cb = &imma_cb;
 4808   IMMSV_EVT evt;
 4809   IMMSV_EVT *out_evt = NULL;
 4810   IMMA_CLIENT_NODE *cl_node = NULL;
 4811   SaTimeT timeout = 0;
 4812   IMMSV_ATTR_DEF_LIST *sysattr = NULL;
 4813   const SaImmAttrDefinitionT_2 *attr;
 4814   int i;
 4815   int persistent = 0;
 4816   TRACE_ENTER();
 4817 
 4818   if (cb->sv_id == 0) {
 4819     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 4820     TRACE_LEAVE();
 4821     return SA_AIS_ERR_BAD_HANDLE;
 4822   }
 4823 
 4824   if ((className == NULL) || (attrDefinitions == NULL)) {
 4825     TRACE_LEAVE();
 4826     return SA_AIS_ERR_INVALID_PARAM;
 4827   }
 4828 
 4829   attr = attrDefinitions[0];
 4830   for (i = 0; attr != 0; attr = attrDefinitions[++i]) {
 4831     if (attr->attrName == NULL) {
 4832       TRACE("NULL attrName , not allowed.");
 4833       TRACE_LEAVE();
 4834       return SA_AIS_ERR_INVALID_PARAM;
 4835     }
 4836 
 4837     if (attr->attrFlags & SA_IMM_ATTR_RDN) {
 4838       if (((attr->attrValueType != SA_IMM_ATTR_SANAMET) &&
 4839            (attr->attrValueType != SA_IMM_ATTR_SASTRINGT))) {
 4840         TRACE(
 4841             "ERR_INVALID_PARAM: RDN '%s' must be of type SaNameT or SaStringT",
 4842             attr->attrName);
 4843         TRACE_LEAVE();
 4844         return SA_AIS_ERR_INVALID_PARAM;
 4845       }
 4846 
 4847       if (attr->attrFlags & SA_IMM_ATTR_MULTI_VALUE) {
 4848         TRACE("ERR_INVALID_PARAM: RDN '%s' can not be multivalued",
 4849               attr->attrName);
 4850         TRACE_LEAVE();
 4851         return SA_AIS_ERR_INVALID_PARAM;
 4852       }
 4853 
 4854       if (attr->attrFlags & SA_IMM_ATTR_NO_DANGLING) {
 4855         TRACE("ERR_INVALID_PARAM: RDN '%s' can not have NO_DANGLING flag",
 4856               attr->attrName);
 4857         TRACE_LEAVE();
 4858         return SA_AIS_ERR_INVALID_PARAM;
 4859       }
 4860 
 4861       if (attr->attrFlags & SA_IMM_ATTR_DN) {
 4862         TRACE("ERR_INVALID_PARAM: RDN '%s' can not have SA_IMM_ATTR_DN flag",
 4863               attr->attrName);
 4864         TRACE_LEAVE();
 4865         return SA_AIS_ERR_INVALID_PARAM;
 4866       }
 4867 
 4868       if (attr->attrFlags & SA_IMM_ATTR_STRONG_DEFAULT) {
 4869         TRACE("ERR_INVALID_PARAM: RDN '%s' can not have STRONG_DEFAULT flag",
 4870               attr->attrName);
 4871         TRACE_LEAVE();
 4872         return SA_AIS_ERR_INVALID_PARAM;
 4873       }
 4874     }
 4875 
 4876     if (attr->attrFlags & SA_IMM_ATTR_NO_DANGLING) {
 4877       if (classCategory == SA_IMM_CLASS_RUNTIME) {
 4878         TRACE(
 4879             "ERR_INVALID_PARAM: NO_DANGLING attribute '%s' cannot be defined for runtime class",
 4880             attr->attrName);
 4881         TRACE_LEAVE();
 4882         return SA_AIS_ERR_INVALID_PARAM;
 4883       }
 4884 
 4885       if ((attr->attrValueType != SA_IMM_ATTR_SANAMET) &&
 4886           !((attr->attrFlags & SA_IMM_ATTR_DN) &&
 4887             (attr->attrValueType == SA_IMM_ATTR_SASTRINGT))) {
 4888         TRACE(
 4889             "ERR_INVALID_PARAM: Attribute '%s' is flagged NO_DANGLING, must be of type SaNameT or SaStringT with DN flag",
 4890             attr->attrName);
 4891         TRACE_LEAVE();
 4892         return SA_AIS_ERR_INVALID_PARAM;
 4893       }
 4894 
 4895       if (attr->attrFlags & SA_IMM_ATTR_RUNTIME) {
 4896         TRACE(
 4897             "ERR_INVALID_PARAM: Runtime attribute '%s' cannot have NO_DANGLING flag",
 4898             attr->attrName);
 4899         TRACE_LEAVE();
 4900         return SA_AIS_ERR_INVALID_PARAM;
 4901       }
 4902     }
 4903 
 4904     if ((attr->attrFlags & SA_IMM_ATTR_DN) &&
 4905         (attr->attrValueType != SA_IMM_ATTR_SASTRINGT)) {
 4906       TRACE(
 4907           "ERR_INVALID_PARAM: Attribute '%s' has SA_IMM_ATTR_DN flag, "
 4908           "but the attribute is not of type SaStringT",
 4909           attr->attrName);
 4910       TRACE_LEAVE();
 4911       return SA_AIS_ERR_INVALID_PARAM;
 4912     }
 4913   }
 4914 
 4915   if (cb->is_immnd_up == false) {
 4916     TRACE_2("ERR_TRY_AGAIN: IMMND is DOWN");
 4917     TRACE_LEAVE();
 4918     return SA_AIS_ERR_TRY_AGAIN;
 4919   }
 4920 
 4921   /* get the CB Lock */
 4922   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4923     rc = SA_AIS_ERR_LIBRARY;
 4924     TRACE_4("ERR_LIBRARY: Lock failed");
 4925     goto lock_fail;
 4926   }
 4927   /*locked is true already */
 4928 
 4929   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 4930   if (!(cl_node && cl_node->isOm)) {
 4931     TRACE_2("ERR_BAD_HANDLE: Client node is missing");
 4932     rc = SA_AIS_ERR_BAD_HANDLE;
 4933     goto client_not_found;
 4934   }
 4935   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 4936     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 4937     rc = SA_AIS_ERR_UNAVAILABLE;
 4938     goto clm_left;
 4939   }
 4940 
 4941   if (cl_node->stale) {
 4942     TRACE_1("IMM Handle %llx is stale", immHandle);
 4943     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 4944 
 4945     if (!locked &&
 4946         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 4947       TRACE_4("ERR_LIBRARY: Lock failed");
 4948       rc = SA_AIS_ERR_LIBRARY;
 4949       goto lock_fail;
 4950     }
 4951     locked = true;
 4952 
 4953     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 4954 
 4955     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 4956       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 4957               immHandle);
 4958       if (cl_node && cl_node->stale) {
 4959         cl_node->exposed = true;
 4960       }
 4961       rc = SA_AIS_ERR_BAD_HANDLE;
 4962       goto stale_handle;
 4963     }
 4964 
 4965     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 4966   }
 4967 
 4968   timeout = cl_node->syncr_timeout;
 4969 
 4970   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 4971     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 4972     goto bad_sync;
 4973   }
 4974 
 4975   /* Populate the ClassCreate event */
 4976   memset(&evt, 0, sizeof(IMMSV_EVT));
 4977   evt.type = IMMSV_EVT_TYPE_IMMND;
 4978   evt.info.immnd.type = IMMND_EVT_A2ND_CLASS_CREATE;
 4979 
 4980   evt.info.immnd.info.classDescr.className.size = strlen(className) + 1;
 4981   if (evt.info.immnd.info.classDescr.className.size == 1) {
 4982     /*ABT bugfix 081029 Empty classname should not be allowed. */
 4983     rc = SA_AIS_ERR_INVALID_PARAM;
 4984     TRACE("Zero length class name, not allowed.");
 4985     goto mds_send_fail;
 4986   }
 4987   evt.info.immnd.info.classDescr.className.buf = (char *)malloc(
 4988       evt.info.immnd.info.classDescr.className.size); /*alloc-1 */
 4989   strncpy(evt.info.immnd.info.classDescr.className.buf, className,
 4990           (size_t)evt.info.immnd.info.classDescr.className.size);
 4991 
 4992   evt.info.immnd.info.classDescr.classCategory = classCategory;
 4993   TRACE("name: %s category:%u", className, classCategory);
 4994   attr = attrDefinitions[0];
 4995   for (i = 0; attr != 0; attr = attrDefinitions[++i]) {
 4996     /* Ignore system attribute definitions that are
 4997        loaded since they are indistinguishable from being set
 4998        by the user. Better that they are redefined below each
 4999        time by the system, even when the class is loaded from
 5000        backup. */
 5001     if (strcmp(attr->attrName, sysaClName) == 0) {
 5002       continue;
 5003     } else if (strcmp(attr->attrName, sysaAdmName) == 0) {
 5004       continue;
 5005     } else if (strcmp(attr->attrName, sysaImplName) == 0) {
 5006       continue;
 5007     }
 5008 
 5009     if ((attr->attrFlags & SA_IMM_ATTR_NO_DANGLING) && !(cl_node->isImmA2d)) {
 5010       TRACE_2("NO_DANGLING flag is supported in version A.02.13 or higher");
 5011       rc = SA_AIS_ERR_VERSION;
 5012       goto mds_send_fail;
 5013     }
 5014 
 5015     if ((attr->attrFlags & SA_IMM_ATTR_DN) && !(cl_node->isImmA2f)) {
 5016       TRACE_2("SA_IMM_ATTR_DN flag is supported in version A.02.15 or higher");
 5017       rc = SA_AIS_ERR_VERSION;
 5018       goto mds_send_fail;
 5019     }
 5020 
 5021     if ((attr->attrFlags & SA_IMM_ATTR_DEFAULT_REMOVED) &&
 5022         !(cl_node->isImmA2x10)) {
 5023       TRACE_2(
 5024           "SA_IMM_ATTR_DEFAULT_REMOVED flag is supported in version A.02.16 or higher");
 5025       rc = SA_AIS_ERR_VERSION;
 5026       goto mds_send_fail;
 5027     }
 5028 
 5029     if ((attr->attrFlags & SA_IMM_ATTR_STRONG_DEFAULT) &&
 5030         !(cl_node->isImmA2x11)) {
 5031       TRACE_2(
 5032           "SA_IMM_ATTR_STRONG_DEFAULT flag is supported in version A.02.17 or higher");
 5033       rc = SA_AIS_ERR_VERSION;
 5034       goto mds_send_fail;
 5035     }
 5036 
 5037     IMMSV_ATTR_DEF_LIST *p = /*alloc-2 */
 5038         (IMMSV_ATTR_DEF_LIST *)malloc(sizeof(IMMSV_ATTR_DEF_LIST));
 5039     memset(p, 0, sizeof(IMMSV_ATTR_DEF_LIST));
 5040 
 5041     p->d.attrName.size = strlen(attr->attrName) + 1;
 5042     if (p->d.attrName.size == 1) {
 5043       rc = SA_AIS_ERR_INVALID_PARAM;
 5044       TRACE("Zero length attribute name in class %s def, not allowed.",
 5045             evt.info.immnd.info.classDescr.className.buf);
 5046       free(p);
 5047       p = NULL;
 5048       goto mds_send_fail;
 5049     }
 5050     p->d.attrName.buf = (char *)malloc(p->d.attrName.size); /* alloc-3 */
 5051     strncpy(p->d.attrName.buf, attr->attrName, p->d.attrName.size);
 5052     p->d.attrName.buf[p->d.attrName.size-1] = 0;
 5053 
 5054     p->d.attrValueType = attr->attrValueType;
 5055     if (!imma_proc_is_valid_type((SaImmValueTypeT)p->d.attrValueType)) {
 5056       rc = SA_AIS_ERR_INVALID_PARAM;
 5057       TRACE("Unknown type not allowed for attr:%s class%s", p->d.attrName.buf,
 5058             evt.info.immnd.info.classDescr.className.buf);
 5059       free(p->d.attrName.buf); /* free-3 */
 5060       p->d.attrName.buf = NULL;
 5061       free(p); /* free-2 */
 5062       p = NULL;
 5063       goto mds_send_fail;
 5064     }
 5065     p->d.attrFlags = attr->attrFlags;
 5066     persistent = persistent | (attr->attrFlags & SA_IMM_ATTR_PERSISTENT);
 5067 
 5068     if (attr->attrDefaultValue) {
 5069       p->d.attrDefaultValue = /*alloc-4.1 */
 5070           (IMMSV_EDU_ATTR_VAL *)malloc(sizeof(IMMSV_EDU_ATTR_VAL));
 5071       memset(p->d.attrDefaultValue, 0, sizeof(IMMSV_EDU_ATTR_VAL));
 5072       /*alloc-4.2 */
 5073       imma_copyAttrValue(p->d.attrDefaultValue, attr->attrValueType,
 5074                          attr->attrDefaultValue);
 5075     }
 5076 
 5077     p->next =
 5078         evt.info.immnd.info.classDescr.attrDefinitions; /*NULL initially */
 5079     evt.info.immnd.info.classDescr.attrDefinitions = p;
 5080   }
 5081 
 5082   /* Add system attribute class-name  */
 5083   /*TRACE("Creating class name attribute def"); */
 5084   sysattr = /*alloc-2 */
 5085       (IMMSV_ATTR_DEF_LIST *)malloc(sizeof(IMMSV_ATTR_DEF_LIST));
 5086   memset(sysattr, 0, sizeof(IMMSV_ATTR_DEF_LIST));
 5087 
 5088   sysattr->d.attrName.size = strlen(sysaClName) + 1;
 5089   sysattr->d.attrName.buf =
 5090       (char *)malloc(sysattr->d.attrName.size); /*alloc-3 */
 5091   strncpy(sysattr->d.attrName.buf, sysaClName, sysattr->d.attrName.size);
 5092   sysattr->d.attrName.buf[sysattr->d.attrName.size-1] = 0;
 5093   sysattr->d.attrValueType = SA_IMM_ATTR_SASTRINGT;
 5094   if (classCategory == SA_IMM_CLASS_CONFIG) {
 5095     sysattr->d.attrFlags |= SA_IMM_ATTR_CONFIG;
 5096   } else if (classCategory == SA_IMM_CLASS_RUNTIME) {
 5097     sysattr->d.attrFlags |= (persistent)
 5098                                 ? (SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_CACHED |
 5099                                    SA_IMM_ATTR_PERSISTENT)
 5100                                 : (SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_CACHED);
 5101   }
 5102   sysattr->d.attrNtfId = 0; /*alloc-4.1 */
 5103   sysattr->d.attrDefaultValue =
 5104       (IMMSV_EDU_ATTR_VAL *)malloc(sizeof(IMMSV_EDU_ATTR_VAL));
 5105   memset(sysattr->d.attrDefaultValue, 0, sizeof(IMMSV_EDU_ATTR_VAL));
 5106   /*alloc-4.2 */
 5107   imma_copyAttrValue(sysattr->d.attrDefaultValue, SA_IMM_ATTR_SASTRINGT,
 5108                      (SaImmAttrValueT)&className);
 5109   sysattr->next = evt.info.immnd.info.classDescr.attrDefinitions;
 5110   evt.info.immnd.info.classDescr.attrDefinitions = sysattr;
 5111 
 5112   /* Add system attribute admin-owner */
 5113   /*TRACE("Creating admin-owner name attribute def"); */
 5114   sysattr = /*alloc-2 */
 5115       (IMMSV_ATTR_DEF_LIST *)malloc(sizeof(IMMSV_ATTR_DEF_LIST));
 5116   memset(sysattr, 0, sizeof(IMMSV_ATTR_DEF_LIST));
 5117 
 5118   sysattr->d.attrName.size = strlen(sysaAdmName) + 1;
 5119   sysattr->d.attrName.buf =
 5120       (char *)malloc(sysattr->d.attrName.size); /*alloc-3 */
 5121   strncpy(sysattr->d.attrName.buf, sysaAdmName, sysattr->d.attrName.size);
 5122   sysattr->d.attrName.buf[sysattr->d.attrName.size-1] = 0;
 5123   sysattr->d.attrValueType = SA_IMM_ATTR_SASTRINGT;
 5124   /* Should this attribute really be a config attribute ?
 5125      Should it really be allowed to be persistent ? */
 5126   if (classCategory == SA_IMM_CLASS_CONFIG) {
 5127     sysattr->d.attrFlags |= SA_IMM_ATTR_CONFIG;
 5128   } else if (classCategory == SA_IMM_CLASS_RUNTIME) {
 5129     sysattr->d.attrFlags |= (persistent)
 5130                                 ? (SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_CACHED |
 5131                                    SA_IMM_ATTR_PERSISTENT)
 5132                                 : (SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_CACHED);
 5133   }
 5134   sysattr->d.attrNtfId = 0;
 5135   sysattr->d.attrDefaultValue = NULL;
 5136   sysattr->next = evt.info.immnd.info.classDescr.attrDefinitions;
 5137   evt.info.immnd.info.classDescr.attrDefinitions = sysattr;
 5138 
 5139   /* Add system attribute implementer-name */
 5140   /*TRACE("Creating implementer name attribute def"); */
 5141   sysattr = /*alloc-2 */
 5142       (IMMSV_ATTR_DEF_LIST *)malloc(sizeof(IMMSV_ATTR_DEF_LIST));
 5143   memset(sysattr, 0, sizeof(IMMSV_ATTR_DEF_LIST));
 5144 
 5145   sysattr->d.attrName.size = strlen(sysaImplName) + 1;
 5146   sysattr->d.attrName.buf =
 5147       (char *)malloc(sysattr->d.attrName.size); /*alloc-3 */
 5148   strncpy(sysattr->d.attrName.buf, sysaImplName, sysattr->d.attrName.size);
 5149   sysattr->d.attrName.buf[sysattr->d.attrName.size-1] = 0;
 5150   sysattr->d.attrValueType = SA_IMM_ATTR_SASTRINGT;
 5151   /* Should this attribute really be a config attribute ?
 5152      Should it really be allowed to be persistent ?
 5153      Config=> persistent but Runtime => can be changed by implementer.
 5154    */
 5155   if (classCategory == SA_IMM_CLASS_CONFIG) {
 5156     sysattr->d.attrFlags |= SA_IMM_ATTR_CONFIG;
 5157   } else if (classCategory == SA_IMM_CLASS_RUNTIME) {
 5158     sysattr->d.attrFlags |= (persistent)
 5159                                 ? (SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_CACHED |
 5160                                    SA_IMM_ATTR_PERSISTENT)
 5161                                 : (SA_IMM_ATTR_RUNTIME | SA_IMM_ATTR_CACHED);
 5162   }
 5163   sysattr->d.attrNtfId = 0;
 5164   sysattr->d.attrDefaultValue = NULL;
 5165   sysattr->next = evt.info.immnd.info.classDescr.attrDefinitions;
 5166   evt.info.immnd.info.classDescr.attrDefinitions = sysattr;
 5167 
 5168   rc = imma_evt_fake_evs(cb, &evt, &out_evt, timeout, cl_node->handle, &locked,
 5169                          true);
 5170   cl_node = NULL;
 5171 
 5172   if (rc != SA_AIS_OK) {
 5173     goto mds_send_fail;
 5174   }
 5175 
 5176   if (out_evt) {
 5177     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 5178     osafassert(out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR);
 5179     rc = out_evt->info.imma.info.errRsp.error;
 5180     TRACE("Return code:%u", rc);
 5181     free(out_evt);
 5182     out_evt = NULL;
 5183   }
 5184 
 5185 mds_send_fail:
 5186 
 5187   free(evt.info.immnd.info.classDescr.className.buf); /*free-1 */
 5188   evt.info.immnd.info.classDescr.className.buf = NULL;
 5189   evt.info.immnd.info.classDescr.className.size = 0;
 5190 
 5191   /*free-2 free-3 free-4.1 free-4.2 */
 5192   immsv_free_attrdefs_list(evt.info.immnd.info.classDescr.attrDefinitions);
 5193   evt.info.immnd.info.classDescr.attrDefinitions = NULL;
 5194 
 5195   if (!locked && m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 5196     rc = SA_AIS_ERR_LIBRARY;
 5197     TRACE_4("ERR_LIBRARY: Lock failed");
 5198     /* Losing track of the pending reply count, but ERR_LIBRARY dominates*/
 5199     goto lock_fail;
 5200   }
 5201   locked = true;
 5202 
 5203   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 5204   if (!(cl_node && cl_node->isOm)) {
 5205     /*rc = SA_AIS_ERR_BAD_HANDLE;*/
 5206     /* Let the result reflect if the class create succeeded or not. */
 5207     TRACE_3("client_node_get failed");
 5208     goto client_not_found;
 5209   }
 5210 
 5211   imma_proc_decrement_pending_reply(cl_node, true);
 5212 
 5213   if ((rc == SA_AIS_ERR_BAD_HANDLE) && cl_node->stale) {
 5214     /* BAD_HANDLE from imma_proc_check_stale */
 5215     /* ABT: We could possibly convert back to TIMEOUT to allow a resurrect?*/
 5216     cl_node->exposed = true;
 5217   }
 5218 
 5219 clm_left:
 5220 client_not_found:
 5221 stale_handle:
 5222 bad_sync:
 5223   if (locked) m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 5224 
 5225 lock_fail:
 5226   TRACE_LEAVE();
 5227   return rc;
 5228 }
 5229 
 5230 SaAisErrorT saImmOmClassDescriptionGet_2(
 5231     SaImmHandleT immHandle, const SaImmClassNameT className,
 5232     SaImmClassCategoryT *classCategory,
 5233     SaImmAttrDefinitionT_2 ***attrDefinition) {
 5234   TRACE_ENTER();
 5235   SaAisErrorT rc = SA_AIS_OK;
 5236   uint32_t proc_rc = NCSCC_RC_SUCCESS;
 5237   bool locked = false;
 5238   IMMA_CB *cb = &imma_cb;
 5239   IMMSV_EVT evt;
 5240   IMMSV_EVT *out_evt = NULL;
 5241   IMMA_CLIENT_NODE *cl_node = NULL;
 5242   SaTimeT timeout = 0;
 5243 
 5244   if (cb->sv_id == 0) {
 5245     TRACE_2("ERR_BAD_HANDLE: No initialized handle exists!");
 5246     return SA_AIS_ERR_BAD_HANDLE;
 5247   }
 5248 
 5249   if ((className == NULL) || (classCategory == NULL) ||
 5250       (attrDefinition == NULL)) {
 5251     TRACE_LEAVE();
 5252     return SA_AIS_ERR_INVALID_PARAM;
 5253   }
 5254 
 5255   if (cb->is_immnd_up == false) {
 5256     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 5257     return SA_AIS_ERR_TRY_AGAIN;
 5258   }
 5259 
 5260   /* get the CB Lock */
 5261   if (m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 5262     rc = SA_AIS_ERR_LIBRARY;
 5263     TRACE_4("ERR_LIBRARY: Lock failed");
 5264     goto lock_fail;
 5265   }
 5266   locked = true;
 5267 
 5268   imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 5269   if (!(cl_node && cl_node->isOm)) {
 5270     TRACE_2("ERR_BAD_HANDLE: Client node is missing");
 5271     rc = SA_AIS_ERR_BAD_HANDLE;
 5272     goto client_not_found;
 5273   }
 5274   if (cl_node->isImmA2x12 && cl_node->clmExposed) {
 5275     TRACE_2("SA_AIS_ERR_UNAVAILABLE: imma CLM node left the cluster");
 5276     rc = SA_AIS_ERR_UNAVAILABLE;
 5277     goto clm_left;
 5278   }
 5279 
 5280   if (cl_node->stale) {
 5281     TRACE_1("IMM Handle %llx is stale", immHandle);
 5282     bool resurrected = imma_om_resurrect(cb, cl_node, &locked);
 5283 
 5284     if (!locked &&
 5285         m_NCS_LOCK(&cb->cb_lock, NCS_LOCK_WRITE) != NCSCC_RC_SUCCESS) {
 5286       TRACE_4("ERR_LIBRARY: Lock failed");
 5287       rc = SA_AIS_ERR_LIBRARY;
 5288       goto lock_fail;
 5289     }
 5290     locked = true;
 5291 
 5292     imma_client_node_get(&cb->client_tree, &immHandle, &cl_node);
 5293 
 5294     if (!resurrected || !cl_node || !(cl_node->isOm) || cl_node->stale) {
 5295       TRACE_3("ERR_BAD_HANDLE: Reactive ressurect of handle %llx failed",
 5296               immHandle);
 5297       if (cl_node && cl_node->stale) {
 5298         cl_node->exposed = true;
 5299       }
 5300       rc = SA_AIS_ERR_BAD_HANDLE;
 5301       goto stale_handle;
 5302     }
 5303 
 5304     TRACE_1("Reactive resurrect of handle %llx succeeded", immHandle);
 5305   }
 5306 
 5307   if ((rc = imma_proc_increment_pending_reply(cl_node, true)) != SA_AIS_OK) {
 5308     TRACE_4("ERR_LIBRARY: Overlapping use of IMM handle by multiple threads");
 5309     goto bad_sync;
 5310   }
 5311 
 5312   /* Populate the ClassDescriptionGet event */
 5313   memset(&evt, 0, sizeof(IMMSV_EVT));
 5314   evt.type = IMMSV_EVT_TYPE_IMMND;
 5315   evt.info.immnd.type = IMMND_EVT_A2ND_CLASS_DESCR_GET;
 5316 
 5317   evt.info.immnd.info.classDescr.className.size = strlen(className) + 1;
 5318   evt.info.immnd.info.classDescr.className.buf = (char *)malloc(
 5319       evt.info.immnd.info.classDescr.className.size); /*alloc-0 */
 5320   strcpy(evt.info.immnd.info.classDescr.className.buf, className);
 5321 
 5322   TRACE("ClassName: %s", className);
 5323 
 5324   timeout = cl_node->syncr_timeout;
 5325   cl_node = NULL;
 5326 
 5327   /* Release the CB lock Before MDS Send */
 5328   m_NCS_UNLOCK(&cb->cb_lock, NCS_LOCK_WRITE);
 5329   locked = false;
 5330 
 5331   /* IMMND GOES DOWN */
 5332   if (false == cb->is_immnd_up) {
 5333     rc = SA_AIS_ERR_TRY_AGAIN;
 5334     TRACE_3("ERR_TRY_AGAIN: IMMND is DOWN");
 5335     goto mds_send_fail;
 5336   }
 5337 
 5338   /* send the request to the IMMND */
 5339   TRACE("ClassDescrGet 3");
 5340   proc_rc = imma_mds_msg_sync_send(cb->imma_mds_hdl, &cb->immnd_mds_dest, &evt,
 5341                                    &out_evt, timeout);
 5342 
 5343   switch (proc_rc) {
 5344     case NCSCC_RC_SUCCESS:
 5345       break;
 5346     case NCSCC_RC_REQ_TIMOUT:
 5347       rc = imma_proc_check_stale(cb, immHandle, SA_AIS_ERR_TIMEOUT);
 5348       goto mds_send_fail;
 5349     default:
 5350       rc = SA_AIS_ERR_LIBRARY;
 5351       TRACE_4("ERR_LIBRARY: MDS returned unexpected error code %u", proc_rc);
 5352       goto mds_send_fail;
 5353   }
 5354 
 5355   if (out_evt) {
 5356     /* Process the outcome, this was a blocking call. */
 5357     osafassert(out_evt->type == IMMSV_EVT_TYPE_IMMA);
 5358     if (out_evt->info.imma.type == IMMA_EVT_ND2A_IMM_ERROR) {
 5359       rc = out_evt->info.imma.info.errRsp.error;
 5360       osafassert(rc != SA_AIS_OK);
 5361     } else {
 5362       osafassert(out_evt->info.imma.type == IMMA_EVT_ND2A_CLASS_DESCR_GET_RSP);
 5363       int noOfAttributes = 0;
 5364       int i = 0;
 5365       SaImmAttrDefinitionT_2 **attr = NULL;
 5366       size_t attrDataSize = 0;
 5367 
 5368       *classCategory =
 5369           (SaImmClassCategoryT)out_evt->info.imma.info.classDescr.classCategory;
 5370       IMMSV_ATTR_DEF_LIST *p =
 5371           out_evt->info.imma.info.classDescr.attrDefinitions;
 5372 
 5373       while (p) {
 5374         ++noOfAttributes;
 5375         p = p->next;
 5376       }
 5377 
 5378       attrDataSize = sizeof(SaImmAttrDefinitionT_2 *) * (noOfAttributes + 1);
 5379       attr = (SaImmAttrDefinitionT_2 **)malloc(attrDataSize); /*alloc-1 */
 5380       TRACE("Alloc attrdefs array:%p", attr);
 5381       memset(attr, 0, attrDataSize);
 5382       p = out_evt->info.imma.info.classDescr.attrDefinitions;
 5383       for (; i < noOfAttributes; i++) {
 5384         IMMSV_ATTR_DEF_LIST *prev = p;
 5385         IMMSV_ATTR_DEFINITION *q = &(p->d);
 5386         attr[i] = (SaImmAttrDefinitionT_2 *)malloc(
 5387             sizeof(SaImmAttrDefinitionT_2));                      /*alloc-2 */
 5388         attr[i]->attrName = (char *)malloc(q->attrName.size); /*alloc-3 */
 5389         strncpy(attr[i]->attrName, (const char *)q->attrName.buf,
 5390                 q->attrName.size);
 5391         attr[i]->attrName[q->attrName.size-1] = 0;
 5392         attr[i]->attrValueType = (SaImmValueTypeT)q->attrValueType;
 5393         attr[i]->attrFlags = q->attrFlags;
 5394         /* attr[i]->attrNtfId = q->attrNtfId; */
 5395 
 5396         /*free-Y */
 5397         free(q->attrName.buf);
 5398         q->attrName.buf = NULL;
 5399         q->attrName.size = 0;
 5400 
 5401         if (!q->attrDefaultValue) {
 5402           attr[i]->attrDefaultValue = 0;
 5403         } else {
 5404           int size = 0;
 5405           switch (q->attrValueType) {
 5406             case SA_IMM_ATTR_SAINT32T: /*intended fall through */
 5407             case SA_IMM_ATTR_SAUINT32T:
 5408               size = sizeof(SaInt32T);
 5409               break;
 5410 
 5411             case SA_IMM_ATTR_SAINT64T: /*intended fall through */
 5412             case SA_IMM_ATTR_SAUINT64T:
 5413               size = sizeof(SaInt64T);
 5414               break;
 5415 
 5416             case SA_IMM_ATTR_SATIMET:
 5417               size = sizeof(SaTimeT);
 5418               break;
 5419 
 5420             case SA_IMM_ATTR_SAFLOATT:
 5421               size = sizeof(SaFloatT);
 5422               break;
 5423 
 5424             case SA_IMM_ATTR_SADOUBLET:
 5425               size = sizeof(SaDoubleT);
 5426               break;
 5427 
 5428             case SA_IMM_ATTR_SASTRINGT: /*A bit harsh with osafassert here ? */
 5429               osafassert(strlen((char *)q->attrDefaultValue->val.x.buf) <=
 5430                          q->attrDefaultValue->val.x.size);
 5431               size = sizeof(SaStringT);
 5432               break;
 5433 
 5434             case SA_IMM_ATTR_SANAMET:
 5435               size = sizeof(SaNameT);
 5436               break;
 5437 
 5438             case SA_IMM_ATTR_SAANYT:
 5439               size = sizeof(SaAnyT);
 5440               break;
 5441             default:
 5442               abort();
 5443           } /*switch */
 5444 
 5445           SaNameT *namep = NULL;
 5446           SaAnyT *anyp = NULL;
 5447           SaStringT *strp = NULL;
 5448           SaImmAttrValueT copyv;
 5449           copyv = (SaImmAttrValueT) /*alloc-4 */
 5450               malloc(size);
 5451           switch (q->attrValueType) {
 5452             case SA_IMM_ATTR_SAINT32T:
 5453               *((SaInt32T *)copyv) = q->attrDefaultValue->val.saint32;
 5454               break;
 5455             case SA_IMM_ATTR_SAUINT32T:
 5456               *((SaUint32T *)copyv) = q->attrDefaultValue->val.sauint32;
 5457               break;
 5458             case SA_IMM_ATTR_SAINT64T:
 5459               *((SaInt64T *)copyv) = q->attrDefaultValue->val.saint64;
 5460               break;
 5461             case SA_IMM_ATTR_SAUINT64T:
 5462               *((SaUint64T *)copyv) = q->attrDefaultValue->val.sauint64;
 5463               break;
 5464             case SA_IMM_ATTR_SATIMET:
 5465               /* I once got a segv on the line below.
 5466                  Allignement problem ? */
 5467               *((SaTimeT *)copyv) = q->attrDefaultValue->val.satime;
 5468               break;
 5469             case SA_IMM_ATTR_SAFLOATT:
 5470               *((SaFloatT *)copyv) = q->attrDefaultValue->val.safloat;
 5471               break;
 5472             case SA_IMM_ATTR_SADOUBLET:
 5473               *((SaDoubleT *)copyv) = q->attrDefaultValue->val.sadouble;
 5474               break;
 5475 
 5476             case SA_IMM_ATTR_SASTRINGT:
 5477               strp = (SaStringT *)copyv;
 5478               *strp = /*alloc-5 */
 5479                   (char *)malloc(q->attrDefaultValue->val.x.size);
 5480               memcpy(*strp, q->attrDefaultValue->val.x.buf,
 5481                      q->attrDefaultValue->val.x.size);
 5482               break;
 5483 
 5484             case SA_IMM_ATTR_SANAMET:
 5485               namep = (SaNameT *)copyv;
 5486               osaf_extended_name_alloc(q->attrDefaultValue->val.x.buf,
 5487                                        namep); /*alloc-5 */
 5488               break;
 5489 
 5490             case SA_IMM_ATTR_SAANYT:
 5491               anyp = (SaAnyT *)copyv;
 5492               memset(anyp, 0, sizeof(SaAnyT));
 5493               anyp->bufferSize = q->attrDefaultValue->val.x.size - 1;
 5494               anyp->bufferAddr =
 5495                   (SaUint8T *)malloc(anyp->bufferSize); /*alloc-5 */
 5496               memcpy(anyp->bufferAddr, q->attrDefaultValue->val.x.buf,
 5497                      anyp->bufferSize);
 5498               break;
 5499             default:
 5500               abort();
 5501           } /*switch */
 5502 
 5503           attr[i]->attrDefaultValue = copyv;
 5504           /*Delete source attr-value */
 5505           immsv_evt_free_att_val(q->attrDefaultValue,
 5506                                  (SaImmValueTypeT)q->attrValueType);
 5507 
 5508           free(q->attrDefaultValue);
 5509           q->attrDefaultValue = NULL;
 5510         }
 5511         p = p->next;
 5512         prev->next = NULL;
 5513         free(prev);
 5514         prev = NULL;
 5515