From c7852cf98d4df6ce3e2b1f7660db634876c42e0e Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Wed, 14 Feb 2018 10:12:50 -0700 Subject: [PATCH] jsonrpc: allow send_buf to grow as needed Reallocate the send buffer if more data is written by the RPC handler than currently fits in the buffer. Change-Id: I590dd173b843aba48c768adfafaf87e4b47bcc19 Signed-off-by: Daniel Verkamp Reviewed-on: https://review.gerrithub.io/399925 Reviewed-by: Jim Harris Tested-by: SPDK Automated Test System Reviewed-by: Shuhei Matsumoto --- CHANGELOG.md | 3 ++ lib/jsonrpc/jsonrpc_internal.h | 11 ++++-- lib/jsonrpc/jsonrpc_server.c | 34 +++++++++++++++++-- .../jsonrpc_server.c/jsonrpc_server_ut.c | 16 +++++++-- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 715cd9760..21a3b35a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The Rpc configuration file section, which was deprecated in v18.01, has been removed. Users should switch to the `-r` command-line parameter instead. +The JSON-RPC server implementation now allows up to 32 megabyte responses, growing as +needed; previously, the response was limited to 32 kilobytes. + ### NVMe Driver EXPERIMENTAL: Adds support for WDS and RDS capable CMBs in NVMe controllers. This support is diff --git a/lib/jsonrpc/jsonrpc_internal.h b/lib/jsonrpc/jsonrpc_internal.h index 5cafc3e44..48d4e24ca 100644 --- a/lib/jsonrpc/jsonrpc_internal.h +++ b/lib/jsonrpc/jsonrpc_internal.h @@ -42,7 +42,8 @@ #include "spdk_internal/log.h" #define SPDK_JSONRPC_RECV_BUF_SIZE (32 * 1024) -#define SPDK_JSONRPC_SEND_BUF_SIZE (32 * 1024) +#define SPDK_JSONRPC_SEND_BUF_SIZE_INIT (32 * 1024) +#define SPDK_JSONRPC_SEND_BUF_SIZE_MAX (32 * 1024 * 1024) #define SPDK_JSONRPC_ID_MAX_LEN 128 #define SPDK_JSONRPC_MAX_CONNS 64 #define SPDK_JSONRPC_MAX_VALUES 1024 @@ -54,9 +55,15 @@ struct spdk_jsonrpc_request { struct spdk_json_val id; uint8_t id_data[SPDK_JSONRPC_ID_MAX_LEN]; + /* Total space allocated for send_buf */ + size_t send_buf_size; + + /* Number of bytes used in send_buf (<= send_buf_size) */ size_t send_len; + size_t send_offset; - uint8_t send_buf[SPDK_JSONRPC_SEND_BUF_SIZE]; + + uint8_t *send_buf; }; struct spdk_jsonrpc_server_conn { diff --git a/lib/jsonrpc/jsonrpc_server.c b/lib/jsonrpc/jsonrpc_server.c index 59ab9470c..d7f564000 100644 --- a/lib/jsonrpc/jsonrpc_server.c +++ b/lib/jsonrpc/jsonrpc_server.c @@ -144,6 +144,13 @@ spdk_jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, void *json, si request->id.type = SPDK_JSON_VAL_INVALID; request->send_offset = 0; request->send_len = 0; + request->send_buf_size = SPDK_JSONRPC_SEND_BUF_SIZE_INIT; + request->send_buf = malloc(request->send_buf_size); + if (request->send_buf == NULL) { + SPDK_ERRLOG("Failed to allocate send_buf (%zu bytes)\n", request->send_buf_size); + free(request); + return -1; + } if (rc < 0 || rc > SPDK_JSONRPC_MAX_VALUES) { SPDK_DEBUGLOG(SPDK_LOG_RPC, "JSON parse error\n"); @@ -184,10 +191,30 @@ static int spdk_jsonrpc_server_write_cb(void *cb_ctx, const void *data, size_t size) { struct spdk_jsonrpc_request *request = cb_ctx; + size_t new_size = request->send_buf_size; - if (SPDK_JSONRPC_SEND_BUF_SIZE - request->send_len < size) { - SPDK_ERRLOG("Not enough space in send buf\n"); - return -1; + while (new_size - request->send_len < size) { + if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) { + SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n", + (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX); + return -1; + } + + new_size *= 2; + } + + if (new_size != request->send_buf_size) { + uint8_t *new_buf; + + new_buf = realloc(request->send_buf, new_size); + if (new_buf == NULL) { + SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n", + request->send_buf_size, new_size); + return -1; + } + + request->send_buf = new_buf; + request->send_buf_size = new_size; } memcpy(request->send_buf + request->send_len, data, size); @@ -229,6 +256,7 @@ void spdk_jsonrpc_free_request(struct spdk_jsonrpc_request *request) { request->conn->outstanding_requests--; + free(request->send_buf); free(request); } diff --git a/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c b/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c index 768b881a5..f37268a26 100644 --- a/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c +++ b/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c @@ -61,14 +61,21 @@ static size_t g_num_reqs; memcpy(g_buf, in, sizeof(in) - 1); \ g_num_reqs = 0; \ g_cur_req = NULL; \ - CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, sizeof(in) - 1) == sizeof(in) - sizeof(trailing)) + CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, sizeof(in) - 1) == sizeof(in) - sizeof(trailing)); \ + if (g_cur_req && g_cur_req->request) { \ + free(g_cur_req->request->send_buf); \ + g_cur_req->request->send_buf = NULL; \ + } #define PARSE_FAIL(in) \ memcpy(g_buf, in, sizeof(in) - 1); \ g_num_reqs = 0; \ g_cur_req = 0; \ - CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, sizeof(in) - 1) < 0) - + CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, sizeof(in) - 1) < 0); \ + if (g_cur_req && g_cur_req->request) { \ + free(g_cur_req->request->send_buf); \ + g_cur_req->request->send_buf = NULL; \ + } #define REQ_BEGIN(expected_error) \ if (g_cur_req == NULL) { \ @@ -148,6 +155,9 @@ static size_t g_num_reqs; g_params++ #define FREE_REQUEST() \ + if (g_reqs->request) { \ + free(g_reqs->request->send_buf); \ + } \ free(g_reqs->request); \ g_reqs->request = NULL