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

Merge on activate support.

If either the origin or snapshot that is to be merged is open the merge
will not start; only the merge metadata will be written.  The merge will
start on the next activation of the origin (or via lvchange --refresh)
IFF both the origin and snapshot are closed.

Merge on activate is particularly important if we want to merge over a
mounted filesystem that cannot be unmounted (until next boot) --- for
example root.
This commit is contained in:
Mike Snitzer 2010-01-13 01:54:34 +00:00
parent 28c3f0354a
commit c582e3c039
3 changed files with 94 additions and 6 deletions

View File

@ -327,6 +327,52 @@ static int _status(const char *name, const char *uuid,
return 0;
}
static int _lv_has_target_type(struct dev_manager *dm,
struct logical_volume *lv,
const char *layer,
const char *target_type)
{
int r = 0;
char *dlid;
struct dm_task *dmt;
struct dm_info info;
void *next = NULL;
uint64_t start, length;
char *type = NULL;
char *params = NULL;
if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
return_0;
if (!(dmt = _setup_task(NULL, dlid, 0,
DM_DEVICE_STATUS, 0, 0)))
return_0;
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt))
goto_out;
if (!dm_task_get_info(dmt, &info) || !info.exists)
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 && !info.inactive_table)
r = 1;
break;
}
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
static percent_range_t _combine_percent_ranges(percent_range_t a,
percent_range_t b)
{
@ -1062,12 +1108,33 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
struct lv_segment *seg;
struct lv_layer *lvlayer;
struct dm_tree_node *dnode;
struct dm_info dinfo;
char *name, *dlid, *lv_name;
uint32_t max_stripe_size = UINT32_C(0);
uint32_t read_ahead = lv->read_ahead;
uint32_t read_ahead_flags = UINT32_C(0);
uint16_t udev_flags = 0;
if (lv_is_origin(lv) && lv->merging_snapshot && !layer) {
/*
* Clear merge attributes if merge isn't currently possible:
* either origin or merging snapshot are open
* - must refresh info's open_count, so using the tree's
* existing nodes' info isn't an option
* - but use "snapshot-merge" if it is already being used
*/
if ((dev_manager_info(dm->mem, NULL, lv,
0, 1, 0, &dinfo, NULL) && dinfo.open_count) ||
(dev_manager_info(dm->mem, NULL, lv->merging_snapshot->cow,
0, 1, 0, &dinfo, NULL) && dinfo.open_count)) {
if (!_lv_has_target_type(dm, lv, NULL, "snapshot-merge")) {
/* clear merge attributes */
lv->merging_snapshot->status &= ~SNAPSHOT_MERGE;
lv->merging_snapshot = NULL;
}
}
}
lv_name = lv->name;
if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE) {
if (layer) {

View File

@ -1032,8 +1032,16 @@ static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm
if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
(percent_range == PERCENT_INVALID)) {
*sortval = UINT64_C(100);
dm_report_field_set_value(field, "100.00", sortval);
if (!lv->merging_snapshot) {
*sortval = UINT64_C(100);
dm_report_field_set_value(field, "100.00", sortval);
} else {
/* onactivate merge that hasn't started yet would
* otherwise display incorrect snap% in origin
*/
*sortval = UINT64_C(0);
dm_report_field_set_value(field, "", sortval);
}
return 1;
}

View File

@ -1117,6 +1117,7 @@ static int lvconvert_merge(struct cmd_context *cmd,
struct lvconvert_params *lp)
{
int r = 0;
int merge_on_activate = 0;
struct logical_volume *origin = origin_from_cow(lv);
struct lv_segment *cow_seg = find_cow(lv);
struct lvinfo info;
@ -1134,7 +1135,9 @@ static int lvconvert_merge(struct cmd_context *cmd,
/*
* Prevent merge with open device(s) as it would likely lead
* to application/filesystem failure.
* to application/filesystem failure. Merge on origin's next
* activation if either the origin or snapshot LV are currently
* open.
*
* FIXME testing open_count is racey; snapshot-merge target's
* constructor and DM should prevent appropriate devices from
@ -1143,13 +1146,13 @@ static int lvconvert_merge(struct cmd_context *cmd,
if (lv_info(cmd, origin, &info, 1, 0)) {
if (info.open_count) {
log_error("Can't merge over open origin volume");
return 0;
merge_on_activate = 1;
}
}
if (lv_info(cmd, lv, &info, 1, 0)) {
if (info.open_count) {
log_error("Can't merge when snapshot is open");
return 0;
log_print("Can't merge when snapshot is open");
merge_on_activate = 1;
}
}
@ -1159,6 +1162,16 @@ static int lvconvert_merge(struct cmd_context *cmd,
if (!vg_write(lv->vg))
return_0;
if (merge_on_activate) {
/* commit vg but skip starting the merge */
if (!vg_commit(lv->vg))
return_0;
r = 1;
log_print("Merging of snapshot %s will start "
"next activation.", lv->name);
goto out;
}
/* Perform merge */
if (!suspend_lv(cmd, origin)) {
log_error("Failed to suspend origin %s", origin->name);