changeset 19956:e038f95fdccd

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)
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 24 Mar 2016 10:00:00 +0900
parents 4ed6a9d7c232
children 87c5013dc8e3
files src/director/director.c
diffstat 1 files changed, 17 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/director/director.c	Thu Mar 24 09:43:43 2016 +0900
+++ b/src/director/director.c	Thu Mar 24 10:00:00 2016 +0900
@@ -728,6 +728,8 @@
 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 @@
 	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 @@
 	}
 
 	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);