1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-02 01:18:26 +03:00

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.
This commit is contained in:
Jonathan Brassow 2013-09-09 15:07:28 -05:00
parent 9f2fc2471c
commit ca51435153
2 changed files with 57 additions and 40 deletions

View File

@ -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;

View File

@ -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 */
}
/*