Commit 17c006a7 authored by yidong0635's avatar yidong0635 Committed by Darek Stojaczyk
Browse files

lib/jsonrpc: Fix memory leaks about connection request.



There're outstanding requests in spdk_jsonrpc_parse_request which caused by
	connection close.
There are methods to call spdk_jsonrpc_server_conn_close, including
	spdk_jsonrpc_server_conn_remove and spdk_jsonrpc_server_shutdown,
Some rpc methods call these functions to terminate connections ,that leads to
	memory leaks.
Try to free outstanding requests after deciding to terminate a connection.
And do this follwing with close(conn->sockfd).

Fix issue #784, and can resolve other similar memory leaks about this.

Signed-off-by: default avataryidong0635 <dongx.yi@intel.com>
Change-Id: Icd287bd0c5670ee8ec32750b999f82b0fa89cf84
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458438


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
parent 6629202c
Loading
Loading
Loading
Loading
+29 −35
Original line number Diff line number Diff line
@@ -98,12 +98,39 @@ spdk_jsonrpc_server_listen(int domain, int protocol,
	return server;
}

static struct spdk_jsonrpc_request *
spdk_jsonrpc_server_dequeue_request(struct spdk_jsonrpc_server_conn *conn)
{
	struct spdk_jsonrpc_request *request = NULL;

	pthread_spin_lock(&conn->queue_lock);
	request = STAILQ_FIRST(&conn->send_queue);
	if (request) {
		STAILQ_REMOVE_HEAD(&conn->send_queue, link);
	}
	pthread_spin_unlock(&conn->queue_lock);
	return request;
}

static void
spdk_jsonrpc_server_free_conn_request(struct spdk_jsonrpc_server_conn *conn)
{
	struct spdk_jsonrpc_request *request;

	spdk_jsonrpc_free_request(conn->send_request);
	conn->send_request = NULL ;
	while ((request = spdk_jsonrpc_server_dequeue_request(conn)) != NULL) {
		spdk_jsonrpc_free_request(request);
	}
}

static void
spdk_jsonrpc_server_conn_close(struct spdk_jsonrpc_server_conn *conn)
{
	conn->closed = true;

	if (conn->sockfd >= 0) {
		spdk_jsonrpc_server_free_conn_request(conn);
		close(conn->sockfd);
		conn->sockfd = -1;

@@ -315,20 +342,6 @@ spdk_jsonrpc_server_send_response(struct spdk_jsonrpc_request *request)
	pthread_spin_unlock(&conn->queue_lock);
}

static struct spdk_jsonrpc_request *
spdk_jsonrpc_server_dequeue_request(struct spdk_jsonrpc_server_conn *conn)
{
	struct spdk_jsonrpc_request *request = NULL;

	pthread_spin_lock(&conn->queue_lock);
	request = STAILQ_FIRST(&conn->send_queue);
	if (request) {
		STAILQ_REMOVE_HEAD(&conn->send_queue, link);
	}
	pthread_spin_unlock(&conn->queue_lock);
	return request;
}


static int
spdk_jsonrpc_server_conn_send(struct spdk_jsonrpc_server_conn *conn)
@@ -392,29 +405,10 @@ spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server)
			spdk_jsonrpc_server_conn_close(conn);
		}

		if (conn->sockfd == -1) {
			struct spdk_jsonrpc_request *request;

			/*
			 * The client closed the connection, but there may still be requests
			 * outstanding; we have no way to cancel outstanding requests, so wait until
			 * each outstanding request sends a response (which will be discarded, since
			 * the connection is closed).
			 */

			spdk_jsonrpc_free_request(conn->send_request);
			conn->send_request = NULL;

			while ((request = spdk_jsonrpc_server_dequeue_request(conn)) != NULL) {
				spdk_jsonrpc_free_request(request);
			}

			if (conn->outstanding_requests == 0) {
				SPDK_DEBUGLOG(SPDK_LOG_RPC, "all outstanding requests completed\n");
		if (conn->sockfd == -1 && conn->outstanding_requests == 0) {
			spdk_jsonrpc_server_conn_remove(conn);
		}
	}
	}

	/* Check listen socket */
	if (!TAILQ_EMPTY(&server->free_conns)) {