[lvm-devel] master - Misc/RAID: Enable resume_lv to handle some renaming conflicts.
Jonathan Brassow
jbrassow at fedoraproject.org
Mon Sep 9 20:23:40 UTC 2013
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ca514351536c2dd8929944bb6b01a64587cb0a46
Commit: ca514351536c2dd8929944bb6b01a64587cb0a46
Parent: 9f2fc2471cd39effccd549d73c2fc9c0e6419f94
Author: Jonathan Brassow <jbrassow at redhat.com>
AuthorDate: Mon Sep 9 15:07:28 2013 -0500
Committer: Jonathan Brassow <jbrassow at redhat.com>
CommitterDate: Mon Sep 9 15:07:28 2013 -0500
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.
---
lib/metadata/raid_manip.c | 42 +--------------------------------
libdm/libdm-deptree.c | 55 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 40 deletions(-)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 47c2788..d13750d 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -59,24 +59,6 @@ uint32_t lv_raid_image_count(const struct logical_volume *lv)
return seg->area_count;
}
-/*
- * Resume sub-LVs first, then top-level LV
- */
-static int _bottom_up_resume(struct logical_volume *lv)
-{
- uint32_t s;
- struct lv_segment *seg = first_seg(lv);
-
- if (seg_is_raid(seg) && (seg->area_count > 1)) {
- for (s = 0; s < seg->area_count; s++)
- if (!resume_lv(lv->vg->cmd, seg_lv(seg, s)) ||
- !resume_lv(lv->vg->cmd, seg_metalv(seg, s)))
- return_0;
- }
-
- return resume_lv(lv->vg->cmd, lv);
-}
-
static int _activate_sublv_preserving_excl(struct logical_volume *top_lv,
struct logical_volume *sub_lv)
{
@@ -991,17 +973,7 @@ static int _raid_remove_images(struct logical_volume *lv,
}
}
- /*
- * Resume the remaining LVs
- * We must start by resuming the sub-LVs first (which would
- * otherwise be handled automatically) because the shifting
- * of positions could otherwise cause name collisions. For
- * example, if position 0 of a 3-way array is removed, position
- * 1 and 2 must be shifted and renamed 0 and 1. If position 2
- * tries to rename first, it will collide with the existing
- * position 1.
- */
- if (!_bottom_up_resume(lv)) {
+ if (!resume_lv(lv->vg->cmd, lv)) {
log_error("Failed to resume %s/%s after committing changes",
lv->vg->name, lv->name);
return 0;
@@ -1164,17 +1136,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
if (!resume_lv(cmd, lvl->lv))
return_0;
- /*
- * Resume the remaining LVs
- * We must start by resuming the sub-LVs first (which would
- * otherwise be handled automatically) because the shifting
- * of positions could otherwise cause name collisions. For
- * example, if position 0 of a 3-way array is split, position
- * 1 and 2 must be shifted and renamed 0 and 1. If position 2
- * tries to rename first, it will collide with the existing
- * position 1.
- */
- if (!_bottom_up_resume(lv)) {
+ if (!resume_lv(lv->vg->cmd, lv)) {
log_error("Failed to resume %s/%s after committing changes",
lv->vg->name, lv->name);
return 0;
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index 57f00f6..752a44b 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 */
}
/*
More information about the lvm-devel
mailing list