commit d9800577e91610ab372b3fa543a0a4431f56b02b
Author: Gao,Yan <ygao@suse.com>
Date:   Tue Sep 8 16:31:06 2015 +0200

    Feature: pengine: Support concurrent fencing
    
    A pengine property "concurrent-fencing" can be configured to allow
    performing fencing operations in parallel. It defaults to "false".

Index: pacemaker/include/crm/pengine/status.h
===================================================================
--- pacemaker.orig/include/crm/pengine/status.h
+++ pacemaker/include/crm/pengine/status.h
@@ -62,6 +62,7 @@ enum pe_find {
 #  define pe_flag_stonith_enabled	0x00000010ULL
 #  define pe_flag_have_stonith_resource	0x00000020ULL
 #  define pe_flag_enable_unfencing	0x00000040ULL
+#  define pe_flag_concurrent_fencing	0x00000080ULL
 
 #  define pe_flag_stop_rsc_orphans	0x00000100ULL
 #  define pe_flag_stop_action_orphans	0x00000200ULL
Index: pacemaker/lib/pengine/common.c
===================================================================
--- pacemaker.orig/lib/pengine/common.c
+++ pacemaker/lib/pengine/common.c
@@ -124,6 +124,8 @@ pe_cluster_option pe_opts[] = {
 	  "Action to send to STONITH device", NULL },
 	{ "stonith-timeout", NULL, "time", NULL, "60s", &check_timer,
 	  "How long to wait for the STONITH action to complete", NULL },
+	{ "concurrent-fencing", NULL, "boolean", NULL, "false", &check_boolean,
+	  "Allow performing fencing operations in parallel", NULL },
 	{ "startup-fencing", "startup_fencing", "boolean", NULL, "true", &check_boolean,
 	  "STONITH unseen nodes", "Advanced Use Only!  Not using the default is very unsafe!" },
 
Index: pacemaker/lib/pengine/unpack.c
===================================================================
--- pacemaker.orig/lib/pengine/unpack.c
+++ pacemaker/lib/pengine/unpack.c
@@ -153,6 +153,10 @@ unpack_config(xmlNode * config, pe_worki
     data_set->stonith_action = pe_pref(data_set->config_hash, "stonith-action");
     crm_trace("STONITH will %s nodes", data_set->stonith_action);
 
+    set_config_flag(data_set, "concurrent-fencing", pe_flag_concurrent_fencing);
+    crm_debug("Concurrent fencing is %s",
+              is_set(data_set->flags, pe_flag_concurrent_fencing) ? "enabled" : "disabled");
+
     set_config_flag(data_set, "stop-all-resources", pe_flag_stop_everything);
     crm_debug("Stop all active resources: %s",
               is_set(data_set->flags, pe_flag_stop_everything) ? "true" : "false");
Index: pacemaker/pengine/allocate.c
===================================================================
--- pacemaker.orig/pengine/allocate.c
+++ pacemaker/pengine/allocate.c
@@ -1322,6 +1322,7 @@ stage6(pe_working_set_t * data_set)
     action_t *done = get_pseudo_op(STONITH_DONE, data_set);
     gboolean need_stonith = TRUE;
     GListPtr gIter = data_set->nodes;
+    GListPtr stonith_ops = NULL;
 
     crm_trace("Processing fencing and shutdown cases");
 
@@ -1367,11 +1368,15 @@ stage6(pe_working_set_t * data_set)
                 dc_down = stonith_op;
                 dc_fence = stonith_op;
 
-            } else {
+            } else if (is_set(data_set->flags, pe_flag_concurrent_fencing) == FALSE) {
                 if (last_stonith) {
                     order_actions(last_stonith, stonith_op, pe_order_optional);
                 }
                 last_stonith = stonith_op;
+
+            } else {
+                order_actions(stonith_op, done, pe_order_implies_then);
+                stonith_ops = g_list_append(stonith_ops, stonith_op);
             }
 
         } else if (node->details->online && node->details->shutdown &&
@@ -1436,8 +1441,21 @@ stage6(pe_working_set_t * data_set)
             order_actions(node_stop, dc_down, pe_order_optional);
         }
 
-        if (last_stonith && dc_down != last_stonith) {
-            order_actions(last_stonith, dc_down, pe_order_optional);
+        if (last_stonith) {
+            if (dc_down != last_stonith) {
+                order_actions(last_stonith, dc_down, pe_order_optional);
+            }
+
+        } else {
+            GListPtr gIter2 = NULL;
+
+            for (gIter2 = stonith_ops; gIter2 != NULL; gIter2 = gIter2->next) {
+                action_t *stonith_op = (action_t *) gIter2->data;
+
+                if (dc_down != stonith_op) {
+                    order_actions(stonith_op, dc_down, pe_order_optional);
+                }
+            }
         }
     }
 
@@ -1450,6 +1468,8 @@ stage6(pe_working_set_t * data_set)
     }
 
     order_actions(done, all_stopped, pe_order_implies_then);
+
+    g_list_free(stonith_ops);
     return TRUE;
 }
 
