]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
director: Make sure USER-KILLED isn't sent before USER-MOVE
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 20 Jan 2017 13:54:27 +0000 (15:54 +0200)
committerGitLab <gitlab@git.dovecot.net>
Fri, 20 Jan 2017 15:46:57 +0000 (17:46 +0200)
If USER-MOVE was for a user that didn't exist, killing sent USER-KILLED
immediately before the forwarding USER-MOVE. This caused the move to get
stuck, giving errors like:

director: Error: Finishing user 3224731354 move timed out, its state may now be inconsistent (state=waiting-for-everyone)

src/director/director.c

index 777baca029963d13e47261a0c4b2f98318ce8d7c..72008ad35b64a9bb2b3469e5c734ea18f092f4fb 100644 (file)
@@ -1032,6 +1032,7 @@ void director_move_user(struct director *dir, struct director_host *src,
                        unsigned int username_hash, struct mail_host *host)
 {
        struct user_directory *users = host->tag->users;
+       struct mail_host *old_host = NULL;
        struct user *user;
 
        /* 1. move this user's host, and set its "killing" flag to delay all of
@@ -1054,10 +1055,7 @@ void director_move_user(struct director *dir, struct director_host *src,
        if (user == NULL) {
                user = user_directory_add(users, username_hash,
                                          host, ioloop_time);
-               director_kill_user(dir, src, user, host->tag, NULL);
        } else {
-               struct mail_host *old_host = user->host;
-
                if (user->host == host) {
                        /* user is already in this host */
                        return;
@@ -1066,11 +1064,11 @@ void director_move_user(struct director *dir, struct director_host *src,
                   the old tag has to be the same. */
                i_assert(user->host->tag == host->tag);
 
+               old_host = user->host;
                user->host->user_count--;
                user->host = host;
                user->host->user_count++;
                user->timestamp = ioloop_time;
-               director_kill_user(dir, src, user, old_host->tag, old_host);
        }
 
        if (orig_src == NULL) {
@@ -1081,6 +1079,9 @@ void director_move_user(struct director *dir, struct director_host *src,
                "USER-MOVE\t%s\t%u\t%u\t%u\t%s\n",
                net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
                user->username_hash, net_ip2addr(&user->host->ip)));
+       /* kill the user only after sending the USER-MOVE, because the kill
+          may finish instantly. */
+       director_kill_user(dir, src, user, host->tag, old_host);
 }
 
 static void