From: Stefan Metzmacher Date: Wed, 15 Nov 2023 15:31:53 +0000 (+0100) Subject: ctdb: add/implement CTDB_CONTROL_TCP_CLIENT_DISCONNECTED X-Git-Tag: samba-4.18.10~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f769415799332387ea7b2daa73d47f2f18fbe386;p=thirdparty%2Fsamba.git ctdb: add/implement CTDB_CONTROL_TCP_CLIENT_DISCONNECTED With multichannel a ctdb connection from smbd may hold multiple tcp connections, which can be disconnected before the smbd process terminates the whole ctdb connection, so we a way to remove undo 'CTDB_CONTROL_TCP_CLIENT' again. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15523 Signed-off-by: Stefan Metzmacher Reviewed-by: Martin Schwenke (cherry picked from commit c6602b686b4e50d93272667ef86d3904181fb1ab) --- diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 37842a151d6..ca350df2cf4 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -892,6 +892,9 @@ int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses); int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata); +int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb, + uint32_t client_id, + TDB_DATA indata); int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed); int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata); diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h index fb6e39f33b5..42b992ae6db 100644 --- a/ctdb/protocol/protocol.h +++ b/ctdb/protocol/protocol.h @@ -381,6 +381,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, CTDB_CONTROL_ECHO_DATA = 156, CTDB_CONTROL_DISABLE_NODE = 157, CTDB_CONTROL_ENABLE_NODE = 158, + CTDB_CONTROL_TCP_CLIENT_DISCONNECTED = 159, }; #define MAX_COUNT_BUCKETS 16 diff --git a/ctdb/protocol/protocol_control.c b/ctdb/protocol/protocol_control.c index a7c797f5dbc..5e2cf13c579 100644 --- a/ctdb/protocol/protocol_control.c +++ b/ctdb/protocol/protocol_control.c @@ -410,6 +410,10 @@ static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd) case CTDB_CONTROL_ENABLE_NODE: break; + + case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED: + len = ctdb_connection_len(cd->data.conn); + break; } return len; @@ -1016,6 +1020,14 @@ static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen, &cd->data.echo_data, &np); break; + + case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED: + ret = ctdb_connection_pull(buf, + buflen, + mem_ctx, + &cd->data.conn, + &np); + break; } if (ret != 0) { @@ -1376,6 +1388,9 @@ static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd) case CTDB_CONTROL_ENABLE_NODE: break; + + case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED: + break; } return len; diff --git a/ctdb/protocol/protocol_debug.c b/ctdb/protocol/protocol_debug.c index d94cb548d68..2dc4a702eae 100644 --- a/ctdb/protocol/protocol_debug.c +++ b/ctdb/protocol/protocol_debug.c @@ -245,6 +245,7 @@ static void ctdb_opcode_print(uint32_t opcode, FILE *fp) { CTDB_CONTROL_ECHO_DATA, "ECHO_DATA" }, { CTDB_CONTROL_DISABLE_NODE, "DISABLE_NODE" }, { CTDB_CONTROL_ENABLE_NODE, "ENABLE_NODE" }, + { CTDB_CONTROL_TCP_CLIENT_DISCONNECTED, "TCP_CLIENT_DISCONNECTED" }, { MAP_END, "" }, }; diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 08268512bfa..3ea93f52cfe 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -868,6 +868,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, CHECK_CONTROL_DATA_SIZE(0); return ctdb_control_enable_node(ctdb); + case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED: + CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); + return ctdb_control_tcp_client_disconnected(ctdb, client_id, indata); + default: DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode)); return -1; diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c index abafffd03fc..cedb2b921c4 100644 --- a/ctdb/server/ctdb_takeover.c +++ b/ctdb/server/ctdb_takeover.c @@ -1377,6 +1377,92 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, return 0; } +static bool ctdb_client_remove_tcp(struct ctdb_client *client, + const struct ctdb_connection *conn) +{ + struct ctdb_tcp_list *tcp = NULL; + struct ctdb_tcp_list *tcp_next = NULL; + bool found = false; + + for (tcp = client->tcp_list; tcp != NULL; tcp = tcp_next) { + bool same; + + tcp_next = tcp->next; + + same = ctdb_connection_same(conn, &tcp->connection); + if (!same) { + continue; + } + + TALLOC_FREE(tcp); + found = true; + } + + return found; +} + +/* + called by a client to inform us of a TCP connection that was disconnected + */ +int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb, + uint32_t client_id, + TDB_DATA indata) +{ + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); + struct ctdb_connection *tcp_sock = NULL; + int ret; + TDB_DATA data; + char conn_str[132] = { 0, }; + bool found = false; + + tcp_sock = (struct ctdb_connection *)indata.dptr; + + ctdb_canonicalize_ip_inplace(&tcp_sock->src); + ctdb_canonicalize_ip_inplace(&tcp_sock->dst); + + ret = ctdb_connection_to_buf(conn_str, + sizeof(conn_str), + tcp_sock, + false, + " -> "); + if (ret != 0) { + strlcpy(conn_str, "UNKNOWN", sizeof(conn_str)); + } + + found = ctdb_client_remove_tcp(client, tcp_sock); + if (!found) { + DBG_DEBUG("TCP connection %s not found " + "(client_id %u pid %u).\n", + conn_str, client_id, client->pid); + return 0; + } + + D_INFO("deregistered TCP connection %s " + "(client_id %u pid %u)\n", + conn_str, client_id, client->pid); + + data.dptr = (uint8_t *)tcp_sock; + data.dsize = sizeof(*tcp_sock); + + /* tell all nodes about this tcp connection is gone */ + ret = ctdb_daemon_send_control(ctdb, + CTDB_BROADCAST_CONNECTED, + 0, + CTDB_CONTROL_TCP_REMOVE, + 0, + CTDB_CTRL_FLAG_NOREPLY, + data, + NULL, + NULL); + if (ret != 0) { + DBG_ERR("Failed to send CTDB_CONTROL_TCP_REMOVE: %s\n", + conn_str); + return -1; + } + + return 0; +} + /* find a tcp address on a list */