LCOV - code coverage report
Current view: top level - spdk/lib/init - json_config.c (source / functions) Hit Total Coverage
Test: Combined Lines: 206 284 72.5 %
Date: 2024-07-15 13:26:16 Functions: 19 20 95.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 96 183 52.5 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2018 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  *   Copyright (c) 2022, 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "spdk/stdinc.h"
       8                 :            : 
       9                 :            : #include "spdk/init.h"
      10                 :            : #include "spdk/util.h"
      11                 :            : #include "spdk/file.h"
      12                 :            : #include "spdk/log.h"
      13                 :            : #include "spdk/env.h"
      14                 :            : #include "spdk/thread.h"
      15                 :            : #include "spdk/jsonrpc.h"
      16                 :            : #include "spdk/rpc.h"
      17                 :            : #include "spdk/string.h"
      18                 :            : 
      19                 :            : #include "spdk_internal/event.h"
      20                 :            : 
      21                 :            : #define SPDK_DEBUG_APP_CFG(...) SPDK_DEBUGLOG(app_config, __VA_ARGS__)
      22                 :            : 
      23                 :            : /* JSON configuration format is as follows
      24                 :            :  *
      25                 :            :  * {
      26                 :            :  *  "subsystems" : [                          <<== *subsystems JSON array
      27                 :            :  *    {                                       <<== *subsystems_it array entry pointer (iterator)
      28                 :            :  *      "subsystem": "<< SUBSYSTEM NAME >>",
      29                 :            :  *      "config": [                           <<== *config JSON array
      30                 :            :  *         {                                  <<== *config_it array entry pointer (iterator)
      31                 :            :  *           "method": "<< METHOD NAME >>",   <<== *method
      32                 :            :  *           "params": { << PARAMS >> }       <<== *params
      33                 :            :  *         },
      34                 :            :  *         << MORE "config" ARRY ENTRIES >>
      35                 :            :  *      ]
      36                 :            :  *    },
      37                 :            :  *    << MORE "subsystems" ARRAY ENTRIES >>
      38                 :            :  *  ]
      39                 :            :  *
      40                 :            :  *  << ANYTHING ELSE IS IGNORED IN ROOT OBJECT>>
      41                 :            :  * }
      42                 :            :  *
      43                 :            :  */
      44                 :            : 
      45                 :            : struct load_json_config_ctx;
      46                 :            : typedef void (*client_resp_handler)(struct load_json_config_ctx *,
      47                 :            :                                     struct spdk_jsonrpc_client_response *);
      48                 :            : 
      49                 :            : #define RPC_SOCKET_PATH_MAX SPDK_SIZEOF_MEMBER(struct sockaddr_un, sun_path)
      50                 :            : 
      51                 :            : /* 1s connections timeout */
      52                 :            : #define RPC_CLIENT_CONNECT_TIMEOUT_US (1U * 1000U * 1000U)
      53                 :            : 
      54                 :            : /*
      55                 :            :  * Currently there is no timeout in SPDK for any RPC command. This result that
      56                 :            :  * we can't put a hard limit during configuration load as it most likely randomly fail.
      57                 :            :  * So just print WARNLOG every 10s. */
      58                 :            : #define RPC_CLIENT_REQUEST_TIMEOUT_US (10U * 1000 * 1000)
      59                 :            : 
      60                 :            : struct load_json_config_ctx {
      61                 :            :         /* Thread used during configuration. */
      62                 :            :         struct spdk_thread *thread;
      63                 :            :         spdk_subsystem_init_fn cb_fn;
      64                 :            :         void *cb_arg;
      65                 :            :         bool stop_on_error;
      66                 :            : 
      67                 :            :         /* Current subsystem */
      68                 :            :         struct spdk_json_val *subsystems; /* "subsystems" array */
      69                 :            :         struct spdk_json_val *subsystems_it; /* current subsystem array position in "subsystems" array */
      70                 :            : 
      71                 :            :         struct spdk_json_val *subsystem_name; /* current subsystem name */
      72                 :            :         char subsystem_name_str[128];
      73                 :            : 
      74                 :            :         /* Current "config" entry we are processing */
      75                 :            :         struct spdk_json_val *config; /* "config" array */
      76                 :            :         struct spdk_json_val *config_it; /* current config position in "config" array */
      77                 :            : 
      78                 :            :         /* Current request id we are sending. */
      79                 :            :         uint32_t rpc_request_id;
      80                 :            : 
      81                 :            :         /* Whole configuration file read and parsed. */
      82                 :            :         size_t json_data_size;
      83                 :            :         char *json_data;
      84                 :            : 
      85                 :            :         size_t values_cnt;
      86                 :            :         struct spdk_json_val *values;
      87                 :            : 
      88                 :            :         char rpc_socket_path_temp[RPC_SOCKET_PATH_MAX + 1];
      89                 :            : 
      90                 :            :         struct spdk_jsonrpc_client *client_conn;
      91                 :            :         struct spdk_poller *client_conn_poller;
      92                 :            : 
      93                 :            :         client_resp_handler client_resp_cb;
      94                 :            : 
      95                 :            :         /* Timeout for current RPC client action. */
      96                 :            :         uint64_t timeout;
      97                 :            : 
      98                 :            :         /* Signals that the code should follow deprecated path of execution. */
      99                 :            :         bool initalize_subsystems;
     100                 :            : };
     101                 :            : 
     102                 :            : static void app_json_config_load_subsystem(void *_ctx);
     103                 :            : 
     104                 :            : static void
     105                 :       2192 : app_json_config_load_done(struct load_json_config_ctx *ctx, int rc)
     106                 :            : {
     107                 :       2192 :         spdk_poller_unregister(&ctx->client_conn_poller);
     108         [ +  + ]:       2192 :         if (ctx->client_conn != NULL) {
     109                 :       2138 :                 spdk_jsonrpc_client_close(ctx->client_conn);
     110                 :            :         }
     111                 :            : 
     112                 :       2192 :         spdk_rpc_server_finish(ctx->rpc_socket_path_temp);
     113                 :            : 
     114   [ -  +  -  + ]:       2192 :         SPDK_DEBUG_APP_CFG("Config load finished with rc %d\n", rc);
     115                 :       2192 :         ctx->cb_fn(rc, ctx->cb_arg);
     116                 :            : 
     117                 :       2192 :         free(ctx->json_data);
     118                 :       2192 :         free(ctx->values);
     119                 :       2192 :         free(ctx);
     120                 :       2192 : }
     121                 :            : 
     122                 :            : static void
     123                 :       6967 : rpc_client_set_timeout(struct load_json_config_ctx *ctx, uint64_t timeout_us)
     124                 :            : {
     125                 :       6967 :         ctx->timeout = spdk_get_ticks() + timeout_us * spdk_get_ticks_hz() / (1000 * 1000);
     126                 :       6967 : }
     127                 :            : 
     128                 :            : static int
     129                 :     987902 : rpc_client_check_timeout(struct load_json_config_ctx *ctx)
     130                 :            : {
     131         [ -  + ]:     987902 :         if (ctx->timeout < spdk_get_ticks()) {
     132                 :          0 :                 SPDK_WARNLOG("RPC client command timeout.\n");
     133                 :          0 :                 return -ETIMEDOUT;
     134                 :            :         }
     135                 :            : 
     136                 :     987902 :         return 0;
     137                 :            : }
     138                 :            : 
     139                 :            : struct json_write_buf {
     140                 :            :         char data[1024];
     141                 :            :         unsigned cur_off;
     142                 :            : };
     143                 :            : 
     144                 :            : static int
     145                 :          0 : json_write_stdout(void *cb_ctx, const void *data, size_t size)
     146                 :            : {
     147                 :          0 :         struct json_write_buf *buf = cb_ctx;
     148                 :            :         size_t rc;
     149                 :            : 
     150         [ #  # ]:          0 :         rc = snprintf(buf->data + buf->cur_off, sizeof(buf->data) - buf->cur_off,
     151                 :            :                       "%s", (const char *)data);
     152         [ #  # ]:          0 :         if (rc > 0) {
     153                 :          0 :                 buf->cur_off += rc;
     154                 :            :         }
     155         [ #  # ]:          0 :         return rc == size ? 0 : -1;
     156                 :            : }
     157                 :            : 
     158                 :            : static int
     159                 :     992731 : rpc_client_poller(void *arg)
     160                 :            : {
     161                 :     992731 :         struct load_json_config_ctx *ctx = arg;
     162                 :            :         struct spdk_jsonrpc_client_response *resp;
     163                 :            :         client_resp_handler cb;
     164                 :            :         int rc;
     165                 :            : 
     166         [ -  + ]:     992731 :         assert(spdk_get_thread() == ctx->thread);
     167                 :            : 
     168                 :     992731 :         rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0);
     169         [ +  + ]:     992731 :         if (rc == 0) {
     170                 :     987902 :                 rc = rpc_client_check_timeout(ctx);
     171         [ -  + ]:     987902 :                 if (rc == -ETIMEDOUT) {
     172                 :          0 :                         rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US);
     173                 :          0 :                         rc = 0;
     174                 :            :                 }
     175                 :            :         }
     176                 :            : 
     177         [ +  + ]:     992731 :         if (rc == 0) {
     178                 :            :                 /* No response yet */
     179                 :     987902 :                 return SPDK_POLLER_BUSY;
     180         [ -  + ]:       4829 :         } else if (rc < 0) {
     181                 :          0 :                 app_json_config_load_done(ctx, rc);
     182                 :          0 :                 return SPDK_POLLER_BUSY;
     183                 :            :         }
     184                 :            : 
     185                 :       4829 :         resp = spdk_jsonrpc_client_get_response(ctx->client_conn);
     186         [ -  + ]:       4829 :         assert(resp);
     187                 :            : 
     188         [ -  + ]:       4829 :         if (resp->error) {
     189                 :          0 :                 struct json_write_buf buf = {};
     190                 :          0 :                 struct spdk_json_write_ctx *w = spdk_json_write_begin(json_write_stdout,
     191                 :            :                                                 &buf, SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
     192                 :            : 
     193         [ #  # ]:          0 :                 if (w == NULL) {
     194                 :          0 :                         SPDK_ERRLOG("error response: (?)\n");
     195                 :            :                 } else {
     196                 :          0 :                         spdk_json_write_val(w, resp->error);
     197                 :          0 :                         spdk_json_write_end(w);
     198                 :          0 :                         SPDK_ERRLOG("error response: \n%s\n", buf.data);
     199                 :            :                 }
     200                 :            :         }
     201                 :            : 
     202   [ -  +  -  -  :       4829 :         if (resp->error && ctx->stop_on_error) {
                   -  - ]
     203                 :          0 :                 spdk_jsonrpc_client_free_response(resp);
     204                 :          0 :                 app_json_config_load_done(ctx, -EINVAL);
     205                 :            :         } else {
     206                 :            :                 /* We have response so we must have callback for it. */
     207                 :       4829 :                 cb = ctx->client_resp_cb;
     208         [ -  + ]:       4829 :                 assert(cb != NULL);
     209                 :            : 
     210                 :            :                 /* Mark we are done with this handler. */
     211                 :       4829 :                 ctx->client_resp_cb = NULL;
     212                 :       4829 :                 cb(ctx, resp);
     213                 :            :         }
     214                 :            : 
     215                 :            : 
     216                 :       4829 :         return SPDK_POLLER_BUSY;
     217                 :            : }
     218                 :            : 
     219                 :            : static int
     220                 :       2138 : rpc_client_connect_poller(void *_ctx)
     221                 :            : {
     222                 :       2138 :         struct load_json_config_ctx *ctx = _ctx;
     223                 :            :         int rc;
     224                 :            : 
     225                 :       2138 :         rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0);
     226         [ +  - ]:       2138 :         if (rc != -ENOTCONN) {
     227                 :            :                 /* We are connected. Start regular poller and issue first request */
     228                 :       2138 :                 spdk_poller_unregister(&ctx->client_conn_poller);
     229                 :       2138 :                 ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_poller, ctx, 100);
     230                 :       2138 :                 app_json_config_load_subsystem(ctx);
     231                 :            :         } else {
     232                 :          0 :                 rc = rpc_client_check_timeout(ctx);
     233         [ #  # ]:          0 :                 if (rc) {
     234                 :          0 :                         app_json_config_load_done(ctx, rc);
     235                 :            :                 }
     236                 :            : 
     237                 :          0 :                 return SPDK_POLLER_IDLE;
     238                 :            :         }
     239                 :            : 
     240                 :       2138 :         return SPDK_POLLER_BUSY;
     241                 :            : }
     242                 :            : 
     243                 :            : static int
     244                 :       4829 : client_send_request(struct load_json_config_ctx *ctx, struct spdk_jsonrpc_client_request *request,
     245                 :            :                     client_resp_handler client_resp_cb)
     246                 :            : {
     247                 :            :         int rc;
     248                 :            : 
     249         [ -  + ]:       4829 :         assert(spdk_get_thread() == ctx->thread);
     250                 :            : 
     251                 :       4829 :         ctx->client_resp_cb = client_resp_cb;
     252                 :       4829 :         rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US);
     253                 :       4829 :         rc = spdk_jsonrpc_client_send_request(ctx->client_conn, request);
     254                 :            : 
     255         [ -  + ]:       4829 :         if (rc) {
     256   [ #  #  #  # ]:          0 :                 SPDK_DEBUG_APP_CFG("Sending request to client failed (%d)\n", rc);
     257                 :            :         }
     258                 :            : 
     259                 :       4829 :         return rc;
     260                 :            : }
     261                 :            : 
     262                 :            : static int
     263                 :       4008 : cap_string(const struct spdk_json_val *val, void *out)
     264                 :            : {
     265                 :       4008 :         const struct spdk_json_val **vptr = out;
     266                 :            : 
     267         [ -  + ]:       4008 :         if (val->type != SPDK_JSON_VAL_STRING) {
     268                 :          0 :                 return -EINVAL;
     269                 :            :         }
     270                 :            : 
     271                 :       4008 :         *vptr = val;
     272                 :       4008 :         return 0;
     273                 :            : }
     274                 :            : 
     275                 :            : static int
     276                 :       8470 : cap_object(const struct spdk_json_val *val, void *out)
     277                 :            : {
     278                 :       8470 :         const struct spdk_json_val **vptr = out;
     279                 :            : 
     280         [ -  + ]:       8470 :         if (val->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
     281                 :          0 :                 return -EINVAL;
     282                 :            :         }
     283                 :            : 
     284                 :       8470 :         *vptr = val;
     285                 :       8470 :         return 0;
     286                 :            : }
     287                 :            : 
     288                 :            : 
     289                 :            : static int
     290                 :       4008 : cap_array_or_null(const struct spdk_json_val *val, void *out)
     291                 :            : {
     292                 :       4008 :         const struct spdk_json_val **vptr = out;
     293                 :            : 
     294   [ +  +  -  + ]:       4008 :         if (val->type != SPDK_JSON_VAL_ARRAY_BEGIN && val->type != SPDK_JSON_VAL_NULL) {
     295                 :          0 :                 return -EINVAL;
     296                 :            :         }
     297                 :            : 
     298                 :       4008 :         *vptr = val;
     299                 :       4008 :         return 0;
     300                 :            : }
     301                 :            : 
     302                 :            : struct config_entry {
     303                 :            :         char *method;
     304                 :            :         struct spdk_json_val *params;
     305                 :            : };
     306                 :            : 
     307                 :            : static struct spdk_json_object_decoder jsonrpc_cmd_decoders[] = {
     308                 :            :         {"method", offsetof(struct config_entry, method), spdk_json_decode_string},
     309                 :            :         {"params", offsetof(struct config_entry, params), cap_object, true}
     310                 :            : };
     311                 :            : 
     312                 :            : static void app_json_config_load_subsystem_config_entry(void *_ctx);
     313                 :            : 
     314                 :            : static void
     315                 :       4829 : app_json_config_load_subsystem_config_entry_next(struct load_json_config_ctx *ctx,
     316                 :            :                 struct spdk_jsonrpc_client_response *resp)
     317                 :            : {
     318                 :            :         /* Don't care about the response */
     319                 :       4829 :         spdk_jsonrpc_client_free_response(resp);
     320                 :            : 
     321                 :       4829 :         ctx->config_it = spdk_json_next(ctx->config_it);
     322                 :       4829 :         app_json_config_load_subsystem_config_entry(ctx);
     323                 :       4829 : }
     324                 :            : 
     325                 :            : /* Load "config" entry */
     326                 :            : static void
     327                 :      13666 : app_json_config_load_subsystem_config_entry(void *_ctx)
     328                 :            : {
     329                 :      13666 :         struct load_json_config_ctx *ctx = _ctx;
     330                 :            :         struct spdk_jsonrpc_client_request *rpc_request;
     331                 :            :         struct spdk_json_write_ctx *w;
     332                 :      13666 :         struct config_entry cfg = {};
     333                 :            :         struct spdk_json_val *params_end;
     334                 :      13666 :         size_t params_len = 0;
     335                 :      13666 :         uint32_t state_mask = 0, cur_state_mask, startup_runtime = SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME;
     336                 :            :         int rc;
     337                 :            : 
     338         [ +  + ]:      13666 :         if (ctx->config_it == NULL) {
     339   [ -  +  -  + ]:       4008 :                 SPDK_DEBUG_APP_CFG("Subsystem '%.*s': configuration done.\n", ctx->subsystem_name->len,
     340                 :            :                                    (char *)ctx->subsystem_name->start);
     341                 :       4008 :                 ctx->subsystems_it = spdk_json_next(ctx->subsystems_it);
     342                 :            :                 /* Invoke later to avoid recursion */
     343                 :       4008 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem, ctx);
     344                 :       4008 :                 return;
     345                 :            :         }
     346                 :            : 
     347         [ -  + ]:       9658 :         if (spdk_json_decode_object(ctx->config_it, jsonrpc_cmd_decoders,
     348                 :            :                                     SPDK_COUNTOF(jsonrpc_cmd_decoders), &cfg)) {
     349                 :          0 :                 SPDK_ERRLOG("Failed to decode config entry\n");
     350                 :          0 :                 app_json_config_load_done(ctx, -EINVAL);
     351                 :          0 :                 goto out;
     352                 :            :         }
     353                 :            : 
     354                 :       9658 :         rc = spdk_rpc_get_method_state_mask(cfg.method, &state_mask);
     355         [ -  + ]:       9658 :         if (rc == -ENOENT) {
     356   [ #  #  #  # ]:          0 :                 if (!ctx->stop_on_error) {
     357                 :            :                         /* Invoke later to avoid recursion */
     358                 :          0 :                         ctx->config_it = spdk_json_next(ctx->config_it);
     359                 :          0 :                         spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     360         [ #  # ]:          0 :                 } else if (!spdk_subsystem_exists(ctx->subsystem_name_str)) {
     361                 :            :                         /* If the subsystem does not exist, just skip it, even
     362                 :            :                          * if we are supposed to stop_on_error. Users may generate
     363                 :            :                          * a JSON config from one application, and want to use parts
     364                 :            :                          * of it in another application that may not have all of the
     365                 :            :                          * same subsystems linked - for example, nvmf_tgt => bdevperf.
     366                 :            :                          * That's OK, we don't need to throw an error, since any nvmf
     367                 :            :                          * configuration wouldn't be used by bdevperf anyways. That is
     368                 :            :                          * different than if some subsystem does exist in bdevperf and
     369                 :            :                          * one of its RPCs fails.
     370                 :            :                          */
     371                 :          0 :                         SPDK_NOTICELOG("Skipping method '%s' because its subsystem '%s' "
     372                 :            :                                        "is not linked into this application.\n",
     373                 :            :                                        cfg.method, ctx->subsystem_name_str);
     374                 :            :                         /* Invoke later to avoid recursion */
     375                 :          0 :                         ctx->config_it = spdk_json_next(ctx->config_it);
     376                 :          0 :                         spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     377                 :            :                 } else {
     378                 :          0 :                         SPDK_ERRLOG("Method '%s' was not found\n", cfg.method);
     379                 :          0 :                         app_json_config_load_done(ctx, rc);
     380                 :            :                 }
     381                 :          0 :                 goto out;
     382                 :            :         }
     383                 :       9658 :         cur_state_mask = spdk_rpc_get_state();
     384         [ +  + ]:       9658 :         if ((state_mask & cur_state_mask) != cur_state_mask) {
     385   [ -  +  -  + ]:       3986 :                 SPDK_DEBUG_APP_CFG("Method '%s' not allowed -> skipping\n", cfg.method);
     386                 :            :                 /* Invoke later to avoid recursion */
     387                 :       3986 :                 ctx->config_it = spdk_json_next(ctx->config_it);
     388                 :       3986 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     389                 :       3986 :                 goto out;
     390                 :            :         }
     391   [ +  +  +  + ]:       5672 :         if ((state_mask & startup_runtime) == startup_runtime && cur_state_mask == SPDK_RPC_RUNTIME) {
     392                 :            :                 /* Some methods are allowed to be run in both STARTUP and RUNTIME states.
     393                 :            :                  * We should not call such methods twice, so ignore the second attempt in RUNTIME state */
     394   [ -  +  -  + ]:        843 :                 SPDK_DEBUG_APP_CFG("Method '%s' has already been run in STARTUP state\n", cfg.method);
     395                 :            :                 /* Invoke later to avoid recursion */
     396                 :        843 :                 ctx->config_it = spdk_json_next(ctx->config_it);
     397                 :        843 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     398                 :        843 :                 goto out;
     399                 :            :         }
     400                 :            : 
     401   [ -  +  -  + ]:       4829 :         SPDK_DEBUG_APP_CFG("\tmethod: %s\n", cfg.method);
     402                 :            : 
     403         [ +  + ]:       4829 :         if (cfg.params) {
     404                 :            :                 /* Get _END by skipping params and going back by one element. */
     405                 :       4235 :                 params_end = cfg.params + spdk_json_val_len(cfg.params) - 1;
     406                 :            : 
     407                 :            :                 /* Need to add one character to include '}' */
     408                 :       4235 :                 params_len = params_end->start - cfg.params->start + 1;
     409                 :            : 
     410   [ -  +  -  + ]:       4235 :                 SPDK_DEBUG_APP_CFG("\tparams: %.*s\n", (int)params_len, (char *)cfg.params->start);
     411                 :            :         }
     412                 :            : 
     413                 :       4829 :         rpc_request = spdk_jsonrpc_client_create_request();
     414         [ -  + ]:       4829 :         if (!rpc_request) {
     415                 :          0 :                 app_json_config_load_done(ctx, -errno);
     416                 :          0 :                 goto out;
     417                 :            :         }
     418                 :            : 
     419                 :       4829 :         w = spdk_jsonrpc_begin_request(rpc_request, ctx->rpc_request_id, NULL);
     420         [ -  + ]:       4829 :         if (!w) {
     421                 :          0 :                 spdk_jsonrpc_client_free_request(rpc_request);
     422                 :          0 :                 app_json_config_load_done(ctx, -ENOMEM);
     423                 :          0 :                 goto out;
     424                 :            :         }
     425                 :            : 
     426                 :       4829 :         spdk_json_write_named_string(w, "method", cfg.method);
     427                 :            : 
     428         [ +  + ]:       4829 :         if (cfg.params) {
     429                 :            :                 /* No need to parse "params". Just dump the whole content of "params"
     430                 :            :                  * directly into the request and let the remote side verify it. */
     431                 :       4235 :                 spdk_json_write_name(w, "params");
     432                 :       4235 :                 spdk_json_write_val_raw(w, cfg.params->start, params_len);
     433                 :            :         }
     434                 :            : 
     435                 :       4829 :         spdk_jsonrpc_end_request(rpc_request, w);
     436                 :            : 
     437                 :       4829 :         rc = client_send_request(ctx, rpc_request, app_json_config_load_subsystem_config_entry_next);
     438         [ +  - ]:       4829 :         if (rc != 0) {
     439                 :          0 :                 app_json_config_load_done(ctx, -rc);
     440                 :          0 :                 goto out;
     441                 :            :         }
     442                 :       7244 : out:
     443                 :       9658 :         free(cfg.method);
     444                 :            : }
     445                 :            : 
     446                 :            : static void
     447                 :         48 : subsystem_init_done(int rc, void *arg1)
     448                 :            : {
     449                 :         48 :         struct load_json_config_ctx *ctx = arg1;
     450                 :            : 
     451         [ -  + ]:         48 :         if (rc) {
     452                 :          0 :                 app_json_config_load_done(ctx, rc);
     453                 :          0 :                 return;
     454                 :            :         }
     455                 :            : 
     456                 :         48 :         spdk_rpc_set_state(SPDK_RPC_RUNTIME);
     457                 :            :         /* Another round. This time for RUNTIME methods */
     458   [ -  +  -  + ]:         48 :         SPDK_DEBUG_APP_CFG("'framework_start_init' done - continuing configuration\n");
     459                 :            : 
     460         [ -  + ]:         48 :         assert(ctx != NULL);
     461         [ +  - ]:         48 :         if (ctx->subsystems) {
     462                 :         48 :                 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
     463                 :            :         }
     464                 :            : 
     465                 :         48 :         app_json_config_load_subsystem(ctx);
     466                 :            : }
     467                 :            : 
     468                 :            : static struct spdk_json_object_decoder subsystem_decoders[] = {
     469                 :            :         {"subsystem", offsetof(struct load_json_config_ctx, subsystem_name), cap_string},
     470                 :            :         {"config", offsetof(struct load_json_config_ctx, config), cap_array_or_null}
     471                 :            : };
     472                 :            : 
     473                 :            : /*
     474                 :            :  * Start loading subsystem pointed by ctx->subsystems_it. This must point to the
     475                 :            :  * beginning of the "subsystem" object in "subsystems" array or be NULL. If it is
     476                 :            :  * NULL then no more subsystems to load.
     477                 :            :  *
     478                 :            :  * If "initalize_subsystems" is unset, then the function performs one iteration
     479                 :            :  * and does not call subsystem initialization.
     480                 :            :  *
     481                 :            :  * There are two iterations, when "initalize_subsystems" context flag is set:
     482                 :            :  *
     483                 :            :  * In first iteration only STARTUP RPC methods are used, other methods are ignored. When
     484                 :            :  * allsubsystems are walked the ctx->subsystems_it became NULL and "framework_start_init"
     485                 :            :  * is called to let the SPDK move to RUNTIME state (initialize all subsystems) and
     486                 :            :  * second iteration begins.
     487                 :            :  *
     488                 :            :  * In second iteration "subsystems" array is walked through again, this time only
     489                 :            :  * RUNTIME RPC methods are used. When ctx->subsystems_it became NULL second time it
     490                 :            :  * indicate that there is no more subsystems to load. The cb_fn is called to finish
     491                 :            :  * configuration.
     492                 :            :  */
     493                 :            : static void
     494                 :       6194 : app_json_config_load_subsystem(void *_ctx)
     495                 :            : {
     496                 :       6194 :         struct load_json_config_ctx *ctx = _ctx;
     497                 :            : 
     498         [ +  + ]:       6194 :         if (ctx->subsystems_it == NULL) {
     499   [ +  +  +  +  :       2186 :                 if (ctx->initalize_subsystems && spdk_rpc_get_state() == SPDK_RPC_STARTUP) {
                   +  + ]
     500   [ -  +  -  + ]:         48 :                         SPDK_DEBUG_APP_CFG("No more entries for current state, calling 'framework_start_init'\n");
     501                 :         48 :                         spdk_subsystem_init(subsystem_init_done, ctx);
     502                 :            :                 } else {
     503   [ -  +  -  + ]:       2138 :                         SPDK_DEBUG_APP_CFG("No more entries for current state\n");
     504                 :       2138 :                         app_json_config_load_done(ctx, 0);
     505                 :            :                 }
     506                 :            : 
     507                 :       2186 :                 return;
     508                 :            :         }
     509                 :            : 
     510                 :            :         /* Capture subsystem name and config array */
     511         [ -  + ]:       4008 :         if (spdk_json_decode_object(ctx->subsystems_it, subsystem_decoders,
     512                 :            :                                     SPDK_COUNTOF(subsystem_decoders), ctx)) {
     513                 :          0 :                 SPDK_ERRLOG("Failed to parse subsystem configuration\n");
     514                 :          0 :                 app_json_config_load_done(ctx, -EINVAL);
     515                 :          0 :                 return;
     516                 :            :         }
     517                 :            : 
     518         [ -  + ]:       4008 :         snprintf(ctx->subsystem_name_str, sizeof(ctx->subsystem_name_str),
     519                 :       4008 :                  "%.*s", ctx->subsystem_name->len, (char *)ctx->subsystem_name->start);
     520                 :            : 
     521   [ -  +  -  + ]:       4008 :         SPDK_DEBUG_APP_CFG("Loading subsystem '%s' configuration\n", ctx->subsystem_name_str);
     522                 :            : 
     523                 :            :         /* Get 'config' array first configuration entry */
     524                 :       4008 :         ctx->config_it = spdk_json_array_first(ctx->config);
     525                 :       4008 :         app_json_config_load_subsystem_config_entry(ctx);
     526                 :            : }
     527                 :            : 
     528                 :            : static int
     529                 :       2192 : parse_json(void *json, ssize_t json_size, struct load_json_config_ctx *ctx)
     530                 :            : {
     531                 :       1056 :         void *end;
     532                 :            :         ssize_t rc;
     533                 :            : 
     534   [ +  -  +  + ]:       2192 :         if (!json || json_size <= 0) {
     535                 :          6 :                 SPDK_ERRLOG("JSON data cannot be empty\n");
     536                 :          6 :                 goto err;
     537                 :            :         }
     538                 :            : 
     539                 :       2186 :         ctx->json_data = calloc(1, json_size);
     540         [ -  + ]:       2186 :         if (!ctx->json_data) {
     541                 :          0 :                 goto err;
     542                 :            :         }
     543   [ -  +  -  + ]:       2186 :         memcpy(ctx->json_data, json, json_size);
     544                 :       2186 :         ctx->json_data_size = json_size;
     545                 :            : 
     546                 :       2186 :         rc = spdk_json_parse(ctx->json_data, ctx->json_data_size, NULL, 0, &end,
     547                 :            :                              SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
     548         [ -  + ]:       2186 :         if (rc < 0) {
     549                 :          0 :                 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc);
     550                 :          0 :                 goto err;
     551                 :            :         }
     552                 :            : 
     553                 :       2186 :         ctx->values_cnt = rc;
     554                 :       2186 :         ctx->values = calloc(ctx->values_cnt, sizeof(struct spdk_json_val));
     555         [ -  + ]:       2186 :         if (ctx->values == NULL) {
     556                 :          0 :                 SPDK_ERRLOG("Out of memory\n");
     557                 :          0 :                 goto err;
     558                 :            :         }
     559                 :            : 
     560                 :       2186 :         rc = spdk_json_parse(ctx->json_data, ctx->json_data_size, ctx->values,
     561                 :            :                              ctx->values_cnt, &end,
     562                 :            :                              SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
     563         [ -  + ]:       2186 :         if ((size_t)rc != ctx->values_cnt) {
     564                 :          0 :                 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc);
     565                 :          0 :                 goto err;
     566                 :            :         }
     567                 :            : 
     568                 :       2186 :         return 0;
     569                 :          6 : err:
     570                 :          6 :         free(ctx->values);
     571                 :          6 :         return -EINVAL;
     572                 :            : }
     573                 :            : 
     574                 :            : static void
     575                 :       2192 : json_config_prepare_ctx(spdk_subsystem_init_fn cb_fn, void *cb_arg, bool stop_on_error, void *json,
     576                 :            :                         ssize_t json_size, bool initalize_subsystems)
     577                 :            : {
     578                 :       2192 :         struct load_json_config_ctx *ctx = calloc(1, sizeof(*ctx));
     579                 :            :         int rc;
     580                 :            : 
     581         [ -  + ]:       2192 :         if (!ctx) {
     582                 :          0 :                 cb_fn(-ENOMEM, cb_arg);
     583                 :          0 :                 return;
     584                 :            :         }
     585                 :            : 
     586                 :       2192 :         ctx->cb_fn = cb_fn;
     587                 :       2192 :         ctx->cb_arg = cb_arg;
     588                 :       2192 :         ctx->stop_on_error = stop_on_error;
     589                 :       2192 :         ctx->thread = spdk_get_thread();
     590                 :       2192 :         ctx->initalize_subsystems = initalize_subsystems;
     591                 :            : 
     592                 :       2192 :         rc = parse_json(json, json_size, ctx);
     593         [ +  + ]:       2192 :         if (rc < 0) {
     594                 :          6 :                 goto fail;
     595                 :            :         }
     596                 :            : 
     597                 :            :         /* Capture subsystems array */
     598                 :       2186 :         rc = spdk_json_find_array(ctx->values, "subsystems", NULL, &ctx->subsystems);
     599   [ +  +  -  +  :       2186 :         switch (rc) {
                      - ]
     600                 :       2138 :         case 0:
     601                 :            :                 /* Get first subsystem */
     602                 :       2138 :                 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
     603         [ -  + ]:       2138 :                 if (ctx->subsystems_it == NULL) {
     604                 :          0 :                         SPDK_NOTICELOG("'subsystems' configuration is empty\n");
     605                 :            :                 }
     606                 :       2138 :                 break;
     607                 :         24 :         case -EPROTOTYPE:
     608                 :         24 :                 SPDK_ERRLOG("Invalid JSON configuration: not enclosed in {}.\n");
     609                 :         24 :                 goto fail;
     610                 :          0 :         case -ENOENT:
     611                 :          0 :                 SPDK_WARNLOG("No 'subsystems' key JSON configuration file.\n");
     612                 :          0 :                 break;
     613                 :         24 :         case -EDOM:
     614                 :         24 :                 SPDK_ERRLOG("Invalid JSON configuration: 'subsystems' should be an array.\n");
     615                 :         24 :                 goto fail;
     616                 :          0 :         default:
     617                 :          0 :                 SPDK_ERRLOG("Failed to parse JSON configuration.\n");
     618                 :          0 :                 goto fail;
     619                 :            :         }
     620                 :            : 
     621                 :            :         /* FIXME: rpc client should use socketpair() instead of this temporary socket nonsense */
     622         [ -  + ]:       2138 :         rc = snprintf(ctx->rpc_socket_path_temp, sizeof(ctx->rpc_socket_path_temp),
     623                 :            :                       "%s.%d_%"PRIu64"_config", SPDK_DEFAULT_RPC_ADDR, getpid(), spdk_get_ticks());
     624         [ -  + ]:       2138 :         if (rc >= (int)sizeof(ctx->rpc_socket_path_temp)) {
     625                 :          0 :                 SPDK_ERRLOG("Socket name create failed\n");
     626                 :          0 :                 goto fail;
     627                 :            :         }
     628                 :            : 
     629                 :       2138 :         rc = spdk_rpc_initialize(ctx->rpc_socket_path_temp, NULL);
     630         [ -  + ]:       2138 :         if (rc) {
     631                 :          0 :                 goto fail;
     632                 :            :         }
     633                 :            : 
     634                 :       2138 :         ctx->client_conn = spdk_jsonrpc_client_connect(ctx->rpc_socket_path_temp, AF_UNIX);
     635         [ -  + ]:       2138 :         if (ctx->client_conn == NULL) {
     636                 :          0 :                 SPDK_ERRLOG("Failed to connect to '%s'\n", ctx->rpc_socket_path_temp);
     637                 :          0 :                 goto fail;
     638                 :            :         }
     639                 :            : 
     640                 :       2138 :         rpc_client_set_timeout(ctx, RPC_CLIENT_CONNECT_TIMEOUT_US);
     641                 :       2138 :         ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_connect_poller, ctx, 100);
     642                 :       2138 :         return;
     643                 :            : 
     644                 :         54 : fail:
     645                 :         54 :         app_json_config_load_done(ctx, -EINVAL);
     646                 :            : }
     647                 :            : 
     648         [ -  + ]:       2988 : SPDK_LOG_DEPRECATION_REGISTER(spdk_subsystem_init_from_json_config,
     649                 :            :                               "spdk_subsystem_init_from_json_config is deprecated", "v24.09", 0);
     650                 :            : 
     651                 :            : void
     652                 :         48 : spdk_subsystem_init_from_json_config(const char *json_config_file, const char *rpc_addr,
     653                 :            :                                      spdk_subsystem_init_fn cb_fn, void *cb_arg,
     654                 :            :                                      bool stop_on_error)
     655                 :            : {
     656                 :         48 :         char *json = NULL;
     657                 :         48 :         ssize_t json_size = 0;
     658                 :            : 
     659                 :         48 :         SPDK_LOG_DEPRECATED(spdk_subsystem_init_from_json_config);
     660                 :            : 
     661         [ -  + ]:         48 :         assert(cb_fn);
     662                 :            : 
     663                 :         48 :         json = spdk_posix_file_load_from_name(json_config_file, &json_size);
     664         [ -  + ]:         48 :         if (!json) {
     665                 :          0 :                 SPDK_ERRLOG("Could not read JSON config file\n");
     666                 :          0 :                 cb_fn(-EINVAL, cb_arg);
     667                 :          0 :                 return;
     668                 :            :         }
     669                 :            : 
     670                 :         48 :         json_config_prepare_ctx(cb_fn, cb_arg, stop_on_error, json, json_size, true);
     671                 :         48 :         free(json);
     672                 :            : }
     673                 :            : 
     674                 :            : void
     675                 :       2144 : spdk_subsystem_load_config(void *json, ssize_t json_size, spdk_subsystem_init_fn cb_fn,
     676                 :            :                            void *cb_arg, bool stop_on_error)
     677                 :            : {
     678         [ -  + ]:       2144 :         assert(cb_fn);
     679                 :       2144 :         json_config_prepare_ctx(cb_fn, cb_arg, stop_on_error, json, json_size, false);
     680                 :       2144 : }
     681                 :            : 
     682                 :       2988 : SPDK_LOG_REGISTER_COMPONENT(app_config)

Generated by: LCOV version 1.14