mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-30 17:18:21 +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:
parent
109e6334b0
commit
68e8f5a4a2
@ -61,6 +61,7 @@ static const struct flag _lv_flags[] = {
|
|||||||
{MIRRORED, NULL, 0},
|
{MIRRORED, NULL, 0},
|
||||||
{VIRTUAL, NULL, 0},
|
{VIRTUAL, NULL, 0},
|
||||||
{SNAPSHOT, NULL, 0},
|
{SNAPSHOT, NULL, 0},
|
||||||
|
{SNAPSHOT_MERGE, NULL, 0},
|
||||||
{ACTIVATE_EXCL, NULL, 0},
|
{ACTIVATE_EXCL, NULL, 0},
|
||||||
{CONVERTING, NULL, 0},
|
{CONVERTING, NULL, 0},
|
||||||
{PARTIAL_LV, NULL, 0},
|
{PARTIAL_LV, NULL, 0},
|
||||||
|
@ -1877,6 +1877,7 @@ struct logical_volume *alloc_lv(struct dm_pool *mem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
lv->snapshot = NULL;
|
lv->snapshot = NULL;
|
||||||
|
lv->merging_snapshot = NULL;
|
||||||
dm_list_init(&lv->snapshot_segs);
|
dm_list_init(&lv->snapshot_segs);
|
||||||
dm_list_init(&lv->segments);
|
dm_list_init(&lv->segments);
|
||||||
dm_list_init(&lv->tags);
|
dm_list_init(&lv->tags);
|
||||||
@ -2941,6 +2942,11 @@ int lv_create_single(struct volume_group *vg,
|
|||||||
"supported yet");
|
"supported yet");
|
||||||
return 0;
|
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) ||
|
if ((org->status & MIRROR_IMAGE) ||
|
||||||
(org->status & MIRROR_LOG)) {
|
(org->status & MIRROR_LOG)) {
|
||||||
log_error("Snapshots of mirror %ss "
|
log_error("Snapshots of mirror %ss "
|
||||||
|
@ -69,6 +69,8 @@
|
|||||||
//#define POSTORDER_OPEN_FLAG 0x04000000U temporary use inside vg_read_internal. */
|
//#define POSTORDER_OPEN_FLAG 0x04000000U temporary use inside vg_read_internal. */
|
||||||
//#define VIRTUAL_ORIGIN 0x08000000U /* LV - internal use only */
|
//#define VIRTUAL_ORIGIN 0x08000000U /* LV - internal use only */
|
||||||
|
|
||||||
|
#define SNAPSHOT_MERGE 0x10000000U /* SEG */
|
||||||
|
|
||||||
#define LVM_READ 0x00000100U /* LV VG */
|
#define LVM_READ 0x00000100U /* LV VG */
|
||||||
#define LVM_WRITE 0x00000200U /* LV VG */
|
#define LVM_WRITE 0x00000200U /* LV VG */
|
||||||
#define CLUSTERED 0x00000400U /* VG */
|
#define CLUSTERED 0x00000400U /* VG */
|
||||||
@ -328,6 +330,9 @@ struct logical_volume {
|
|||||||
struct dm_list snapshot_segs;
|
struct dm_list snapshot_segs;
|
||||||
struct lv_segment *snapshot;
|
struct lv_segment *snapshot;
|
||||||
|
|
||||||
|
/* A snapshot that is merging into this origin */
|
||||||
|
struct lv_segment *merging_snapshot;
|
||||||
|
|
||||||
struct dm_list segments;
|
struct dm_list segments;
|
||||||
struct dm_list tags;
|
struct dm_list tags;
|
||||||
struct dm_list segs_using_this_lv;
|
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);
|
struct logical_volume *origin_from_cow(const struct logical_volume *lv);
|
||||||
|
|
||||||
void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
|
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,
|
int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
|
||||||
union lvid *lvid, uint32_t extent_count,
|
union lvid *lvid, uint32_t extent_count,
|
||||||
|
@ -37,6 +37,9 @@ int lv_is_visible(const struct logical_volume *lv)
|
|||||||
if (lv_is_virtual_origin(origin_from_cow(lv)))
|
if (lv_is_virtual_origin(origin_from_cow(lv)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (find_cow(lv)->status & SNAPSHOT_MERGE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return lv_is_visible(origin_from_cow(lv));
|
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,
|
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->chunk_size = chunk_size;
|
||||||
seg->origin = origin;
|
seg->origin = origin;
|
||||||
@ -79,10 +82,30 @@ void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
|
|||||||
origin->status |= VIRTUAL_ORIGIN;
|
origin->status |= VIRTUAL_ORIGIN;
|
||||||
|
|
||||||
seg->lv->status |= (SNAPSHOT | VIRTUAL);
|
seg->lv->status |= (SNAPSHOT | VIRTUAL);
|
||||||
|
if (merge)
|
||||||
|
init_snapshot_merge(seg, origin);
|
||||||
|
|
||||||
dm_list_add(&origin->snapshot_segs, &seg->origin_list);
|
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,
|
int vg_add_snapshot(struct logical_volume *origin,
|
||||||
struct logical_volume *cow, union lvid *lvid,
|
struct logical_volume *cow, union lvid *lvid,
|
||||||
uint32_t extent_count, uint32_t chunk_size)
|
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)))
|
if (!(seg = alloc_snapshot_seg(snap, 0, 0)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
init_snapshot_seg(seg, origin, cow, chunk_size);
|
init_snapshot_seg(seg, origin, cow, chunk_size, 0);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -122,6 +145,8 @@ int vg_remove_snapshot(struct logical_volume *cow)
|
|||||||
{
|
{
|
||||||
dm_list_del(&cow->snapshot->origin_list);
|
dm_list_del(&cow->snapshot->origin_list);
|
||||||
cow->snapshot->origin->origin_count--;
|
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)) {
|
if (!lv_remove(cow->snapshot->lv)) {
|
||||||
log_error("Failed to remove internal snapshot LV %s",
|
log_error("Failed to remove internal snapshot LV %s",
|
||||||
|
@ -37,7 +37,7 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
|
|||||||
uint32_t chunk_size;
|
uint32_t chunk_size;
|
||||||
const char *org_name, *cow_name;
|
const char *org_name, *cow_name;
|
||||||
struct logical_volume *org, *cow;
|
struct logical_volume *org, *cow;
|
||||||
int old_suppress;
|
int old_suppress, merge = 0;
|
||||||
|
|
||||||
if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
|
if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
|
||||||
log_error("Couldn't read chunk size for snapshot.");
|
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);
|
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_suppress(old_suppress);
|
||||||
log_error("Snapshot cow storage not specified.");
|
log_error("Snapshot cow storage not specified.");
|
||||||
return 0;
|
return 0;
|
||||||
@ -72,7 +75,7 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_snapshot_seg(seg, org, cow, chunk_size);
|
init_snapshot_seg(seg, org, cow, chunk_size, merge);
|
||||||
|
|
||||||
return 1;
|
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, "chunk_size = %u", seg->chunk_size);
|
||||||
outf(f, "origin = \"%s\"", seg->origin->name);
|
outf(f, "origin = \"%s\"", seg->origin->name);
|
||||||
|
if (!(seg->status & SNAPSHOT_MERGE))
|
||||||
outf(f, "cow_store = \"%s\"", seg->cow->name);
|
outf(f, "cow_store = \"%s\"", seg->cow->name);
|
||||||
|
else
|
||||||
|
outf(f, "merging_store = \"%s\"", seg->cow->name);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user