Fix segfault when ALWAYS_PRIMARY is set but DISALLOW_TO_FAILOVER.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Tue, 15 Dec 2020 10:38:04 +0000 (19:38 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Tue, 15 Dec 2020 10:54:20 +0000 (19:54 +0900)
If a primary node (for example node 0) has ALWAYS_PRIMARY but does
have DISALLOW_TO_FAILOVER, segfault happens in following step:

1) node 0 stops

2) failover happens. all children restart. The primary node is still 0
because ALWAYS_PRIMARY is set.

2) node 0 starts and it becomes online by using pcp_attach_node.

3) failback process is executed but child process do not restart.

4) child process accesses node 0 because Req_info->primary_node_id is
0 but connection to node 0 does not exist and this causes segfault.

To fix this, do additional check to make sure that failback node is
not former primary node. If it is, do full restart of child process.

Per bug 672.

src/main/pgpool_main.c

index 1de4fcc4a76c15c013768b1f1894d817c591a2b0..bc4f5733447021e19a1708273fab914b58cc1b4f 100644 (file)
@@ -1871,11 +1871,18 @@ static void failover(void)
                 * went down, restarted, re-attached without promotion. Then existing
                 * child process loses connection slot to node 0 and keeps on using it
                 * when node 0 comes back. This could result in segfault later on in
-                * the child process because there's no connection to node id 0.  See
-                * bug 672 for more details.
+                * the child process because there's no connection to node id 0.
+                *
+                * Actually we need to think about when ALWAYS_PRIMARY flag is set
+                * *but* DISALLOW_TO_FAILOVER flag is not set case. In the case after
+                * primary failover Req_info->primary_node_id is set, but connection
+                * to the primary node does not exist. So we should do full restart if
+                * requested node id is the former primary node.
+                *
+                * See bug 672 for more details.
                 */
                if (STREAM && reqkind == NODE_UP_REQUEST && all_backend_down == false &&
-                       Req_info->primary_node_id >= 0)
+                       Req_info->primary_node_id >= 0 && Req_info->primary_node_id != node_id)
                {
                        /*
                         * The decision to restart/no-restart children for update status request has already been