diff options
author | Jonathan Brassow <jbrassow@redhat.com> | 2013-09-09 15:07:28 -0500 |
---|---|---|
committer | Jonathan Brassow <jbrassow@redhat.com> | 2013-09-09 15:07:28 -0500 |
commit | ca514351536c2dd8929944bb6b01a64587cb0a46 (patch) | |
tree | 58397d940cba62c8cb362480cd4828946cbb2bfd /libdm | |
parent | 9f2fc2471cd39effccd549d73c2fc9c0e6419f94 (diff) | |
download | lvm2-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.c | 55 |
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 */ } /* |