LCOV - code coverage report
Current view: top level - spdk/lib/init - json_config.c (source / functions) Hit Total Coverage
Test: Combined Lines: 208 269 77.3 %
Date: 2024-07-13 15:09:50 Functions: 17 18 94.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 90 159 56.6 %

           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                 :            : 
      73                 :            :         /* Current "config" entry we are processing */
      74                 :            :         struct spdk_json_val *config; /* "config" array */
      75                 :            :         struct spdk_json_val *config_it; /* current config position in "config" array */
      76                 :            : 
      77                 :            :         /* Current request id we are sending. */
      78                 :            :         uint32_t rpc_request_id;
      79                 :            : 
      80                 :            :         /* Whole configuration file read and parsed. */
      81                 :            :         size_t json_data_size;
      82                 :            :         char *json_data;
      83                 :            : 
      84                 :            :         size_t values_cnt;
      85                 :            :         struct spdk_json_val *values;
      86                 :            : 
      87                 :            :         char rpc_socket_path_temp[RPC_SOCKET_PATH_MAX + 1];
      88                 :            : 
      89                 :            :         struct spdk_jsonrpc_client *client_conn;
      90                 :            :         struct spdk_poller *client_conn_poller;
      91                 :            : 
      92                 :            :         client_resp_handler client_resp_cb;
      93                 :            : 
      94                 :            :         /* Timeout for current RPC client action. */
      95                 :            :         uint64_t timeout;
      96                 :            : };
      97                 :            : 
      98                 :            : static void app_json_config_load_subsystem(void *_ctx);
      99                 :            : 
     100                 :            : static void
     101                 :       1568 : app_json_config_load_done(struct load_json_config_ctx *ctx, int rc)
     102                 :            : {
     103                 :       1568 :         spdk_poller_unregister(&ctx->client_conn_poller);
     104         [ +  + ]:       1568 :         if (ctx->client_conn != NULL) {
     105                 :       1515 :                 spdk_jsonrpc_client_close(ctx->client_conn);
     106                 :            :         }
     107                 :            : 
     108                 :       1568 :         spdk_rpc_finish();
     109                 :            : 
     110   [ -  +  -  + ]:       1568 :         SPDK_DEBUG_APP_CFG("Config load finished with rc %d\n", rc);
     111                 :       1568 :         ctx->cb_fn(rc, ctx->cb_arg);
     112                 :            : 
     113                 :       1568 :         free(ctx->json_data);
     114                 :       1568 :         free(ctx->values);
     115                 :       1568 :         free(ctx);
     116                 :       1568 : }
     117                 :            : 
     118                 :            : static void
     119                 :       5786 : rpc_client_set_timeout(struct load_json_config_ctx *ctx, uint64_t timeout_us)
     120                 :            : {
     121                 :       5786 :         ctx->timeout = spdk_get_ticks() + timeout_us * spdk_get_ticks_hz() / (1000 * 1000);
     122                 :       5786 : }
     123                 :            : 
     124                 :            : static int
     125                 :    1089510 : rpc_client_check_timeout(struct load_json_config_ctx *ctx)
     126                 :            : {
     127         [ +  + ]:    1089510 :         if (ctx->timeout < spdk_get_ticks()) {
     128                 :          1 :                 SPDK_WARNLOG("RPC client command timeout.\n");
     129                 :          1 :                 return -ETIMEDOUT;
     130                 :            :         }
     131                 :            : 
     132                 :    1089509 :         return 0;
     133                 :            : }
     134                 :            : 
     135                 :            : struct json_write_buf {
     136                 :            :         char data[1024];
     137                 :            :         unsigned cur_off;
     138                 :            : };
     139                 :            : 
     140                 :            : static int
     141                 :          0 : json_write_stdout(void *cb_ctx, const void *data, size_t size)
     142                 :            : {
     143                 :          0 :         struct json_write_buf *buf = cb_ctx;
     144                 :            :         size_t rc;
     145                 :            : 
     146         [ #  # ]:          0 :         rc = snprintf(buf->data + buf->cur_off, sizeof(buf->data) - buf->cur_off,
     147                 :            :                       "%s", (const char *)data);
     148         [ #  # ]:          0 :         if (rc > 0) {
     149                 :          0 :                 buf->cur_off += rc;
     150                 :            :         }
     151         [ #  # ]:          0 :         return rc == size ? 0 : -1;
     152                 :            : }
     153                 :            : 
     154                 :            : static int
     155                 :    1093780 : rpc_client_poller(void *arg)
     156                 :            : {
     157                 :    1093780 :         struct load_json_config_ctx *ctx = arg;
     158                 :            :         struct spdk_jsonrpc_client_response *resp;
     159                 :            :         client_resp_handler cb;
     160                 :            :         int rc;
     161                 :            : 
     162         [ -  + ]:    1093780 :         assert(spdk_get_thread() == ctx->thread);
     163                 :            : 
     164                 :    1093780 :         rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0);
     165         [ +  + ]:    1093780 :         if (rc == 0) {
     166                 :    1089510 :                 rc = rpc_client_check_timeout(ctx);
     167         [ +  + ]:    1089510 :                 if (rc == -ETIMEDOUT) {
     168                 :          1 :                         rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US);
     169                 :          1 :                         rc = 0;
     170                 :            :                 }
     171                 :            :         }
     172                 :            : 
     173         [ +  + ]:    1093780 :         if (rc == 0) {
     174                 :            :                 /* No response yet */
     175                 :    1089510 :                 return SPDK_POLLER_BUSY;
     176         [ -  + ]:       4270 :         } else if (rc < 0) {
     177                 :          0 :                 app_json_config_load_done(ctx, rc);
     178                 :          0 :                 return SPDK_POLLER_BUSY;
     179                 :            :         }
     180                 :            : 
     181                 :       4270 :         resp = spdk_jsonrpc_client_get_response(ctx->client_conn);
     182         [ -  + ]:       4270 :         assert(resp);
     183                 :            : 
     184         [ -  + ]:       4270 :         if (resp->error) {
     185                 :          0 :                 struct json_write_buf buf = {};
     186                 :          0 :                 struct spdk_json_write_ctx *w = spdk_json_write_begin(json_write_stdout,
     187                 :            :                                                 &buf, SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
     188                 :            : 
     189         [ #  # ]:          0 :                 if (w == NULL) {
     190                 :          0 :                         SPDK_ERRLOG("error response: (?)\n");
     191                 :            :                 } else {
     192                 :          0 :                         spdk_json_write_val(w, resp->error);
     193                 :          0 :                         spdk_json_write_end(w);
     194                 :          0 :                         SPDK_ERRLOG("error response: \n%s\n", buf.data);
     195                 :            :                 }
     196                 :            :         }
     197                 :            : 
     198   [ -  +  -  -  :       4270 :         if (resp->error && ctx->stop_on_error) {
                   -  - ]
     199                 :          0 :                 spdk_jsonrpc_client_free_response(resp);
     200                 :          0 :                 app_json_config_load_done(ctx, -EINVAL);
     201                 :            :         } else {
     202                 :            :                 /* We have response so we must have callback for it. */
     203                 :       4270 :                 cb = ctx->client_resp_cb;
     204         [ -  + ]:       4270 :                 assert(cb != NULL);
     205                 :            : 
     206                 :            :                 /* Mark we are done with this handler. */
     207                 :       4270 :                 ctx->client_resp_cb = NULL;
     208                 :       4270 :                 cb(ctx, resp);
     209                 :            :         }
     210                 :            : 
     211                 :            : 
     212                 :       4270 :         return SPDK_POLLER_BUSY;
     213                 :            : }
     214                 :            : 
     215                 :            : static int
     216                 :       1515 : rpc_client_connect_poller(void *_ctx)
     217                 :            : {
     218                 :       1515 :         struct load_json_config_ctx *ctx = _ctx;
     219                 :            :         int rc;
     220                 :            : 
     221                 :       1515 :         rc = spdk_jsonrpc_client_poll(ctx->client_conn, 0);
     222         [ +  - ]:       1515 :         if (rc != -ENOTCONN) {
     223                 :            :                 /* We are connected. Start regular poller and issue first request */
     224                 :       1515 :                 spdk_poller_unregister(&ctx->client_conn_poller);
     225                 :       1515 :                 ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_poller, ctx, 100);
     226                 :       1515 :                 app_json_config_load_subsystem(ctx);
     227                 :            :         } else {
     228                 :          0 :                 rc = rpc_client_check_timeout(ctx);
     229         [ #  # ]:          0 :                 if (rc) {
     230                 :          0 :                         app_json_config_load_done(ctx, rc);
     231                 :            :                 }
     232                 :            : 
     233                 :          0 :                 return SPDK_POLLER_IDLE;
     234                 :            :         }
     235                 :            : 
     236                 :       1515 :         return SPDK_POLLER_BUSY;
     237                 :            : }
     238                 :            : 
     239                 :            : static int
     240                 :       4270 : client_send_request(struct load_json_config_ctx *ctx, struct spdk_jsonrpc_client_request *request,
     241                 :            :                     client_resp_handler client_resp_cb)
     242                 :            : {
     243                 :            :         int rc;
     244                 :            : 
     245         [ -  + ]:       4270 :         assert(spdk_get_thread() == ctx->thread);
     246                 :            : 
     247                 :       4270 :         ctx->client_resp_cb = client_resp_cb;
     248                 :       4270 :         rpc_client_set_timeout(ctx, RPC_CLIENT_REQUEST_TIMEOUT_US);
     249                 :       4270 :         rc = spdk_jsonrpc_client_send_request(ctx->client_conn, request);
     250                 :            : 
     251         [ -  + ]:       4270 :         if (rc) {
     252   [ #  #  #  # ]:          0 :                 SPDK_DEBUG_APP_CFG("Sending request to client failed (%d)\n", rc);
     253                 :            :         }
     254                 :            : 
     255                 :       4270 :         return rc;
     256                 :            : }
     257                 :            : 
     258                 :            : static int
     259                 :       4164 : cap_string(const struct spdk_json_val *val, void *out)
     260                 :            : {
     261                 :       4164 :         const struct spdk_json_val **vptr = out;
     262                 :            : 
     263         [ -  + ]:       4164 :         if (val->type != SPDK_JSON_VAL_STRING) {
     264                 :          0 :                 return -EINVAL;
     265                 :            :         }
     266                 :            : 
     267                 :       4164 :         *vptr = val;
     268                 :       4164 :         return 0;
     269                 :            : }
     270                 :            : 
     271                 :            : static int
     272                 :       7448 : cap_object(const struct spdk_json_val *val, void *out)
     273                 :            : {
     274                 :       7448 :         const struct spdk_json_val **vptr = out;
     275                 :            : 
     276         [ -  + ]:       7448 :         if (val->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
     277                 :          0 :                 return -EINVAL;
     278                 :            :         }
     279                 :            : 
     280                 :       7448 :         *vptr = val;
     281                 :       7448 :         return 0;
     282                 :            : }
     283                 :            : 
     284                 :            : 
     285                 :            : static int
     286                 :       4164 : cap_array_or_null(const struct spdk_json_val *val, void *out)
     287                 :            : {
     288                 :       4164 :         const struct spdk_json_val **vptr = out;
     289                 :            : 
     290   [ +  +  -  + ]:       4164 :         if (val->type != SPDK_JSON_VAL_ARRAY_BEGIN && val->type != SPDK_JSON_VAL_NULL) {
     291                 :          0 :                 return -EINVAL;
     292                 :            :         }
     293                 :            : 
     294                 :       4164 :         *vptr = val;
     295                 :       4164 :         return 0;
     296                 :            : }
     297                 :            : 
     298                 :            : struct config_entry {
     299                 :            :         char *method;
     300                 :            :         struct spdk_json_val *params;
     301                 :            : };
     302                 :            : 
     303                 :            : static struct spdk_json_object_decoder jsonrpc_cmd_decoders[] = {
     304                 :            :         {"method", offsetof(struct config_entry, method), spdk_json_decode_string},
     305                 :            :         {"params", offsetof(struct config_entry, params), cap_object, true}
     306                 :            : };
     307                 :            : 
     308                 :            : static void app_json_config_load_subsystem_config_entry(void *_ctx);
     309                 :            : 
     310                 :            : static void
     311                 :       4270 : app_json_config_load_subsystem_config_entry_next(struct load_json_config_ctx *ctx,
     312                 :            :                 struct spdk_jsonrpc_client_response *resp)
     313                 :            : {
     314                 :            :         /* Don't care about the response */
     315                 :       4270 :         spdk_jsonrpc_client_free_response(resp);
     316                 :            : 
     317                 :       4270 :         ctx->config_it = spdk_json_next(ctx->config_it);
     318                 :       4270 :         app_json_config_load_subsystem_config_entry(ctx);
     319                 :       4270 : }
     320                 :            : 
     321                 :            : /* Load "config" entry */
     322                 :            : static void
     323                 :      12704 : app_json_config_load_subsystem_config_entry(void *_ctx)
     324                 :            : {
     325                 :      12704 :         struct load_json_config_ctx *ctx = _ctx;
     326                 :            :         struct spdk_jsonrpc_client_request *rpc_request;
     327                 :            :         struct spdk_json_write_ctx *w;
     328                 :      12704 :         struct config_entry cfg = {};
     329                 :            :         struct spdk_json_val *params_end;
     330                 :      12704 :         size_t params_len = 0;
     331                 :      12704 :         uint32_t state_mask = 0, cur_state_mask, startup_runtime = SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME;
     332                 :            :         int rc;
     333                 :            : 
     334         [ +  + ]:      12704 :         if (ctx->config_it == NULL) {
     335   [ -  +  -  + ]:       4164 :                 SPDK_DEBUG_APP_CFG("Subsystem '%.*s': configuration done.\n", ctx->subsystem_name->len,
     336                 :            :                                    (char *)ctx->subsystem_name->start);
     337                 :       4164 :                 ctx->subsystems_it = spdk_json_next(ctx->subsystems_it);
     338                 :            :                 /* Invoke later to avoid recurrence */
     339                 :       4164 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem, ctx);
     340                 :       4164 :                 return;
     341                 :            :         }
     342                 :            : 
     343         [ -  + ]:       8540 :         if (spdk_json_decode_object(ctx->config_it, jsonrpc_cmd_decoders,
     344                 :            :                                     SPDK_COUNTOF(jsonrpc_cmd_decoders), &cfg)) {
     345                 :          0 :                 SPDK_ERRLOG("Failed to decode config entry\n");
     346                 :          0 :                 app_json_config_load_done(ctx, -EINVAL);
     347                 :          0 :                 goto out;
     348                 :            :         }
     349                 :            : 
     350                 :       8540 :         rc = spdk_rpc_get_method_state_mask(cfg.method, &state_mask);
     351         [ -  + ]:       8540 :         if (rc == -ENOENT) {
     352                 :          0 :                 SPDK_ERRLOG("Method '%s' was not found\n", cfg.method);
     353                 :          0 :                 app_json_config_load_done(ctx, rc);
     354                 :          0 :                 goto out;
     355                 :            :         }
     356                 :       8540 :         cur_state_mask = spdk_rpc_get_state();
     357         [ +  + ]:       8540 :         if ((state_mask & cur_state_mask) != cur_state_mask) {
     358   [ -  +  -  + ]:       3544 :                 SPDK_DEBUG_APP_CFG("Method '%s' not allowed -> skipping\n", cfg.method);
     359                 :            :                 /* Invoke later to avoid recurrence */
     360                 :       3544 :                 ctx->config_it = spdk_json_next(ctx->config_it);
     361                 :       3544 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     362                 :       3544 :                 goto out;
     363                 :            :         }
     364   [ +  +  +  + ]:       4996 :         if ((state_mask & startup_runtime) == startup_runtime && cur_state_mask == SPDK_RPC_RUNTIME) {
     365                 :            :                 /* Some methods are allowed to be run in both STARTUP and RUNTIME states.
     366                 :            :                  * We should not call such methods twice, so ignore the second attempt in RUNTIME state */
     367   [ -  +  -  + ]:        726 :                 SPDK_DEBUG_APP_CFG("Method '%s' has already been run in STARTUP state\n", cfg.method);
     368                 :            :                 /* Invoke later to avoid recurrence */
     369                 :        726 :                 ctx->config_it = spdk_json_next(ctx->config_it);
     370                 :        726 :                 spdk_thread_send_msg(ctx->thread, app_json_config_load_subsystem_config_entry, ctx);
     371                 :        726 :                 goto out;
     372                 :            :         }
     373                 :            : 
     374   [ -  +  -  + ]:       4270 :         SPDK_DEBUG_APP_CFG("\tmethod: %s\n", cfg.method);
     375                 :            : 
     376         [ +  + ]:       4270 :         if (cfg.params) {
     377                 :            :                 /* Get _END by skipping params and going back by one element. */
     378                 :       3724 :                 params_end = cfg.params + spdk_json_val_len(cfg.params) - 1;
     379                 :            : 
     380                 :            :                 /* Need to add one character to include '}' */
     381                 :       3724 :                 params_len = params_end->start - cfg.params->start + 1;
     382                 :            : 
     383   [ -  +  -  + ]:       3724 :                 SPDK_DEBUG_APP_CFG("\tparams: %.*s\n", (int)params_len, (char *)cfg.params->start);
     384                 :            :         }
     385                 :            : 
     386                 :       4270 :         rpc_request = spdk_jsonrpc_client_create_request();
     387         [ -  + ]:       4270 :         if (!rpc_request) {
     388                 :          0 :                 app_json_config_load_done(ctx, -errno);
     389                 :          0 :                 goto out;
     390                 :            :         }
     391                 :            : 
     392                 :       4270 :         w = spdk_jsonrpc_begin_request(rpc_request, ctx->rpc_request_id, NULL);
     393         [ -  + ]:       4270 :         if (!w) {
     394                 :          0 :                 spdk_jsonrpc_client_free_request(rpc_request);
     395                 :          0 :                 app_json_config_load_done(ctx, -ENOMEM);
     396                 :          0 :                 goto out;
     397                 :            :         }
     398                 :            : 
     399                 :       4270 :         spdk_json_write_named_string(w, "method", cfg.method);
     400                 :            : 
     401         [ +  + ]:       4270 :         if (cfg.params) {
     402                 :            :                 /* No need to parse "params". Just dump the whole content of "params"
     403                 :            :                  * directly into the request and let the remote side verify it. */
     404                 :       3724 :                 spdk_json_write_name(w, "params");
     405                 :       3724 :                 spdk_json_write_val_raw(w, cfg.params->start, params_len);
     406                 :            :         }
     407                 :            : 
     408                 :       4270 :         spdk_jsonrpc_end_request(rpc_request, w);
     409                 :            : 
     410                 :       4270 :         rc = client_send_request(ctx, rpc_request, app_json_config_load_subsystem_config_entry_next);
     411         [ +  - ]:       4270 :         if (rc != 0) {
     412                 :          0 :                 app_json_config_load_done(ctx, -rc);
     413                 :          0 :                 goto out;
     414                 :            :         }
     415                 :       6439 : out:
     416                 :       8540 :         free(cfg.method);
     417                 :            : }
     418                 :            : 
     419                 :            : static void
     420                 :       1515 : subsystem_init_done(int rc, void *arg1)
     421                 :            : {
     422                 :       1515 :         struct load_json_config_ctx *ctx = arg1;
     423                 :            : 
     424         [ -  + ]:       1515 :         if (rc) {
     425                 :          0 :                 app_json_config_load_done(ctx, rc);
     426                 :          0 :                 return;
     427                 :            :         }
     428                 :            : 
     429                 :       1515 :         spdk_rpc_set_state(SPDK_RPC_RUNTIME);
     430                 :            :         /* Another round. This time for RUNTIME methods */
     431   [ -  +  -  + ]:       1515 :         SPDK_DEBUG_APP_CFG("'framework_start_init' done - continuing configuration\n");
     432                 :            : 
     433         [ -  + ]:       1515 :         assert(ctx != NULL);
     434         [ +  - ]:       1515 :         if (ctx->subsystems) {
     435                 :       1515 :                 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
     436                 :            :         }
     437                 :            : 
     438                 :       1515 :         app_json_config_load_subsystem(ctx);
     439                 :            : }
     440                 :            : 
     441                 :            : static struct spdk_json_object_decoder subsystem_decoders[] = {
     442                 :            :         {"subsystem", offsetof(struct load_json_config_ctx, subsystem_name), cap_string},
     443                 :            :         {"config", offsetof(struct load_json_config_ctx, config), cap_array_or_null}
     444                 :            : };
     445                 :            : 
     446                 :            : /*
     447                 :            :  * Start loading subsystem pointed by ctx->subsystems_it. This must point to the
     448                 :            :  * beginning of the "subsystem" object in "subsystems" array or be NULL. If it is
     449                 :            :  * NULL then no more subsystems to load.
     450                 :            :  *
     451                 :            :  * There are two iterations:
     452                 :            :  *
     453                 :            :  * In first iteration only STARTUP RPC methods are used, other methods are ignored. When
     454                 :            :  * allsubsystems are walked the ctx->subsystems_it became NULL and "framework_start_init"
     455                 :            :  * is called to let the SPDK move to RUNTIME state (initialize all subsystems) and
     456                 :            :  * second iteration begins.
     457                 :            :  *
     458                 :            :  * In second iteration "subsystems" array is walked through again, this time only
     459                 :            :  * RUNTIME RPC methods are used. When ctx->subsystems_it became NULL second time it
     460                 :            :  * indicate that there is no more subsystems to load. The cb_fn is called to finish
     461                 :            :  * configuration.
     462                 :            :  */
     463                 :            : static void
     464                 :       7194 : app_json_config_load_subsystem(void *_ctx)
     465                 :            : {
     466                 :       7194 :         struct load_json_config_ctx *ctx = _ctx;
     467                 :            : 
     468         [ +  + ]:       7194 :         if (ctx->subsystems_it == NULL) {
     469         [ +  + ]:       3030 :                 if (spdk_rpc_get_state() == SPDK_RPC_STARTUP) {
     470   [ -  +  -  + ]:       1515 :                         SPDK_DEBUG_APP_CFG("No more entries for current state, calling 'framework_start_init'\n");
     471                 :       1515 :                         spdk_subsystem_init(subsystem_init_done, ctx);
     472                 :            :                 } else {
     473                 :       1515 :                         app_json_config_load_done(ctx, 0);
     474                 :            :                 }
     475                 :            : 
     476                 :       3030 :                 return;
     477                 :            :         }
     478                 :            : 
     479                 :            :         /* Capture subsystem name and config array */
     480         [ -  + ]:       4164 :         if (spdk_json_decode_object(ctx->subsystems_it, subsystem_decoders,
     481                 :            :                                     SPDK_COUNTOF(subsystem_decoders), ctx)) {
     482                 :          0 :                 SPDK_ERRLOG("Failed to parse subsystem configuration\n");
     483                 :          0 :                 app_json_config_load_done(ctx, -EINVAL);
     484                 :          0 :                 return;
     485                 :            :         }
     486                 :            : 
     487   [ -  +  -  + ]:       4164 :         SPDK_DEBUG_APP_CFG("Loading subsystem '%.*s' configuration\n", ctx->subsystem_name->len,
     488                 :            :                            (char *)ctx->subsystem_name->start);
     489                 :            : 
     490                 :            :         /* Get 'config' array first configuration entry */
     491                 :       4164 :         ctx->config_it = spdk_json_array_first(ctx->config);
     492                 :       4164 :         app_json_config_load_subsystem_config_entry(ctx);
     493                 :            : }
     494                 :            : 
     495                 :            : static void *
     496                 :       1568 : read_file(const char *filename, size_t *size)
     497                 :            : {
     498                 :       1568 :         FILE *file = fopen(filename, "r");
     499                 :            :         void *data;
     500                 :            : 
     501         [ +  + ]:       1568 :         if (file == NULL) {
     502                 :            :                 /* errno is set by fopen */
     503                 :          1 :                 return NULL;
     504                 :            :         }
     505                 :            : 
     506                 :       1567 :         data = spdk_posix_file_load(file, size);
     507                 :       1567 :         fclose(file);
     508                 :       1567 :         return data;
     509                 :            : }
     510                 :            : 
     511                 :            : static int
     512                 :       1568 : app_json_config_read(const char *config_file, struct load_json_config_ctx *ctx)
     513                 :            : {
     514                 :       1568 :         struct spdk_json_val *values = NULL;
     515                 :       1568 :         void *json = NULL, *end;
     516                 :            :         ssize_t values_cnt, rc;
     517                 :        706 :         size_t json_size;
     518                 :            : 
     519                 :       1568 :         json = read_file(config_file, &json_size);
     520         [ +  + ]:       1568 :         if (!json) {
     521                 :          1 :                 SPDK_ERRLOG("Read JSON configuration file %s failed: %s\n",
     522                 :            :                             config_file, spdk_strerror(errno));
     523                 :          1 :                 return -errno;
     524                 :            :         }
     525                 :            : 
     526                 :       1567 :         rc = spdk_json_parse(json, json_size, NULL, 0, &end,
     527                 :            :                              SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
     528         [ +  + ]:       1567 :         if (rc < 0) {
     529                 :          6 :                 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc);
     530                 :          6 :                 goto err;
     531                 :            :         }
     532                 :            : 
     533                 :       1561 :         values_cnt = rc;
     534                 :       1561 :         values = calloc(values_cnt, sizeof(struct spdk_json_val));
     535         [ -  + ]:       1561 :         if (values == NULL) {
     536                 :          0 :                 SPDK_ERRLOG("Out of memory\n");
     537                 :          0 :                 goto err;
     538                 :            :         }
     539                 :            : 
     540                 :       1561 :         rc = spdk_json_parse(json, json_size, values, values_cnt, &end,
     541                 :            :                              SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
     542         [ -  + ]:       1561 :         if (rc != values_cnt) {
     543                 :          0 :                 SPDK_ERRLOG("Parsing JSON configuration failed (%zd)\n", rc);
     544                 :          0 :                 goto err;
     545                 :            :         }
     546                 :            : 
     547                 :       1561 :         ctx->json_data = json;
     548                 :       1561 :         ctx->json_data_size = json_size;
     549                 :            : 
     550                 :       1561 :         ctx->values = values;
     551                 :       1561 :         ctx->values_cnt = values_cnt;
     552                 :            : 
     553                 :       1561 :         return 0;
     554                 :          6 : err:
     555                 :          6 :         free(json);
     556                 :          6 :         free(values);
     557                 :          6 :         return rc;
     558                 :            : }
     559                 :            : 
     560                 :            : void
     561                 :       1568 : spdk_subsystem_init_from_json_config(const char *json_config_file, const char *rpc_addr,
     562                 :            :                                      spdk_subsystem_init_fn cb_fn, void *cb_arg,
     563                 :            :                                      bool stop_on_error)
     564                 :            : {
     565                 :       1568 :         struct load_json_config_ctx *ctx = calloc(1, sizeof(*ctx));
     566                 :            :         int rc;
     567                 :            : 
     568         [ -  + ]:       1568 :         assert(cb_fn);
     569         [ -  + ]:       1568 :         if (!ctx) {
     570                 :          0 :                 cb_fn(-ENOMEM, cb_arg);
     571                 :          0 :                 return;
     572                 :            :         }
     573                 :            : 
     574                 :       1568 :         ctx->cb_fn = cb_fn;
     575                 :       1568 :         ctx->cb_arg = cb_arg;
     576                 :       1568 :         ctx->stop_on_error = stop_on_error;
     577                 :       1568 :         ctx->thread = spdk_get_thread();
     578                 :            : 
     579                 :       1568 :         rc = app_json_config_read(json_config_file, ctx);
     580         [ +  + ]:       1568 :         if (rc) {
     581                 :          7 :                 goto fail;
     582                 :            :         }
     583                 :            : 
     584                 :            :         /* Capture subsystems array */
     585                 :       1561 :         rc = spdk_json_find_array(ctx->values, "subsystems", NULL, &ctx->subsystems);
     586   [ +  +  -  +  :       1561 :         switch (rc) {
                      - ]
     587                 :       1515 :         case 0:
     588                 :            :                 /* Get first subsystem */
     589                 :       1515 :                 ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
     590         [ -  + ]:       1515 :                 if (ctx->subsystems_it == NULL) {
     591                 :          0 :                         SPDK_NOTICELOG("'subsystems' configuration is empty\n");
     592                 :            :                 }
     593                 :       1515 :                 break;
     594                 :         23 :         case -EPROTOTYPE:
     595                 :         23 :                 SPDK_ERRLOG("Invalid JSON configuration: not enclosed in {}.\n");
     596                 :         23 :                 goto fail;
     597                 :          0 :         case -ENOENT:
     598                 :          0 :                 SPDK_WARNLOG("No 'subsystems' key JSON configuration file.\n");
     599                 :          0 :                 break;
     600                 :         23 :         case -EDOM:
     601                 :         23 :                 SPDK_ERRLOG("Invalid JSON configuration: 'subsystems' should be an array.\n");
     602                 :         23 :                 goto fail;
     603                 :          0 :         default:
     604                 :          0 :                 SPDK_ERRLOG("Failed to parse JSON configuration.\n");
     605                 :          0 :                 goto fail;
     606                 :            :         }
     607                 :            : 
     608                 :            :         /* If rpc_addr is not an Unix socket use default address as prefix. */
     609   [ +  +  -  + ]:       1515 :         if (rpc_addr == NULL || rpc_addr[0] != '/') {
     610                 :        133 :                 rpc_addr = SPDK_DEFAULT_RPC_ADDR;
     611                 :            :         }
     612                 :            : 
     613                 :            :         /* FIXME: rpc client should use socketpair() instead of this temporary socket nonsense */
     614         [ -  + ]:       1515 :         rc = snprintf(ctx->rpc_socket_path_temp, sizeof(ctx->rpc_socket_path_temp), "%s.%d_config",
     615                 :            :                       rpc_addr, getpid());
     616         [ -  + ]:       1515 :         if (rc >= (int)sizeof(ctx->rpc_socket_path_temp)) {
     617                 :          0 :                 SPDK_ERRLOG("Socket name create failed\n");
     618                 :          0 :                 goto fail;
     619                 :            :         }
     620                 :            : 
     621                 :       1515 :         rc = spdk_rpc_initialize(ctx->rpc_socket_path_temp, NULL);
     622         [ -  + ]:       1515 :         if (rc) {
     623                 :          0 :                 goto fail;
     624                 :            :         }
     625                 :            : 
     626                 :       1515 :         ctx->client_conn = spdk_jsonrpc_client_connect(ctx->rpc_socket_path_temp, AF_UNIX);
     627         [ -  + ]:       1515 :         if (ctx->client_conn == NULL) {
     628                 :          0 :                 SPDK_ERRLOG("Failed to connect to '%s'\n", ctx->rpc_socket_path_temp);
     629                 :          0 :                 goto fail;
     630                 :            :         }
     631                 :            : 
     632                 :       1515 :         rpc_client_set_timeout(ctx, RPC_CLIENT_CONNECT_TIMEOUT_US);
     633                 :       1515 :         ctx->client_conn_poller = SPDK_POLLER_REGISTER(rpc_client_connect_poller, ctx, 100);
     634                 :       1515 :         return;
     635                 :            : 
     636                 :         53 : fail:
     637                 :         53 :         app_json_config_load_done(ctx, -EINVAL);
     638                 :            : }
     639                 :            : 
     640                 :       3209 : SPDK_LOG_REGISTER_COMPONENT(app_config)

Generated by: LCOV version 1.14