s3:smbd: avoid invalid lock_order panic triggered by "CTDB_SRVID_RELEASE_IP"
authorStefan Metzmacher <metze@samba.org>
Thu, 13 Feb 2014 14:36:27 +0000 (15:36 +0100)
committerKarolin Seeger <kseeger@samba.org>
Tue, 1 Apr 2014 07:08:05 +0000 (09:08 +0200)
If smbd_server_connection_terminate("CTDB_SRVID_RELEASE_IP") is triggered from
within ctdbd_migrate(), we got a smb_panic complaining about invalid
lock_order, as ctdbd_migrate is called from dbwrap_fetch_locked().

Bug: https://bugzilla.samba.org/show_bug.cgi?id=10444
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Fri Feb 21 14:51:51 CET 2014 on sn-devel-104
(cherry picked from commit 33f10d06baf44e31d558bc5bd926c886915322cc)

source3/smbd/process.c

index 5d2c8ee994da0e591aae9e44b49b6f41eba29f5b..65be50f890468905f96ea40c25ea7d42fd06c575 100644 (file)
@@ -2499,9 +2499,28 @@ static void smbd_server_echo_handler(struct event_context *ev,
 
 struct smbd_release_ip_state {
        struct smbd_server_connection *sconn;
+       struct tevent_immediate *im;
        char addr[INET6_ADDRSTRLEN];
 };
 
+static void smbd_release_ip_immediate(struct tevent_context *ctx,
+                                     struct tevent_immediate *im,
+                                     void *private_data)
+{
+       struct smbd_release_ip_state *state =
+               talloc_get_type_abort(private_data,
+               struct smbd_release_ip_state);
+
+       if (!NT_STATUS_EQUAL(state->sconn->status, NT_STATUS_ADDRESS_CLOSED)) {
+               /*
+                * smbd_server_connection_terminate() already triggered ?
+                */
+               return;
+       }
+
+       smbd_server_connection_terminate(state->sconn, "CTDB_SRVID_RELEASE_IP");
+}
+
 /****************************************************************************
 received when we should release a specific IP
 ****************************************************************************/
@@ -2513,6 +2532,11 @@ static bool release_ip(const char *ip, void *priv)
        const char *addr = state->addr;
        const char *p = addr;
 
+       if (!NT_STATUS_IS_OK(state->sconn->status)) {
+               /* avoid recursion */
+               return false;
+       }
+
        if (strncmp("::ffff:", addr, 7) == 0) {
                p = addr + 7;
        }
@@ -2539,9 +2563,18 @@ static bool release_ip(const char *ip, void *priv)
                 * triggered and has implication on our process model,
                 * we can just use smbd_server_connection_terminate()
                 * (also for SMB1).
+                *
+                * We don't call smbd_server_connection_terminate() directly
+                * as we might be called from within ctdbd_migrate(),
+                * we need to defer our action to the next event loop
                 */
-               smbd_server_connection_terminate(state->sconn,
-                                                "CTDB_SRVID_RELEASE_IP");
+               tevent_schedule_immediate(state->im, state->sconn->ev_ctx,
+                                         smbd_release_ip_immediate, state);
+
+               /*
+                * Make sure we don't get any io on the connection.
+                */
+               state->sconn->status = NT_STATUS_ADDRESS_CLOSED;
                return true;
        }
 
@@ -2565,6 +2598,10 @@ static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn,
                return NT_STATUS_NO_MEMORY;
        }
        state->sconn = sconn;
+       state->im = tevent_create_immediate(state);
+       if (state->im == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
        if (print_sockaddr(state->addr, sizeof(state->addr), srv) == NULL) {
                return NT_STATUS_NO_MEMORY;
        }