Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 03 Oct 2010 12:06:53 +0300
From:      Mikolaj Golub <to.my.trociny@gmail.com>
To:        freebsd-fs@freebsd.org
Cc:        pjd@freebsd.org
Subject:   Re: hastd: assertion (res->hr_event != NULL) fails in secondary on split-brain
Message-ID:  <86ocbbir0y.fsf@kopusha.home.net>
In-Reply-To: <86aamw4l42.fsf@kopusha.home.net> (Mikolaj Golub's message of "Sat, 02 Oct 2010 19:26:05 %2B0300")
References:  <86hbh44wgl.fsf@kopusha.home.net> <86aamw4l42.fsf@kopusha.home.net>

next in thread | previous in thread | raw e-mail | index | archive | help
--=-=-=


On Sat, 02 Oct 2010 19:26:05 +0300 Mikolaj Golub wrote to Mikolaj Golub:

 MG> What do you think about the attached patch?

Here is updated version of the patch :-)

1) I didn't notice previously that in the different parts kill() was called
with different signals. So in the new version I have child_kill(res, sig)
instead of child_kill(res);

2) Testing hastd I faced another issue (which is not related to my patch, and
shows up also with unpatched hastd. It is easy to hang hastd running the
following test:

for i in `jot 1000`; do
        hastctl role primary storage
        hastctl role secondary storage
done

Other host should be configured as secondary and should have some fix for the
problem described initially in this thread (avoid double close of
res->hr_event) so secondary would not crash on assertion.

hastd hangs when switching to secondary, killing primary worker and waiting
for it:

root   1631   0.0  0.5  11244   2364  ??  Is   12:18PM   0:00.37 /sbin/hastd -ddd
root   1869   0.0  7.0  49004  35700  ??  I    12:37PM   0:01.42 hastd: storage (primary) (hastd)
root   1937   0.0  0.3  10924   1764  ??  I    12:37PM   0:00.02 /sbin/hastctl role secondary storage

lolek# gdb /usr/obj/usr/src/sbin/hastd/hastd 1631

[Switching to Thread 28404140 (LWP 100045)]
0x282ba689 in wait4 () from /lib/libc.so.7
(gdb) bt
#0  0x282ba689 in wait4 () from /lib/libc.so.7
#1  0x282912a3 in waitpid () from /lib/libc.so.7
#2  0x280df272 in waitpid () from /lib/libthr.so.3
#3  0x0804c6d4 in control_set_role_common (cfg=0x28419600, nvout=0x2850e0d0, role=3 '\003', 
    res=0x284eb500, name=0x284a3442 "storage", no=0) at /usr/src/sbin/hastd/control.c:115
#4  0x0804d001 in control_handle (cfg=0x28419600) at /usr/src/sbin/hastd/control.c:356
#5  0x08050555 in main_loop () at /usr/src/sbin/hastd/hastd.c:671
#6  0x08050a7f in main (argc=0, argv=0xbfbfed04) at /usr/src/sbin/hastd/hastd.c:784
(gdb) fr 3
#3  0x0804c6d4 in control_set_role_common (cfg=0x28419600, nvout=0x2850e0d0, role=3 '\003', 
    res=0x284eb500, name=0x284a3442 "storage", no=0) at /usr/src/sbin/hastd/control.c:115
