mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
thin: snapshot merge support
This commit is contained in:
parent
572983d793
commit
e286904da6
@ -491,14 +491,14 @@ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
|
||||
/* If this is thin volume, thin snapshot is being created */
|
||||
if (lv_is_thin_volume(thin_pool_lv)) {
|
||||
seg->transaction_id = first_seg(first_seg(thin_pool_lv)->pool_lv)->transaction_id;
|
||||
if (!attach_pool_lv(seg, first_seg(thin_pool_lv)->pool_lv, thin_pool_lv))
|
||||
if (!attach_pool_lv(seg, first_seg(thin_pool_lv)->pool_lv, thin_pool_lv, NULL))
|
||||
return_NULL;
|
||||
/* Use the same external origin */
|
||||
if (!attach_thin_external_origin(seg, first_seg(thin_pool_lv)->external_lv))
|
||||
return_NULL;
|
||||
} else if (lv_is_thin_pool(thin_pool_lv)) {
|
||||
seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
|
||||
if (!attach_pool_lv(seg, thin_pool_lv, NULL))
|
||||
if (!attach_pool_lv(seg, thin_pool_lv, NULL, NULL))
|
||||
return_NULL;
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Volume %s is not thin volume or thin pool",
|
||||
|
@ -258,6 +258,19 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
lv->name, seg->external_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (seg->merge_lv) {
|
||||
if (!lv_is_thin_volume(seg->merge_lv)) {
|
||||
log_error("LV %s: thin volume segment %u merging LV %s is not flagged as a thin LV",
|
||||
lv->name, seg_count, seg->merge_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (!lv_is_merging_origin(seg->merge_lv)) {
|
||||
log_error("LV %s: merging LV %s is not flagged as merging.",
|
||||
lv->name, seg->merge_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (seg->pool_lv) {
|
||||
log_error("LV %s: segment %u must not have thin pool LV set",
|
||||
|
@ -360,6 +360,7 @@ struct lv_segment {
|
||||
uint32_t chunk_size; /* For snapshots/thin_pool. In sectors. */
|
||||
/* For thin_pool, 128..2097152. */
|
||||
struct logical_volume *origin; /* snap and thin */
|
||||
struct logical_volume *merge_lv; /* thin, merge descendent lv into this ancestor */
|
||||
struct logical_volume *cow;
|
||||
struct dm_list origin_list;
|
||||
uint32_t region_size; /* For mirrors, replicators - in sectors */
|
||||
@ -881,7 +882,7 @@ int lv_is_visible(const struct logical_volume *lv);
|
||||
|
||||
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
|
||||
|
||||
/* Given a cow LV, return return the snapshot lv_segment that uses it */
|
||||
/* Given a cow or thin LV, return the snapshot lv_segment that uses it */
|
||||
struct lv_segment *find_snapshot(const struct logical_volume *lv);
|
||||
|
||||
/* Given a cow LV, return its origin */
|
||||
|
@ -462,11 +462,12 @@ int fixup_imported_mirrors(struct volume_group *vg);
|
||||
* From thin_manip.c
|
||||
*/
|
||||
int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
|
||||
struct logical_volume *origin_lv);
|
||||
struct logical_volume *origin_lv, struct logical_volume *merge_lv);
|
||||
int detach_pool_lv(struct lv_segment *seg);
|
||||
int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
|
||||
struct logical_volume *lv, uint32_t delete_id,
|
||||
int auto_increment);
|
||||
int lv_is_merging_thin_snapshot(const struct logical_volume *lv);
|
||||
int pool_has_message(const struct lv_segment *seg,
|
||||
const struct logical_volume *lv, uint32_t device_id);
|
||||
int pool_below_threshold(const struct lv_segment *pool_seg);
|
||||
|
@ -27,7 +27,8 @@ int lv_is_origin(const struct logical_volume *lv)
|
||||
|
||||
int lv_is_cow(const struct logical_volume *lv)
|
||||
{
|
||||
return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0;
|
||||
/* Make sure a merging thin origin isn't confused as a cow LV */
|
||||
return (!lv_is_thin_volume(lv) && !lv_is_origin(lv) && lv->snapshot) ? 1 : 0;
|
||||
}
|
||||
|
||||
static uint64_t _cow_max_size(uint64_t origin_size, uint32_t chunk_size)
|
||||
@ -150,6 +151,13 @@ void init_snapshot_merge(struct lv_segment *snap_seg,
|
||||
origin->snapshot = snap_seg;
|
||||
origin->status |= MERGING;
|
||||
|
||||
if (lv_is_thin_volume(origin)) {
|
||||
snap_seg->merge_lv = origin;
|
||||
/* Making thin LV inivisible with regular log */
|
||||
lv_set_hidden(snap_seg->lv);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Even though lv_is_visible(snap_seg->lv) returns 0,
|
||||
* the snap_seg->lv (name: snapshotX) is _not_ hidden;
|
||||
@ -166,6 +174,11 @@ void init_snapshot_merge(struct lv_segment *snap_seg,
|
||||
void clear_snapshot_merge(struct logical_volume *origin)
|
||||
{
|
||||
/* clear merge attributes */
|
||||
if (origin->snapshot->merge_lv)
|
||||
/* Removed thin volume has to be visible */
|
||||
lv_set_visible(origin->snapshot->lv);
|
||||
|
||||
origin->snapshot->merge_lv = NULL;
|
||||
origin->snapshot->status &= ~MERGING;
|
||||
origin->snapshot = NULL;
|
||||
origin->status &= ~MERGING;
|
||||
|
@ -60,7 +60,7 @@ int attach_pool_data_lv(struct lv_segment *pool_seg, struct logical_volume *pool
|
||||
}
|
||||
|
||||
int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
|
||||
struct logical_volume *origin)
|
||||
struct logical_volume *origin, struct logical_volume *merge_lv)
|
||||
{
|
||||
seg->pool_lv = pool_lv;
|
||||
seg->lv->status |= THIN_VOLUME;
|
||||
@ -69,7 +69,19 @@ int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
|
||||
if (origin && !add_seg_to_segs_using_this_lv(origin, seg))
|
||||
return_0;
|
||||
|
||||
return add_seg_to_segs_using_this_lv(pool_lv, seg);
|
||||
if (!add_seg_to_segs_using_this_lv(pool_lv, seg))
|
||||
return_0;
|
||||
|
||||
if (merge_lv) {
|
||||
if (origin != merge_lv) {
|
||||
if (!add_seg_to_segs_using_this_lv(merge_lv, seg))
|
||||
return_0;
|
||||
}
|
||||
|
||||
init_snapshot_merge(seg, merge_lv);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int detach_pool_lv(struct lv_segment *seg)
|
||||
@ -247,6 +259,11 @@ int detach_thin_external_origin(struct lv_segment *seg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_is_merging_thin_snapshot(const struct logical_volume *lv)
|
||||
{
|
||||
return (first_seg(lv)->status & MERGING) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether pool has some message queued for LV or for device_id
|
||||
* When LV is NULL and device_id is 0 it just checks for any message.
|
||||
|
@ -456,7 +456,7 @@ static int _thin_text_import(struct lv_segment *seg,
|
||||
struct dm_hash_table *pv_hash __attribute__((unused)))
|
||||
{
|
||||
const char *lv_name;
|
||||
struct logical_volume *pool_lv, *origin = NULL, *external_lv = NULL;
|
||||
struct logical_volume *pool_lv, *origin = NULL, *external_lv = NULL, *merge_lv = NULL;
|
||||
|
||||
if (!dm_config_get_str(sn, "thin_pool", &lv_name))
|
||||
return SEG_LOG_ERROR("Thin pool must be a string in");
|
||||
@ -475,6 +475,13 @@ static int _thin_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("Unknown origin %s in", lv_name);
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "merge")) {
|
||||
if (!dm_config_get_str(sn, "merge", &lv_name))
|
||||
return SEG_LOG_ERROR("Merge lv must be a string in");
|
||||
if (!(merge_lv = find_lv(seg->lv->vg, lv_name)))
|
||||
return SEG_LOG_ERROR("Unknown merge lv %s in", lv_name);
|
||||
}
|
||||
|
||||
if (!dm_config_get_uint32(sn, "device_id", &seg->device_id))
|
||||
return SEG_LOG_ERROR("Could not read device_id for");
|
||||
|
||||
@ -490,7 +497,7 @@ static int _thin_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("Unknown external origin %s in", lv_name);
|
||||
}
|
||||
|
||||
if (!attach_pool_lv(seg, pool_lv, origin))
|
||||
if (!attach_pool_lv(seg, pool_lv, origin, merge_lv))
|
||||
return_0;
|
||||
|
||||
if (!attach_thin_external_origin(seg, external_lv))
|
||||
@ -509,6 +516,8 @@ static int _thin_text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
outf(f, "external_origin = \"%s\"", seg->external_lv->name);
|
||||
if (seg->origin)
|
||||
outf(f, "origin = \"%s\"", seg->origin->name);
|
||||
if (seg->merge_lv)
|
||||
outf(f, "merge = \"%s\"", seg->merge_lv->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -519,7 +528,7 @@ static int _thin_add_target_line(struct dev_manager *dm,
|
||||
struct cmd_context *cmd __attribute__((unused)),
|
||||
void **target_state __attribute__((unused)),
|
||||
struct lv_segment *seg,
|
||||
const struct lv_activate_opts *laopts __attribute__((unused)),
|
||||
const struct lv_activate_opts *laopts,
|
||||
struct dm_tree_node *node, uint64_t len,
|
||||
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
||||
{
|
||||
@ -537,6 +546,21 @@ static int _thin_add_target_line(struct dev_manager *dm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!laopts->no_merging) {
|
||||
/*
|
||||
* merge support for thinp snapshots is implemented by
|
||||
* simply swapping the thinp device_id of the snapshot
|
||||
* and origin.
|
||||
*/
|
||||
if (seg->merge_lv) {
|
||||
/* snapshot, use merging lv's device_id */
|
||||
device_id = first_seg(seg->merge_lv)->device_id;
|
||||
} else if (lv_is_merging_origin(seg->lv)) {
|
||||
/* origin, use merging snapshot's device_id */
|
||||
device_id = find_snapshot(seg->lv)->device_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm_tree_node_add_thin_target(node, len, pool_dlid, device_id))
|
||||
return_0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user