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

Add 'SNAPSHOT_MERGE' lv_segment 'status' flag.

Make 'merging_snapshot' pointer that points from the origin to the
segment that represents the merging snapshot.

Import/export 'merging_store' metadata.

Do not allow creating snapshots while another snapshot is merging.
Snapshot created in this state would certainly contain invalid data.

NOTE: patches at the end of this series will remove 'merging_snapshot'
and will introduce helpful wrappers and cleanups.
This commit is contained in:
Mike Snitzer 2010-01-13 01:35:49 +00:00
parent 109e6334b0
commit 68e8f5a4a2
5 changed files with 52 additions and 7 deletions

View File

@ -61,6 +61,7 @@ static const struct flag _lv_flags[] = {
{MIRRORED, NULL, 0},
{VIRTUAL, NULL, 0},
{SNAPSHOT, NULL, 0},
{SNAPSHOT_MERGE, NULL, 0},
{ACTIVATE_EXCL, NULL, 0},
{CONVERTING, NULL, 0},
{PARTIAL_LV, NULL, 0},

View File

@ -1877,6 +1877,7 @@ struct logical_volume *alloc_lv(struct dm_pool *mem)
}
lv->snapshot = NULL;
lv->merging_snapshot = NULL;
dm_list_init(&lv->snapshot_segs);
dm_list_init(&lv->segments);
dm_list_init(&lv->tags);
@ -2941,6 +2942,11 @@ int lv_create_single(struct volume_group *vg,
"supported yet");
return 0;
}
if (org->merging_snapshot) {
log_error("Snapshots of an origin that has a "
"merging snapshot is not supported");
return 0;
}
if ((org->status & MIRROR_IMAGE) ||
(org->status & MIRROR_LOG)) {
log_error("Snapshots of mirror %ss "

View File

@ -69,6 +69,8 @@
//#define POSTORDER_OPEN_FLAG 0x04000000U temporary use inside vg_read_internal. */
//#define VIRTUAL_ORIGIN 0x08000000U /* LV - internal use only */
#define SNAPSHOT_MERGE 0x10000000U /* SEG */
#define LVM_READ 0x00000100U /* LV VG */
#define LVM_WRITE 0x00000200U /* LV VG */
#define CLUSTERED 0x00000400U /* VG */
@ -328,6 +330,9 @@ struct logical_volume {
struct dm_list snapshot_segs;
struct lv_segment *snapshot;
/* A snapshot that is merging into this origin */
struct lv_segment *merging_snapshot;
struct dm_list segments;
struct dm_list tags;
struct dm_list segs_using_this_lv;
@ -624,7 +629,9 @@ struct lv_segment *find_cow(const struct logical_volume *lv);
struct logical_volume *origin_from_cow(const struct logical_volume *lv);
void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
struct logical_volume *cow, uint32_t chunk_size);
struct logical_volume *cow, uint32_t chunk_size, int merge);
void init_snapshot_merge(struct lv_segment *cow_seg, struct logical_volume *origin);
int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
union lvid *lvid, uint32_t extent_count,

View File

@ -37,6 +37,9 @@ int lv_is_visible(const struct logical_volume *lv)
if (lv_is_virtual_origin(origin_from_cow(lv)))
return 1;
if (find_cow(lv)->status & SNAPSHOT_MERGE)
return 0;
return lv_is_visible(origin_from_cow(lv));
}
@ -62,7 +65,7 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
}
void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
struct logical_volume *cow, uint32_t chunk_size)
struct logical_volume *cow, uint32_t chunk_size, int merge)
{
seg->chunk_size = chunk_size;
seg->origin = origin;
@ -79,10 +82,30 @@ void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
origin->status |= VIRTUAL_ORIGIN;
seg->lv->status |= (SNAPSHOT | VIRTUAL);
if (merge)
init_snapshot_merge(seg, origin);
dm_list_add(&origin->snapshot_segs, &seg->origin_list);
}
void init_snapshot_merge(struct lv_segment *cow_seg,
struct logical_volume *origin)
{
/*
* Even though lv_is_visible(cow_seg->lv) returns 0,
* the cow_seg->lv (name: snapshotX) is _not_ hidden;
* this is part of the lvm2 snapshot fiction. Must
* clear VISIBLE_LV directly (lv_set_visible can't)
* - cow_seg->lv->status is used to control whether 'lv'
* (with user provided snapshot LV name) is visible
* - this also enables vg_validate() to succeed with
* merge metadata (cow_seg->lv is now "internal")
*/
cow_seg->lv->status &= ~VISIBLE_LV;
cow_seg->status |= SNAPSHOT_MERGE;
origin->merging_snapshot = cow_seg;
}
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow, union lvid *lvid,
uint32_t extent_count, uint32_t chunk_size)
@ -113,7 +136,7 @@ int vg_add_snapshot(struct logical_volume *origin,
if (!(seg = alloc_snapshot_seg(snap, 0, 0)))
return_0;
init_snapshot_seg(seg, origin, cow, chunk_size);
init_snapshot_seg(seg, origin, cow, chunk_size, 0);
return 1;
}
@ -122,6 +145,8 @@ int vg_remove_snapshot(struct logical_volume *cow)
{
dm_list_del(&cow->snapshot->origin_list);
cow->snapshot->origin->origin_count--;
if (cow->snapshot->origin->merging_snapshot == cow->snapshot)
cow->snapshot->origin->merging_snapshot = NULL;
if (!lv_remove(cow->snapshot->lv)) {
log_error("Failed to remove internal snapshot LV %s",

View File

@ -37,7 +37,7 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
uint32_t chunk_size;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
int old_suppress;
int old_suppress, merge = 0;
if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
log_error("Couldn't read chunk size for snapshot.");
@ -46,7 +46,10 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
old_suppress = log_suppress(1);
if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
cow_name = find_config_str(sn, "merging_store", NULL);
if (cow_name) {
merge = 1;
} else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
log_suppress(old_suppress);
log_error("Snapshot cow storage not specified.");
return 0;
@ -72,7 +75,7 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
return 0;
}
init_snapshot_seg(seg, org, cow, chunk_size);
init_snapshot_seg(seg, org, cow, chunk_size, merge);
return 1;
}
@ -81,7 +84,10 @@ static int _snap_text_export(const struct lv_segment *seg, struct formatter *f)
{
outf(f, "chunk_size = %u", seg->chunk_size);
outf(f, "origin = \"%s\"", seg->origin->name);
if (!(seg->status & SNAPSHOT_MERGE))
outf(f, "cow_store = \"%s\"", seg->cow->name);
else
outf(f, "merging_store = \"%s\"", seg->cow->name);
return 1;
}