Create snapshots in the shared store. If there is not a store, we create the store first. At the end, if the user specified a snapshot name, jump again to the beginning to create the first snapshot. If there is a store, the routine will be creating a virtual snapshot inside the store. Signed-off-by: Mikulas Patocka --- lib/activate/dev_manager.c | 5 +- lib/metadata/lv_manip.c | 102 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 8 deletions(-) Index: LVM2.2.02.60/lib/metadata/lv_manip.c =================================================================== --- LVM2.2.02.60.orig/lib/metadata/lv_manip.c 2010-02-10 22:42:54.000000000 +0100 +++ LVM2.2.02.60/lib/metadata/lv_manip.c 2010-02-10 22:42:59.000000000 +0100 @@ -2865,6 +2865,7 @@ int lv_create_single(struct volume_group const char *lv_name; struct lvinfo info; +again: if (lp->lv_name && find_lv_in_vg(vg, lp->lv_name)) { log_error("Logical volume \"%s\" already exists in " "volume group \"%s\"", lp->lv_name, lp->vg_name); @@ -2956,7 +2957,7 @@ int lv_create_single(struct volume_group "supported yet."); return 0; } - if (lv_is_multisnap_origin(org)) { + if (lv_is_multisnap_origin(org) && !lp->lv_name) { log_error("It is not allowed to create more " "shared snapshot stores."); return 0; @@ -2994,9 +2995,27 @@ int lv_create_single(struct volume_group origin_active = info.exists; } - lp->segtype = get_segtype_from_string(cmd, "striped"); - if (!lp->segtype) - return_0; + if (!lv_is_multisnap_origin(org)) { + /* + * If we are creating non-shared snapshot or + * the shared snapshot store, create the underlying + * volume first. + */ + lp->segtype = get_segtype_from_string(cmd, "striped"); + if (!lp->segtype) + return_0; + } else { + /* + * If there is already a shared snapshot, create + * the virtual segment. + */ + if (!(lp->segtype = get_segtype_from_string(cmd, "multisnap-snap"))) + return_0; + } + } + + if (lp->snapshot && lv_is_multisnap_origin(org)) { + lp->extents = org->le_count; } if (!lp->extents) { @@ -3047,7 +3066,7 @@ int lv_create_single(struct volume_group lv_name = lp->lv_name ? lp->lv_name : "lvol%d"; - if (lp->shared_store) { + if (lp->shared_store && !lv_is_multisnap_origin(org)) { char *name = dm_pool_alloc(cmd->mem, strlen(lp->origin) + strlen(SHARED_SUFFIX) + 1); strcpy(name, lp->origin); @@ -3095,6 +3114,59 @@ int lv_create_single(struct volume_group } } + if (lp->snapshot && seg_is_virtual(lp)) { + char *snapid = NULL; + + struct lv_segment *first = first_seg(lv); + if (!first) { + log_error("Logical volume is empty."); + return 0; + } + + if (!origin_active) { + if (!activate_lv(cmd, org)) { + log_error("Couldn't activate origin LV %s", org->name); + return 0; + } + } + + if (!lv_multisnap_prepare_create(cmd, org, &snapid)) { + log_error("Couldn't make new snapshot for origin LV %s", org->name); + +multisnapshot_error: + if (!origin_active) + if (!deactivate_lv(cmd, org)) + log_error("Couldn't deactivate origin LV %s", org->name); + return 0; + } + + first->origin = org; + first->snapid = snapid; + + /* + * Suspend and resume will quiescent a filesystem and create + * the snapshot. + */ + + if (!suspend_lv(cmd, org)) { + log_error("Failed to suspend origin %s", org->name); + goto multisnapshot_error; + } + + if (!resume_lv(cmd, org)) { + log_error("Problem reactivating origin %s", org->name); + goto multisnapshot_error; + } + + if (!origin_active) { + if (!deactivate_lv(cmd, org)) { + log_error("Couldn't deactivate origin LV %s", org->name); + return 0; + } + } + lp->zero = 0; + } + /* store vg on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) return_0; @@ -3102,6 +3174,8 @@ int lv_create_single(struct volume_group backup(vg); if (lp->snapshot) { + if (!origin_active && lv_is_multisnap_cow(lv)) + goto dont_activate; if (!activate_lv_excl(cmd, lv)) { log_error("Aborting. Failed to activate snapshot " "exception store."); @@ -3116,8 +3190,11 @@ int lv_create_single(struct volume_group log_error("Failed to activate new LV."); return 0; } +dont_activate: - if (!lp->zero && !lp->snapshot) + if (lv_is_multisnap_cow(lv)) + /* shared snapshot - do nothing */ ; + else if (!lp->zero && !lp->snapshot) log_error("WARNING: \"%s\" not zeroed", lv->name); else if (!set_lv(cmd, lv, UINT64_C(0), 0)) { log_error("Aborting. Failed to wipe %s.", @@ -3126,7 +3203,11 @@ int lv_create_single(struct volume_group goto deactivate_and_revert_new_lv; } - if (lp->snapshot) { + /* + * If we are creating non-shared snapshot or the shared snapshot + * store, zero it. + */ + if (lp->snapshot && !lv_is_multisnap_cow(lv)) { /* Reset permission after zeroing */ if (!(lp->permission & LVM_WRITE)) lv->status &= ~LVM_WRITE; @@ -3211,6 +3292,13 @@ snapshot_failure: if (!origin_active && lp->shared_store) deactivate_lv(cmd, org); + + /* + * If we created the shared store and the user spcified a name, + * we must create the first individual snapshot in the store. + */ + if (lp->shared_store && lp->lv_name) + goto again; } /* FIXME out of sequence */ backup(vg); Index: LVM2.2.02.60/lib/activate/dev_manager.c =================================================================== --- LVM2.2.02.60.orig/lib/activate/dev_manager.c 2010-02-10 22:42:54.000000000 +0100 +++ LVM2.2.02.60/lib/activate/dev_manager.c 2010-02-10 22:42:59.000000000 +0100 @@ -1006,12 +1006,15 @@ static struct dm_tree *_create_partial_d goto_bad; /* Add any LVs used by segments in this LV */ - dm_list_iterate_items(seg, &lv->segments) + dm_list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s)) { if (!_add_lv_to_dtree(dm, dtree, seg_lv(seg, s))) goto_bad; } + if (seg->origin) + _add_lv_to_dtree(dm, dtree, seg->origin); + } return dtree;