Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4525765
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c
index 8bab58cb1a..21dd56ff84 100644
--- a/crm/pengine/utils.c
+++ b/crm/pengine/utils.c
@@ -1,999 +1,1009 @@
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xmlutils.h>
#include <crm/common/crmutils.h>
#include <crm/cib.h>
#include <glib.h>
#include <libxml/tree.h>
#include <pengine.h>
#include <pe_utils.h>
void print_str_str(gpointer key, gpointer value, gpointer user_data);
/* only for rsc_to_rsc constraints */
rsc_to_rsc_t *
invert_constraint(rsc_to_rsc_t *constraint)
{
pdebug("Inverting constraint");
rsc_to_rsc_t *inverted_con =
crm_malloc(sizeof(rsc_to_node_t));
inverted_con->id = crm_strdup(constraint->id);
inverted_con->strength = constraint->strength;
// swap the direction
inverted_con->rsc_lh = constraint->rsc_rh;
inverted_con->rsc_rh = constraint->rsc_lh;
pdebug_action(
print_rsc_to_rsc("Inverted constraint", inverted_con, FALSE)
);
return inverted_con;
}
rsc_to_node_t *
copy_constraint(rsc_to_node_t *constraint)
{
rsc_to_node_t *copied_con = crm_malloc(sizeof(rsc_to_node_t));
copied_con->id = crm_strdup(constraint->id);
copied_con->rsc_lh = constraint->rsc_lh;
copied_con->node_list_rh = constraint->node_list_rh;
copied_con->modifier = constraint->modifier;
copied_con->weight = constraint->weight;
return copied_con;
}
/* are the contents of list1 and list2 equal */
/* nodes with weight < 0 are ignored */
gboolean
node_list_eq(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
if(g_slist_length(list1) != g_slist_length(list2)) {
return FALSE;
}
// do stuff
cl_log(LOG_ERR, "Not yet implemented");
return g_slist_length(result) != 0;
}
/* the intersection of list1 and list2
* when merging weights, nodes set to < 0 in either list will always
* have their weight set to -1 in the result
*/
GSListPtr
node_list_and(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
int lpc = 0;
for(lpc = 0; lpc < g_slist_length(list1); lpc++) {
node_t *node = (node_t*)g_slist_nth_data(list1, lpc);
node_t *new_node = NULL;
node_t *other_node = find_list_node(list2, node->details->id);
if(node == NULL || other_node == NULL) {
continue;
// merge node weights
} else if(node->weight < 0 || other_node->weight < 0) {
new_node = node_copy(node);
new_node->weight = -1;
} else {
new_node = node_copy(node);
new_node->weight =
node->weight + other_node->weight;
if(new_node->weight != 0) {
new_node->weight = new_node->weight /2.0;
}
}
result = g_slist_append(result, new_node);
}
return result;
}
node_t *
find_list_node(GSListPtr list, const char *id)
{
int lpc = 0;
slist_iter(
thing, node_t, list, lpc,
if(safe_str_eq(thing->details->id, id)) {
return thing;
}
);
return NULL;
}
/* list1 - list2 */
GSListPtr
node_list_minus(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
int lpc = 0;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = find_list_node(list2, node->details->id);
if(node == NULL || other_node != NULL) {
continue;
}
node_t *new_node = node_copy(node);
result = g_slist_append(result, new_node);
);
pdebug("Minus result len: %d",
g_slist_length(result));
return result;
}
/* list1 + list2 - (intersection of list1 and list2) */
GSListPtr
node_list_xor(GSListPtr list1, GSListPtr list2)
{
GSListPtr result = NULL;
int lpc = 0;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = (node_t*)find_list_node(list2, node->details->id);
if(node == NULL || other_node != NULL) {
continue;
}
node_t *new_node = node_copy(node);
result = g_slist_append(result, new_node);
);
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = (node_t*)find_list_node(list1, node->details->id);
if(node == NULL || other_node != NULL) {
continue;
}
node_t *new_node = node_copy(node);
result = g_slist_append(result, new_node);
);
pdebug("Xor result len: %d", g_slist_length(result));
return result;
}
GSListPtr
node_list_dup(GSListPtr list1)
{
GSListPtr result = NULL;
int lpc = 0;
slist_iter(
this_node, node_t, list1, lpc,
node_t *new_node = node_copy(this_node);
if(new_node != NULL) {
result = g_slist_append(result, new_node);
}
);
return result;
}
node_t *
node_copy(node_t *this_node)
{
if(this_node == NULL) {
print_node("Failed copy of", this_node, TRUE);
return NULL;
}
node_t *new_node = crm_malloc(sizeof(node_t));
new_node->weight = this_node->weight;
new_node->fixed = this_node->fixed;
new_node->details = this_node->details;
return new_node;
}
static int color_id = 0;
/*
* Create a new color with the contents of "nodes" as the list of
* possible nodes that resources with this color can be run on.
*
* Typically, when creating a color you will provide the node list from
* the resource you will first assign the color to.
*
* If "colors" != NULL, it will be added to that list
* If "resources" != NULL, it will be added to every provisional resource
* in that list
*/
color_t *
create_color(GSListPtr *colors, GSListPtr nodes, GSListPtr resources)
{
color_t *new_color = crm_malloc(sizeof(color_t));
new_color->id = color_id++;
new_color->local_weight = 1.0;
new_color->details = crm_malloc(sizeof(struct color_shared_s));
+ new_color->details->id = new_color->id;
new_color->details->chosen_node = NULL;
new_color->details->candidate_nodes = node_list_dup(nodes);
pdebug_action(print_color("Created color", new_color, TRUE));
if(colors != NULL) {
*colors = g_slist_append(*colors, new_color);
}
if(resources != NULL) {
/* Add any new color to the list of candidate_colors for
* resources that havent been decided yet
*/
int lpc;
slist_iter(
rsc, resource_t, resources, lpc,
if(rsc->provisional && rsc->runnable) {
- color_t *color_copy = cl_malloc(sizeof(color_t));
+ color_t *color_copy = (color_t *)
+ cl_malloc(sizeof(color_t));
color_copy->id = new_color->id;
color_copy->details = new_color->details;
color_copy->local_weight = 1.0;
rsc->candidate_colors =
g_slist_append(rsc->candidate_colors,
color_copy);
}
);
}
return new_color;
}
/*
* Remove any nodes with a -ve weight
*/
gboolean
filter_nodes(resource_t *rsc)
{
int lpc2 = 0;
pdebug_action(print_resource("Filtering nodes for", rsc, FALSE));
slist_iter(
node, node_t, rsc->allowed_nodes, lpc2,
if(node == NULL) {
cl_log(LOG_ERR, "Invalid NULL node");
} else if(node->weight < 0.0
|| node->details->online == FALSE
|| node->details->type == node_ping) {
pdebug_action(print_node("Removing", node, FALSE));
rsc->allowed_nodes =
g_slist_remove(rsc->allowed_nodes,node);
crm_free(node);
lpc2--;
}
);
return TRUE;
}
resource_t *
pe_find_resource(GSListPtr rsc_list, const char *id_rh)
{
int lpc = 0;
for(lpc = 0; lpc < g_slist_length(rsc_list); lpc++) {
resource_t *rsc = g_slist_nth_data(rsc_list, lpc);
if(rsc != NULL && safe_str_eq(rsc->id, id_rh)){
return rsc;
}
}
// error
return NULL;
}
node_t *
pe_find_node(GSListPtr nodes, const char *id)
{
int lpc = 0;
for(lpc = 0; lpc < g_slist_length(nodes); lpc++) {
node_t *node = g_slist_nth_data(nodes, lpc);
if(safe_str_eq(node->details->id, id)) {
return node;
}
}
// error
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b);
color_t *
find_color(GSListPtr candidate_colors, color_t *other_color)
{
- return (color_t *)g_slist_find_custom(candidate_colors, other_color,
- gslist_color_compare);
+ GSListPtr tmp = g_slist_find_custom(candidate_colors, other_color,
+ gslist_color_compare);
+ if(tmp != NULL) {
+ return (color_t *)tmp->data;
+ }
+ return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b)
{
const color_t *color_a = (const color_t*)a;
const color_t *color_b = (const color_t*)b;
- if(color_a->id == color_b->id) {
+ if(a == b) {
+ return 0;
+ } else if(a == NULL || b == NULL) {
+ return 1;
+ } else if(color_a->id == color_b->id) {
return 0;
}
return 1;
}
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(resource1->priority > resource2->priority)
return -1;
if(resource1->priority < resource2->priority)
return 1;
return 0;
}
gint sort_cons_strength(gconstpointer a, gconstpointer b)
{
const rsc_to_rsc_t *rsc_constraint1 = (const rsc_to_rsc_t*)a;
const rsc_to_rsc_t *rsc_constraint2 = (const rsc_to_rsc_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(rsc_constraint1->strength > rsc_constraint2->strength)
return 1;
if(rsc_constraint1->strength < rsc_constraint2->strength)
return -1;
return 0;
}
gint sort_color_weight(gconstpointer a, gconstpointer b)
{
const color_t *color1 = (const color_t*)a;
const color_t *color2 = (const color_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(color1->local_weight > color2->local_weight)
return -1;
if(color1->local_weight < color2->local_weight)
return 1;
return 0;
}
gint sort_node_weight(gconstpointer a, gconstpointer b)
{
const node_t *node1 = (const node_t*)a;
const node_t *node2 = (const node_t*)b;
if(a == NULL) return 1;
if(b == NULL) return -1;
if(node1->weight > node2->weight)
return -1;
if(node1->weight < node2->weight)
return 1;
return 0;
}
action_t *
action_new(int id, resource_t *rsc, enum action_tasks task)
{
action_t *action = (action_t*)crm_malloc(sizeof(action_t));
action->id = id;
action->rsc = rsc;
action->task = task;
action->node = NULL; // fill node in later
action->actions_before = NULL;
action->actions_after = NULL;
action->failure_is_fatal = TRUE;
action->discard = FALSE;
action->runnable = FALSE;
action->processed = FALSE;
action->optional = FALSE;
action->seen_count = 0;
return action;
}
const char *
contype2text(enum con_type type)
{
const char *result = "<unknown>";
switch(type)
{
case type_none:
result = "none";
break;
case rsc_to_rsc:
result = "rsc_to_rsc";
break;
case rsc_to_node:
result = "rsc_to_node";
break;
case rsc_to_attr:
result = "rsc_to_attr";
break;
case base_weight:
result = "base_weight";
break;
}
return result;
};
const char *
strength2text(enum con_strength strength)
{
const char *result = "<unknown>";
switch(strength)
{
case ignore:
result = "ignore";
break;
case must:
result = "must";
break;
case should:
result = "should";
break;
case should_not:
result = "should_not";
break;
case must_not:
result = "must_not";
break;
case startstop:
result = "start/stop";
break;
}
return result;
};
const char *
modifier2text(enum con_modifier modifier)
{
const char *result = "<unknown>";
switch(modifier)
{
case modifier_none:
result = "modifier_none";
break;
case set:
result = "set";
break;
case inc:
result = "inc";
break;
case dec:
result = "dec";
break;
}
return result;
};
const char *
task2text(enum action_tasks task)
{
const char *result = "<unknown>";
switch(task)
{
case no_action:
result = "no_action";
break;
case stop_rsc:
result = "stop";
break;
case start_rsc:
result = "start";
break;
case shutdown_crm:
result = "shutdown_crm";
break;
case stonith_op:
result = "stonith";
break;
}
return result;
};
void
print_node(const char *pre_text, node_t *node, gboolean details)
{
if(node == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
cl_log(LOG_DEBUG, "%s%s%sNode %s: (weight=%f, fixed=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ",
node->details->id,
node->weight,
node->fixed?"True":"False");
if(details && node->details != NULL) {
char *mutable = crm_strdup("\t\t");
cl_log(LOG_DEBUG, "\t\t===Node Attributes");
g_hash_table_foreach(node->details->attrs,
print_str_str, mutable);
crm_free(mutable);
}
if(details) {
int lpc = 0;
cl_log(LOG_DEBUG, "\t\t===Node Attributes");
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
print_resource("\t\t", rsc, FALSE);
);
}
};
/*
* Used by the HashTable for-loop
*/
void print_str_str(gpointer key, gpointer value, gpointer user_data)
{
cl_log(LOG_DEBUG, "%s%s %s ==> %s",
user_data==NULL?"":(char*)user_data,
user_data==NULL?"":": ",
(char*)key,
(char*)value);
}
void
print_color_details(const char *pre_text,
struct color_shared_s *color,
gboolean details)
{
if(color == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
cl_log(LOG_DEBUG, "%s%sColor %d: node=%s (from %d candidates)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->chosen_node==NULL?"<unset>":color->chosen_node->details->id,
g_slist_length(color->candidate_nodes));
if(details) {
int lpc = 0;
slist_iter(node, node_t, color->candidate_nodes, lpc,
print_node("\t", node, FALSE));
}
}
void
print_color(const char *pre_text, color_t *color, gboolean details)
{
if(color == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
cl_log(LOG_DEBUG, "%s%sColor %d: (weight=%f, node=%s, possible=%d)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->local_weight,
color->details->chosen_node==NULL?"<unset>":color->details->chosen_node->details->id,
g_slist_length(color->details->candidate_nodes));
if(details) {
print_color_details("\t", color->details, details);
}
}
void
print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details)
{
if(cons == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
cl_log(LOG_DEBUG, "%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_node",
cons->id, cons);
if(details == FALSE) {
cl_log(LOG_DEBUG,
"\t%s --> %s, %f (node placement rule)",
cons->rsc_lh->id,
modifier2text(cons->modifier),
cons->weight);
int lpc = 0;
slist_iter(
node, node_t, cons->node_list_rh, lpc,
print_node("\t\t-->", node, FALSE)
);
}
}
void
print_rsc_to_rsc(const char *pre_text, rsc_to_rsc_t *cons, gboolean details)
{
if(cons == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
cl_log(LOG_DEBUG, "%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_rsc", cons->id, cons);
if(details == FALSE) {
cl_log(LOG_DEBUG,
"\t%s --> %s, %s",
cons->rsc_lh==NULL?"null":cons->rsc_lh->id,
cons->rsc_rh==NULL?"null":cons->rsc_rh->id,
strength2text(cons->strength));
}
}
void
print_resource(const char *pre_text, resource_t *rsc, gboolean details)
{
if(rsc == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
cl_log(LOG_DEBUG,
"%s%s%s%sResource %s: (priority=%f, color=%d, now=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
rsc->provisional?"Provisional ":"",
rsc->runnable?"":"(Non-Startable) ",
rsc->id,
(double)rsc->priority,
safe_val3(-1, rsc, color, id),
safe_val4(NULL, rsc, cur_node, details, id));
cl_log(LOG_DEBUG,
"\t%d candidate colors, %d allowed nodes, %d rsc_cons and %d node_cons",
g_slist_length(rsc->candidate_colors),
g_slist_length(rsc->allowed_nodes),
g_slist_length(rsc->rsc_cons),
g_slist_length(rsc->node_cons));
if(details) {
int lpc = 0;
cl_log(LOG_DEBUG, "\t=== Actions");
print_action("\tStop: ", rsc->stop, FALSE);
print_action("\tStart: ", rsc->start, FALSE);
cl_log(LOG_DEBUG, "\t=== Colors");
slist_iter(
color, color_t, rsc->candidate_colors, lpc,
print_color("\t", color, FALSE)
);
cl_log(LOG_DEBUG, "\t=== Allowed Nodes");
slist_iter(
node, node_t, rsc->allowed_nodes, lpc,
print_node("\t", node, FALSE);
);
}
}
void
print_action(const char *pre_text, action_t *action, gboolean details)
{
if(action == NULL) {
cl_log(LOG_DEBUG, "%s%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
__FUNCTION__);
return;
}
switch(action->task) {
case stonith_op:
case shutdown_crm:
cl_log(LOG_DEBUG, "%s%s%sAction %d: %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->discard?"Discarded ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id,
task2text(action->task),
safe_val4(NULL, action, node, details, id));
break;
default:
cl_log(LOG_DEBUG, "%s%s%sAction %d: %s %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id,
task2text(action->task),
safe_val3(NULL, action, rsc, id),
safe_val7(NULL, action, rsc, color, details, chosen_node, details, id));
break;
}
if(details) {
int lpc = 0;
#if 1
cl_log(LOG_DEBUG, "\t\t====== Preceeding Actions");
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
print_action("\t\t", other->action, FALSE);
);
cl_log(LOG_DEBUG, "\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
print_action("\t\t", other->action, FALSE);
);
#else
cl_log(LOG_DEBUG, "\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
print_action("\t\t", other->action, FALSE);
);
#endif
cl_log(LOG_DEBUG, "\t\t====== End");
} else {
cl_log(LOG_DEBUG, "\t\t(seen=%d, before=%d, after=%d)",
action->seen_count,
g_slist_length(action->actions_before),
g_slist_length(action->actions_after));
}
}
xmlNodePtr
action2xml(action_t *action)
{
xmlNodePtr action_xml = NULL;
if(action == NULL) {
return NULL;
}
switch(action->task) {
case stonith_op:
action_xml = create_xml_node(NULL, "pseduo_event");
break;
case shutdown_crm:
action_xml = create_xml_node(NULL, "crm_event");
break;
default:
action_xml = create_xml_node(NULL, "rsc_op");
add_node_copy(action_xml, action->rsc->xml);
break;
}
set_xml_property_copy(action_xml,
"on_node",
safe_val4(NULL, action, node, details, id));
set_xml_property_copy(action_xml,
"id",
crm_itoa(action->id));
set_xml_property_copy(action_xml,
"runnable",
action->runnable?"true":"false");
set_xml_property_copy(action_xml,
"optional",
action->optional?"true":"false");
set_xml_property_copy(action_xml,
"task",
task2text(action->task));
set_xml_property_copy(action_xml,
"discard",
action->discard?"true":"false");
set_xml_property_copy(action_xml,
"allow_fail",
action->failure_is_fatal?"false":"true");
return action_xml;
}
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
void
pe_free_nodes(GSListPtr nodes)
{
while(nodes != NULL){
GSListPtr list_item = nodes;
node_t *node = (node_t*)list_item->data;
struct node_shared_s *details = node->details;
nodes = nodes->next;
if(details != NULL) {
crm_free(details->id);
g_hash_table_foreach_remove(details->attrs,
ghash_free_str_str, NULL);
crm_free(details);
}
crm_free(node);
}
g_slist_free(nodes);
}
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data)
{
crm_free(key);
crm_free(value);
return TRUE;
}
void
pe_free_colors(GSListPtr colors)
{
while(colors != NULL) {
GSListPtr list_item = colors;
color_t *color = (color_t *)list_item->data;
struct color_shared_s *details = color->details;
colors = colors->next;
if(details != NULL) {
pe_free_shallow(details->candidate_nodes);
crm_free(details->chosen_node);
crm_free(details);
}
crm_free(color);
}
g_slist_free(colors);
}
void
pe_free_shallow(GSListPtr alist)
{
pe_free_shallow_adv(alist, TRUE);
}
void
pe_free_shallow_adv(GSListPtr alist, gboolean with_data)
{
GSListPtr item;
GSListPtr item_next = alist;
while(item_next != NULL) {
item = item_next;
item_next = item_next->next;
if(with_data) {
crm_free(item->data);
}
item->data = NULL;
item->next = NULL;
g_slist_free(item);
}
}
void
pe_free_resources(GSListPtr resources)
{
volatile GSListPtr list_item = NULL;
resource_t *rsc = NULL;
while(resources != NULL) {
list_item = resources;
rsc = (resource_t *)list_item->data;
resources = resources->next;
crm_free(rsc->id);
// pdebug("color");
// crm_free(rsc->color);
int lpc;
slist_iter(clr, color_t, rsc->candidate_colors, lpc,
print_color("deleting", clr, FALSE));
// pe_free_shallow(rsc->candidate_colors);
pe_free_shallow(rsc->allowed_nodes);
while(rsc->rsc_cons) {
pe_free_rsc_to_rsc((rsc_to_rsc_t*)rsc->rsc_cons->data);
rsc->rsc_cons = rsc->rsc_cons->next;
}
g_slist_free(rsc->rsc_cons);
crm_free(rsc);
}
g_slist_free(resources);
}
void
pe_free_actions(GSListPtr actions)
{
while(actions != NULL) {
GSListPtr list_item = actions;
action_t *action = (action_t *)list_item->data;
actions = actions->next;
pe_free_shallow(action->actions_before); // action_warpper_t*
pe_free_shallow(action->actions_after); // action_warpper_t*
action->actions_before = NULL;
action->actions_after = NULL;
crm_free(action);
}
g_slist_free(actions);
}
void
pe_free_rsc_to_rsc(rsc_to_rsc_t *cons)
{
if(cons != NULL) {
crm_free(cons->id);
crm_free(cons);
}
}
void
pe_free_rsc_to_node(rsc_to_node_t *cons)
{
if(cons != NULL) {
crm_free(cons->id);
pe_free_shallow(cons->node_list_rh); // node_t*
crm_free(cons);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 26, 8:08 PM (1 d, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1959643
Default Alt Text
(23 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment