RDMA: Use conn ref counter to prevent double close (#1250)

RDMA: Use connection reference counter style
    
The reference counter of connection is used to protect re-entry of closenmethod.
Use this style instead the unsafe one.

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
This commit is contained in:
zhenwei pi 2024-11-08 16:33:01 +08:00 committed by GitHub
parent e972d56460
commit 45d596e121
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1199,6 +1199,14 @@ static void connRdmaClose(connection *conn) {
conn->fd = -1; conn->fd = -1;
} }
/* If called from within a handler, schedule the close but
* keep the connection until the handler returns.
*/
if (connHasRefs(conn)) {
conn->flags |= CONN_FLAG_CLOSE_SCHEDULED;
return;
}
if (!cm_id) { if (!cm_id) {
return; return;
} }
@ -1689,7 +1697,6 @@ static int rdmaProcessPendingData(void) {
listNode *ln; listNode *ln;
rdma_connection *rdma_conn; rdma_connection *rdma_conn;
connection *conn; connection *conn;
listNode *node;
int processed; int processed;
processed = listLength(pending_list); processed = listLength(pending_list);
@ -1697,17 +1704,17 @@ static int rdmaProcessPendingData(void) {
while ((ln = listNext(&li))) { while ((ln = listNext(&li))) {
rdma_conn = listNodeValue(ln); rdma_conn = listNodeValue(ln);
conn = &rdma_conn->c; conn = &rdma_conn->c;
node = rdma_conn->pending_list_node;
/* a connection can be disconnected by remote peer, CM event mark state as CONN_STATE_CLOSED, kick connection /* a connection can be disconnected by remote peer, CM event mark state as CONN_STATE_CLOSED, kick connection
* read/write handler to close connection */ * read/write handler to close connection */
if (conn->state == CONN_STATE_ERROR || conn->state == CONN_STATE_CLOSED) { if (conn->state == CONN_STATE_ERROR || conn->state == CONN_STATE_CLOSED) {
listDelNode(pending_list, node); listDelNode(pending_list, rdma_conn->pending_list_node);
/* do NOT call callHandler(conn, conn->read_handler) here, conn is freed in handler! */ rdma_conn->pending_list_node = NULL;
if (conn->read_handler) { /* Invoke both read_handler and write_handler, unless read_handler
conn->read_handler(conn); returns 0, indicating the connection has closed, in which case
} else if (conn->write_handler) { write_handler will be skipped. */
conn->write_handler(conn); if (callHandler(conn, conn->read_handler)) {
callHandler(conn, conn->write_handler);
} }
continue; continue;