File pacemaker-libservices-handle-in-flight-first-cancelling-an-operation.patch of Package pacemaker.14737

commit dc36d4375c049024a6f9e4d2277a3e6444fad05b
Author: Ken Gaillot <kgaillot@redhat.com>
Date:   Tue Feb 28 15:41:10 2017 -0600

    Refactor: libservices: handle in-flight case first when cancelling an operation
    
    will make next bugfix easier

diff --git a/lib/services/services.c b/lib/services/services.c
index 78a078133..dba4e6675 100644
--- a/lib/services/services.c
+++ b/lib/services/services.c
@@ -470,43 +470,62 @@ cancel_recurring_action(svc_action_t * op)
     return TRUE;
 }
 
+/*!
+ * \brief Cancel a recurring action
+ *
+ * \param[in] name      Name of resource that operation is for
+ * \param[in] action    Name of operation to cancel
+ * \param[in] interval  Interval of operation to cancel
+ *
+ * \return TRUE if action was successfully cancelled, FALSE otherwise
+ */
 gboolean
 services_action_cancel(const char *name, const char *action, int interval)
 {
-    svc_action_t *op = NULL;
+    gboolean cancelled = FALSE;
     char *id = generate_op_key(name, action, interval);
+    svc_action_t *op = g_hash_table_lookup(recurring_actions, id);
 
-    if (!(op = g_hash_table_lookup(recurring_actions, id))) {
-        free(id);
-        return FALSE;
+    /* We can only cancel a recurring action */
+    if (op == NULL) {
+        goto done;
     }
 
-    /* Always kill the recurring timer */
+    /* Tell operation_finalize() not to reschedule the operation */
+    op->cancel = TRUE;
+
+    /* Stop tracking it as a recurring operation, and stop its timer */
     cancel_recurring_action(op);
 
-    if (op->pid == 0) {
-        op->status = PCMK_LRM_OP_CANCELLED;
-        if (op->opaque->callback) {
-            op->opaque->callback(op);
+    /* If the op has a PID, it's an in-flight child process, so kill it.
+     *
+     * Whether the kill succeeds or fails, the main loop will send the op to
+     * operation_finished() (and thus operation_finalize()) when the process
+     * goes away.
+     */
+    if (op->pid != 0) {
+        crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled",
+                 id, op->pid);
+        cancelled = mainloop_child_kill(op->pid);
+        if (cancelled == FALSE) {
+            crm_err("Termination of %s (pid %d) failed", id, op->pid);
         }
+        goto done;
+    }
 
-        blocked_ops = g_list_remove(blocked_ops, op);
-        services_action_free(op);
-
-    } else {
-        crm_info("Cancelling in-flight op: performing early termination of %s (pid=%d)", id, op->pid);
-        op->cancel = 1;
-        if (mainloop_child_kill(op->pid) == FALSE) {
-            /* even though the early termination failed,
-             * the op will be marked as cancelled once it completes. */
-            crm_err("Termination of %s (pid=%d) failed", id, op->pid);
-            free(id);
-            return FALSE;
-        }
+    /* Otherwise, operation is not in-flight, just report as cancelled */
+    op->status = PCMK_LRM_OP_CANCELLED;
+    if (op->opaque->callback) {
+        op->opaque->callback(op);
     }
 
+    blocked_ops = g_list_remove(blocked_ops, op);
+    services_action_free(op);
+    cancelled = TRUE;
+
+done:
     free(id);
-    return TRUE;
+    return cancelled;
 }
 
 gboolean
openSUSE Build Service is sponsored by