Merge on activate (lvconvert -M --onactivate) support. It is needed if we want to merge over a mounted filesystem that cannot be unmounted --- for example root. Signed-off-by: Mikulas Patocka --- lib/format_text/flags.c | 1 lib/metadata/metadata-exported.h | 3 - lib/metadata/snapshot_manip.c | 7 ++- lib/report/report.c | 2 lib/snapshot/snapshot.c | 6 ++ tools/args.h | 1 tools/commands.h | 3 - tools/lvchange.c | 9 ++++ tools/lvconvert.c | 79 ++++++++++++++++++++++++++++++++++----- tools/tools.h | 2 tools/vgchange.c | 4 + 11 files changed, 102 insertions(+), 15 deletions(-) Index: LVM2.2.02.45/lib/format_text/flags.c =================================================================== --- LVM2.2.02.45.orig/lib/format_text/flags.c 2009-05-11 13:08:29.000000000 +0200 +++ LVM2.2.02.45/lib/format_text/flags.c 2009-05-11 13:09:27.000000000 +0200 @@ -62,6 +62,7 @@ static struct flag _lv_flags[] = { {VIRTUAL, NULL, 0}, {SNAPSHOT, NULL, 0}, {SNAPSHOT_MERGE, NULL, 0}, + {SNAPSHOT_MERGE_ON_ACT, NULL, 0}, {ACTIVATE_EXCL, NULL, 0}, {CONVERTING, NULL, 0}, {PARTIAL_LV, NULL, 0}, Index: LVM2.2.02.45/lib/metadata/metadata-exported.h =================================================================== --- LVM2.2.02.45.orig/lib/metadata/metadata-exported.h 2009-05-11 13:08:34.000000000 +0200 +++ LVM2.2.02.45/lib/metadata/metadata-exported.h 2009-05-11 13:09:27.000000000 +0200 @@ -71,6 +71,7 @@ struct pv_segment; //#define PRECOMMITTED 0x00200000U /* VG - internal use only */ #define CONVERTING 0x00400000U /* LV */ #define SNAPSHOT_MERGE 0x00800000U /* SEG */ +#define SNAPSHOT_MERGE_ON_ACT 0x01000000U /* SEG */ #define MISSING_PV 0x00800000U /* PV */ #define PARTIAL_LV 0x01000000U /* LV - derived flag, not @@ -551,7 +552,7 @@ struct logical_volume *origin_from_cow(c int vg_add_snapshot(const char *name, struct logical_volume *origin, struct logical_volume *cow, union lvid *lvid, uint32_t extent_count, - uint32_t chunk_size, int merge); + uint32_t chunk_size, uint32_t merge_flags); int vg_remove_snapshot(struct logical_volume *cow); Index: LVM2.2.02.45/lib/report/report.c =================================================================== --- LVM2.2.02.45.orig/lib/report/report.c 2009-05-11 13:08:44.000000000 +0200 +++ LVM2.2.02.45/lib/report/report.c 2009-05-11 13:09:27.000000000 +0200 @@ -330,7 +330,7 @@ static int _lvstatus_disp(struct dm_repo else repstr[0] = 'o'; else if (lv_is_cow(lv)) { - if (find_cow(lv)->status & SNAPSHOT_MERGE) + if (find_cow(lv)->status & (SNAPSHOT_MERGE | SNAPSHOT_MERGE_ON_ACT)) repstr[0] = 'S'; else repstr[0] = 's'; Index: LVM2.2.02.45/lib/snapshot/snapshot.c =================================================================== --- LVM2.2.02.45.orig/lib/snapshot/snapshot.c 2009-05-11 13:08:29.000000000 +0200 +++ LVM2.2.02.45/lib/snapshot/snapshot.c 2009-05-11 13:09:27.000000000 +0200 @@ -42,6 +42,8 @@ static int _snap_text_import(struct lv_s if (find_config_bool(sn, "merge", 0)) seg->status |= SNAPSHOT_MERGE; + else if (find_config_bool(sn, "merge_on_activate", 0)) + seg->status |= SNAPSHOT_MERGE_ON_ACT; if (!get_config_uint32(sn, "chunk_size", &chunk_size)) { log_error("Couldn't read chunk size for snapshot."); @@ -78,7 +80,7 @@ static int _snap_text_import(struct lv_s if (!vg_add_snapshot(seg->lv->name, org, cow, &seg->lv->lvid, seg->len, chunk_size, - !!(seg->status & SNAPSHOT_MERGE))) + seg->status)) return_0; return 1; @@ -90,6 +92,8 @@ static int _snap_text_export(const struc outf(f, "origin = \"%s\"", seg->origin->name); if (!(seg->status & SNAPSHOT_MERGE)) { outf(f, "cow_store = \"%s\"", seg->cow->name); + if (seg->status & SNAPSHOT_MERGE_ON_ACT) + outf(f, "merge_on_activate = 1"); } else { outf(f, "merging_store = \"%s\"", seg->cow->name); outf(f, "merge = 1"); Index: LVM2.2.02.45/tools/args.h =================================================================== --- LVM2.2.02.45.orig/tools/args.h 2009-05-11 13:09:15.000000000 +0200 +++ LVM2.2.02.45/tools/args.h 2009-05-11 13:09:27.000000000 +0200 @@ -100,6 +100,7 @@ arg(persistent_ARG, 'M', "persistent", y arg(merge_ARG, 'M', "merge", NULL, 0) arg(merge_origin_ARG, '\0', "nameorigin", NULL, 0) arg(merge_snapshot_ARG, '\0', "namesnapshot", NULL, 0) +arg(merge_on_activate_ARG, '\0', "onactivate", NULL, 0) arg(major_ARG, 'j', "major", major_arg, 0) arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0) arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0) Index: LVM2.2.02.45/tools/commands.h =================================================================== --- LVM2.2.02.45.orig/tools/commands.h 2009-05-11 13:09:15.000000000 +0200 +++ LVM2.2.02.45/tools/commands.h 2009-05-11 13:09:27.000000000 +0200 @@ -118,11 +118,12 @@ xx(lvconvert, "[-M|--merge]\n" "\t[--nameorigin]\n" "\t[--namesnapshot]\n" + "\t[--onactivate]\n" "\tSnapshotLogicalVolume[Path]\n", alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG, mirrorlog_ARG, mirrors_ARG, regionsize_ARG, snapshot_ARG, test_ARG, zero_ARG, - merge_ARG, merge_origin_ARG, merge_snapshot_ARG) + merge_ARG, merge_origin_ARG, merge_snapshot_ARG, merge_on_activate_ARG) xx(lvcreate, "Create a logical volume", Index: LVM2.2.02.45/tools/lvconvert.c =================================================================== --- LVM2.2.02.45.orig/tools/lvconvert.c 2009-05-11 13:09:26.000000000 +0200 +++ LVM2.2.02.45/tools/lvconvert.c 2009-05-11 13:09:27.000000000 +0200 @@ -18,6 +18,7 @@ #define MERGE_AS_SNAPSHOT 1 #define MERGE_AS_ORIGIN 2 +#define MERGE_ON_ACTIVATE 3 struct lvconvert_params { int snapshot; @@ -142,6 +143,10 @@ static int _read_params(struct lvconvert if (lp->merge) goto invalid_merge_args; lp->merge = MERGE_AS_SNAPSHOT; } + if (arg_count(cmd, merge_on_activate_ARG)) { + if (lp->merge) goto invalid_merge_args; + lp->merge = MERGE_ON_ACTIVATE; + } if (!lp->merge) { lp->merge = MERGE_AS_ORIGIN; } @@ -818,19 +823,22 @@ static int lvconvert_check_merge(struct return 0; } - if (lv_info(cmd, origin, &info, 1, 0)) { - if (info.open_count) { - log_error("Can't merge over open origin volume"); - return 0; + if (type != MERGE_ON_ACTIVATE) { + if (lv_info(cmd, origin, &info, 1, 0)) { + if (info.open_count) { + log_error("Can't merge over open origin volume"); + return 0; + } } - } - if (lv_info(cmd, lv, &info, 1, 0)) { - if (info.open_count && type != MERGE_AS_SNAPSHOT) { - log_error("Can't merge when snapshot is open"); - return 0; + if (lv_info(cmd, lv, &info, 1, 0)) { + if (info.open_count && type != MERGE_AS_SNAPSHOT) { + log_error("Can't merge when snapshot is open"); + return 0; + } } } + if (origin->origin_count != 1 && type == MERGE_AS_SNAPSHOT) { log_error("There must not be other snapshots when preserving snapshot name"); return 0; @@ -896,6 +904,34 @@ static int lvconvert_do_merge(struct cmd return 1; } +static int lvconvert_do_merge_on_activate(struct cmd_context *cmd, + struct logical_volume *lv) +{ + struct lv_segment *cow_seg = find_cow(lv); + + cow_seg->status |= SNAPSHOT_MERGE_ON_ACT; + + /* store vg on disk(s) */ + if (!vg_write(lv->vg)) + return_0; + + backup(lv->vg); + + if (!vg_commit(lv->vg)) + return_0; + + return 1; +} + +static void lvconvert_turn_off_merge_on_activate(struct logical_volume *origin) +{ + struct lv_segment *snap_seg; + + /* turn off all merge-on-activate flags */ + dm_list_iterate_items_gen(snap_seg, &origin->snapshot_segs, origin_list) + snap_seg->status &= ~SNAPSHOT_MERGE_ON_ACT; +} + static int lvconvert_merge(struct cmd_context *cmd, struct logical_volume *lv, struct lvconvert_params *lp) @@ -908,6 +944,12 @@ static int lvconvert_merge(struct cmd_co lv_name = lv->name; + lvconvert_turn_off_merge_on_activate(origin); + + if (lp->merge == MERGE_ON_ACTIVATE) { + return lvconvert_do_merge_on_activate(cmd, lv); + } + if (!lvconvert_do_merge(cmd, lv, lp->merge)) return 0; @@ -919,6 +961,25 @@ static int lvconvert_merge(struct cmd_co return 1; } +void lvconvert_preactivate(struct cmd_context *cmd, struct logical_volume *origin) +{ + struct lv_segment *snap_seg; + + dm_list_iterate_items_gen(snap_seg, &origin->snapshot_segs, origin_list) + if (snap_seg->status & SNAPSHOT_MERGE_ON_ACT) { + struct logical_volume *lv = snap_seg->cow; + + if (!lvconvert_check_merge(cmd, lv, MERGE_AS_ORIGIN)) + return; + + lvconvert_turn_off_merge_on_activate(origin); + + lvconvert_do_merge(cmd, lv, MERGE_AS_ORIGIN); + + return; + } +} + static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { Index: LVM2.2.02.45/lib/metadata/snapshot_manip.c =================================================================== --- LVM2.2.02.45.orig/lib/metadata/snapshot_manip.c 2009-05-11 13:08:34.000000000 +0200 +++ LVM2.2.02.45/lib/metadata/snapshot_manip.c 2009-05-11 13:09:27.000000000 +0200 @@ -58,7 +58,8 @@ struct logical_volume *origin_from_cow(c int vg_add_snapshot(const char *name, struct logical_volume *origin, struct logical_volume *cow, union lvid *lvid, - uint32_t extent_count, uint32_t chunk_size, int merge) + uint32_t extent_count, uint32_t chunk_size, + uint32_t merge_flags) { struct logical_volume *snap; struct lv_segment *seg; @@ -95,10 +96,12 @@ int vg_add_snapshot(const char *name, st seg->origin = origin; seg->cow = cow; seg->lv->status |= SNAPSHOT; - if (merge) { + if (merge_flags & SNAPSHOT_MERGE) { seg->status |= SNAPSHOT_MERGE; origin->merging_snapshot = seg; } + if (merge_flags & SNAPSHOT_MERGE_ON_ACT) + seg->status |= SNAPSHOT_MERGE_ON_ACT; origin->origin_count++; origin->vg->snapshot_count++; Index: LVM2.2.02.45/tools/lvchange.c =================================================================== --- LVM2.2.02.45.orig/tools/lvchange.c 2009-05-11 13:08:58.000000000 +0200 +++ LVM2.2.02.45/tools/lvchange.c 2009-05-11 13:09:27.000000000 +0200 @@ -99,6 +99,12 @@ static int lvchange_monitoring(struct cm return 1; } +void lvchange_pre_activate(struct cmd_context *cmd, struct logical_volume *lv) +{ + if (lv_is_origin(lv)) + lvconvert_preactivate(cmd, lv); +} + void lvchange_activate_background_polling(struct cmd_context *cmd, struct logical_volume *lv) { @@ -135,6 +141,9 @@ static int lvchange_availability(struct if (!deactivate_lv(cmd, lv)) return_0; } else { + if (!lv_is_active(lv)) + lvchange_pre_activate(cmd, lv); + if (lockingfailed() && (vg_is_clustered(lv->vg))) { log_verbose("Locking failed: ignoring clustered " "logical volume %s", lv->name); Index: LVM2.2.02.45/tools/tools.h =================================================================== --- LVM2.2.02.45.orig/tools/tools.h 2009-05-11 13:08:56.000000000 +0200 +++ LVM2.2.02.45/tools/tools.h 2009-05-11 13:09:27.000000000 +0200 @@ -168,7 +168,9 @@ int arg_count_increment(struct cmd_conte const char *command_name(struct cmd_context *cmd); int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background); +void lvconvert_preactivate(struct cmd_context *cmd, struct logical_volume *lv); int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background); +void lvchange_pre_activate(struct cmd_context *cmd, struct logical_volume *lv); void lvchange_activate_background_polling(struct cmd_context *cmd, struct logical_volume *lv); #endif Index: LVM2.2.02.45/tools/vgchange.c =================================================================== --- LVM2.2.02.45.orig/tools/vgchange.c 2009-05-11 13:08:56.000000000 +0200 +++ LVM2.2.02.45/tools/vgchange.c 2009-05-11 13:09:27.000000000 +0200 @@ -75,6 +75,10 @@ static int _activate_lvs_in_vg(struct cm ((lv->status & PVMOVE) )) continue; + if (activate != CHANGE_AN && activate != CHANGE_ALN && + !lv_is_active(lv)) + lvchange_pre_activate(cmd, lv); + if (activate == CHANGE_AN) { if (!deactivate_lv(cmd, lv)) continue;