jsonrpc: fix closed connection hadling

The spdk_jsonrpc_server_conn_remove() was just swapping last connection
with that is being removed. This was fine but not for BSD queues which
rely on its own address.

Simple fix would be to add STAILQ_INIT and STAILQ_SWAP for queued
requests but we can hit the same nasty and easy to overlook bug in
future. Instead convert connection array to linked list and move around
only pointers.

Fixes #322

Change-Id: Ibb359d281f6164bcd17df37ba9d31ffdb46c2e0a
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Reviewed-on: https://review.gerrithub.io/414257
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Pawel Wodkowski 2018-06-07 22:21:03 +02:00 committed by Daniel Verkamp
parent 967339f3e5
commit 01a9118d0c
2 changed files with 31 additions and 25 deletions

View File

@ -80,13 +80,18 @@ struct spdk_jsonrpc_server_conn {
STAILQ_HEAD(, spdk_jsonrpc_request) send_queue;
struct spdk_jsonrpc_request *send_request;
TAILQ_ENTRY(spdk_jsonrpc_server_conn) link;
};
struct spdk_jsonrpc_server {
int sockfd;
spdk_jsonrpc_handle_request_fn handle_request;
struct spdk_jsonrpc_server_conn conns[SPDK_JSONRPC_MAX_CONNS];
int num_conns;
TAILQ_HEAD(, spdk_jsonrpc_server_conn) free_conns;
TAILQ_HEAD(, spdk_jsonrpc_server_conn) conns;
struct spdk_jsonrpc_server_conn conns_array[SPDK_JSONRPC_MAX_CONNS];
};
/* jsonrpc_server_tcp */

View File

@ -40,13 +40,20 @@ spdk_jsonrpc_server_listen(int domain, int protocol,
spdk_jsonrpc_handle_request_fn handle_request)
{
struct spdk_jsonrpc_server *server;
int rc, val, flag;
int rc, val, flag, i;
server = calloc(1, sizeof(struct spdk_jsonrpc_server));
if (server == NULL) {
return NULL;
}
TAILQ_INIT(&server->free_conns);
TAILQ_INIT(&server->conns);
for (i = 0; i < SPDK_JSONRPC_MAX_CONNS; i++) {
TAILQ_INSERT_TAIL(&server->free_conns, &server->conns_array[i], link);
}
server->handle_request = handle_request;
server->sockfd = socket(domain, SOCK_STREAM, protocol);
@ -93,12 +100,12 @@ spdk_jsonrpc_server_listen(int domain, int protocol,
void
spdk_jsonrpc_server_shutdown(struct spdk_jsonrpc_server *server)
{
int i;
struct spdk_jsonrpc_server_conn *conn;
close(server->sockfd);
for (i = 0; i < server->num_conns; i++) {
close(server->conns[i].sockfd);
TAILQ_FOREACH(conn, &server->conns, link) {
close(conn->sockfd);
}
free(server);
@ -119,29 +126,27 @@ static void
spdk_jsonrpc_server_conn_remove(struct spdk_jsonrpc_server_conn *conn)
{
struct spdk_jsonrpc_server *server = conn->server;
int conn_idx = conn - server->conns;
spdk_jsonrpc_server_conn_close(conn);
pthread_spin_destroy(&conn->queue_lock);
assert(STAILQ_EMPTY(&conn->send_queue));
/* Swap conn with the last entry in conns */
server->conns[conn_idx] = server->conns[server->num_conns - 1];
server->num_conns--;
TAILQ_REMOVE(&server->conns, conn, link);
TAILQ_INSERT_HEAD(&server->free_conns, conn, link);
}
static int
spdk_jsonrpc_server_accept(struct spdk_jsonrpc_server *server)
{
struct spdk_jsonrpc_server_conn *conn;
int rc, conn_idx, flag;
int rc, flag;
rc = accept(server->sockfd, NULL, NULL);
if (rc >= 0) {
assert(server->num_conns < SPDK_JSONRPC_MAX_CONNS);
conn_idx = server->num_conns;
conn = &server->conns[conn_idx];
conn = TAILQ_FIRST(&server->free_conns);
assert(conn != NULL);
conn->server = server;
conn->sockfd = rc;
conn->closed = false;
@ -159,8 +164,8 @@ spdk_jsonrpc_server_accept(struct spdk_jsonrpc_server *server)
return -1;
}
server->num_conns++;
TAILQ_REMOVE(&server->free_conns, conn, link);
TAILQ_INSERT_TAIL(&server->conns, conn, link);
return 0;
}
@ -332,12 +337,10 @@ more:
int
spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server)
{
int rc, i;
struct spdk_jsonrpc_server_conn *conn;
for (i = 0; i < server->num_conns; i++) {
conn = &server->conns[i];
int rc;
struct spdk_jsonrpc_server_conn *conn, *conn_tmp;
TAILQ_FOREACH_SAFE(conn, &server->conns, link, conn_tmp) {
if (conn->closed) {
struct spdk_jsonrpc_request *request;
@ -365,13 +368,11 @@ spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server)
}
/* Check listen socket */
if (server->num_conns < SPDK_JSONRPC_MAX_CONNS) {
if (!TAILQ_EMPTY(&server->free_conns)) {
spdk_jsonrpc_server_accept(server);
}
for (i = 0; i < server->num_conns; i++) {
conn = &server->conns[i];
TAILQ_FOREACH(conn, &server->conns, link) {
if (conn->closed) {
continue;
}