LCOV - code coverage report
Current view: top level - spdk/lib/init - json_config.c (source / functions) Hit Total Coverage
Test: Combined Lines: 203 302 67.2 %
Date: 2024-11-17 18:18:59 Functions: 16 18 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 321 681 47.1 %

           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" ARRAY 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                 :       1521 : app_json_config_load_done(struct load_json_config_ctx *ctx, int rc)
     106                 :            : {
     107         [ +  - ]:       1521 :         spdk_poller_unregister(&ctx->client_conn_poller);
     108   [ +  +  +  -  :       1521 :         if (ctx->client_conn != NULL) {
                   -  + ]
     109   [ +  -  +  - ]:       1472 :                 spdk_jsonrpc_client_close(ctx->client_conn);
     110                 :         68 :         }
     111                 :            : 
     112         [ +  - ]:       1521 :         spdk_rpc_server_finish(ctx->rpc_socket_path_temp);
     113                 :            : 
     114   [ +  +  +  +  :       1521 :         SPDK_DEBUG_APP_CFG("Config load finished with rc %d\n", rc);
                   +  - ]
     115   [ +  -  +  -  :       1521 :         ctx->cb_fn(rc, ctx->cb_arg);
          -  +  +  -  +  
                -  +  - ]
     116                 :            : 
     117   [ +  -  +  - ]:       1521 :         free(ctx->json_data);
     118   [ +  -  +  - ]:       1521 :         free(ctx->values);
     119                 :       1521 :         free(ctx);
     120                 :       1521 : }
     121                 :            : 
     122                 :            : static void
     123                 :       6485 : rpc_client_set_timeout(struct load_json_config_ctx *ctx, uint64_t timeout_us)
     124                 :            : {
     125   [ +  -  +  -  :       6485 :         ctx->timeout = spdk_get_ticks() + timeout_us * spdk_get_ticks_hz() / (1000 * 1000);
                   +  - ]
     126                 :       6485 : }
     127                 :            : 
     128                 :            : static int
     129                 :    1172172 : rpc_client_check_timeout(struct load_json_config_ctx *ctx)
     130                 :            : {
     131   [ +  +  +  -  :    1172172 :         if (ctx->timeout < spdk_get_ticks()) {
                   -  + ]
     132                 :          0 :                 SPDK_WARNLOG("RPC client command timeout.\n");
     133                 :          0 :                 return -ETIMEDOUT;
     134                 :            :         }
     135                 :            : 
     136                 :    1172172 :         return 0;
     137                 :      22698 : }
     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                 :          0 :                       "%s", (const char *)data);
     152         [ #  # ]:          0 :         if (rc > 0) {
     153   [ #  #  #  # ]:          0 :                 buf->cur_off += rc;
     154                 :          0 :         }
     155         [ #  # ]:          0 :         return rc == size ? 0 : -1;
     156                 :            : }
     157                 :            : 
     158                 :            : static int
     159                 :    1177185 : rpc_client_poller(void *arg)
     160                 :            : {
     161                 :    1177185 :         struct load_json_config_ctx *ctx = arg;
     162                 :            :         struct spdk_jsonrpc_client_response *resp;
     163                 :            :         client_resp_handler cb;
     164                 :            :         int rc;
     165                 :            : 
     166   [ +  +  +  -  :    1177185 :         assert(spdk_get_thread() == ctx->thread);
             +  -  #  # ]
     167                 :            : 
     168   [ +  -  +  - ]:    1177185 :         rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0);
     169         [ +  + ]:    1177185 :         if (rc == 0) {
     170                 :    1172172 :                 rc = rpc_client_check_timeout(ctx);
     171         [ +  + ]:    1172172 :                 if (rc == -ETIMEDOUT) {
     172                 :          0 :                         rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US);
     173                 :          0 :                         rc = 0;
     174                 :          0 :                 }
     175                 :      22698 :         }
     176                 :            : 
     177         [ +  + ]:    1177185 :         if (rc == 0) {
     178                 :            :                 /* No response yet */
     179                 :    1172172 :                 return SPDK_POLLER_BUSY;
     180         [ -  + ]:       5013 :         } else if (rc < 0) {
     181                 :          0 :                 app_json_config_load_done(ctx, rc);
     182                 :          0 :                 return SPDK_POLLER_BUSY;
     183                 :            :         }
     184                 :            : 
     185   [ +  -  +  - ]:       5013 :         resp = spdk_jsonrpc_client_get_response(ctx->client_conn);
     186   [ +  +  #  # ]:       5013 :         assert(resp);
     187                 :            : 
     188   [ +  +  +  -  :       5013 :         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                 :          0 :                 } 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                 :          0 :         }
     201                 :            : 
     202   [ +  +  +  -  :       5013 :         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                 :          0 :         } else {
     206                 :            :                 /* We have response so we must have callback for it. */
     207   [ +  -  +  - ]:       5013 :                 cb = ctx->client_resp_cb;
     208   [ +  +  #  # ]:       5013 :                 assert(cb != NULL);
     209                 :            : 
     210                 :            :                 /* Mark we are done with this handler. */
     211   [ +  -  +  - ]:       5013 :                 ctx->client_resp_cb = NULL;
     212   [ -  +  +  - ]:       5013 :                 cb(ctx, resp);
     213                 :            :         }
     214                 :            : 
     215                 :            : 
     216                 :       5013 :         return SPDK_POLLER_BUSY;
     217                 :      23013 : }
     218                 :            : 
     219                 :            : static int
     220                 :       1472 : rpc_client_connect_poller(void *_ctx)
     221                 :            : {
     222                 :       1472 :         struct load_json_config_ctx *ctx = _ctx;
     223                 :            :         int rc;
     224                 :            : 
     225   [ +  -  +  - ]:       1472 :         rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0);
     226         [ +  - ]:       1472 :         if (rc != -ENOTCONN) {
     227                 :            :                 /* We are connected. Start regular poller and issue first request */
     228         [ -  + ]:       1472 :                 spdk_poller_unregister(&ctx->client_conn_poller);
     229   [ -  +  -  + ]:       1472 :                 ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_poller, ctx, 100);
     230                 :       1472 :                 app_json_config_load_subsystem(ctx);
     231                 :         68 :         } else {
     232                 :          0 :                 rc = rpc_client_check_timeout(ctx);
     233         [ #  # ]:          0 :                 if (rc) {
     234                 :          0 :                         app_json_config_load_done(ctx, rc);
     235                 :          0 :                 }
     236                 :            : 
     237                 :          0 :                 return SPDK_POLLER_IDLE;
     238                 :            :         }
     239                 :            : 
     240                 :       1472 :         return SPDK_POLLER_BUSY;
     241                 :         68 : }
     242                 :            : 
     243                 :            : static int
     244                 :       5013 : 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   [ +  +  +  -  :       5013 :         assert(spdk_get_thread() == ctx->thread);
             +  -  #  # ]
     250                 :            : 
     251   [ +  -  +  - ]:       5013 :         ctx->client_resp_cb = client_resp_cb;
     252                 :       5013 :         rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US);
     253   [ +  -  +  - ]:       5013 :         rc = spdk_jsonrpc_client_send_request(ctx->client_conn, request);
     254                 :            : 
     255         [ +  + ]:       5013 :         if (rc) {
     256   [ #  #  #  #  :          0 :                 SPDK_DEBUG_APP_CFG("Sending request to client failed (%d)\n", rc);
                   #  # ]
     257                 :          0 :         }
     258                 :            : 
     259                 :       5013 :         return rc;
     260                 :            : }
     261                 :            : 
     262                 :            : static int
     263                 :       3412 : cap_string(const struct spdk_json_val *val, void *out)
     264                 :            : {
     265                 :       3412 :         const struct spdk_json_val **vptr = out;
     266                 :            : 
     267   [ +  +  +  -  :       3412 :         if (val->type != SPDK_JSON_VAL_STRING) {
                   -  + ]
     268                 :          0 :                 return -EINVAL;
     269                 :            :         }
     270                 :            : 
     271         [ +  - ]:       3412 :         *vptr = val;
     272                 :       3412 :         return 0;
     273                 :        162 : }
     274                 :            : 
     275                 :            : static int
     276                 :       8768 : cap_object(const struct spdk_json_val *val, void *out)
     277                 :            : {
     278                 :       8768 :         const struct spdk_json_val **vptr = out;
     279                 :            : 
     280   [ +  +  +  -  :       8768 :         if (val->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
                   -  + ]
     281                 :          0 :                 return -EINVAL;
     282                 :            :         }
     283                 :            : 
     284         [ +  - ]:       8768 :         *vptr = val;
     285                 :       8768 :         return 0;
     286                 :        564 : }
     287                 :            : 
     288                 :            : 
     289                 :            : static int
     290                 :       3412 : cap_array_or_null(const struct spdk_json_val *val, void *out)
     291                 :            : {
     292                 :       3412 :         const struct spdk_json_val **vptr = out;
     293                 :            : 
     294   [ +  +  +  +  :       3412 :         if (val->type != SPDK_JSON_VAL_ARRAY_BEGIN && val->type != SPDK_JSON_VAL_NULL) {
          +  +  +  -  +  
                -  +  - ]
     295                 :          0 :                 return -EINVAL;
     296                 :            :         }
     297                 :            : 
     298         [ +  - ]:       3412 :         *vptr = val;
     299                 :       3412 :         return 0;
     300                 :        162 : }
     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                 :       5013 : 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                 :       5013 :         spdk_jsonrpc_client_free_response(resp);
     320                 :            : 
     321   [ +  -  +  -  :       5013 :         ctx->config_it = spdk_json_next(ctx->config_it);
             +  -  +  - ]
     322                 :       5013 :         app_json_config_load_subsystem_config_entry(ctx);
     323                 :       5013 : }
     324                 :            : 
     325                 :            : /* Load "config" entry */
     326                 :            : static void
     327                 :      13438 : app_json_config_load_subsystem_config_entry(void *_ctx)
     328                 :            : {
     329                 :      13438 :         struct load_json_config_ctx *ctx = _ctx;
     330                 :            :         struct spdk_jsonrpc_client_request *rpc_request;
     331                 :            :         struct spdk_json_write_ctx *w;
     332                 :      13438 :         struct config_entry cfg = {};
     333                 :            :         struct spdk_json_val *params_end;
     334                 :      13438 :         size_t params_len = 0;
     335                 :      13438 :         uint32_t state_mask = 0, cur_state_mask, startup_runtime = SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME;
     336                 :            :         int rc;
     337                 :            : 
     338   [ +  +  +  -  :      13438 :         if (ctx->config_it == NULL) {
                   +  + ]
     339   [ +  +  +  +  :       3412 :                 SPDK_DEBUG_APP_CFG("Subsystem '%.*s': configuration done.\n", ctx->subsystem_name->len,
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     340                 :            :                                    (char *)ctx->subsystem_name->start);
     341   [ +  -  +  -  :       3412 :                 ctx->subsystems_it = spdk_json_next(ctx->subsystems_it);
             +  -  +  - ]
     342                 :            :                 /* Invoke later to avoid recursion */
     343   [ +  -  +  - ]:       3412 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem, ctx);
     344                 :       3412 :                 return;
     345                 :            :         }
     346                 :            : 
     347   [ +  +  +  -  :      10026 :         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                 :      10026 :         rc = spdk_rpc_get_method_state_mask(cfg.method, &state_mask);
     355         [ -  + ]:      10026 :         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                 :          0 :                 } 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                 :      10026 :         cur_state_mask = spdk_rpc_get_state();
     384         [ +  + ]:      10026 :         if ((state_mask & cur_state_mask) != cur_state_mask) {
     385   [ +  +  +  +  :       4141 :                 SPDK_DEBUG_APP_CFG("Method '%s' not allowed -> skipping\n", cfg.method);
                   +  - ]
     386                 :            :                 /* Invoke later to avoid recursion */
     387   [ +  -  +  -  :       4141 :                 ctx->config_it = spdk_json_next(ctx->config_it);
             +  -  +  - ]
     388   [ +  -  +  - ]:       4141 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     389                 :       4141 :                 goto out;
     390                 :            :         }
     391   [ +  +  +  + ]:       5885 :         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   [ +  +  +  +  :        872 :                 SPDK_DEBUG_APP_CFG("Method '%s' has already been run in STARTUP state\n", cfg.method);
                   +  - ]
     395                 :            :                 /* Invoke later to avoid recursion */
     396   [ +  -  +  -  :        872 :                 ctx->config_it = spdk_json_next(ctx->config_it);
             +  -  +  - ]
     397   [ +  -  +  - ]:        872 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     398                 :        872 :                 goto out;
     399                 :            :         }
     400                 :            : 
     401   [ +  +  +  +  :       5013 :         SPDK_DEBUG_APP_CFG("\tmethod: %s\n", cfg.method);
                   +  - ]
     402                 :            : 
     403   [ +  +  +  + ]:       5013 :         if (cfg.params) {
     404                 :            :                 /* Get _END by skipping params and going back by one element. */
     405   [ +  -  +  -  :       4384 :                 params_end = cfg.params + spdk_json_val_len(cfg.params) - 1;
             +  -  +  - ]
     406                 :            : 
     407                 :            :                 /* Need to add one character to include '}' */
     408   [ +  -  +  -  :       4384 :                 params_len = params_end->start - cfg.params->start + 1;
          +  -  +  -  +  
                -  +  - ]
     409                 :            : 
     410   [ +  +  +  +  :       4384 :                 SPDK_DEBUG_APP_CFG("\tparams: %.*s\n", (int)params_len, (char *)cfg.params->start);
          +  -  #  #  #  
                #  #  # ]
     411                 :        282 :         }
     412                 :            : 
     413                 :       5013 :         rpc_request = spdk_jsonrpc_client_create_request();
     414         [ +  + ]:       5013 :         if (!rpc_request) {
     415   [ #  #  #  # ]:          0 :                 app_json_config_load_done(ctx, -errno);
     416                 :          0 :                 goto out;
     417                 :            :         }
     418                 :            : 
     419   [ +  -  +  - ]:       5013 :         w = spdk_jsonrpc_begin_request(rpc_request, ctx->rpc_request_id, NULL);
     420         [ +  + ]:       5013 :         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                 :       5013 :         spdk_json_write_named_string(w, "method", cfg.method);
     427                 :            : 
     428   [ +  +  +  + ]:       5013 :         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                 :       4384 :                 spdk_json_write_name(w, "params");
     432   [ -  +  -  +  :       4384 :                 spdk_json_write_val_raw(w, cfg.params->start, params_len);
                   -  + ]
     433                 :        282 :         }
     434                 :            : 
     435                 :       5013 :         spdk_jsonrpc_end_request(rpc_request, w);
     436                 :            : 
     437                 :       5013 :         rc = client_send_request(ctx, rpc_request, app_json_config_load_subsystem_config_entry_next);
     438         [ +  + ]:       5013 :         if (rc != 0) {
     439         [ #  # ]:          0 :                 app_json_config_load_done(ctx, -rc);
     440                 :          0 :                 goto out;
     441                 :            :         }
     442                 :       6853 : out:
     443                 :      10026 :         free(cfg.method);
     444                 :        792 : }
     445                 :            : 
     446                 :            : static void
     447                 :          0 : subsystem_init_done(int rc, void *arg1)
     448                 :            : {
     449                 :          0 :         struct load_json_config_ctx *ctx = arg1;
     450                 :            : 
     451         [ #  # ]:          0 :         if (rc) {
     452                 :          0 :                 app_json_config_load_done(ctx, rc);
     453                 :          0 :                 return;
     454                 :            :         }
     455                 :            : 
     456                 :          0 :         spdk_rpc_set_state(SPDK_RPC_RUNTIME);
     457                 :            :         /* Another round. This time for RUNTIME methods */
     458   [ #  #  #  #  :          0 :         SPDK_DEBUG_APP_CFG("'framework_start_init' done - continuing configuration\n");
                   #  # ]
     459                 :            : 
     460   [ #  #  #  # ]:          0 :         assert(ctx != NULL);
     461   [ #  #  #  #  :          0 :         if (ctx->subsystems) {
                   #  # ]
     462   [ #  #  #  #  :          0 :                 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
             #  #  #  # ]
     463                 :          0 :         }
     464                 :            : 
     465                 :          0 :         app_json_config_load_subsystem(ctx);
     466                 :          0 : }
     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                 :       4884 : app_json_config_load_subsystem(void *_ctx)
     495                 :            : {
     496                 :       4884 :         struct load_json_config_ctx *ctx = _ctx;
     497                 :            : 
     498   [ +  +  +  -  :       4884 :         if (ctx->subsystems_it == NULL) {
                   +  + ]
     499   [ +  +  +  +  :       1472 :                 if (ctx->initalize_subsystems && spdk_rpc_get_state() == SPDK_RPC_STARTUP) {
          +  -  -  +  #  
                      # ]
     500   [ #  #  #  #  :          0 :                         SPDK_DEBUG_APP_CFG("No more entries for current state, calling 'framework_start_init'\n");
                   #  # ]
     501                 :          0 :                         spdk_subsystem_init(subsystem_init_done, ctx);
     502                 :          0 :                 } else {
     503   [ +  +  +  +  :       1472 :                         SPDK_DEBUG_APP_CFG("No more entries for current state\n");
                   +  - ]
     504                 :       1472 :                         app_json_config_load_done(ctx, 0);
     505                 :            :                 }
     506                 :            : 
     507                 :       1472 :                 return;
     508                 :            :         }
     509                 :            : 
     510                 :            :         /* Capture subsystem name and config array */
     511   [ +  +  +  -  :       3412 :         if (spdk_json_decode_object(ctx->subsystems_it, subsystem_decoders,
             -  +  -  + ]
     512                 :        162 :                                     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         [ +  + ]:       3574 :         snprintf(ctx->subsystem_name_str, sizeof(ctx->subsystem_name_str),
     519   [ +  -  +  -  :       3412 :                  "%.*s", ctx->subsystem_name->len, (char *)ctx->subsystem_name->start);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     520                 :            : 
     521   [ +  +  +  +  :       3412 :         SPDK_DEBUG_APP_CFG("Loading subsystem '%s' configuration\n", ctx->subsystem_name_str);
             +  -  #  # ]
     522                 :            : 
     523                 :            :         /* Get 'config' array first configuration entry */
     524   [ +  -  +  -  :       3412 :         ctx->config_it = spdk_json_array_first(ctx->config);
             +  -  +  - ]
     525                 :       3412 :         app_json_config_load_subsystem_config_entry(ctx);
     526                 :        230 : }
     527                 :            : 
     528                 :            : static int
     529                 :       1521 : parse_json(void *json, ssize_t json_size, struct load_json_config_ctx *ctx)
     530                 :            : {
     531                 :        635 :         void *end;
     532                 :            :         ssize_t rc;
     533                 :            : 
     534   [ +  -  +  + ]:       1521 :         if (!json || json_size <= 0) {
     535                 :          5 :                 SPDK_ERRLOG("JSON data cannot be empty\n");
     536                 :          5 :                 goto err;
     537                 :            :         }
     538                 :            : 
     539   [ +  -  +  - ]:       1516 :         ctx->json_data = calloc(1, json_size);
     540   [ +  +  +  -  :       1516 :         if (!ctx->json_data) {
                   +  - ]
     541                 :          0 :                 goto err;
     542                 :            :         }
     543   [ +  +  +  +  :       1516 :         memcpy(ctx->json_data, json, json_size);
             +  -  +  - ]
     544   [ +  -  +  - ]:       1516 :         ctx->json_data_size = json_size;
     545                 :            : 
     546   [ +  -  +  -  :       1516 :         rc = spdk_json_parse(ctx->json_data, ctx->json_data_size, NULL, 0, &end,
             +  -  +  - ]
     547                 :            :                              SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
     548         [ +  + ]:       1516 :         if (rc < 0) {
     549                 :          0 :                 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc);
     550                 :          0 :                 goto err;
     551                 :            :         }
     552                 :            : 
     553   [ +  -  +  - ]:       1516 :         ctx->values_cnt = rc;
     554   [ +  -  +  -  :       1516 :         ctx->values = calloc(ctx->values_cnt, sizeof(struct spdk_json_val));
             +  -  +  - ]
     555   [ +  +  +  -  :       1516 :         if (ctx->values == NULL) {
                   +  - ]
     556                 :          0 :                 SPDK_ERRLOG("Out of memory\n");
     557                 :          0 :                 goto err;
     558                 :            :         }
     559                 :            : 
     560   [ -  +  -  +  :       1584 :         rc = spdk_json_parse(ctx->json_data, ctx->json_data_size, ctx->values,
          -  +  -  +  -  
                +  -  + ]
     561   [ -  +  -  + ]:         68 :                              ctx->values_cnt, &end,
     562                 :            :                              SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
     563   [ -  +  -  +  :       1516 :         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                 :       1516 :         return 0;
     569                 :          5 : err:
     570   [ #  #  #  # ]:          5 :         free(ctx->values);
     571                 :          5 :         return -EINVAL;
     572                 :         68 : }
     573                 :            : 
     574                 :            : static void
     575                 :       1521 : 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                 :       1521 :         struct load_json_config_ctx *ctx = calloc(1, sizeof(*ctx));
     579                 :            :         int rc;
     580                 :            : 
     581         [ -  + ]:       1521 :         if (!ctx) {
     582   [ #  #  #  # ]:          0 :                 cb_fn(-ENOMEM, cb_arg);
     583                 :          0 :                 return;
     584                 :            :         }
     585                 :            : 
     586   [ +  -  +  - ]:       1521 :         ctx->cb_fn = cb_fn;
     587   [ +  -  +  - ]:       1521 :         ctx->cb_arg = cb_arg;
     588   [ +  -  +  -  :       1521 :         ctx->stop_on_error = stop_on_error;
                   +  - ]
     589   [ +  -  +  - ]:       1521 :         ctx->thread = spdk_get_thread();
     590   [ +  -  +  -  :       1521 :         ctx->initalize_subsystems = initalize_subsystems;
                   +  - ]
     591                 :            : 
     592                 :       1521 :         rc = parse_json(json, json_size, ctx);
     593         [ +  + ]:       1521 :         if (rc < 0) {
     594                 :          5 :                 goto fail;
     595                 :            :         }
     596                 :            : 
     597                 :            :         /* Capture subsystems array */
     598   [ +  -  +  -  :       1516 :         rc = spdk_json_find_array(ctx->values, "subsystems", NULL, &ctx->subsystems);
                   +  - ]
     599   [ +  +  -  +  :       1516 :         switch (rc) {
                      - ]
     600                 :       1404 :         case 0:
     601                 :            :                 /* Get first subsystem */
     602   [ +  -  +  -  :       1472 :                 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
             +  -  +  - ]
     603   [ +  +  +  -  :       1472 :                 if (ctx->subsystems_it == NULL) {
                   +  - ]
     604                 :          0 :                         SPDK_NOTICELOG("'subsystems' configuration is empty\n");
     605                 :          0 :                 }
     606                 :       1472 :                 break;
     607                 :         22 :         case -EPROTOTYPE:
     608                 :         22 :                 SPDK_ERRLOG("Invalid JSON configuration: not enclosed in {}.\n");
     609                 :         22 :                 goto fail;
     610                 :          0 :         case -ENOENT:
     611                 :          0 :                 SPDK_WARNLOG("No 'subsystems' key JSON configuration file.\n");
     612                 :          0 :                 break;
     613                 :         22 :         case -EDOM:
     614                 :         22 :                 SPDK_ERRLOG("Invalid JSON configuration: 'subsystems' should be an array.\n");
     615                 :         22 :                 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         [ +  + ]:       1472 :         rc = snprintf(ctx->rpc_socket_path_temp, sizeof(ctx->rpc_socket_path_temp),
     623                 :         68 :                       "%s.%d_%"PRIu64"_config", SPDK_DEFAULT_RPC_ADDR, getpid(), spdk_get_ticks());
     624         [ -  + ]:       1472 :         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         [ +  - ]:       1472 :         rc = spdk_rpc_initialize(ctx->rpc_socket_path_temp, NULL);
     630         [ -  + ]:       1472 :         if (rc) {
     631                 :          0 :                 goto fail;
     632                 :            :         }
     633                 :            : 
     634   [ +  -  +  -  :       1472 :         ctx->client_conn = spdk_jsonrpc_client_connect(ctx->rpc_socket_path_temp, AF_UNIX);
                   +  - ]
     635   [ +  +  +  -  :       1472 :         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                 :       1472 :         rpc_client_set_timeout(ctx, RPC_CLIENT_CONNECT_TIMEOUT_US);
     641   [ +  -  +  - ]:       1472 :         ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_connect_poller, ctx, 100);
     642                 :       1472 :         return;
     643                 :            : 
     644                 :         49 : fail:
     645                 :         49 :         app_json_config_load_done(ctx, -EINVAL);
     646                 :         68 : }
     647                 :            : 
     648                 :            : void
     649                 :       1521 : spdk_subsystem_load_config(void *json, ssize_t json_size, spdk_subsystem_init_fn cb_fn,
     650                 :            :                            void *cb_arg, bool stop_on_error)
     651                 :            : {
     652   [ +  +  #  # ]:       1521 :         assert(cb_fn);
     653         [ +  - ]:       1521 :         json_config_prepare_ctx(cb_fn, cb_arg, stop_on_error, json, json_size, false);
     654                 :       1521 : }
     655                 :            : 
     656                 :       2405 : SPDK_LOG_REGISTER_COMPONENT(app_config)

Generated by: LCOV version 1.14