From: Timo Sirainen Date: Thu, 24 Mar 2016 01:00:00 +0000 (+0900) Subject: director: Make sure a long-delayed kill reply for user doesn't mess up the state. X-Git-Tag: 2.2.23~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6e06d93ebd252b66c966c4dc1cd1479ffcb1021f;p=thirdparty%2Fdovecot%2Fcore.git director: Make sure a long-delayed kill reply for user doesn't mess up the state. This should fix assert-crash: director: Panic: file director.c: line 690 (director_user_kill_finish_delayed_to): assertion failed: (ctx->user->kill_state == USER_KILL_STATE_DELAY) --- diff --git a/src/director/director.c b/src/director/director.c index 10896c2039..a07c2e8c11 100644 --- a/src/director/director.c +++ b/src/director/director.c @@ -728,6 +728,8 @@ struct director_kill_context { static void director_finish_user_kill(struct director *dir, struct user *user, bool self) { + i_assert(user->kill_state != USER_KILL_STATE_DELAY); + if (dir->right == NULL) { /* we're alone */ director_user_kill_finish_delayed(dir, user); @@ -748,8 +750,12 @@ static void director_kill_user_callback(enum ipc_client_cmd_state state, struct director_kill_context *ctx = context; struct user *user; + /* this is an asynchronous notification about user being killed. + there are no guarantees about what might have happened to the user + in the mean time. */ switch (state) { case IPC_CLIENT_CMD_STATE_REPLY: + /* shouldn't get here. the command reply isn't finished yet. */ return; case IPC_CLIENT_CMD_STATE_OK: break; @@ -761,14 +767,21 @@ static void director_kill_user_callback(enum ipc_client_cmd_state state, } user = user_directory_lookup(ctx->dir->users, ctx->username_hash); - if (user == NULL || user->kill_state == USER_KILL_STATE_NONE) - return; - - director_finish_user_kill(ctx->dir, user, ctx->self); + if (user == NULL) { + /* user was already freed - ignore */ + } else if (user->kill_state == USER_KILL_STATE_KILLING || + user->kill_state == USER_KILL_STATE_KILLING_NOTIFY_RECEIVED) { + /* we were still waiting for the kill notification */ + director_finish_user_kill(ctx->dir, user, ctx->self); + } else { + /* we don't currently want to kill the user */ + } } static void director_user_move_timeout(struct user *user) { + i_assert(user->kill_state != USER_KILL_STATE_DELAY); + i_error("Finishing user %u move timed out, " "its state may now be inconsistent", user->username_hash);