115                     } else if (waitpid(res->hr_workerpid, NULL, 0) !=
(gdb) list
110             if (res->hr_workerpid != 0) {
111                     if (kill(res->hr_workerpid, SIGTERM) < 0) {
112                             pjdlog_errno(LOG_WARNING,
113                                 "Unable to kill worker process %u",
114                                 (unsigned int)res->hr_workerpid);
115                     } else if (waitpid(res->hr_workerpid, NULL, 0) !=
116                         res->hr_workerpid) {
117                             pjdlog_errno(LOG_WARNING,
118                                 "Error while waiting for worker process %u",
119                                 (unsigned int)res->hr_workerpid);

It looks like the worker does not die because guard_thread() is sending
CONNECT event to parent and waiting for a response.  

lolek# gdb /usr/obj/usr/src/sbin/hastd/hastd 1869

Thread 8 (Thread 28404140 (LWP 100075)):
#0  0x28301ed7 in recvfrom () from /lib/libc.so.7
#1  0x28287f52 in recv () from /lib/libc.so.7
#2  0x0805f467 in proto_common_recv (fd=10, data=0xbfbfe967 "(", size=5)
    at /usr/src/sbin/hastd/proto_common.c:77
#3  0x0805f8bd in sp_recv (ctx=0x2850e110, data=0xbfbfe967 "(", size=5)
    at /usr/src/sbin/hastd/proto_socketpair.c:185
#4  0x0805ee91 in proto_recv (conn=0x2850e100, data=0xbfbfe967, size=5)
    at /usr/src/sbin/hastd/proto.c:207
#5  0x0804e4ae in hast_proto_recv_hdr (conn=0x2850e100, nvp=0xbfbfe9a4)
    at /usr/src/sbin/hastd/hast_proto.c:308
#6  0x0804dbbc in event_send (res=0x284eb500, event=1) at /usr/src/sbin/hastd/event.c:69
#7  0x0805a411 in init_remote (res=0x284eb500, inp=0xbfbfea34, outp=0xbfbfea30)
    at /usr/src/sbin/hastd/primary.c:661
#8  0x0805e48a in guard_one (res=0x284eb500, ncomp=1) at /usr/src/sbin/hastd/primary.c:1912
#9  0x0805e7e9 in guard_thread (arg=0x284eb500) at /usr/src/sbin/hastd/primary.c:1977
#10 0x0805ac5f in hastd_primary (res=0x284eb500) at /usr/src/sbin/hastd/primary.c:823
#11 0x0804c743 in control_set_role_common (cfg=0x28419600, nvout=0x2850e0d0, role=2 '\002', 
    res=0x284eb500, name=0x284a3442 "storage", no=0) at /usr/src/sbin/hastd/control.c:129
#12 0x0804d001 in control_handle (cfg=0x28419600) at /usr/src/sbin/hastd/control.c:356
#13 0x08050555 in main_loop () at /usr/src/sbin/hastd/hastd.c:671
#14 0x08050a7f in main (argc=0, argv=0xbfbfed04) at /usr/src/sbin/hastd/hastd.c:784

After changing the code so parent closes hr_event and hr_ctrl after kill()
but before wait() the hang has not been observed.

-- 
Mikolaj Golub


--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=hast.child_kill.patch

Index: sbin/hastd/hastd.c
===================================================================
--- sbin/hastd/hastd.c	(revision 213377)
+++ sbin/hastd/hastd.c	(working copy)
@@ -94,22 +94,6 @@ g_gate_load(void)
 }
 
 static void
-child_exit_log(unsigned int pid, int status)
-{
-
-	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-		pjdlog_debug(1, "Worker process exited gracefully (pid=%u).",
-		    pid);
-	} else if (WIFSIGNALED(status)) {
-		pjdlog_error("Worker process killed (pid=%u, signal=%d).",
-		    pid, WTERMSIG(status));
-	} else {
-		pjdlog_error("Worker process exited ungracefully (pid=%u, exitcode=%d).",
-		    pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1);
-	}
-}
-
-static void
 child_exit(void)
 {
 	struct hast_resource *res;
@@ -388,8 +372,6 @@ listen_accept(void)
 	const unsigned char *token;
 	char laddr[256], raddr[256];
 	size_t size;
-	pid_t pid;
-	int status;
 
 	proto_local_address(cfg->hc_listenconn, laddr, sizeof(laddr));
 	pjdlog_debug(1, "Accepting connection to %s.", laddr);
@@ -504,26 +486,7 @@ listen_accept(void)
 			    "Worker process exists (pid=%u), stopping it.",
 			    (unsigned int)res->hr_workerpid);
 			/* Stop child process. */
