]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-master: Fix crash when reaching client_limit with restart_request_count>1 and...
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 26 Mar 2026 09:45:24 +0000 (11:45 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Thu, 2 Apr 2026 20:25:49 +0000 (20:25 +0000)
Fixes:
Panic: file master-service.c: line 1909 (master_service_listen): assertion failed: (service->master_status.available_count > 0)

src/lib-master/master-service-private.h
src/lib-master/master-service.c

index b139990ecf77f19a90cbd9ba2aaced575073a903..7385ab353438f77de4cbca765cf583dbbcbb18c5 100644 (file)
@@ -48,7 +48,10 @@ struct master_service {
        unsigned int socket_count;
 
        struct io *io_status_write, *io_status_error;
+       /* Number of requests left before process is stopped. */
        unsigned int restart_request_count_left;
+       /* Starts as service's client_limit, but never more than
+          restart_request_count_left. */
        unsigned int total_available_count;
        unsigned int process_limit;
        unsigned int process_min_avail;
index faf0167b632a2c892441c6d0d7ee5fea3c57334a..73906922a7bdf6a6fbd99ed334b2ceddcff1d929 100644 (file)
@@ -1455,8 +1455,9 @@ static bool master_service_want_listener(struct master_service *service)
                /* more concurrent clients can still be added */
                return TRUE;
        }
-       if (service->restart_request_count_left == 1) {
-               /* after handling this client, the whole process will stop. */
+       if (service->restart_request_count_left == service->total_available_count) {
+               /* after handling the existing clients,
+                  the whole process will stop. */
                return FALSE;
        }
        if (service->avail_overflow_callback != NULL) {
@@ -1484,7 +1485,7 @@ void master_service_client_connection_handled(struct master_service *service,
        if (!master_service_want_listener(service)) {
                i_assert(service->listeners != NULL);
                master_service_io_listeners_remove(service);
-               if (service->restart_request_count_left == 1 &&
+               if (service->restart_request_count_left == service->total_available_count &&
                   service->avail_overflow_callback == NULL) {
                        /* we're not going to accept any more connections after
                           this. go ahead and close the connection early. don't
@@ -1523,6 +1524,8 @@ void master_service_client_connection_destroyed(struct master_service *service)
        i_assert(service->restart_request_count_left > 0);
 
        if (service->restart_request_count_left == service->total_available_count) {
+               /* There may or may not be available clients, but we no longer
+                  increse them. */
                service->total_available_count--;
                service->restart_request_count_left--;
        } else {
@@ -1805,6 +1808,12 @@ static bool master_service_full(struct master_service *service)
                /* This process can still create multiple concurrent
                   clients if we just kill some of the existing ones.
                   Do it immediately. */
+               if (service->restart_request_count_left == service->total_available_count) {
+                       /* restart_request_count is reached - killing existing
+                          processes won't increase the number of available
+                          clients anymore. */
+                       return TRUE;
+               }
                return !service->avail_overflow_callback(TRUE, &created);
        }