From 6954de22e2281876506c0db1c98972242de977fb Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Fri, 15 Apr 2016 02:21:27 +0100 Subject: [PATCH] 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.) --- WHATS_NEW | 1 + lib/activate/activate.c | 1 + lib/activate/activate.h | 1 + lib/activate/dev_manager.c | 40 +++++++++++++++++++++++++++----------- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 8c58c8d91..123c38390 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -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. diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 8e6ee33c9..ac547ce5b 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -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; diff --git a/lib/activate/activate.h b/lib/activate/activate.h index 64c026ee4..880689cee 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -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); diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index d25c07ebd..92f2a05d7 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -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, ¶ms); - 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; } }