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:
parent
28c3f0354a
commit
c582e3c039
@ -327,6 +327,52 @@ static int _status(const char *name, const char *uuid,
|
|||||||
return 0;
|
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, ¶ms);
|
||||||
|
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,
|
static percent_range_t _combine_percent_ranges(percent_range_t a,
|
||||||
percent_range_t b)
|
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_segment *seg;
|
||||||
struct lv_layer *lvlayer;
|
struct lv_layer *lvlayer;
|
||||||
struct dm_tree_node *dnode;
|
struct dm_tree_node *dnode;
|
||||||
|
struct dm_info dinfo;
|
||||||
char *name, *dlid, *lv_name;
|
char *name, *dlid, *lv_name;
|
||||||
uint32_t max_stripe_size = UINT32_C(0);
|
uint32_t max_stripe_size = UINT32_C(0);
|
||||||
uint32_t read_ahead = lv->read_ahead;
|
uint32_t read_ahead = lv->read_ahead;
|
||||||
uint32_t read_ahead_flags = UINT32_C(0);
|
uint32_t read_ahead_flags = UINT32_C(0);
|
||||||
uint16_t udev_flags = 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;
|
lv_name = lv->name;
|
||||||
if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE) {
|
if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE) {
|
||||||
if (layer) {
|
if (layer) {
|
||||||
|
@ -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) ||
|
if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
|
||||||
(percent_range == PERCENT_INVALID)) {
|
(percent_range == PERCENT_INVALID)) {
|
||||||
*sortval = UINT64_C(100);
|
if (!lv->merging_snapshot) {
|
||||||
dm_report_field_set_value(field, "100.00", sortval);
|
*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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1117,6 +1117,7 @@ static int lvconvert_merge(struct cmd_context *cmd,
|
|||||||
struct lvconvert_params *lp)
|
struct lvconvert_params *lp)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
int merge_on_activate = 0;
|
||||||
struct logical_volume *origin = origin_from_cow(lv);
|
struct logical_volume *origin = origin_from_cow(lv);
|
||||||
struct lv_segment *cow_seg = find_cow(lv);
|
struct lv_segment *cow_seg = find_cow(lv);
|
||||||
struct lvinfo info;
|
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
|
* 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
|
* FIXME testing open_count is racey; snapshot-merge target's
|
||||||
* constructor and DM should prevent appropriate devices from
|
* 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 (lv_info(cmd, origin, &info, 1, 0)) {
|
||||||
if (info.open_count) {
|
if (info.open_count) {
|
||||||
log_error("Can't merge over open origin volume");
|
log_error("Can't merge over open origin volume");
|
||||||
return 0;
|
merge_on_activate = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lv_info(cmd, lv, &info, 1, 0)) {
|
if (lv_info(cmd, lv, &info, 1, 0)) {
|
||||||
if (info.open_count) {
|
if (info.open_count) {
|
||||||
log_error("Can't merge when snapshot is open");
|
log_print("Can't merge when snapshot is open");
|
||||||
return 0;
|
merge_on_activate = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1159,6 +1162,16 @@ static int lvconvert_merge(struct cmd_context *cmd,
|
|||||||
if (!vg_write(lv->vg))
|
if (!vg_write(lv->vg))
|
||||||
return_0;
|
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 */
|
/* Perform merge */
|
||||||
if (!suspend_lv(cmd, origin)) {
|
if (!suspend_lv(cmd, origin)) {
|
||||||
log_error("Failed to suspend origin %s", origin->name);
|
log_error("Failed to suspend origin %s", origin->name);
|
||||||
|
Loading…
Reference in New Issue
Block a user