* [PATCH 1/6] thin: add support for external origin
2013-02-05 13:56 [PATCH 0/6] Thin external origin support Zdenek Kabelac
@ 2013-02-05 13:56 ` Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 2/6] thin: external origin cannot be changed Zdenek Kabelac
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Zdenek Kabelac @ 2013-02-05 13:56 UTC (permalink / raw)
To: lvm-devel
Add internal support for thin volume's external origin.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/activate/dev_manager.c | 40 ++++++++++++++++++++++++++++++++
lib/format_text/flags.c | 3 ++-
lib/metadata/lv.c | 2 +-
lib/metadata/lv_manip.c | 5 +++-
lib/metadata/merge.c | 7 +++++-
lib/metadata/metadata-exported.h | 5 +++-
lib/metadata/metadata.h | 5 +++-
lib/metadata/thin_manip.c | 50 ++++++++++++++++++++++++++++++++++++++++
lib/thin/thin.c | 33 ++++++++++++++++++++++----
9 files changed, 140 insertions(+), 10 deletions(-)
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index e8f449c..db64f26 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -1565,6 +1565,7 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
/* FIXME Can we avoid doing this every time? */
+ /* Reused also for lv_is_external_origin(lv) */
if (!_add_dev_to_dtree(dm, dtree, lv, "real"))
return_0;
@@ -1605,6 +1606,11 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
dm_tree_node_skip_children(thin_node, 1);
#endif
} else {
+ /* Add external origin */
+ if (seg->external_lv &&
+ !_add_dev_to_dtree(dm, dtree, seg->external_lv,
+ lv_layer(seg->external_lv)))
+ return_0;
/* Add thin pool LV layer */
lv = seg->pool_lv;
seg = first_seg(lv);
@@ -1832,6 +1838,28 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
return 1;
}
+static int _add_external_origin_target_to_dtree(struct dev_manager *dm,
+ struct dm_tree_node *dnode,
+ struct logical_volume *lv)
+{
+ const char *layer_dlid;
+
+ if (!(layer_dlid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv))))
+ return_0;
+
+ /* Add linear mapping to layered external origin */
+ if (!add_linear_area_to_dtree(dnode,
+ (uint64_t)lv->vg->extent_size * lv->le_count,
+ lv->vg->extent_size,
+ lv->vg->cmd->use_linear_target,
+ lv->vg->name, lv->name) ||
+ !dm_tree_node_add_target_area(dnode, NULL, layer_dlid, 0))
+ return_0;
+
+ return 1;
+}
+
+
static int _add_origin_target_to_dtree(struct dev_manager *dm,
struct dm_tree_node *dnode,
struct logical_volume *lv)
@@ -2020,6 +2048,18 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
return 0;
}
+ /* Add external origin */
+ if (seg->external_lv &&
+ !_add_new_lv_to_dtree(dm, dtree, seg->external_lv, laopts,
+ lv_layer(seg->external_lv)))
+ return_0;
+ else if (!layer && lv_is_external_origin(seg->lv)) {
+ if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, laopts,
+ lv_layer(seg->lv)))
+ return_0;
+ return _add_external_origin_target_to_dtree(dm, dnode, seg->lv);
+ }
+
/* Add mirror log */
if (seg->log_lv &&
!_add_new_lv_to_dtree(dm, dtree, seg->log_lv, laopts, NULL))
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index a3a3d0e..66e4bde 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -58,6 +58,7 @@ static const struct flag _lv_flags[] = {
{LOCKED, "LOCKED", STATUS_FLAG},
{LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
{LV_REBUILD, "REBUILD", STATUS_FLAG},
+ {EXTERNAL_ORIGIN, NULL, 0},
{RAID, NULL, 0},
{RAID_META, NULL, 0},
{RAID_IMAGE, NULL, 0},
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index c27ef08..9f6b327 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -229,7 +229,7 @@ const char *lv_layer(const struct logical_volume *lv)
{
if (lv_is_thin_pool(lv))
return "tpool";
- else if (lv_is_origin(lv))
+ else if (lv_is_origin(lv) || lv_is_external_origin(lv))
return "real";
return NULL;
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 50e42dc..07d3fd7 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -278,6 +278,9 @@ struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
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;
+ /* Use the same external origin */
+ if (!attach_thin_external_origin(seg, first_seg(thin_pool_lv)->external_lv))
+ return_NULL;
} else {
seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
if (!attach_pool_lv(seg, thin_pool_lv, NULL))
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index a4563f8..477d7bb 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -243,6 +243,11 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
lv->name, seg_count, seg->device_id);
inc_error_count;
}
+ if (seg->external_lv && (seg->external_lv->status & LVM_WRITE)) {
+ log_error("LV %s: external origin %s is writable.",
+ lv->name, seg->external_lv->name);
+ inc_error_count;
+ }
} else {
if (seg->pool_lv) {
log_error("LV %s: segment %u must not have thin pool LV set",
@@ -372,7 +377,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
seg_found++;
if (seg->metadata_lv == lv || seg->pool_lv == lv)
seg_found++;
- if (seg_is_thin_volume(seg) && seg->origin == lv)
+ if (seg_is_thin_volume(seg) && (seg->origin == lv || seg->external_lv == lv))
seg_found++;
if (!seg_found) {
log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index ffec129..202ab2d 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -89,6 +89,7 @@
#define THIN_POOL UINT64_C(0x0000002000000000) /* LV */
#define THIN_POOL_DATA UINT64_C(0x0000004000000000) /* LV */
#define THIN_POOL_METADATA UINT64_C(0x0000008000000000) /* LV */
+#define EXTERNAL_ORIGIN UINT64_C(0x0000010000000000) /* LV */
#define LVM_READ UINT64_C(0x00000100) /* LV, VG */
#define LVM_WRITE UINT64_C(0x00000200) /* LV, VG */
@@ -141,6 +142,7 @@
#define lv_is_used_thin_pool(lv) (lv_is_thin_pool(lv) && !dm_list_empty(&(lv)->segs_using_this_lv))
#define lv_is_thin_pool_data(lv) ((lv)->status & THIN_POOL_DATA ? 1 : 0)
#define lv_is_thin_pool_metadata(lv) ((lv)->status & THIN_POOL_METADATA ? 1 : 0)
+#define lv_is_external_origin(lv) ((lv)->status & EXTERNAL_ORIGIN ? 1 : 0)
#define lv_is_mirrored(lv) ((lv)->status & MIRRORED ? 1 : 0)
#define lv_is_rlog(lv) ((lv)->status & REPLICATOR_LOG ? 1 : 0)
@@ -355,6 +357,7 @@ struct lv_segment {
unsigned zero_new_blocks; /* For thin_pool */
thin_discards_t discards; /* For thin_pool */
struct dm_list thin_messages; /* For thin_pool */
+ struct logical_volume *external_lv; /* For thin */
struct logical_volume *pool_lv; /* For thin */
uint32_t device_id; /* For thin, 24bit */
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 8a80147..9ee455c 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -476,6 +476,9 @@ int pool_is_active(const struct lv_segment *pool_seg);
int pool_below_threshold(const struct lv_segment *pool_seg);
int extend_pool(struct logical_volume *lv, const struct segment_type *segtype,
struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size);
+int attach_thin_external_origin(struct lv_segment *seg,
+ struct logical_volume *external_lv);
+int detach_thin_external_origin(struct lv_segment *seg);
/*
* Begin skeleton for external LVM library
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
index 6ec97d4..3eca06b 100644
--- a/lib/metadata/thin_manip.c
+++ b/lib/metadata/thin_manip.c
@@ -108,6 +108,9 @@ int detach_pool_lv(struct lv_segment *seg)
}
}
+ if (!detach_thin_external_origin(seg))
+ return_0;
+
if (!attach_pool_message(first_seg(seg->pool_lv),
DM_THIN_MESSAGE_DELETE,
NULL, seg->device_id, no_update))
@@ -198,6 +201,53 @@ int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
return 1;
}
+int attach_thin_external_origin(struct lv_segment *seg,
+ struct logical_volume *external_lv)
+{
+ seg->external_lv = external_lv;
+
+ if (external_lv) {
+ if (!add_seg_to_segs_using_this_lv(external_lv, seg))
+ return_0;
+
+ external_lv->status |= EXTERNAL_ORIGIN;
+
+ if (external_lv->status & LVM_WRITE) {
+ log_verbose("Setting logical volume \"%s\" read-only.",
+ external_lv->name);
+ external_lv->status &= ~LVM_WRITE;
+ }
+ }
+
+ return 1;
+}
+
+int detach_thin_external_origin(struct lv_segment *seg)
+{
+ if (seg->external_lv) {
+ if (!lv_is_external_origin(seg->external_lv)) {
+ log_error(INTERNAL_ERROR "Inconsitent external origin.");
+ return 0;
+ }
+
+ if (!remove_seg_from_segs_using_this_lv(seg->external_lv, seg))
+ return_0;
+
+ if (dm_list_empty(&seg->external_lv->segs_using_this_lv)) {
+ seg->external_lv->status &= ~EXTERNAL_ORIGIN;
+
+ /* FIXME - we do not keep original state */
+ //log_verbose("Setting logical volume \"%s\" writable",
+ // seg->external_lv->name);
+ //seg->external_lv->status |= LVM_WRITE;
+ }
+
+ seg->external_lv = NULL;
+ }
+
+ return 1;
+}
+
/*
* 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.
diff --git a/lib/thin/thin.c b/lib/thin/thin.c
index 8c0ec82..807e0ee 100644
--- a/lib/thin/thin.c
+++ b/lib/thin/thin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -439,7 +439,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;
+ struct logical_volume *pool_lv, *origin = NULL, *external_lv = NULL;
if (!dm_config_get_str(sn, "thin_pool", &lv_name))
return SEG_LOG_ERROR("Thin pool must be a string in");
@@ -465,9 +465,20 @@ static int _thin_text_import(struct lv_segment *seg,
return SEG_LOG_ERROR("Unsupported value %u for device_id",
seg->device_id);
+ if (dm_config_has_node(sn, "external_origin")) {
+ if (!dm_config_get_str(sn, "external_origin", &lv_name))
+ return SEG_LOG_ERROR("External origin must be a string in");
+
+ if (!(external_lv = find_lv(seg->lv->vg, lv_name)))
+ return SEG_LOG_ERROR("Unknown external origin %s in", lv_name);
+ }
+
if (!attach_pool_lv(seg, pool_lv, origin))
return_0;
+ if (!attach_thin_external_origin(seg, external_lv))
+ return_0;
+
return 1;
}
@@ -477,6 +488,8 @@ static int _thin_text_export(const struct lv_segment *seg, struct formatter *f)
outf(f, "transaction_id = %" PRIu64, seg->transaction_id);
outf(f, "device_id = %d", seg->device_id);
+ if (seg->external_lv)
+ outf(f, "external_origin = \"%s\"", seg->external_lv->name);
if (seg->origin)
outf(f, "origin = \"%s\"", seg->origin->name);
@@ -493,10 +506,10 @@ static int _thin_add_target_line(struct dev_manager *dm,
struct dm_tree_node *node, uint64_t len,
uint32_t *pvmove_mirror_count __attribute__((unused)))
{
- char *pool_dlid;
+ char *pool_dlid, *external_dlid;
uint32_t device_id = seg->device_id;
- if (!(pool_dlid = build_dm_uuid(mem, seg->pool_lv->lvid.s, "tpool"))) {
+ if (!(pool_dlid = build_dm_uuid(mem, seg->pool_lv->lvid.s, lv_layer(seg->pool_lv)))) {
log_error("Failed to build uuid for pool LV %s.",
seg->pool_lv->name);
return 0;
@@ -505,6 +518,18 @@ static int _thin_add_target_line(struct dev_manager *dm,
if (!dm_tree_node_add_thin_target(node, len, pool_dlid, device_id))
return_0;
+ /* Add external origin LV */
+ if (seg->external_lv) {
+ if (!(external_dlid = build_dm_uuid(mem, seg->external_lv->lvid.s,
+ lv_layer(seg->external_lv)))) {
+ log_error("Failed to build uuid for external origin LV %s.",
+ seg->external_lv->name);
+ return 0;
+ }
+ if (!dm_tree_node_set_thin_external_origin(node, external_dlid))
+ return_0;
+ }
+
return 1;
}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/6] thin: external origin cannot be changed
2013-02-05 13:56 [PATCH 0/6] Thin external origin support Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 1/6] thin: add support for external origin Zdenek Kabelac
@ 2013-02-05 13:56 ` Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 3/6] thin: report external origin Zdenek Kabelac
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Zdenek Kabelac @ 2013-02-05 13:56 UTC (permalink / raw)
To: lvm-devel
Do not allow conversion of external origin into writeable LV,
and prohibit changing the external origin size.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
tools/lvchange.c | 6 ++++++
tools/lvresize.c | 9 +++++++++
2 files changed, 15 insertions(+)
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 0ea2e78..7ac4a39 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -36,6 +36,12 @@ static int lvchange_permission(struct cmd_context *cmd,
return 0;
}
+ if (lv_is_external_origin(lv)) {
+ log_error("Cannot change permissions of external origin "
+ "\"%s\".", lv->name);
+ return 0;
+ }
+
if ((lv->status & MIRRORED) && (vg_is_clustered(lv->vg)) &&
lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) {
log_error("Cannot change permissions of mirror \"%s\" "
diff --git a/tools/lvresize.c b/tools/lvresize.c
index 4c9580d..d49da8a 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -390,6 +390,15 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
+ if (lv_is_external_origin(lvl->lv)) {
+ /*
+ * Since external-origin can be activated read-only,
+ * there is no way to use extended areas.
+ */
+ log_error("Cannot resize external origin \"%s\".", lvl->lv->name);
+ return EINVALID_CMD_LINE;
+ }
+
if (lvl->lv->status & (RAID_IMAGE | RAID_META)) {
log_error("Cannot resize a RAID %s directly",
(lvl->lv->status & RAID_IMAGE) ? "image" :
--
1.8.1.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/6] thin: report external origin
2013-02-05 13:56 [PATCH 0/6] Thin external origin support Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 1/6] thin: add support for external origin Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 2/6] thin: external origin cannot be changed Zdenek Kabelac
@ 2013-02-05 13:56 ` Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 4/6] thin: removal of " Zdenek Kabelac
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Zdenek Kabelac @ 2013-02-05 13:56 UTC (permalink / raw)
To: lvm-devel
Use the field 'origin' for reporting external origin lv name.
For thin volumes with external origin, report the size of
external origin size via:
lvs -o+origin_size
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/metadata/lv.c | 7 ++++++-
lib/report/report.c | 3 +++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index 9f6b327..f1c79be 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -169,6 +169,9 @@ char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv)
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
return lv_name_dup(mem, first_seg(lv)->origin);
+ if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
+ return lv_name_dup(mem, first_seg(lv)->external_lv);
+
return NULL;
}
@@ -282,6 +285,8 @@ uint64_t lv_origin_size(const struct logical_volume *lv)
{
if (lv_is_cow(lv))
return (uint64_t) find_cow(lv)->len * lv->vg->extent_size;
+ if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
+ return first_seg(lv)->external_lv->size;
if (lv_is_origin(lv))
return lv->size;
return 0;
diff --git a/lib/report/report.c b/lib/report/report.c
index 5a4e4df..633dfe4 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -343,6 +343,9 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private);
+ if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
+ return _lvname_disp(rh, mem, field, first_seg(lv)->external_lv, private);
+
dm_report_field_set_value(field, "", NULL);
return 1;
}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/6] thin: removal of external origin
2013-02-05 13:56 [PATCH 0/6] Thin external origin support Zdenek Kabelac
` (2 preceding siblings ...)
2013-02-05 13:56 ` [PATCH 3/6] thin: report external origin Zdenek Kabelac
@ 2013-02-05 13:56 ` Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 5/6] thin: lvconvert support for " Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 6/6] tests: lvconvert " Zdenek Kabelac
5 siblings, 0 replies; 7+ messages in thread
From: Zdenek Kabelac @ 2013-02-05 13:56 UTC (permalink / raw)
To: lvm-devel
If the removal of external origin is requested,
query if the user also want to remove all its users.
Create common static function _lv_remove_segs_using_this_lv()
so the same code can be shared with thin pool removal.
Note: the function cannot use dm_list_iterate_items_safe()
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/metadata/lv_manip.c | 57 +++++++++++++++++++++++++++++++++++--------------
1 file changed, 41 insertions(+), 16 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 07d3fd7..11bd3a4 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -3309,6 +3309,12 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
+ if (lv_is_external_origin(lv)) {
+ log_error("Can't remove external origin logical volume \"%s\".",
+ lv->name);
+ return 0;
+ }
+
if (lv->status & MIRROR_IMAGE) {
log_error("Can't remove logical volume %s used by a mirror",
lv->name);
@@ -3448,6 +3454,35 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
return 1;
}
+static int _lv_remove_segs_using_this_lv(struct cmd_context *cmd, struct logical_volume *lv,
+ const force_t force, unsigned level,
+ const char *lv_type)
+{
+ struct seg_list *sl;
+
+ if ((force == PROMPT) &&
+ yes_no_prompt("Removing %s \"%s\" will remove %u dependent volume(s). "
+ "Proceed? [y/n]: ", lv_type, lv->name,
+ dm_list_size(&lv->segs_using_this_lv)) == 'n') {
+ log_error("Logical volume \"%s\" not removed.", lv->name);
+ return 0;
+ }
+ /*
+ * Not using _safe iterator here - since we may delete whole subtree
+ * (similar as process_each_lv_in_vg())
+ * the code is roughly equivalent to this:
+ *
+ * while (!dm_list_empty(&lv->segs_using_this_lv))
+ * dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+ * break;
+ */
+ dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+ if (!lv_remove_with_dependencies(cmd, sl->seg->lv,
+ force, level + 1))
+ return_0;
+
+ return 1;
+}
/*
* remove LVs with its dependencies - LV leaf nodes should be removed first
*/
@@ -3456,7 +3491,6 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
{
percent_t snap_percent;
struct dm_list *snh, *snht;
- struct seg_list *sl, *tsl;
struct lvinfo info;
if (lv_is_cow(lv)) {
@@ -3507,22 +3541,13 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
return_0;
}
- if (lv_is_used_thin_pool(lv)) {
- /* Remove thin LVs first */
- if ((force == PROMPT) &&
- yes_no_prompt("Removing pool %s will also remove %u "
- "thin volume(s). OK? [y/n]: ", lv->name,
- /* Note: Snaphosts not included */
- dm_list_size(&lv->segs_using_this_lv)) == 'n') {
- log_error("Logical volume %s not removed.", lv->name);
- return 0;
- }
+ if (lv_is_external_origin(lv) &&
+ !_lv_remove_segs_using_this_lv(cmd, lv, force, level, "external origin"))
+ return_0;
- dm_list_iterate_items_safe(sl, tsl, &lv->segs_using_this_lv)
- if (!lv_remove_with_dependencies(cmd, sl->seg->lv,
- force, level + 1))
- return_0;
- }
+ if (lv_is_used_thin_pool(lv) &&
+ !_lv_remove_segs_using_this_lv(cmd, lv, force, level, "pool"))
+ return_0;
return lv_remove_single(cmd, lv, force);
}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 5/6] thin: lvconvert support for external origin
2013-02-05 13:56 [PATCH 0/6] Thin external origin support Zdenek Kabelac
` (3 preceding siblings ...)
2013-02-05 13:56 ` [PATCH 4/6] thin: removal of " Zdenek Kabelac
@ 2013-02-05 13:56 ` Zdenek Kabelac
2013-02-05 13:56 ` [PATCH 6/6] tests: lvconvert " Zdenek Kabelac
5 siblings, 0 replies; 7+ messages in thread
From: Zdenek Kabelac @ 2013-02-05 13:56 UTC (permalink / raw)
To: lvm-devel
Add basic support for converting LV into an external origin volume.
Syntax:
lvconvert --thinpool vg/pool --originname renamed_origin -T origin
It will convert volume 'origin' into a thin volume, which will
use 'renamed_origin' as an external read-only origin.
All read/write into origin will go via 'pool'.
renamed_origin volume is read-only volume, that could be activated
only in read-only mode, and cannot be modified.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/activate/activate.c | 6 +-
man/lvconvert.8.in | 32 +++++++++
tools/args.h | 3 +-
tools/commands.h | 7 +-
tools/lvconvert.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 210 insertions(+), 11 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 6187828..f19dff7 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -1580,6 +1580,10 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
(lv_is_origin(lv_pre) || lv_is_cow(lv_pre)))
lockfs = 1;
+ /* Converting non-thin LV to thin external origin ? */
+ if (!lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
+ lockfs = 1; /* Sync before conversion */
+
if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
lockfs = 1;
diff --git a/man/lvconvert.8.in b/man/lvconvert.8.in
index 578047b..c5929c2 100644
--- a/man/lvconvert.8.in
+++ b/man/lvconvert.8.in
@@ -99,6 +99,10 @@ lvconvert \- convert a logical volume from linear to mirror or snapshot
.RB [ \-h | \-? | \-\-help ]
.RB [ \-v | \-\-verbose ]
.RB [ \-\-version ]
+.RB [ \-T | \-\-thin
+.IR ExternalOriginLogicalVolume { Name | Path }
+.RB [ \-\-originname
+.IR NewExternalOriginVolumeName ]]
.RI [ PhysicalVolume [ Path ][ :PE [ -PE ]]...]
.sp
@@ -230,6 +234,13 @@ merge finishes, the merged snapshot is removed. Multiple snapshots may
be specified on the commandline or a @tag may be used to specify
multiple snapshots be merged to their respective origin.
.TP
+.B \-\-originname \fINewExternalOriginVolumeName\fP
+The name for converted external origin volume.
+.br
+Without this option a default names of "lvol#" will be generated where
+# is the LVM internal number of the logical volume.
+Converted volume will be read-only.
+.TP
.BR \-\-poolmetadata " " \fIThinPoolMetadataLogicalVolume { \fIName | \fIPath }
Specifies thin pool metadata logical volume.
The size should be in between 2MiB and 16GiB.
@@ -288,6 +299,13 @@ StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format.
For metadata in LVM2 format, the stripe size may be a larger
power of 2 but must not exceed the physical extent size.
.TP
+.IR \fB\-T ", " \fB\-\-thin " " ExternalOriginLogicalVolume { Name | Path }
+Changes the logical volume into a thin volume for the thin pool
+specified with the option \fB\-\-thinpool\fP. \fIExternalOriginLogicalVolume\fP
+is converted into a new read-only logical volume which will be used as an
+external origin volume for unprovisioned areas.
+The non-default name for this new volume can be specified with \fB\-\-originname\fP.
+.TP
.IR \fB\-\-thinpool " " ThinPoolLogicalVolume { Name | Path }
Changes logical volume into a thin pool volume. The volume
will store the pool's data.
@@ -379,6 +397,20 @@ available in the volume group.
.sp
.B lvconvert \-\-replace /dev/sdb1 vg00/my_raid1 /dev/sdf1
+Convert the logical volume "vg00/lvpool" into a thin pool with chunk size 128KiB
+and convert "vg00/lv1" into a thin volume using this pool. Original "vg00/lv1"
+is used as an external read-only origin, where all writes to such volume
+are stored in the "vg00/lvpool".
+.sp
+.B lvconvert \-\-thinpool vg00/lvpool -c 128 -T lv1
+
+Convert the logical volume "vg00/origin" into a thin volume from the thin pool
+"vg00/lvpool". This thin volume will use "vg00/origin" as an external origin
+volume for unprovisioned areas in this volume.
+For the read-only external origin use the new name "vg00/external".
+.sp
+.B lvconvert \-\-thinpool vg00/lvpool \-\-originname external -T vg00/origin
+
.SH SEE ALSO
.BR lvm (8),
.BR vgcreate (8),
diff --git a/tools/args.h b/tools/args.h
index d4d6c40..b140cdb 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -69,6 +69,7 @@ arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0)
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0)
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
+arg(originname_ARG, '\0', "originname", string_arg, 0)
arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0)
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index 986539e..32d3c96 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -151,6 +151,8 @@ xx(lvconvert,
"\t [--poolmetadatasize size]\n"
"\t [-r|--readahead ReadAheadSectors|auto|none]\n"
"\t [--stripes Stripes [-I|--stripesize StripeSize]]]\n"
+ "\t[-T|--thin ExternalLogicalVolume[Path]\n"
+ "\t [--originname NewExternalOriginVolumeName]]\n"
"\t[-Z|--zero {y|n}]\n"
"\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n",
@@ -158,7 +160,8 @@ xx(lvconvert,
merge_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG, noudevsync_ARG,
readahead_ARG, regionsize_ARG, repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG,
trackchanges_ARG, type_ARG, stripes_long_ARG, stripesize_ARG, test_ARG,
- chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG, thinpool_ARG,
+ chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG,
+ originname_ARG, thin_ARG, thinpool_ARG,
use_policies_ARG, yes_ARG, force_ARG, zero_ARG)
xx(lvcreate,
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 0e15888..133b456 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -57,6 +57,7 @@ struct lvconvert_params {
struct logical_volume *lv_to_poll;
uint64_t poolmetadata_size;
+ const char *origin_lv_name;
const char *pool_data_lv_name;
const char *pool_metadata_lv_name;
thin_discards_t discards;
@@ -68,6 +69,7 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
{
char *ptr;
const char *vg_name = NULL;
+ const char *tmp_str;
if (lp->merge)
return 1;
@@ -94,16 +96,35 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
if (lp->pool_data_lv_name) {
if (*pargc) {
- log_error("More then one logical volume name name specified.");
- return 0;
+ if (!arg_count(cmd, thin_ARG)) {
+ log_error("More then one logical volume name specified.");
+ return 0;
+ }
+ } else {
+ if (arg_count(cmd, thin_ARG)) {
+ log_error("External thin volume name is missing.");
+ return 0;
+ }
+
+ if (!lp->vg_name || !validate_name(lp->vg_name)) {
+ log_error("Please provide a valid volume group name.");
+ return 0;
+ }
+
+ lp->lv_name = lp->pool_data_lv_name;
+ return 1;
}
+ }
- if (!lp->vg_name || !validate_name(lp->vg_name)) {
- log_error("Please provide a valid volume group name.");
- return 0;
+ if (lp->origin_lv_name) {
+ /* FIXME: Using generic routine */
+ if (strchr(lp->origin_lv_name, '/')) {
+ if (!(lp->vg_name = extract_vgname(cmd, lp->origin_lv_name)))
+ return_0;
+ /* Strip VG from origin_lv_name */
+ if ((tmp_str = strrchr(lp->origin_lv_name, '/')))
+ lp->origin_lv_name = tmp_str + 1;
}
- lp->lv_name = lp->pool_data_lv_name;
- return 1; /* Create metadata LV on it's own */
}
if (!*pargc) {
@@ -219,6 +240,9 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0;
}
lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
+ } else if (arg_count(cmd, thin_ARG)) {
+ log_error("--thin is only valid with --thinpool.");
+ return 0;
} else if (arg_count(cmd, discards_ARG)) {
log_error("--discards is only valid with --thinpool.");
return 0;
@@ -376,6 +400,13 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
lp->pool_data_lv_name = tmp_str + 1;
}
+ if (arg_count(cmd, originname_ARG)) {
+ if (!(lp->origin_lv_name = arg_str_value(cmd, originname_ARG, NULL))) {
+ log_error("--originname is invalid.");
+ return 0;
+ }
+ }
+
lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "thin-pool"));
if (!lp->segtype)
return_0;
@@ -1827,6 +1858,115 @@ out:
return r;
}
+/* Swap lvid and LV names */
+static int _swap_lv(struct cmd_context *cmd,
+ struct logical_volume *a, struct logical_volume *b)
+{
+ union lvid lvid;
+ const char *name;
+
+ lvid = a->lvid;
+ a->lvid = b->lvid;
+ b->lvid = lvid;
+
+ name = a->name;
+ a->name = b->name;
+ if (!lv_rename_update(cmd, b, name, 0))
+ return_0;
+
+ return 1;
+}
+
+static int _lvconvert_thinpool_external(struct cmd_context *cmd,
+ struct logical_volume *pool_lv,
+ struct logical_volume *external_lv,
+ struct lvconvert_params *lp)
+{
+ struct logical_volume *torigin_lv;
+ struct volume_group *vg = pool_lv->vg;
+ struct lvcreate_params lvc = { 0 };
+
+ dm_list_init(&lvc.tags);
+
+ if (!(lvc.segtype = get_segtype_from_string(cmd, "thin")))
+ return_0;
+
+ lvc.activate = CHANGE_AE;
+ lvc.alloc = ALLOC_INHERIT;
+ lvc.lv_name = lp->origin_lv_name;
+ lvc.major = -1;
+ lvc.minor = -1;
+ lvc.permission = LVM_READ;
+ lvc.pool = pool_lv->name;
+ lvc.pvh = &vg->pvs;
+ lvc.read_ahead = DM_READ_AHEAD_AUTO;
+ lvc.stripes = 1;
+ lvc.vg_name = vg->name;
+ lvc.voriginextents = external_lv->le_count;
+ lvc.voriginsize = external_lv->size;
+
+ /* New thin LV needs to be created (all messages sent to pool) */
+ if (!(torigin_lv = lv_create_single(vg, &lvc)))
+ return_0;
+
+ /* Activate again via -torigin, so this active LV is not needed */
+ if (!deactivate_lv(cmd, torigin_lv)) {
+ log_error("Aborting. Unable to deactivate new LV. "
+ "Manual intervention required.");
+ return 0;
+ }
+
+ /*
+ * Crashing till this point will leave plain thin volume
+ * which could be easily removed by the user after i.e. power-off
+ */
+
+ if (!_swap_lv(cmd, torigin_lv, external_lv)) {
+ stack;
+ goto revert_new_lv;
+ }
+
+ /* FIXME: is that useful to preserve status here ? */
+ torigin_lv->status |= (external_lv->status & LVM_WRITE);
+
+ if (!attach_thin_external_origin(first_seg(torigin_lv), external_lv)) {
+ goto revert_new_lv;
+ }
+
+ if (!_reload_lv(cmd, vg, torigin_lv)) {
+ stack;
+ goto deactivate_and_revert_new_lv;
+ }
+
+ log_print_unless_silent("Converted %s/%s to thin external origin.",
+ vg->name, external_lv->name);
+
+ return 1;
+
+deactivate_and_revert_new_lv:
+ if (!_swap_lv(cmd, torigin_lv, external_lv))
+ stack;
+
+ if (!deactivate_lv(cmd, torigin_lv)) {
+ log_error("Unable to deactivate failed new LV. "
+ "Manual intervention required.");
+ return 0;
+ }
+
+ if (!detach_thin_external_origin(first_seg(torigin_lv)))
+ return_0;
+
+revert_new_lv:
+ /* FIXME Better to revert to backup of metadata? */
+ if (!lv_remove(torigin_lv) || !vg_write(vg) || !vg_commit(vg))
+ log_error("Manual intervention may be required to remove "
+ "abandoned LV(s) before retrying.");
+ else
+ backup(vg);
+
+ return 0;
+}
+
/*
* Thin lvconvert version which
* rename metadata
@@ -1845,6 +1985,7 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
struct logical_volume *data_lv;
struct logical_volume *metadata_lv;
struct logical_volume *pool_metadata_lv;
+ struct logical_volume *external_lv = NULL;
if (!lv_is_visible(pool_lv)) {
log_error("Can't convert internal LV %s/%s.",
@@ -1852,6 +1993,19 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
return 0;
}
+ if (arg_count(cmd, thin_ARG)) {
+ external_lv = pool_lv;
+ if (!(pool_lv = find_lv(external_lv->vg, lp->pool_data_lv_name))) {
+ log_error("Can't find pool LV %s/%s.",
+ external_lv->vg->name, lp->pool_data_lv_name);
+ return 0;
+ }
+ if (lv_is_thin_pool(pool_lv)) {
+ r = 1; /* Already existing thin pool */
+ goto out;
+ }
+ }
+
if (lv_is_thin_type(pool_lv) && !lp->pool_metadata_lv_name) {
log_error("Can't use thin logical volume %s/%s for thin pool data.",
pool_lv->vg->name, pool_lv->name);
@@ -2066,7 +2220,12 @@ mda_write:
r = 1;
out:
+ if (r && external_lv &&
+ !(r = _lvconvert_thinpool_external(cmd, pool_lv, external_lv, lp)))
+ stack;
+
backup(pool_lv->vg);
+
return r;
}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 6/6] tests: lvconvert external origin
2013-02-05 13:56 [PATCH 0/6] Thin external origin support Zdenek Kabelac
` (4 preceding siblings ...)
2013-02-05 13:56 ` [PATCH 5/6] thin: lvconvert support for " Zdenek Kabelac
@ 2013-02-05 13:56 ` Zdenek Kabelac
5 siblings, 0 replies; 7+ messages in thread
From: Zdenek Kabelac @ 2013-02-05 13:56 UTC (permalink / raw)
To: lvm-devel
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
test/shell/lvconvert-thin-external.sh | 82 +++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 test/shell/lvconvert-thin-external.sh
diff --git a/test/shell/lvconvert-thin-external.sh b/test/shell/lvconvert-thin-external.sh
new file mode 100644
index 0000000..06fc731
--- /dev/null
+++ b/test/shell/lvconvert-thin-external.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# Copyright (C) 2013 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# test thin external origin behavior
+
+. lib/test
+
+#
+# Main
+#
+aux have_thin 1 5 0 || skip
+
+aux prepare_pvs 2 64
+
+vgcreate $vg -s 64K $(cat DEVICES)
+
+# create thin pool
+lvcreate -L8M -T $vg/pool
+
+# create plain LV
+lvcreate -L8M -n $lv1 $vg
+
+mkfs.ext4 $DM_DEV_DIR/$vg/$lv1
+mkdir mnt
+mount $DM_DEV_DIR/$vg/$lv1 mnt
+
+dd if=/dev/zero of=mnt/test1 bs=1M count=1
+
+# convert plain LV into thin external snapshot volume
+# during conversion dd above could be still flushed
+
+lvconvert -T --originname extorg --thinpool $vg/pool $vg/$lv1
+
+check active $vg $lv1
+check inactive $vg extorg
+
+touch mnt/test
+umount mnt
+
+fsck $DM_DEV_DIR/$vg/$lv1
+
+lvchange -ay $vg/extorg
+lvchange -an $vg/$lv1
+
+check active $vg extorg
+check inactive $vg $lv1
+
+# fsck in read-only mode
+fsck -n $DM_DEV_DIR/$vg/extorg
+
+not lvresize -l+8 $vg/extorg
+not lvresize -l-4 $vg/extorg
+not lvchange -p rw $vg/extorg
+
+lvresize -L+8M $vg/$lv1
+lvresize -L-4M $vg/$lv1
+lvchange -p r $vg/$lv1
+lvchange -p rw $vg/$lv1
+
+lvconvert --originname extorg1 --thinpool $vg/pool -T $vg/extorg
+lvconvert --originname extorglv1 --thinpool $vg/pool -T $vg/extorg1
+
+lvcreate -l10 -s $vg/$lv1
+
+# Remove all volumes dependent on external origin
+lvremove -f $vg/extorglv1
+
+#lvs -a -o+origin_size,seg_size $vg
+
+# Only pool is left
+check vg_field $vg lv_count 1
+
+vgremove -ff $vg
--
1.8.1.2
^ permalink raw reply related [flat|nested] 7+ messages in thread