1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

activate: Improve snapshot merge initiation

A snapshot merge into its origin cannot be initiated while the devices
are in use.  If there is outside interference (such as from udev),
the suspend (preload) and resume stages can reach conflicting decisions
about whether or not to proceed.

Try to make the logic more robust by checking the inactive or live
table during resume.  (This is still not perfect.)
This commit is contained in:
Alasdair G Kergon 2016-04-15 02:21:27 +01:00
parent 150cff9cce
commit 6954de22e2
4 changed files with 32 additions and 11 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.151 -
=================================
Avoid deciding to initiate a pending snapshot merge during resume.
Improve retrying lvmetad requests while lvmetad is being updated.
Read devices instead of using the lvmetad cache if rescan fails.
Move lvmetad token/filter check and device rescan to the start of commands.

View File

@ -2063,6 +2063,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
}
laopts->read_only = _passes_readonly_filter(cmd, lv);
laopts->resuming = 1;
if (!_lv_activate_lv(lv, laopts))
goto_out;

View File

@ -81,6 +81,7 @@ struct lv_activate_opts {
* set of flags to avoid any scanning in udev. These udev
* flags are persistent in udev db for any spurious event
* that follows. */
unsigned resuming; /* Set when resuming after a suspend. */
};
void set_activation(int activation, int silent);

View File

@ -806,13 +806,28 @@ int lv_has_target_type(struct dm_pool *mem, const struct logical_volume *lv,
if (!dm_task_get_info(dmt, &info) || !info.exists)
goto_out;
/* If there is a preloaded table, use that in preference. */
if (info.inactive_table) {
dm_task_destroy(dmt);
if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_STATUS, 0, 0, 0)))
goto_bad;
if (!dm_task_query_inactive_table(dmt))
goto_out;
if (!dm_task_run(dmt))
goto_out;
if (!dm_task_get_info(dmt, &info) || !info.exists || !info.inactive_table)
goto_out;
}
do {
next = dm_get_next_target(dmt, next, &start, &length,
&type, &params);
if (type && strncmp(type, target_type,
strlen(target_type)) == 0) {
if (info.live_table)
r = 1;
if (type && !strncmp(type, target_type, strlen(target_type))) {
r = 1;
break;
}
} while (next);
@ -2665,6 +2680,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
uint32_t read_ahead = lv->read_ahead;
uint32_t read_ahead_flags = UINT32_C(0);
int save_pending_delete = dm->track_pending_delete;
int snap_dev_is_open = 0;
/* LV with pending delete is never put new into a table */
if (lv_is_pending_delete(lv) && !_cached_dm_info(dm->mem, dtree, lv, NULL))
@ -2697,13 +2713,15 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
((dinfo = _cached_dm_info(dm->mem, dtree,
seg_is_thin_volume(seg) ?
seg->lv : seg->cow, NULL)) &&
dinfo->open_count)) {
if (seg_is_thin_volume(seg) ||
/* FIXME Is there anything simpler to check for instead? */
!lv_has_target_type(dm->mem, lv, NULL, TARGET_NAME_SNAPSHOT_MERGE)) {
log_debug_activation("Postponing pending snapshot merge for origin LV %s.", display_lvname(lv));
laopts->no_merging = 1;
}
dinfo->open_count))
snap_dev_is_open = 1;
/* Preload considers open devices. */
/* Resume looks at the table that will be the live one after the operation. */
if ((!laopts->resuming && snap_dev_is_open && (seg_is_thin_volume(seg) || !lv_has_target_type(dm->mem, lv, NULL, TARGET_NAME_SNAPSHOT_MERGE))) ||
(laopts->resuming && !seg_is_thin_volume(seg) && !lv_has_target_type(dm->mem, lv, NULL, TARGET_NAME_SNAPSHOT_MERGE))) {
log_debug_activation("Postponing pending snapshot merge for origin LV %s.", display_lvname(lv));
laopts->no_merging = 1;
}
}