1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00

dm: remove created devices on error path

DM tree keeps track of created device while preloading a device tree.
When fail occures during such preload, it will now try to remove
all created and preloaded device. This makes it easier to maintain
stacking of device, since we do not need to check in-depth for
existance of all possible created devices during the failure.
This commit is contained in:
Zdenek Kabelac 2020-10-16 20:58:58 +02:00
parent 7c262bfc85
commit ef5cddc208
2 changed files with 26 additions and 50 deletions

View File

@ -1,5 +1,6 @@
Version 1.02.172 - Version 1.02.172 -
================================== ==================================
Try to remove all created devices on dm preload tree error path.
Fix dm_list interators with gcc 10 optimization (-ftree-pta). Fix dm_list interators with gcc 10 optimization (-ftree-pta).
Dmeventd handles timer without looping on short intervals. Dmeventd handles timer without looping on short intervals.

View File

@ -1937,7 +1937,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
return r; return r;
} }
static int _create_node(struct dm_tree_node *dnode) static int _create_node(struct dm_tree_node *dnode, struct dm_tree_node *parent)
{ {
int r = 0; int r = 0;
struct dm_task *dmt; struct dm_task *dmt;
@ -1986,38 +1986,15 @@ static int _create_node(struct dm_tree_node *dnode)
"Unable to get DM task info for %s.", "Unable to get DM task info for %s.",
dnode->name); dnode->name);
} }
if (r)
dm_list_add_h(&parent->activated, &dnode->activated_list);
out: out:
dm_task_destroy(dmt); dm_task_destroy(dmt);
return r; return r;
} }
/*
* _remove_node
*
* This function is only used to remove a DM device that has failed
* to load any table.
*/
static int _remove_node(struct dm_tree_node *dnode)
{
if (!dnode->info.exists)
return 1;
if (dnode->info.live_table || dnode->info.inactive_table) {
log_error(INTERNAL_ERROR
"_remove_node called on device with loaded table(s).");
return 0;
}
if (!_deactivate_node(dnode->name, dnode->info.major, dnode->info.minor,
&dnode->dtree->cookie, dnode->udev_flags, 0)) {
log_error("Failed to clean-up device with no table: %s.",
_node_name(dnode));
return 0;
}
return 1;
}
static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node) static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node)
{ {
if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) { if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) {
@ -2798,6 +2775,16 @@ static int _dm_tree_revert_activated(struct dm_tree_node *parent)
return 1; return 1;
} }
static int _dm_tree_wait_and_revert_activated(struct dm_tree_node *dnode)
{
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
return _dm_tree_revert_activated(dnode);
}
int dm_tree_preload_children(struct dm_tree_node *dnode, int dm_tree_preload_children(struct dm_tree_node *dnode,
const char *uuid_prefix, const char *uuid_prefix,
size_t uuid_prefix_len) size_t uuid_prefix_len)
@ -2827,7 +2814,7 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
return_0; return_0;
/* FIXME Cope if name exists with no uuid? */ /* FIXME Cope if name exists with no uuid? */
if (!child->info.exists && !(node_created = _create_node(child))) if (!child->info.exists && !(node_created = _create_node(child, dnode)))
return_0; return_0;
/* Propagate delayed resume from exteded child node */ /* Propagate delayed resume from exteded child node */
@ -2837,18 +2824,15 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
if (!child->info.inactive_table && if (!child->info.inactive_table &&
child->props.segment_count && child->props.segment_count &&
!_load_node(child)) { !_load_node(child)) {
stack;
/* /*
* If the table load does not succeed, we remove the * If the table load fails, try to device in the kernel
* device in the kernel that would otherwise have an * together with other created and preloaded devices.
* empty table. This makes the create + load of the
* device atomic. However, if other dependencies have
* already been created and loaded; this code is
* insufficient to remove those - only the node
* encountering the table load failure is removed.
*/ */
if (node_created && !_remove_node(child)) if (!_dm_tree_wait_and_revert_activated(dnode))
return_0; stack;
return_0; r = 0;
continue;
} }
/* No resume for a device without parents or with unchanged or smaller size */ /* No resume for a device without parents or with unchanged or smaller size */
@ -2863,28 +2847,19 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
&child->info, &child->dtree->cookie, child->udev_flags, &child->info, &child->dtree->cookie, child->udev_flags,
child->info.suspended)) { child->info.suspended)) {
log_error("Unable to resume %s.", _node_name(child)); log_error("Unable to resume %s.", _node_name(child));
/* If the device was not previously active, we might as well remove this node. */ if (!_dm_tree_wait_and_revert_activated(dnode))
if (!child->info.live_table && stack;
!_deactivate_node(child->name, child->info.major, child->info.minor,
&child->dtree->cookie, child->udev_flags, 0))
log_error("Unable to deactivate %s.", _node_name(child));
r = 0; r = 0;
/* Each child is handled independently */
continue; continue;
} }
if (node_created) { if (node_created) {
/* Collect newly introduced devices for revert */
dm_list_add_h(&dnode->activated, &child->activated_list);
/* When creating new node also check transaction_id. */ /* When creating new node also check transaction_id. */
if (child->props.send_messages && if (child->props.send_messages &&
!_node_send_messages(child, uuid_prefix, uuid_prefix_len, 0)) { !_node_send_messages(child, uuid_prefix, uuid_prefix_len, 0)) {
stack; stack;
if (!dm_udev_wait(dm_tree_get_cookie(dnode))) if (!_dm_tree_wait_and_revert_activated(dnode))
stack; stack;
dm_tree_set_cookie(dnode, 0);
(void) _dm_tree_revert_activated(dnode);
r = 0; r = 0;
continue; continue;
} }