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: yidong0635 <dongx.yi@intel.com>
Change-Id: Icd287bd0c5670ee8ec32750b999f82b0fa89cf84
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458438
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
This commit is contained in:
yidong0635 2019-06-18 14:36:05 -04:00 committed by Darek Stojaczyk
parent 6629202cbd
commit 17c006a7c3

View File

@ -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)) {