]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
director: Fix crash when flush is run and all backends are down.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 22 Aug 2017 13:32:32 +0000 (16:32 +0300)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Mon, 18 Sep 2017 07:00:32 +0000 (10:00 +0300)
Instead of moving the users elsewhere, just kill them and flush the backend.

src/director/director.c
src/director/director.h
src/director/doveadm-connection.c

index 63595c0a8ee475c2ab8c125fd61f760ebe244b5a..f8ee8a5bfc62e8344e7ae58c1046806e19e49b95 100644 (file)
@@ -1011,10 +1011,9 @@ static void director_user_move_timeout(struct user *user)
        director_user_move_free(user);
 }
 
-static void
-director_kill_user(struct director *dir, struct director_host *src,
-                  struct user *user, struct mail_tag *tag,
-                  struct mail_host *old_host)
+void director_kill_user(struct director *dir, struct director_host *src,
+                       struct user *user, struct mail_tag *tag,
+                       struct mail_host *old_host)
 {
        struct director_kill_context *ctx;
        const char *cmd;
index ceef55aab4a4887fab6c0fa515d33e3ae3b5e220..383fa83f5a8988162e6b34c515ccb3dd4a3ad2fa 100644 (file)
@@ -201,6 +201,9 @@ void director_update_user_weak(struct director *dir, struct director_host *src,
                               struct director_connection *src_conn,
                               struct director_host *orig_src,
                               struct user *user) ATTR_NULL(3);
+void director_kill_user(struct director *dir, struct director_host *src,
+                       struct user *user, struct mail_tag *tag,
+                       struct mail_host *old_host);
 void director_move_user(struct director *dir, struct director_host *src,
                        struct director_host *orig_src,
                        unsigned int username_hash, struct mail_host *host)
index 5850752b2259c80998a0eea1c85ed69e81f3ce1e..d54f6005b26dd694c4baeaa06edc54523d66371a 100644 (file)
@@ -486,6 +486,7 @@ director_host_reset_users(struct director_reset_cmd *cmd,
        struct director *dir = cmd->dir;
        struct user *user;
        struct mail_host *new_host;
+       bool users_killed = FALSE;
 
        if (dir->users_moving_count >= cmd->max_moving_users)
                return FALSE;
@@ -499,18 +500,32 @@ director_host_reset_users(struct director_reset_cmd *cmd,
        while ((user = director_iterate_users_next(cmd->iter)) != NULL) {
                if (user->host != host)
                        continue;
+
                new_host = mail_host_get_by_hash(dir->mail_hosts,
                                                 user->username_hash,
                                                 mail_host_get_tag(host));
                if (new_host != host) T_BEGIN {
-                       director_move_user(dir, dir->self_host, NULL,
-                                          user->username_hash, new_host);
+                       if (new_host != NULL) {
+                               director_move_user(dir, dir->self_host, NULL,
+                                       user->username_hash, new_host);
+                       } else {
+                               /* there are no more available backends.
+                                  kick the user instead. */
+                               director_kill_user(dir, dir->self_host, user,
+                                                  user->host->tag, user->host);
+                               users_killed = TRUE;
+                       }
                } T_END;
                if (dir->users_moving_count >= cmd->max_moving_users)
                        break;
        }
        if (user == NULL)
                director_iterate_users_deinit(&cmd->iter);
+       if (users_killed) {
+               /* no more backends. we already sent kills. now remove the
+                  users entirely from the host. */
+               director_flush_host(dir, dir->self_host, NULL, host);
+       }
        if (dir->right != NULL)
                director_connection_uncork(dir->right);
        return user == NULL;