jsonrpc: avoid calling poll() with a closed fd

If a connection is closed by the remote end, the JSON-RPC server could
potentially call poll() on the pollfd containing the invalid file
descriptor.  Rework the logic so that the pollfd's fd field is set to a
negative value so that poll() will ignore it until the connection is
fully cleaned up by spdk_jsonrpc_server_conn_remove().

Also add handling for the potential error conditions returned by poll()
so that if something does go wrong, the server doesn't get stuck polling
a broken pollfd forever.

Change-Id: Id02e3a230740c8ffd513888cb0564891b3aca069
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/369285
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Daniel Verkamp 2017-07-12 12:56:02 -07:00 committed by Jim Harris
parent 122e284652
commit cc7407947b
2 changed files with 27 additions and 3 deletions

View File

@ -69,6 +69,7 @@ struct spdk_jsonrpc_server_conn {
uint32_t outstanding_requests;
struct spdk_ring *send_queue;
struct spdk_jsonrpc_request *send_request;
struct pollfd *pfd;
};
struct spdk_jsonrpc_server {

View File

@ -107,13 +107,27 @@ spdk_jsonrpc_server_shutdown(struct spdk_jsonrpc_server *server)
free(server);
}
static void
spdk_jsonrpc_server_conn_close(struct spdk_jsonrpc_server_conn *conn)
{
conn->closed = true;
/* Set the pollfd fd to a negative value so it is ignored by poll() */
conn->pfd->fd = -1;
if (conn->sockfd >= 0) {
close(conn->sockfd);
conn->sockfd = -1;
}
}
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;
close(conn->sockfd);
spdk_jsonrpc_server_conn_close(conn);
spdk_ring_free(conn->send_queue);
@ -159,6 +173,8 @@ spdk_jsonrpc_server_accept(struct spdk_jsonrpc_server *server)
pfd = &server->pollfds[conn_idx + 1];
pfd->fd = conn->sockfd;
pfd->events = POLLIN | POLLOUT;
pfd->revents = 0;
conn->pfd = pfd;
server->num_conns++;
@ -389,7 +405,7 @@ spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server)
rc = spdk_jsonrpc_server_conn_send(conn);
if (rc != 0) {
SPDK_TRACELOG(SPDK_TRACE_RPC, "closing conn due to send failure\n");
conn->closed = true;
spdk_jsonrpc_server_conn_close(conn);
continue;
}
}
@ -398,11 +414,18 @@ spdk_jsonrpc_server_poll(struct spdk_jsonrpc_server *server)
rc = spdk_jsonrpc_server_conn_recv(conn);
if (rc != 0) {
SPDK_TRACELOG(SPDK_TRACE_RPC, "closing conn due to recv failure\n");
conn->closed = true;
spdk_jsonrpc_server_conn_close(conn);
continue;
}
}
if (pfd->revents & (POLLERR | POLLNVAL)) {
SPDK_TRACELOG(SPDK_TRACE_RPC, "closing conn due to poll() flag %d\n",
(int)pfd->revents);
spdk_jsonrpc_server_conn_close(conn);
continue;
}
pfd->revents = 0;
}