-			if (kill(res->hr_workerpid, SIGINT) < 0) {
-				pjdlog_errno(LOG_ERR,
-				    "Unable to stop worker process (pid=%u)",
-				    (unsigned int)res->hr_workerpid);
-				/*
-				 * Other than logging the problem we
-				 * ignore it - nothing smart to do.
-				 */
-			}
-			/* Wait for it to exit. */
-			else if ((pid = waitpid(res->hr_workerpid,
-			    &status, 0)) != res->hr_workerpid) {
-				/* We can only log the problem. */
-				pjdlog_errno(LOG_ERR,
-				    "Waiting for worker process (pid=%u) failed",
-				    (unsigned int)res->hr_workerpid);
-			} else {
-				child_exit_log(res->hr_workerpid, status);
-			}
-			child_cleanup(res);
+			child_kill(res, SIGINT);
 		} else if (res->hr_remotein != NULL) {
 			char oaddr[256];
 
@@ -678,8 +641,8 @@ main_loop(void)
 				if (event_recv(res) == 0)
 					continue;
 				/* The worker process exited? */
-				proto_close(res->hr_event);
-				res->hr_event = NULL;
+				if (res->hr_workerpid != 0)
+					child_kill(res, SIGINT);
 			}
 		}
 	}
Index: sbin/hastd/control.c
===================================================================
--- sbin/hastd/control.c	(revision 213377)
+++ sbin/hastd/control.c	(working copy)
@@ -63,6 +63,52 @@ child_cleanup(struct hast_resource *res)
 	res->hr_workerpid = 0;
 }
 
+void
+child_exit_log(unsigned int pid, int status)
+{
+
+	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+		pjdlog_debug(1, "Worker process exited gracefully (pid=%u).",
+		    pid);
+	} else if (WIFSIGNALED(status)) {
+		pjdlog_error("Worker process killed (pid=%u, signal=%d).",
+		    pid, WTERMSIG(status));
+	} else {
+		pjdlog_error("Worker process exited ungracefully (pid=%u, exitcode=%d).",
+		    pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1);
+	}
+}
+
+void
+child_kill(struct hast_resource *res, int sig)
+{
+	pid_t pid;
+	int status;
+
+	assert(res->hr_workerpid != 0);
+
+	pid = res->hr_workerpid;
+	
+	if (kill(pid, sig) < 0) {
+		pjdlog_errno(LOG_ERR,
+			     "Unable to stop worker process (pid=%u)",
+			     (unsigned int)pid);
+		/*
+		 * Other than logging the problem we
+		 * ignore it - nothing smart to do.
+		 */
+	}
+	child_cleanup(res);
+	/* Wait for it to exit. */
+	if (waitpid(pid, &status, 0) != pid) {
+		/* We can only log the problem. */
+		pjdlog_errno(LOG_ERR,
+			     "Waiting for worker process (pid=%u) failed",
+			     (unsigned int)pid);
+	}
+	child_exit_log(pid, status);
+}
+
 static void
 control_set_role_common(struct hastd_config *cfg, struct nv *nvout,
     uint8_t role, struct hast_resource *res, const char *name, unsigned int no)
@@ -107,22 +153,8 @@ control_set_role_common(struct hastd_config *cfg,
 	 * If previous role was primary or secondary we have to kill process
 	 * doing that work.
 	 */
-	if (res->hr_workerpid != 0) {
-		if (kill(res->hr_workerpid, SIGTERM) < 0) {
-			pjdlog_errno(LOG_WARNING,
-			    "Unable to kill worker process %u",
-			    (unsigned int)res->hr_workerpid);
-		} else if (waitpid(res->hr_workerpid, NULL, 0) !=
-		    res->hr_workerpid) {
-			pjdlog_errno(LOG_WARNING,
-			    "Error while waiting for worker process %u",
-			    (unsigned int)res->hr_workerpid);
-		} else {
-			pjdlog_debug(1, "Worker process %u stopped.",
-			    (unsigned int)res->hr_workerpid);
-		}
-		child_cleanup(res);
-	}
+	if (res->hr_workerpid != 0)
+		child_kill(res, SIGTERM);
 
 	/* Start worker process if we are changing to primary. */
 	if (role == HAST_ROLE_PRIMARY)
Index: sbin/hastd/control.h
===================================================================
--- sbin/hastd/control.h	(revision 213377)
+++ sbin/hastd/control.h	(working copy)
@@ -39,6 +39,8 @@ struct hastd_config;
 struct hast_resource;
 
 void child_cleanup(struct hast_resource *res);
+void child_exit_log(unsigned int pid, int status);
+void child_kill(struct hast_resource *res, int sig);
 
 void control_set_role(struct hast_resource *res, uint8_t role);
 

--=-=-=--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?86ocbbir0y.fsf>