From: Timo Sirainen Date: Tue, 22 Aug 2017 13:32:32 +0000 (+0300) Subject: director: Fix crash when flush is run and all backends are down. X-Git-Tag: 2.3.0.rc1~1009 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f5d82a4b87a9b17894e1869cfe8b1a90afbced59;p=thirdparty%2Fdovecot%2Fcore.git director: Fix crash when flush is run and all backends are down. Instead of moving the users elsewhere, just kill them and flush the backend. --- diff --git a/src/director/director.c b/src/director/director.c index 63595c0a8e..f8ee8a5bfc 100644 --- a/src/director/director.c +++ b/src/director/director.c @@ -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; diff --git a/src/director/director.h b/src/director/director.h index ceef55aab4..383fa83f5a 100644 --- a/src/director/director.h +++ b/src/director/director.h @@ -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) diff --git a/src/director/doveadm-connection.c b/src/director/doveadm-connection.c index 5850752b22..d54f6005b2 100644 --- a/src/director/doveadm-connection.c +++ b/src/director/doveadm-connection.c @@ -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;