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

Thin supports snapshots

Full support for thin snapshots.
Create and remove is supported.

TODO: lvconvert support is not yes available.
This commit is contained in:
Zdenek Kabelac 2011-11-07 11:03:47 +00:00
parent e903e37d0a
commit 97d7e5aedb
7 changed files with 89 additions and 24 deletions

View File

@ -255,9 +255,16 @@ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
dm_list_init(&seg->thin_messages); dm_list_init(&seg->thin_messages);
if (thin_pool_lv) { if (thin_pool_lv) {
seg->transaction_id = first_seg(thin_pool_lv)->transaction_id; /* If this thin volume, thin snapshot is being created */
if (!attach_pool_lv(seg, thin_pool_lv)) if (lv_is_thin_volume(thin_pool_lv)) {
return_NULL; 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))
return_NULL;
} else {
seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
if (!attach_pool_lv(seg, thin_pool_lv, NULL))
return_NULL;
}
} }
if (log_lv && !attach_mirror_log(seg, log_lv)) if (log_lv && !attach_mirror_log(seg, log_lv))
@ -4004,8 +4011,20 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
status |= lp->permission | VISIBLE_LV; status |= lp->permission | VISIBLE_LV;
/* FIXME Thin snapshots are different */ if (lp->snapshot && lp->thin) {
if (lp->snapshot) { if (!(org = find_lv(vg, lp->origin))) {
log_error("Couldn't find origin volume '%s'.",
lp->origin);
return NULL;
}
if (org->status & LOCKED) {
log_error("Snapshots of locked devices are not supported.");
return NULL;
}
lp->voriginextents = org->le_count;
} else if (lp->snapshot) {
if (!activation()) { if (!activation()) {
log_error("Can't create snapshot without using " log_error("Can't create snapshot without using "
"device-mapper kernel driver"); "device-mapper kernel driver");
@ -4074,7 +4093,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
return NULL; return NULL;
} }
if (lp->snapshot && (lp->extents * vg->extent_size < 2 * lp->chunk_size)) { if (lp->snapshot && !lp->thin && (lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
log_error("Unable to create a snapshot smaller than 2 chunks."); log_error("Unable to create a snapshot smaller than 2 chunks.");
return NULL; return NULL;
} }
@ -4105,7 +4124,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
} }
/* The snapshot segment gets created later */ /* The snapshot segment gets created later */
if (lp->snapshot && if (lp->snapshot && !lp->thin &&
!(lp->segtype = get_segtype_from_string(cmd, "striped"))) !(lp->segtype = get_segtype_from_string(cmd, "striped")))
return_NULL; return_NULL;
@ -4173,7 +4192,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
lp->mirrors, lp->mirrors,
seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size, seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size,
seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents, seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents,
seg_is_thin_volume(lp) ? lp->pool : NULL, lp->pvh, lp->alloc)) seg_is_thin_volume(lp) ? (org ? org->name : lp->pool) : NULL, lp->pvh, lp->alloc))
return_NULL; return_NULL;
if (seg_is_thin_pool(lp)) { if (seg_is_thin_pool(lp)) {
@ -4221,6 +4240,24 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
init_dmeventd_monitor(lp->activation_monitoring); init_dmeventd_monitor(lp->activation_monitoring);
if (seg_is_thin(lp)) { if (seg_is_thin(lp)) {
/* For thin snapshot suspend active thin origin first */
if (org && lv_is_active(org)) {
if (!suspend_lv(cmd, org)) {
log_error("Failed to suspend thin origin %s.",
org->name);
goto revert_new_lv;
} else if (!resume_lv(cmd, org)) {
log_error("Failed to resume thin origin %s.",
org->name);
goto revert_new_lv;
}
/* At this point snapshot is active in kernel thin mda */
if (!update_pool_lv(first_seg(org)->pool_lv, 0)) {
stack;
goto deactivate_and_revert_new_lv;
}
}
if (((lp->activate == CHANGE_AY) || if (((lp->activate == CHANGE_AY) ||
(lp->activate == CHANGE_AE) || (lp->activate == CHANGE_AE) ||
(lp->activate == CHANGE_ALY))) { (lp->activate == CHANGE_ALY))) {
@ -4261,7 +4298,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct l
goto deactivate_and_revert_new_lv; goto deactivate_and_revert_new_lv;
} }
if (lp->snapshot) { if (lp->snapshot && !lp->thin) {
/* Reset permission after zeroing */ /* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE)) if (!(lp->permission & LVM_WRITE))
lv->status &= ~LVM_WRITE; lv->status &= ~LVM_WRITE;

View File

@ -373,6 +373,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
seg_found++; seg_found++;
if (seg->pool_metadata_lv == lv || seg->pool_lv == lv) if (seg->pool_metadata_lv == lv || seg->pool_lv == lv)
seg_found++; seg_found++;
if (seg_is_thin_volume(seg) && seg->origin == lv)
seg_found++;
if (!seg_found) { if (!seg_found) {
log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32 log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32
", but missing ptr from %s to %s", ", but missing ptr from %s to %s",

View File

@ -456,7 +456,8 @@ int attach_pool_metadata_lv(struct lv_segment *seg,
struct logical_volume *pool_metadata_lv); struct logical_volume *pool_metadata_lv);
int attach_pool_data_lv(struct lv_segment *seg, int attach_pool_data_lv(struct lv_segment *seg,
struct logical_volume *pool_data_lv); struct logical_volume *pool_data_lv);
int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv); int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
struct logical_volume *origin_lv);
int detach_pool_lv(struct lv_segment *seg); int detach_pool_lv(struct lv_segment *seg);
int attach_pool_message(struct lv_segment *seg, dm_thin_message_t type, int attach_pool_message(struct lv_segment *seg, dm_thin_message_t type,
struct logical_volume *lv, uint32_t delete_id, struct logical_volume *lv, uint32_t delete_id,

View File

@ -39,10 +39,15 @@ int attach_pool_data_lv(struct lv_segment *seg, struct logical_volume *pool_data
return 1; return 1;
} }
int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv) int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
struct logical_volume *origin)
{ {
seg->pool_lv = pool_lv; seg->pool_lv = pool_lv;
seg->lv->status |= THIN_VOLUME; seg->lv->status |= THIN_VOLUME;
seg->origin = origin;
if (origin && !add_seg_to_segs_using_this_lv(origin, seg))
return_0;
return add_seg_to_segs_using_this_lv(pool_lv, seg); return add_seg_to_segs_using_this_lv(pool_lv, seg);
} }
@ -50,6 +55,7 @@ int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv)
int detach_pool_lv(struct lv_segment *seg) int detach_pool_lv(struct lv_segment *seg)
{ {
struct lv_thin_message *tmsg, *tmp; struct lv_thin_message *tmsg, *tmp;
struct seg_list *sl, *tsl;
if (!seg->pool_lv || !lv_is_thin_pool(seg->pool_lv)) { if (!seg->pool_lv || !lv_is_thin_pool(seg->pool_lv)) {
log_error(INTERNAL_ERROR "LV %s is not a thin volume", log_error(INTERNAL_ERROR "LV %s is not a thin volume",
@ -78,7 +84,30 @@ int detach_pool_lv(struct lv_segment *seg)
NULL, seg->device_id, 0)) NULL, seg->device_id, 0))
return_0; return_0;
return remove_seg_from_segs_using_this_lv(seg->pool_lv, seg); if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg))
return_0;
if (seg->origin &&
!remove_seg_from_segs_using_this_lv(seg->origin, seg))
return_0;
/* If thin origin, remove it from related thin snapshots */
/*
* TODO: map removal of origin as snapshot lvconvert --merge?
* i.e. rename thin snapshot to origin thin origin
*/
dm_list_iterate_items_safe(sl, tsl, &seg->lv->segs_using_this_lv) {
if (!seg_is_thin_volume(sl->seg) ||
(seg->lv != sl->seg->origin))
continue;
if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg))
return_0;
/* Thin snapshot is now regular thin volume */
sl->seg->origin = NULL;
}
return 1;
} }
int attach_pool_message(struct lv_segment *seg, dm_thin_message_t type, int attach_pool_message(struct lv_segment *seg, dm_thin_message_t type,

View File

@ -309,6 +309,9 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
if (lv_is_cow(lv)) if (lv_is_cow(lv))
return _lvname_disp(rh, mem, field, origin_from_cow(lv), private); return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private);
dm_report_field_set_value(field, "", NULL); dm_report_field_set_value(field, "", NULL);
return 1; return 1;
} }

View File

@ -317,7 +317,7 @@ static int _thin_text_import(struct lv_segment *seg,
struct dm_hash_table *pv_hash __attribute__((unused))) struct dm_hash_table *pv_hash __attribute__((unused)))
{ {
const char *lv_name; const char *lv_name;
struct logical_volume *pool_lv; struct logical_volume *pool_lv, *origin = NULL;
if (!dm_config_get_str(sn, "thin_pool", &lv_name)) if (!dm_config_get_str(sn, "thin_pool", &lv_name))
return SEG_LOG_ERROR("Thin pool must be a string in"); return SEG_LOG_ERROR("Thin pool must be a string in");
@ -325,9 +325,6 @@ static int _thin_text_import(struct lv_segment *seg,
if (!(pool_lv = find_lv(seg->lv->vg, lv_name))) if (!(pool_lv = find_lv(seg->lv->vg, lv_name)))
return SEG_LOG_ERROR("Unknown thin pool %s in", lv_name); return SEG_LOG_ERROR("Unknown thin pool %s in", lv_name);
if (!attach_pool_lv(seg, pool_lv))
return_0;
if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id)) if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id))
return SEG_LOG_ERROR("Could not read transaction_id for"); return SEG_LOG_ERROR("Could not read transaction_id for");
@ -335,7 +332,7 @@ static int _thin_text_import(struct lv_segment *seg,
if (!dm_config_get_str(sn, "origin", &lv_name)) if (!dm_config_get_str(sn, "origin", &lv_name))
return SEG_LOG_ERROR("Origin must be a string in"); return SEG_LOG_ERROR("Origin must be a string in");
if (!(seg->origin = find_lv(seg->lv->vg, lv_name))) if (!(origin = find_lv(seg->lv->vg, lv_name)))
return SEG_LOG_ERROR("Unknown origin %s in", lv_name); return SEG_LOG_ERROR("Unknown origin %s in", lv_name);
} }
@ -346,6 +343,9 @@ static int _thin_text_import(struct lv_segment *seg,
return SEG_LOG_ERROR("Unsupported value %u for device_id", return SEG_LOG_ERROR("Unsupported value %u for device_id",
seg->device_id); seg->device_id);
if (!attach_pool_lv(seg, pool_lv, origin))
return_0;
return 1; return 1;
} }

View File

@ -1013,13 +1013,6 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
lp.pool, lp.vg_name, lp.snapshot ? " as snapshot of " : "", lp.pool, lp.vg_name, lp.snapshot ? " as snapshot of " : "",
lp.snapshot ? lp.origin : "", lp.segtype->name); lp.snapshot ? lp.origin : "", lp.segtype->name);
/* FIXME Remove when thin snapshots are supported. */
if (lp.thin && lp.snapshot) {
log_error("Thin snapshots are not yet supported.");
r = ECMD_FAILED;
goto_out;
}
if (!lv_create_single(vg, &lp)) { if (!lv_create_single(vg, &lp)) {
stack; stack;
r = ECMD_FAILED; r = ECMD_FAILED;