summaryrefslogtreecommitdiff
path: root/libdm
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2013-09-09 15:07:28 -0500
committerJonathan Brassow <jbrassow@redhat.com>2013-09-09 15:07:28 -0500
commitca514351536c2dd8929944bb6b01a64587cb0a46 (patch)
tree58397d940cba62c8cb362480cd4828946cbb2bfd /libdm
parent9f2fc2471cd39effccd549d73c2fc9c0e6419f94 (diff)
downloadlvm2-ca514351536c2dd8929944bb6b01a64587cb0a46.tar.gz
Misc/RAID: Enable resume_lv to handle some renaming conflicts.
When images and their associated metadata are removed from a RAID1 LV, the remaining sub-LVs are "shifted" down to fill the gaps. For example, if there is a 3-way mirror: [0][1][2] and we remove device#0, the devices will be shifted down [1][2] and renamed. [0][1] This can create a problem for resume_lv (specifically, dm_tree_activate_children) during the renaming process though. This is because it will attempt to rename the higher indexed sub-LVs first and find that it cannot because there are currently other sub-LVs with that name. The solution is to check for a conflicting name before attempting to rename. If a conflict is found and that conflicting sub-LV is also in the process of renaming, we can defer the current rename until the conflicting sub-LV has renamed and cleared the conflict. Now that resume_lv can handle these types of rename conflicts, we can remove the workaround in RAID that was attempting to resume a RAID1 LV from the bottom-up in order to force a proper rename in assending order before attempting a resume on the top-level LV. This "hack" only worked for single machine use-cases of LVM. Clearing this up paves the way for exclusive activation of RAID LVs in a cluster.
Diffstat (limited to 'libdm')
-rw-r--r--libdm/libdm-deptree.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index 57f00f63c..752a44bfe 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -1702,11 +1702,58 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
return r;
}
+/*
+ * _rename_conflict_exists
+ * @dnode
+ * @node
+ * @resolvable
+ *
+ * Check if there is a rename conflict with existing peers in
+ * this tree. 'resolvable' is set if the conflicting node will
+ * also be undergoing a rename. (Allowing that node to rename
+ * first would clear the conflict.)
+ *
+ * Returns: 1 if conflict, 0 otherwise
+ */
+static int _rename_conflict_exists(struct dm_tree_node *parent,
+ struct dm_tree_node *node,
+ int *resolvable)
+{
+ void *handle = NULL;
+ const char *name = dm_tree_node_get_name(node);
+ const char *sibling_name;
+ struct dm_tree_node *sibling;
+
+ *resolvable = 0;
+
+ if (!name)
+ return_0;
+
+ while ((sibling = dm_tree_next_child(&handle, parent, 0))) {
+ if (sibling == node)
+ continue;
+
+ if (!(sibling_name = dm_tree_node_get_name(sibling))) {
+ stack;
+ continue;
+ }
+
+ if (!strcmp(node->props.new_name, sibling_name)) {
+ if (sibling->props.new_name)
+ *resolvable = 1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int dm_tree_activate_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
int r = 1;
+ int resolvable_name_conflict, awaiting_peer_rename = 0;
void *handle = NULL;
struct dm_tree_node *child = dnode;
struct dm_info newinfo;
@@ -1732,6 +1779,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
handle = NULL;
for (priority = 0; priority < 3; priority++) {
+ awaiting_peer_rename = 0;
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (priority != child->activation_priority)
continue;
@@ -1751,6 +1799,11 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
/* Rename? */
if (child->props.new_name) {
+ if (_rename_conflict_exists(dnode, child, &resolvable_name_conflict) &&
+ resolvable_name_conflict) {
+ awaiting_peer_rename++;
+ continue;
+ }
if (!_rename_node(name, child->props.new_name, child->info.major,
child->info.minor, &child->dtree->cookie,
child->udev_flags)) {
@@ -1779,6 +1832,8 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
/* Update cached info */
child->info = newinfo;
}
+ if (awaiting_peer_rename)
+ priority--; /* redo priority level */
}
/*