master - vdo: with created names use vpool
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4b7a57c9ed5187e3239...
Commit: 4b7a57c9ed5187e32394a983e08be3b4a0b19079
Parent: a8f84f78015326125c4884046014a5b93fded77f
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jul 3 20:14:48 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
vdo: with created names use vpool
When user create vdo-pool - use different automatic name.
So unlike with traditional LVs using lvol0, lvol1
use vpool0, vpool1...
TODO: apply similar for thin-pool & cache-pool...
---
lib/metadata/lv_manip.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index b731c2a..2dfe994 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -8125,8 +8125,8 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
/* The VDO segment needs VDO pool which is layer above created striped data LV */
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_VDO_POOL)))
return_NULL;
-
- if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
+ /* Use vpool names for vdo-pool */
+ if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name ? : "vpool%d")))
return_NULL;
} else {
log_error(INTERNAL_ERROR "Creation of pool for unsupported segment type %s.",
5 years, 9 months
master - vdo: introduce segment types and manip functions
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=a8f84f78015326125c4...
Commit: a8f84f78015326125c4884046014a5b93fded77f
Parent: c66a960149ae28f057bc1a91d6974e92fc572c30
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jun 29 11:11:14 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
vdo: introduce segment types and manip functions
Core functionality introducing lvm VDO support.
---
lib/Makefile.in | 5 +
lib/activate/activate.h | 1 +
lib/activate/dev_manager.c | 6 +-
lib/commands/toolcontext.c | 5 +
lib/format_text/flags.c | 3 +
lib/metadata/lv.c | 3 +
lib/metadata/lv_manip.c | 93 +++++++-
lib/metadata/metadata-exported.h | 29 ++-
lib/metadata/segtype.h | 12 +
lib/metadata/vdo_manip.c | 269 +++++++++++++++++++++
lib/misc/lvm-string.c | 2 +
lib/vdo/vdo.c | 484 ++++++++++++++++++++++++++++++++++++++
12 files changed, 903 insertions(+), 9 deletions(-)
diff --git a/lib/Makefile.in b/lib/Makefile.in
index ead443e..737208b 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -77,6 +77,7 @@ SOURCES =\
metadata/segtype.c \
metadata/snapshot_manip.c \
metadata/thin_manip.c \
+ metadata/vdo_manip.c \
metadata/vg.c \
mirror/mirrored.c \
misc/crc.c \
@@ -126,6 +127,10 @@ ifeq ("@BUILD_LVMLOCKD@", "yes")
locking/lvmlockd.c
endif
+ifeq ("@VDO@", "internal")
+ SOURCES += vdo/vdo.c
+endif
+
LIB_NAME = liblvm-internal
LIB_STATIC = $(LIB_NAME).a
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
index 5d77f40..09cd688 100644
--- a/lib/activate/activate.h
+++ b/lib/activate/activate.h
@@ -261,6 +261,7 @@ void fs_unlock(void);
#define TARGET_NAME_STRIPED "striped"
#define TARGET_NAME_THIN "thin"
#define TARGET_NAME_THIN_POOL "thin-pool"
+#define TARGET_NAME_VDO "vdo"
#define TARGET_NAME_ZERO "zero"
#define MODULE_NAME_CLUSTERED_MIRROR "clog"
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 3e4ec86..07fc93e 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -45,7 +45,7 @@ typedef enum {
} action_t;
/* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
-const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "tdata", "tmeta", NULL};
+const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "tdata", "tmeta", "vdata", "vpool", NULL};
struct dlid_list {
struct dm_list list;
@@ -275,6 +275,10 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
(length > DM_THIN_MAX_METADATA_SIZE))
length = DM_THIN_MAX_METADATA_SIZE;
+ /* Uses virtual size with headers for VDO pool device */
+ if (lv_is_vdo_pool(seg_status->seg->lv))
+ length = get_vdo_pool_virtual_size(seg_status->seg);
+
do {
target = dm_get_next_target(dmt, target, &target_start,
&target_length, &target_name, &target_params);
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index eb15581..ec44bdb 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -1399,6 +1399,11 @@ static int _init_segtypes(struct cmd_context *cmd)
return 0;
#endif
+#ifdef VDO_INTERNAL
+ if (!init_vdo_segtypes(cmd, &seglib))
+ return_0;
+#endif
+
#ifdef HAVE_LIBDL
/* Load any formats in shared libs unless static */
if (!is_static() &&
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index 98894e7..6f5ff9f 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -98,6 +98,9 @@ static const struct flag _lv_flags[] = {
{CACHE_POOL, NULL, 0},
{CACHE_POOL_DATA, NULL, 0},
{CACHE_POOL_METADATA, NULL, 0},
+ {LV_VDO, NULL, 0},
+ {LV_VDO_POOL, NULL, 0},
+ {LV_VDO_POOL_DATA, NULL, 0},
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
{LV_REMOVED, NULL, 0},
{0, NULL, 0}
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index 7ab06cb..cf6fafa 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -797,6 +797,9 @@ const char *lv_layer(const struct logical_volume *lv)
if (lv_is_thin_pool(lv))
return "tpool";
+ if (lv_is_vdo_pool(lv))
+ return "vpool";
+
if (lv_is_origin(lv) || lv_is_external_origin(lv))
return "real";
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 6bf851e..b731c2a 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1034,6 +1034,7 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
if (lv_is_mirror_image(lv) ||
lv_is_thin_pool_data(lv) ||
+ lv_is_vdo_pool_data(lv) ||
lv_is_cache_pool_data(lv)) {
if (!lv_reduce(lv, area_reduction))
return_0; /* FIXME: any upper level reporting */
@@ -1102,6 +1103,10 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
seg_type(seg, s) = AREA_UNASSIGNED;
}
+ /* When removed last VDO user automatically removes VDO pool */
+ if (lv_is_vdo_pool(lv) && dm_list_empty(&(lv->segs_using_this_lv)))
+ return lv_remove(lv); /* FIXME: any upper level reporting */
+
return 1;
}
@@ -3265,11 +3270,46 @@ static int _allocate(struct alloc_handle *ah,
return r;
}
+/*
+ * FIXME: Add proper allocation function for VDO segment on top
+ * of VDO pool with virtual size.
+ *
+ * Note: ATM lvm2 can't resize VDO device so it can add only a single segment.
+ */
+static int _lv_add_vdo_segment(struct logical_volume *lv, uint64_t status,
+ uint32_t extents, const struct segment_type *segtype)
+{
+ struct lv_segment *seg;
+
+ if (!dm_list_empty(&lv->segments) &&
+ (seg = last_seg(lv)) && (seg->segtype == segtype)) {
+ seg->area_len += extents;
+ seg->len += extents;
+ } else {
+ if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count, extents, 0,
+ status, 0, NULL, 1,
+ extents, 0, 0, 0, 0, NULL))) {
+ log_error("Couldn't allocate new %s segment.", segtype->name);
+ return 0;
+ }
+ lv->status |= LV_VDO;
+ dm_list_add(&lv->segments, &seg->list);
+ }
+
+ lv->le_count += extents;
+ lv->size += (uint64_t) extents * lv->vg->extent_size;
+
+ return 1;
+}
+
int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status,
uint32_t extents, const struct segment_type *segtype)
{
struct lv_segment *seg;
+ if (segtype_is_vdo(segtype))
+ return _lv_add_vdo_segment(lv, 0u, extents, segtype);
+
if (!dm_list_empty(&lv->segments) &&
(seg = last_seg(lv)) && (seg->segtype == segtype)) {
seg->area_len += extents;
@@ -4362,7 +4402,9 @@ static int _rename_cb(struct logical_volume *lv, void *data)
static int _rename_skip_pools_externals_cb(struct logical_volume *lv, void *data)
{
- if (lv_is_pool(lv) || lv_is_external_origin(lv))
+ if (lv_is_pool(lv) ||
+ lv_is_vdo_pool(lv) ||
+ lv_is_external_origin(lv))
return -1; /* and skip subLVs */
return _rename_cb(lv, data);
@@ -4458,6 +4500,7 @@ int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv,
* (thin pool is 'visible', but cache may not)
*/
if (!lv_is_pool(lv) &&
+ !lv_is_vdo_pool(lv) &&
!lv_is_visible(lv)) {
log_error("Cannot rename internal LV \"%s\".", lv->name);
return 0;
@@ -6351,6 +6394,13 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
!_lv_remove_segs_using_this_lv(cmd, lv, force, level, "pool"))
return_0;
+ if (lv_is_vdo_pool(lv)) {
+ if (!_lv_remove_segs_using_this_lv(cmd, lv, force, level, "VDO pool"))
+ return_0;
+ /* Last user removes VDO pool itself, lv no longer exists */
+ return 1;
+ }
+
if (lv_is_cache_pool(lv) && !lv_is_used_cache_pool(lv)) {
if (!deactivate_lv(cmd, first_seg(lv)->metadata_lv) ||
!deactivate_lv(cmd, seg_lv(first_seg(lv),0))) {
@@ -6787,7 +6837,7 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
uint64_t status,
const char *layer_suffix)
{
- static const char _suffixes[][8] = { "_tdata", "_cdata", "_corig" };
+ static const char _suffixes[][8] = { "_tdata", "_cdata", "_corig", "_vdata" };
int r;
char name[NAME_LEN];
struct dm_str_list *sl;
@@ -7386,6 +7436,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
seg_is_mirror(lp) ||
(seg_is_raid(lp) && !seg_is_raid0(lp)) ||
seg_is_thin(lp) ||
+ seg_is_vdo(lp) ||
lp->snapshot) {
/*
* FIXME: For thin pool add some code to allow delayed
@@ -7451,7 +7502,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (seg_is_pool(lp))
status |= LVM_WRITE; /* Pool is always writable */
- else if (seg_is_cache(lp) || seg_is_thin_volume(lp)) {
+ else if (seg_is_cache(lp) || seg_is_thin_volume(lp) || seg_is_vdo(lp)) {
/* Resolve pool volume */
if (!lp->pool_name) {
/* Should be already checked */
@@ -7619,6 +7670,16 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
status |= LVM_WRITE;
lp->zero = 1;
lp->wipe_signatures = 0;
+ } else if (seg_is_vdo_pool(lp)) {
+ if (!lp->virtual_extents)
+ log_verbose("Virtual size matching available free logical size in VDO pool.");
+
+ if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
+ return_NULL;
+
+ /* Must zero and format data area */
+ status |= LVM_WRITE;
+ lp->zero = 1;
}
if (!segtype_is_virtual(create_segtype) && !lp->approx_alloc &&
@@ -7648,7 +7709,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
log_debug_metadata("Setting read ahead sectors %u.", lv->read_ahead);
}
- if (!segtype_is_pool(create_segtype) && lp->minor >= 0) {
+ if (!segtype_is_pool(create_segtype) &&
+ !segtype_is_vdo_pool(create_segtype) &&
+ lp->minor >= 0) {
lv->major = lp->major;
lv->minor = lp->minor;
lv->status |= FIXED_MINOR;
@@ -7670,7 +7733,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
lp->stripes, lp->stripe_size,
lp->mirrors,
segtype_is_pool(create_segtype) ? lp->pool_metadata_extents : lp->region_size,
- segtype_is_thin_volume(create_segtype) ? lp->virtual_extents : lp->extents,
+ (segtype_is_thin_volume(create_segtype) ||
+ segtype_is_vdo(create_segtype)) ? lp->virtual_extents : lp->extents,
lp->pvh, lp->alloc, lp->approx_alloc)) {
unlink_lv_from_vg(lv); /* Keep VG consistent and remove LV without any segment */
return_NULL;
@@ -7686,6 +7750,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
/* Unlock memory if possible */
memlock_unlock(vg->cmd);
+ if (segtype_is_vdo(create_segtype) && pool_lv) {
+ if (!set_lv_segment_area_lv(first_seg(lv), 0, pool_lv, 0, LV_VDO_POOL))
+ return_NULL;
+ }
+
if (lv_is_cache_pool(lv)) {
if (!cache_set_params(first_seg(lv),
lp->chunk_size,
@@ -7886,7 +7955,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
- if (seg_is_cache(lp) || (origin_lv && lv_is_cache_pool(lv))) {
+ if (seg_is_vdo_pool(lp)) {
+ if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents)) {
+ stack;
+ goto deactivate_and_revert_new_lv;
+ }
+ } else if (seg_is_cache(lp) || (origin_lv && lv_is_cache_pool(lv))) {
/* Finish cache conversion magic */
if (origin_lv) {
/* Convert origin to cached LV */
@@ -8047,6 +8121,13 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
log_print_unless_silent("Logical volume %s is now cached.",
display_lvname(lv));
return lv;
+ } else if (seg_is_vdo(lp)) {
+ /* The VDO segment needs VDO pool which is layer above created striped data LV */
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_VDO_POOL)))
+ return_NULL;
+
+ if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
+ return_NULL;
} else {
log_error(INTERNAL_ERROR "Creation of pool for unsupported segment type %s.",
lp->segtype->name);
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 501d0fa..4a9f2e0 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-2017 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -145,7 +145,12 @@
#define LV_RESHAPE UINT64_C(0x1000000000000000) /* Ongoing reshape (number of stripes, stripesize or raid algorithm change):
used as SEGTYPE_FLAG to prevent activation on old runtime */
#define LV_RESHAPE_DATA_OFFSET UINT64_C(0x2000000000000000) /* LV reshape flag data offset (out of place reshaping) */
-/* Next unused flag: UINT64_C(0x8000000000000000) */
+
+
+#define LV_VDO UINT64_C(0x0000000020000000) /* LV - Internal user only */
+#define LV_VDO_POOL UINT64_C(0x0000000040000000) /* LV - Internal user only */
+#define LV_VDO_POOL_DATA UINT64_C(0x8000000000000000) /* LV - Internal user only */
+
/* Format features flags */
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
@@ -251,6 +256,11 @@
#define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
#define lv_is_lockd_sanlock_lv(lv) (((lv)->status & LOCKD_SANLOCK_LV) ? 1 : 0)
+#define lv_is_vdo(lv) (((lv)->status & LV_VDO) ? 1 : 0)
+#define lv_is_vdo_pool(lv) (((lv)->status & LV_VDO_POOL) ? 1 : 0)
+#define lv_is_vdo_pool_data(lv) (((lv)->status & LV_VDO_POOL_DATA) ? 1 : 0)
+#define lv_is_vdo_type(lv) (((lv)->status & (LV_VDO | LV_VDO_POOL | LV_VDO_POOL_DATA)) ? 1 : 0)
+
#define lv_is_removed(lv) (((lv)->status & LV_REMOVED) ? 1 : 0)
/* Recognize component LV (matching lib/misc/lvm-string.c _lvname_has_reserved_component_string()) */
@@ -487,6 +497,10 @@ struct lv_segment {
const char *policy_name; /* For cache_pool */
struct dm_config_node *policy_settings; /* For cache_pool */
unsigned cleaner_policy; /* For cache */
+
+ struct dm_vdo_target_params vdo_params; /* For VDO-pool */
+ uint32_t vdo_pool_header_size; /* For VDO-pool */
+ uint32_t vdo_pool_virtual_extents; /* For VDO-pool */
};
#define seg_type(seg, s) (seg)->areas[(s)].type
@@ -950,6 +964,7 @@ struct lvcreate_params {
uint32_t read_ahead; /* all */
int approx_alloc; /* all */
alloc_policy_t alloc; /* all */
+ struct dm_vdo_target_params vdo_params; /* vdo */
struct dm_list tags; /* all */
@@ -1232,6 +1247,16 @@ int lv_cache_remove(struct logical_volume *cache_lv);
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
/* -- metadata/cache_manip.c */
+
+/* ++ metadata/vdo_manip.c */
+
+uint64_t get_vdo_pool_virtual_size(const struct lv_segment *vdo_pool_seg);
+struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
+ const struct dm_vdo_target_params *vtp,
+ uint32_t *virtual_extents);
+int get_vdo_write_policy(enum dm_vdo_write_policy *vwp, const char *policy);
+/* -- metadata/vdo_manip.c */
+
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
struct device *dev, uint64_t lv_type);
const struct logical_volume *find_pvmove_lv_in_lv(const struct logical_volume *lv);
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index 5484c23..6fdf075 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -69,6 +69,8 @@ struct dev_manager;
#define SEG_STRIPED_TARGET (1ULL << 39)
#define SEG_LINEAR_TARGET (1ULL << 40)
+#define SEG_VDO (1ULL << 41)
+#define SEG_VDO_POOL (1ULL << 42)
#define SEG_UNKNOWN (1ULL << 63)
@@ -83,6 +85,8 @@ struct dev_manager;
#define SEG_TYPE_NAME_ERROR "error"
#define SEG_TYPE_NAME_FREE "free"
#define SEG_TYPE_NAME_ZERO "zero"
+#define SEG_TYPE_NAME_VDO "vdo"
+#define SEG_TYPE_NAME_VDO_POOL "vdo-pool"
#define SEG_TYPE_NAME_RAID "raid"
#define SEG_TYPE_NAME_RAID0 "raid0"
#define SEG_TYPE_NAME_RAID0_META "raid0_meta"
@@ -151,6 +155,8 @@ struct dev_manager;
#define segtype_is_thin(segtype) ((segtype)->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0)
#define segtype_is_thin_pool(segtype) ((segtype)->flags & SEG_THIN_POOL ? 1 : 0)
#define segtype_is_thin_volume(segtype) ((segtype)->flags & SEG_THIN_VOLUME ? 1 : 0)
+#define segtype_is_vdo(segtype) ((segtype)->flags & SEG_VDO ? 1 : 0)
+#define segtype_is_vdo_pool(segtype) ((segtype)->flags & SEG_VDO_POOL ? 1 : 0)
#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
#define segtype_is_unknown(segtype) ((segtype)->flags & SEG_UNKNOWN ? 1 : 0)
@@ -202,6 +208,8 @@ struct dev_manager;
#define seg_is_thin(seg) segtype_is_thin((seg)->segtype)
#define seg_is_thin_pool(seg) segtype_is_thin_pool((seg)->segtype)
#define seg_is_thin_volume(seg) segtype_is_thin_volume((seg)->segtype)
+#define seg_is_vdo(seg) segtype_is_vdo((seg)->segtype)
+#define seg_is_vdo_pool(seg) segtype_is_vdo_pool((seg)->segtype)
#define seg_is_virtual(seg) segtype_is_virtual((seg)->segtype)
#define seg_unknown(seg) segtype_is_unknown((seg)->segtype)
#define seg_can_split(seg) segtype_can_split((seg)->segtype)
@@ -329,6 +337,10 @@ int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
int init_cache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
#endif
+#ifdef VDO_INTERNAL
+int init_vdo_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
+#endif
+
#define CACHE_FEATURE_POLICY_MQ (1U << 0)
#define CACHE_FEATURE_POLICY_SMQ (1U << 1)
#define CACHE_FEATURE_METADATA2 (1U << 2)
diff --git a/lib/metadata/vdo_manip.c b/lib/metadata/vdo_manip.c
new file mode 100644
index 0000000..451c8bd
--- /dev/null
+++ b/lib/metadata/vdo_manip.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "lib/misc/lib.h"
+#include "lib/metadata/metadata.h"
+#include "lib/locking/locking.h"
+#include "lib/misc/lvm-string.h"
+#include "lib/commands/toolcontext.h"
+#include "lib/display/display.h"
+#include "lib/metadata/segtype.h"
+#include "lib/activate/activate.h"
+#include "lib/config/defaults.h"
+#include "lib/metadata/lv_alloc.h"
+#include "lib/misc/lvm-signal.h"
+#include "lib/misc/lvm-exec.h"
+
+
+/*
+ * Size of VDO virtual LV is adding header_size in front and back of device
+ * to avoid colission with blkid checks.
+ */
+static uint64_t _get_virtual_size(uint32_t extents, uint32_t extent_size,
+ uint32_t header_size)
+{
+ return (uint64_t) extents * extent_size + 2 * header_size;
+}
+
+uint64_t get_vdo_pool_virtual_size(const struct lv_segment *vdo_pool_seg)
+{
+ return _get_virtual_size(vdo_pool_seg->vdo_pool_virtual_extents,
+ vdo_pool_seg->lv->vg->extent_size,
+ vdo_pool_seg->vdo_pool_header_size);
+}
+
+/*
+ * Formats data LV for a use as a VDO pool LV.
+ *
+ * Calls tool 'vdoformat' on the already active volume.
+ */
+static int _format_vdo_pool_data_lv(struct logical_volume *data_lv,
+ const struct dm_vdo_target_params *vtp,
+ uint64_t *logical_size)
+{
+ char *dpath;
+ const struct dm_config_node *cn;
+ const struct dm_config_value *cv;
+ struct pipe_data pdata;
+ FILE *f;
+ uint64_t lb;
+ unsigned slabbits;
+ int args = 1;
+ char buf_args[5][128];
+ char buf[256]; /* buffer for short disk header (64B) */
+ const char *argv[19] = { /* Max supported args */
+ find_config_tree_str_allow_empty(data_lv->vg->cmd, global_vdo_format_executable_CFG, NULL)
+ };
+
+ if (!(dpath = lv_path_dup(data_lv->vg->cmd->mem, data_lv))) {
+ log_error("Failed to build device path for VDO formating of data volume %s.",
+ display_lvname(data_lv));
+ return 0;
+ }
+
+ if (*logical_size) {
+ if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--logical-size=" FMTu64 "K",
+ (*logical_size / 2)) < 0)
+ return_0;
+
+ argv[args] = buf_args[args];
+ args++;
+ }
+
+ slabbits = 31 - clz(vtp->slab_size_mb / DM_VDO_BLOCK_SIZE * 512);
+ log_debug("Slab size %s converted to %u bits.",
+ display_size(data_lv->vg->cmd, vtp->slab_size_mb * UINT64_C(2 * 1024)), slabbits);
+ if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--slab-bits=%u", slabbits) < 0)
+ return_0;
+
+ argv[args] = buf_args[args];
+ args++;
+
+ if (vtp->check_point_frequency) {
+ if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--uds-checkpoint-frequency=%u",
+ vtp->check_point_frequency) < 0)
+ return_0;
+ argv[args] = buf_args[args];
+ args++;
+ }
+
+ /* Convert size to GiB units or one of these strings: 0.25, 0.50, 0.75 */
+ if (vtp->index_memory_size_mb >= 1024) {
+ if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--uds-memory-size=%u",
+ vtp->index_memory_size_mb / 1024) < 0)
+ return_0;
+ } else if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--uds-memory-size=0.%u",
+ (vtp->index_memory_size_mb < 512) ? 25 :
+ (vtp->index_memory_size_mb < 768) ? 50 : 75) < 0)
+ return_0;
+
+ argv[args] = buf_args[args];
+ args++;
+
+ if (vtp->use_sparse_index) {
+ if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--uds-sparse") < 0)
+ return_0;
+
+ argv[args] = buf_args[args];
+ args++;
+ }
+
+ /* Any other user opts add here */
+ if (!(cn = find_config_tree_array(data_lv->vg->cmd, global_vdo_format_options_CFG, NULL))) {
+ log_error(INTERNAL_ERROR "Unable to find configuration for vdoformat command options.");
+ return 0;
+ }
+
+ for (cv = cn->v; cv && args < 16; cv = cv->next) {
+ if (cv->type != DM_CFG_STRING) {
+ log_error("Invalid string in config file: "
+ "global/vdoformat_options.");
+ return 0;
+ }
+ if (cv->v.str[0])
+ argv[++args] = cv->v.str;
+ }
+
+ /* Only unused VDO data LV could be activated and wiped */
+ if (!dm_list_empty(&data_lv->segs_using_this_lv)) {
+ log_error(INTERNAL_ERROR "Failed to wipe logical VDO data for volume %s.",
+ display_lvname(data_lv));
+ return 0;
+ }
+
+ argv[args] = dpath;
+
+ if (!(f = pipe_open(data_lv->vg->cmd, argv, 0, &pdata))) {
+ log_error("WARNING: Cannot read output from %s.", argv[0]);
+ return 0;
+ }
+
+ if (!*logical_size)
+ while (fgets(buf, sizeof(buf), f)) {
+ /* TODO: Watch out for locales */
+ if (sscanf(buf, "Logical blocks defaulted to " FMTu64 " blocks", &lb) == 1) {
+ *logical_size = lb * DM_VDO_BLOCK_SIZE;
+ log_verbose("Available VDO logical blocks " FMTu64 " (%s).",
+ lb, display_size(data_lv->vg->cmd, *logical_size));
+ break;
+ } else
+ log_warn("WARNING: Cannot parse output '%s' from %s.", buf, argv[0]);
+ }
+
+ if (!pipe_close(&pdata)) {
+ log_error("Command %s failed.", argv[0]);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * convert_vdo_pool_lv
+ * @data_lv
+ * @vtp
+ * @virtual_extents
+ *
+ * Convert given data LV and its target parameters into a VDO LV with VDO pool.
+ *
+ * Returns: old data LV on success (passed data LV becomes VDO LV), NULL on failure
+ */
+struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
+ const struct dm_vdo_target_params *vtp,
+ uint32_t *virtual_extents)
+{
+ const uint64_t header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
+ const uint32_t extent_size = data_lv->vg->extent_size;
+ struct cmd_context *cmd = data_lv->vg->cmd;
+ struct logical_volume *vdo_pool_lv = data_lv;
+ const struct segment_type *vdo_pool_segtype;
+ struct lv_segment *vdo_pool_seg;
+ uint64_t vdo_logical_size = 0;
+ uint64_t adjust;
+
+ if (!(vdo_pool_segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_VDO_POOL)))
+ return_NULL;
+
+ adjust = (*virtual_extents * (uint64_t) extent_size) % DM_VDO_BLOCK_SIZE;
+ if (adjust) {
+ *virtual_extents += (DM_VDO_BLOCK_SIZE - adjust) / extent_size;
+ log_print_unless_silent("Rounding size up to 4,00 KiB VDO logical extent boundary: %s.",
+ display_size(data_lv->vg->cmd, *virtual_extents * (uint64_t) extent_size));
+ }
+
+ if (*virtual_extents)
+ vdo_logical_size =
+ _get_virtual_size(*virtual_extents, extent_size, header_size);
+
+ if (!dm_vdo_validate_target_params(vtp, vdo_logical_size))
+ return_0;
+
+ /* Format data LV as VDO volume */
+ if (!_format_vdo_pool_data_lv(data_lv, vtp, &vdo_logical_size)) {
+ log_error("Cannot format VDO pool volume %s.", display_lvname(data_lv));
+ return NULL;
+ }
+
+ if (!deactivate_lv(data_lv->vg->cmd, data_lv)) {
+ log_error("Aborting. Manual intervention required.");
+ return NULL;
+ }
+
+ vdo_logical_size -= 2 * header_size;
+
+ if (vdo_logical_size < extent_size) {
+ if (!*virtual_extents)
+ /* User has not specified size and at least 1 extent is necessary */
+ log_error("Cannot create fully fitting VDO volume, "
+ "--virtualsize has to be specified.");
+
+ log_error("Size %s for VDO volume cannot be smaller then extent size %s.",
+ display_size(data_lv->vg->cmd, vdo_logical_size),
+ display_size(data_lv->vg->cmd, extent_size));
+ return NULL;
+ }
+
+ *virtual_extents = vdo_logical_size / extent_size;
+
+ /* Move segments from existing data_lv into LV_vdata */
+ if (!(data_lv = insert_layer_for_lv(cmd, vdo_pool_lv, 0, "_vdata")))
+ return_NULL;
+
+ vdo_pool_seg = first_seg(vdo_pool_lv);
+ vdo_pool_seg->segtype = vdo_pool_segtype;
+ vdo_pool_seg->vdo_params = *vtp;
+ vdo_pool_seg->vdo_pool_header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
+ vdo_pool_seg->vdo_pool_virtual_extents = *virtual_extents;
+
+ vdo_pool_lv->status |= LV_VDO_POOL;
+ data_lv->status |= LV_VDO_POOL_DATA;
+
+ return data_lv;
+}
+
+int get_vdo_write_policy(enum dm_vdo_write_policy *vwp, const char *policy)
+{
+ if (strcasecmp(policy, "sync") == 0)
+ *vwp = DM_VDO_WRITE_POLICY_SYNC;
+ else if (strcasecmp(policy, "async") == 0)
+ *vwp = DM_VDO_WRITE_POLICY_ASYNC;
+ else if (strcasecmp(policy, "auto") == 0)
+ *vwp = DM_VDO_WRITE_POLICY_AUTO;
+ else {
+ log_error("Unknown VDO write policy %s.", policy);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index 1e9af66..689a6b5 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -258,6 +258,8 @@ char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lv,
lv_is_thin_pool(lv) ? "pool" :
lv_is_thin_pool_data(lv) ? "tdata" :
lv_is_thin_pool_metadata(lv) ? "tmeta" :
+ lv_is_vdo_pool(lv) ? "vpool" :
+ lv_is_vdo_pool_data(lv) ? "vdata" :
NULL;
}
diff --git a/lib/vdo/vdo.c b/lib/vdo/vdo.c
new file mode 100644
index 0000000..a32ffcd
--- /dev/null
+++ b/lib/vdo/vdo.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "lib/misc/lib.h"
+#include "lib/activate/activate.h"
+#include "lib/activate/targets.h"
+#include "lib/commands/toolcontext.h"
+#include "lib/datastruct/str_list.h"
+#include "lib/display/display.h"
+#include "lib/format_text/text_export.h"
+#include "lib/log/lvm-logging.h"
+#include "lib/metadata/metadata.h"
+#include "lib/metadata/lv_alloc.h"
+#include "lib/metadata/segtype.h"
+#include "base/memory/zalloc.h"
+
+static unsigned _feature_mask;
+
+static int _bad_field(const char *field)
+{
+ log_error("Couldn't read '%s' for VDO segment.", field);
+ return 0;
+}
+
+static int _import_bool(const struct dm_config_node *n,
+ const char *name, bool *b)
+{
+ uint32_t t;
+
+ if (dm_config_has_node(n, name)) {
+ if (!dm_config_get_uint32(n, name, &t))
+ return _bad_field(name);
+
+ if (t) {
+ *b = true;
+ return 1;
+ }
+ }
+
+ *b = false;
+
+ return 1;
+}
+
+static void _print_yes_no(const char *name, bool value)
+{
+ log_print(" %s\t%s", name, value ? "yes" : "no");
+}
+
+/*
+ * VDO linear mapping
+ */
+static const char *_vdo_name(const struct lv_segment *seg)
+{
+ return SEG_TYPE_NAME_VDO;
+}
+
+static int _vdo_text_import(struct lv_segment *seg,
+ const struct dm_config_node *n,
+ struct dm_hash_table *pv_hash __attribute__((unused)))
+{
+ struct logical_volume *vdo_pool_lv;
+ const char *str;
+ uint32_t vdo_offset;
+
+ if (!dm_config_has_node(n, "vdo_pool") ||
+ !(str = dm_config_find_str(n, "vdo_pool", NULL)))
+ return _bad_field("vdo_pool");
+ if (!(vdo_pool_lv = find_lv(seg->lv->vg, str))) {
+ log_error("Unknown VDO pool logical volume %s.", str);
+ return 0;
+ }
+
+ if (!dm_config_get_uint32(n, "vdo_offset", &vdo_offset))
+ return _bad_field("vdo_offset");
+
+ if (!set_lv_segment_area_lv(seg, 0, vdo_pool_lv, vdo_offset, LV_VDO_POOL))
+ return_0;
+
+ seg->lv->status |= LV_VDO;
+
+ return 1;
+}
+
+static int _vdo_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+
+ if (!seg_is_vdo(seg)) {
+ log_error(INTERNAL_ERROR "Passed segment is not VDO type.");
+ return 0;
+ }
+
+ outf(f, "vdo_pool = \"%s\"", seg_lv(seg, 0)->name);
+ outf(f, "vdo_offset = %u", seg_le(seg, 0));
+
+ return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _vdo_target_status_compatible(const char *type)
+{
+ return (strcmp(type, TARGET_NAME_LINEAR) == 0);
+}
+
+static int _vdo_add_target_line(struct dev_manager *dm,
+ struct dm_pool *mem __attribute__((unused)),
+ struct cmd_context *cmd,
+ void **target_state __attribute__((unused)),
+ struct lv_segment *seg,
+ const struct lv_activate_opts *laopts __attribute__((unused)),
+ struct dm_tree_node *node, uint64_t len,
+ uint32_t *pvmove_mirror_count __attribute__((unused)))
+{
+ char *vdo_pool_uuid;
+
+ if (!(vdo_pool_uuid = build_dm_uuid(mem, seg_lv(seg, 0), lv_layer(seg_lv(seg, 0)))))
+ return_0;
+
+ if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size,
+ cmd->use_linear_target,
+ seg->lv->vg->name, seg->lv->name))
+ return_0;
+
+ if (!dm_tree_node_add_target_area(node, NULL, vdo_pool_uuid,
+ first_seg(seg_lv(seg, 0))->vdo_pool_header_size +
+ seg->lv->vg->extent_size * (uint64_t)seg_le(seg, 0)))
+ return_0;
+
+ return 1;
+}
+
+#endif
+
+/*
+ * VDO pool
+ */
+static const char *_vdo_pool_name(const struct lv_segment *seg)
+{
+ return SEG_TYPE_NAME_VDO_POOL;
+}
+
+/* reused as _vdo_text_import_area_count */
+static int _vdo_pool_text_import_area_count(const struct dm_config_node *sn __attribute__((unused)),
+ uint32_t *area_count)
+{
+ *area_count = 1;
+
+ return 1;
+}
+
+static int _vdo_pool_text_import(struct lv_segment *seg,
+ const struct dm_config_node *n,
+ struct dm_hash_table *pv_hash __attribute__((unused)))
+{
+ struct dm_vdo_target_params *vtp = &seg->vdo_params;
+ struct logical_volume *data_lv;
+ const char *str;
+
+ if (!dm_config_has_node(n, "data") ||
+ !(str = dm_config_find_str(n, "data", NULL)))
+ return _bad_field("data");
+ if (!(data_lv = find_lv(seg->lv->vg, str))) {
+ log_error("Unknown logical volume %s.", str);
+ return 0;
+ }
+
+ /*
+ * TODO: we may avoid printing settings with FIXED default values
+ * so it would generate smaller metadata.
+ */
+ if (!dm_config_get_uint32(n, "header_size", &seg->vdo_pool_header_size))
+ return _bad_field("header_size");
+
+ if (!dm_config_get_uint32(n, "virtual_extents", &seg->vdo_pool_virtual_extents))
+ return _bad_field("virtual_extents");
+
+ memset(vtp, 0, sizeof(*vtp));
+
+ if (!_import_bool(n, "use_compression", &vtp->use_compression))
+ return_0;
+
+ if (!_import_bool(n, "use_deduplication", &vtp->use_deduplication))
+ return_0;
+
+ if (!_import_bool(n, "emulate_512_sectors", &vtp->emulate_512_sectors))
+ return_0;
+
+ if (!dm_config_get_uint32(n, "block_map_cache_size_mb", &vtp->block_map_cache_size_mb))
+ return _bad_field("block_map_cache_size_mb");
+
+ if (!dm_config_get_uint32(n, "block_map_period", &vtp->block_map_period))
+ return _bad_field("block_map_period");
+
+ if (!_import_bool(n, "use_sparse_index", &vtp->use_sparse_index))
+ return_0;
+
+ if (!dm_config_get_uint32(n, "index_memory_size_mb", &vtp->index_memory_size_mb))
+ return _bad_field("index_memory_size_mb");
+
+ if (!_import_bool(n, "use_read_cache", &vtp->use_read_cache))
+ return_0;
+
+ if (!dm_config_get_uint32(n, "read_cache_size_mb", &vtp->read_cache_size_mb))
+ return _bad_field("read_cache_size_mb");
+
+ if (!dm_config_get_uint32(n, "slab_size_mb", &vtp->slab_size_mb))
+ return _bad_field("slab_size_mb");
+
+ if (!dm_config_get_uint32(n, "ack_threads", &vtp->ack_threads))
+ return _bad_field("ack_threads");
+
+ if (!dm_config_get_uint32(n, "bio_threads", &vtp->bio_threads))
+ return _bad_field("bio_threads");
+
+ if (!dm_config_get_uint32(n, "bio_rotation", &vtp->bio_rotation))
+ return _bad_field("bio_rotation");
+
+ if (!dm_config_get_uint32(n, "cpu_threads", &vtp->cpu_threads))
+ return _bad_field("cpu_threads");
+
+ if (!dm_config_get_uint32(n, "hash_zone_threads", &vtp->hash_zone_threads))
+ return _bad_field("hash_zone_threads");
+
+ if (!dm_config_get_uint32(n, "logical_threads", &vtp->logical_threads))
+ return _bad_field("logical_threads");
+
+ if (!dm_config_get_uint32(n, "physical_threads", &vtp->physical_threads))
+ return _bad_field("physical_threads");
+
+
+ if (!set_lv_segment_area_lv(seg, 0, data_lv, 0, LV_VDO_POOL_DATA))
+ return_0;
+
+ seg->lv->status |= LV_VDO_POOL;
+ lv_set_hidden(data_lv);
+
+ return 1;
+}
+
+static int _vdo_pool_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+ const struct dm_vdo_target_params *vtp = &seg->vdo_params;
+
+ outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
+ outsize(f, seg->vdo_pool_header_size, "header_size = %u\t",
+ seg->vdo_pool_header_size);
+ outsize(f, seg->vdo_pool_virtual_extents * (uint64_t) seg->lv->vg->extent_size,
+ "virtual_extents = %u\t", seg->vdo_pool_virtual_extents);
+
+ outnl(f);
+
+ if (vtp->use_compression)
+ outf(f, "use_compression = 1");
+ if (vtp->use_deduplication)
+ outf(f, "use_deduplication = 1");
+ if (vtp->emulate_512_sectors)
+ outf(f, "emulate_512_sectors = 1");
+
+ outsize(f, vtp->block_map_cache_size_mb * UINT64_C(2 * 1024),
+ "block_map_cache_size_mb = %u", vtp->block_map_cache_size_mb);
+ outf(f, "block_map_period = %u", vtp->block_map_period);
+
+ if (vtp->use_sparse_index)
+ outf(f, "use_sparse_index = 1");
+ // TODO - conditionally
+ outsize(f, vtp->index_memory_size_mb * UINT64_C(2 * 1024),
+ "index_memory_size_mb = %u", vtp->index_memory_size_mb);
+
+ if (vtp->use_read_cache)
+ outf(f, "use_read_cache = 1");
+ // TODO - conditionally
+ outsize(f, vtp->read_cache_size_mb * UINT64_C(2 * 1024),
+ "read_cache_size_mb = %u", vtp->read_cache_size_mb);
+ outsize(f, vtp->slab_size_mb * UINT64_C(2 * 1024),
+ "slab_size_mb = %u", vtp->slab_size_mb);
+ outf(f, "ack_threads = %u", (unsigned) vtp->ack_threads);
+ outf(f, "bio_threads = %u", (unsigned) vtp->bio_threads);
+ outf(f, "bio_rotation = %u", (unsigned) vtp->bio_rotation);
+ outf(f, "cpu_threads = %u", (unsigned) vtp->cpu_threads);
+ outf(f, "hash_zone_threads = %u", (unsigned) vtp->hash_zone_threads);
+ outf(f, "logical_threads = %u", (unsigned) vtp->logical_threads);
+ outf(f, "physical_threads = %u", (unsigned) vtp->physical_threads);
+
+ return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _vdo_pool_target_status_compatible(const char *type)
+{
+ return (strcmp(type, TARGET_NAME_VDO) == 0);
+}
+
+static int _vdo_pool_add_target_line(struct dev_manager *dm,
+ struct dm_pool *mem __attribute__((unused)),
+ struct cmd_context *cmd __attribute__((unused)),
+ void **target_state __attribute__((unused)),
+ struct lv_segment *seg,
+ const struct lv_activate_opts *laopts __attribute__((unused)),
+ struct dm_tree_node *node, uint64_t len,
+ uint32_t *pvmove_mirror_count __attribute__((unused)))
+{
+ char *data_uuid;
+
+ if (!seg_is_vdo_pool(seg)) {
+ log_error(INTERNAL_ERROR "Passed segment is not VDO pool.");
+ return 0;
+ }
+
+ if (!(data_uuid = build_dm_uuid(mem, seg_lv(seg, 0), lv_layer(seg_lv(seg, 0)))))
+ return_0;
+
+ /* VDO uses virtual size instead of its physical size */
+ if (!dm_tree_node_add_vdo_target(node, get_vdo_pool_virtual_size(seg),
+ data_uuid, &seg->vdo_params))
+ return_0;
+
+ return 1;
+}
+
+static int _vdo_target_present(struct cmd_context *cmd,
+ const struct lv_segment *seg __attribute__((unused)),
+ unsigned *attributes __attribute__((unused)))
+{
+ /* List of features with their kernel target version */
+ static const struct feature {
+ uint32_t maj;
+ uint32_t min;
+ unsigned vdo_feature;
+ const char *feature;
+ } _features[] = {
+ { 1, 1, 0, "" },
+ //{ 9, 9, VDO_FEATURE_RESIZE, "resize" },
+ };
+ //static const char _lvmconf[] = "global/vdo_disabled_features";
+ static int _vdo_checked = 0;
+ static int _vdo_present = 0;
+ static unsigned _vdo_attrs = 0;
+ uint32_t i, maj, min, patchlevel;
+ const struct segment_type *segtype;
+
+ if (!activation())
+ return 0;
+
+ if (!_vdo_checked) {
+ _vdo_checked = 1;
+
+ if (!target_present_version(cmd, TARGET_NAME_VDO, 0,
+ &maj, &min, &patchlevel)) {
+ /* Try to load kmod VDO module */
+ if (!module_present(cmd, MODULE_NAME_VDO) ||
+ !target_version(TARGET_NAME_VDO, &maj, &min, &patchlevel))
+ return_0;
+ }
+
+ if (maj < 6 || (maj == 6 && min < 2)) {
+ log_warn("WARNING: VDO target version %u.%u.%u is too old.",
+ maj, min, patchlevel);
+ return 0;
+ }
+
+ /* If stripe target was already detected, reuse its result */
+ if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)) ||
+ !segtype->ops->target_present || !segtype->ops->target_present(cmd, NULL, NULL)) {
+ /* Linear/Stripe targer is for mapping LVs on top of single VDO volume. */
+ if (!target_present(cmd, TARGET_NAME_LINEAR, 0) ||
+ !target_present(cmd, TARGET_NAME_STRIPED, 0))
+ return 0;
+ }
+
+ _vdo_present = 1;
+ /* Prepare for adding supported features */
+ for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
+ if ((maj > _features[i].maj) ||
+ (maj == _features[i].maj && min >= _features[i].min))
+ _vdo_attrs |= _features[i].vdo_feature;
+ else
+ log_very_verbose("Target %s does not support %s.",
+ TARGET_NAME_VDO,
+ _features[i].feature);
+ }
+
+ if (attributes) {
+ *attributes = _vdo_attrs & _feature_mask;
+ }
+
+ return _vdo_present;
+}
+
+static int _vdo_modules_needed(struct dm_pool *mem,
+ const struct lv_segment *seg __attribute__((unused)),
+ struct dm_list *modules)
+{
+ if (!str_list_add(mem, modules, MODULE_NAME_VDO)) {
+ log_error("String list allocation failed for VDO module.");
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+/* reused as _vdo_destroy */
+static void _vdo_pool_destroy(struct segment_type *segtype)
+{
+ free((void *)segtype->dso);
+ free((void *)segtype);
+}
+
+static struct segtype_handler _vdo_ops = {
+ .name = _vdo_name,
+ .text_import = _vdo_text_import,
+ .text_import_area_count = _vdo_pool_text_import_area_count,
+ .text_export = _vdo_text_export,
+
+#ifdef DEVMAPPER_SUPPORT
+ .target_status_compatible = _vdo_target_status_compatible,
+ .add_target_line = _vdo_add_target_line,
+ .target_present = _vdo_target_present,
+ .modules_needed = _vdo_modules_needed,
+#endif
+ .destroy = _vdo_pool_destroy,
+};
+
+static struct segtype_handler _vdo_pool_ops = {
+ .name = _vdo_pool_name,
+ .text_import = _vdo_pool_text_import,
+ .text_import_area_count = _vdo_pool_text_import_area_count,
+ .text_export = _vdo_pool_text_export,
+
+#ifdef DEVMAPPER_SUPPORT
+ .target_status_compatible = _vdo_pool_target_status_compatible,
+ .add_target_line = _vdo_pool_add_target_line,
+ .target_present = _vdo_target_present,
+ .modules_needed = _vdo_modules_needed,
+#endif
+ .destroy = _vdo_pool_destroy,
+};
+
+int init_vdo_segtypes(struct cmd_context *cmd,
+ struct segtype_library *seglib)
+{
+ struct segment_type *segtype, *pool_segtype;
+
+ if (!(segtype = zalloc(sizeof(*segtype))) ||
+ !(pool_segtype = zalloc(sizeof(*segtype)))) {
+ log_error("Failed to allocate memory for VDO segtypes.");
+ free(segtype);
+ return 0;
+ }
+
+ segtype->name = SEG_TYPE_NAME_VDO;
+ segtype->flags = SEG_VDO | SEG_VIRTUAL | SEG_ONLY_EXCLUSIVE;
+ segtype->ops = &_vdo_ops;
+
+ if (!lvm_register_segtype(seglib, segtype)) {
+ free(pool_segtype);
+ return_0;
+ }
+
+ pool_segtype->name = SEG_TYPE_NAME_VDO_POOL;
+ pool_segtype->flags = SEG_VDO_POOL | SEG_ONLY_EXCLUSIVE;
+ pool_segtype->ops = &_vdo_pool_ops;
+
+ if (!lvm_register_segtype(seglib, pool_segtype))
+ return_0;
+
+ log_very_verbose("Initialised segtypes: %s, %s.", segtype->name, pool_segtype->name);
+
+ /* Reset mask for recalc */
+ _feature_mask = 0;
+
+ return 1;
+}
5 years, 9 months
master - build: install VDO small allocation profile
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c66a960149ae28f057b...
Commit: c66a960149ae28f057bc1a91d6974e92fc572c30
Parent: d8a41f22e9a68b0424ee18b1859fb6369c712622
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jul 3 11:10:57 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
build: install VDO small allocation profile
Profile shows all VDO configurables.
Usable with: lvcreate --metadataprofile vdo-small ...
---
conf/Makefile.in | 3 ++-
conf/vdo-small.profile | 25 +++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/conf/Makefile.in b/conf/Makefile.in
index d47c759..e906835 100644
--- a/conf/Makefile.in
+++ b/conf/Makefile.in
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -25,6 +25,7 @@ PROFILES=$(PROFILE_TEMPLATES) \
$(srcdir)/cache-smq.profile \
$(srcdir)/thin-generic.profile \
$(srcdir)/thin-performance.profile \
+ $(srcdir)/vdo-small.profile \
$(srcdir)/lvmdbusd.profile
include $(top_builddir)/make.tmpl
diff --git a/conf/vdo-small.profile b/conf/vdo-small.profile
new file mode 100644
index 0000000..0bd47b5
--- /dev/null
+++ b/conf/vdo-small.profile
@@ -0,0 +1,25 @@
+# Demo configuration for 'VDO' using less memory.
+#
+
+allocation {
+ vdo_use_compression = 1
+ vdo_use_deduplication = 1
+ vdo_emulate_512_sectors = 0
+ vdo_block_map_cache_size_mb = 128
+ vdo_block_map_period = 16380
+ vdo_check_point_frequency = 0
+ vdo_use_sparse_index = 0
+ vdo_index_memory_size_mb = 256
+ vdo_use_read_cache = 0
+ vdo_read_cache_size_mb = 0
+ vdo_slab_size_mb = 2048
+
+ vdo_ack_threads = 1
+ vdo_bio_threads = 1
+ vdo_bio_rotation = 64
+ vdo_cpu_threads = 2
+ vdo_hash_zone_threads = 1
+ vdo_logical_threads = 1
+ vdo_physical_threads = 1
+ vdo_write_policy = "auto"
+}
5 years, 9 months
master - device_mapper: basic support for vdo dm target
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d8a41f22e9a68b0424e...
Commit: d8a41f22e9a68b0424ee18b1859fb6369c712622
Parent: 0d9a4c69896137f1b440ec6da187387f6394d1fb
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jun 29 11:08:51 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
device_mapper: basic support for vdo dm target
---
device_mapper/Makefile | 4 +-
device_mapper/all.h | 9 ++
device_mapper/libdm-deptree.c | 162 ++++++++++++++++++++++++++++++++++++++++
device_mapper/vdo/target.h | 40 ++++++++++
device_mapper/vdo/vdo_target.c | 121 ++++++++++++++++++++++++++++++
5 files changed, 335 insertions(+), 1 deletions(-)
diff --git a/device_mapper/Makefile b/device_mapper/Makefile
index 30717b6..d74a751 100644
--- a/device_mapper/Makefile
+++ b/device_mapper/Makefile
@@ -24,7 +24,9 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/regex/matcher.c \
device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \
- device_mapper/ioctl/libdm-iface.c
+ device_mapper/ioctl/libdm-iface.c \
+ device_mapper/vdo/vdo_target.c \
+ device_mapper/vdo/status.c
DEVICE_MAPPER_DEPENDS=$(addprefix $(top_builddir)/,$(subst .c,.d,$(DEVICE_MAPPER_SOURCE)))
DEVICE_MAPPER_OBJECTS=$(addprefix $(top_builddir)/,$(subst .c,.o,$(DEVICE_MAPPER_SOURCE)))
diff --git a/device_mapper/all.h b/device_mapper/all.h
index 602b7ba..e56bae9 100644
--- a/device_mapper/all.h
+++ b/device_mapper/all.h
@@ -19,6 +19,7 @@
#include "base/data-struct/list.h"
#include "base/data-struct/hash.h"
+#include "vdo/target.h"
#include <inttypes.h>
#include <stdarg.h>
@@ -914,6 +915,14 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
uint32_t data_block_size);
/*
+ * VDO target
+ */
+int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
+ uint64_t size,
+ const char *data_uuid,
+ const struct dm_vdo_target_params *param);
+
+/*
* FIXME Add individual cache policy pairs <key> = value, like:
* int dm_tree_node_add_cache_policy_arg(struct dm_tree_node *dnode,
* const char *key, uint64_t value);
diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
index 2dc33ae..f49675c 100644
--- a/device_mapper/libdm-deptree.c
+++ b/device_mapper/libdm-deptree.c
@@ -17,6 +17,7 @@
#include "libdm-common.h"
#include "misc/kdev_t.h"
#include "misc/dm-ioctl.h"
+#include "vdo/target.h"
#include <stdarg.h>
#include <string.h>
@@ -39,6 +40,7 @@ enum {
SEG_ZERO,
SEG_THIN_POOL,
SEG_THIN,
+ SEG_VDO,
SEG_RAID0,
SEG_RAID0_META,
SEG_RAID1,
@@ -77,6 +79,7 @@ static const struct {
{ SEG_ZERO, "zero"},
{ SEG_THIN_POOL, "thin-pool"},
{ SEG_THIN, "thin"},
+ { SEG_VDO, "vdo" },
{ SEG_RAID0, "raid0"},
{ SEG_RAID0_META, "raid0_meta"},
{ SEG_RAID1, "raid1"},
@@ -142,6 +145,7 @@ struct thin_message {
};
/* Per-segment properties */
+// FIXME: use a union to discriminate between target types.
struct load_segment {
struct dm_list list;
@@ -200,6 +204,10 @@ struct load_segment {
unsigned read_only; /* Thin pool target vsn 1.3 */
uint32_t device_id; /* Thin */
+ // VDO params
+ struct dm_tree_node *vdo_data; /* VDO */
+ struct dm_vdo_target_params vdo_params; /* VDO */
+ const char *vdo_name; /* VDO - device name is ALSO passed as table arg */
};
/* Per-device properties */
@@ -1442,6 +1450,39 @@ out:
return r;
}
+static int _vdo_get_status(struct dm_tree_node *dnode,
+ struct dm_vdo_status_parse_result *s)
+{
+ struct dm_task *dmt;
+ int r = 0;
+ uint64_t start, length;
+ char *type = NULL;
+ char *params = NULL;
+
+ if (!(dmt = _dm_task_create_device_status(dnode->info.major,
+ dnode->info.minor)))
+ return_0;
+
+ dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
+
+ if (!type || (strcmp(type, "vdo") != 0)) {
+ log_error("Expected vdo target for %s and got %s.",
+ _node_name(dnode), type ? : "no target");
+ goto out;
+ }
+
+ log_debug("Parsing VDO status: %s", params);
+
+ if (!dm_vdo_status_parse(NULL, params, s))
+ goto_out;
+
+ r = 1;
+out:
+ dm_task_destroy(dmt);
+
+ return r;
+}
+
static int _node_message(uint32_t major, uint32_t minor,
int expected_errno, const char *message)
{
@@ -1587,6 +1628,55 @@ static int _thin_pool_node_send_messages(struct dm_tree_node *dnode,
return 1;
}
+static int _vdo_node_send_messages(struct dm_tree_node *dnode,
+ struct load_segment *seg,
+ int send)
+{
+ struct dm_vdo_status_parse_result vdo_status;
+ int send_compression_message = 0;
+ int send_deduplication_message = 0;
+ int r = 0;
+
+ if (!_vdo_get_status(dnode, &vdo_status))
+ return_0;
+
+ if (seg->vdo_params.use_compression) {
+ if (vdo_status.status->compression_state == DM_VDO_COMPRESSION_OFFLINE)
+ send_compression_message = 1;
+ } else if (vdo_status.status->compression_state != DM_VDO_COMPRESSION_OFFLINE)
+ send_compression_message = 1;
+
+ if (seg->vdo_params.use_deduplication) {
+ if (vdo_status.status->index_state == DM_VDO_INDEX_OFFLINE)
+ send_deduplication_message = 1;
+ } else if (vdo_status.status->index_state != DM_VDO_INDEX_OFFLINE)
+ send_deduplication_message = 1;
+
+ log_debug("VDO needs message for compression %u(%u) and deduplication %u(%u).",
+ send_compression_message, vdo_status.status->index_state,
+ send_deduplication_message, vdo_status.status->compression_state);
+
+ if (send_compression_message &&
+ !_node_message(dnode->info.major, dnode->info.minor, 0,
+ seg->vdo_params.use_compression ?
+ "compression on" : "compression off"))
+ goto_out;
+
+ if (send_deduplication_message &&
+ !_node_message(dnode->info.major, dnode->info.minor, 0,
+ seg->vdo_params.use_deduplication ?
+ "index-enable" : "index-disable"))
+ goto_out;
+
+ r = 1;
+out:
+ free(vdo_status.status->device);
+ free(vdo_status.status);
+
+ return r;
+}
+
+
static int _node_send_messages(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len,
@@ -1611,6 +1701,7 @@ static int _node_send_messages(struct dm_tree_node *dnode,
switch (seg->type) {
case SEG_THIN_POOL: return _thin_pool_node_send_messages(dnode, seg, send);
+ case SEG_VDO: return _vdo_node_send_messages(dnode, seg, send);
}
return 1;
@@ -2536,6 +2627,44 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
return 1;
}
+static int _vdo_emit_segment_line(struct dm_task *dmt,
+ struct load_segment *seg,
+ char *params, size_t paramsize)
+{
+ int pos = 0;
+ char data[DM_FORMAT_DEV_BUFSIZE];
+ char data_dev[128]; // for /dev/dm-XXXX
+
+ if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
+ return_0;
+ /* Unlike normal targets, current VDO requires device path */
+ if (dm_snprintf(data_dev, sizeof(data_dev), "/dev/dm-%u", seg->vdo_data->info.minor) < 0) {
+ log_error("Can create VDO data volume path for %s.", data);
+ return_0;
+ }
+
+ EMIT_PARAMS(pos, "%s %u %s " FMTu64 " " FMTu64 " %u on %s %s "
+ "ack=%u,bio=%u,bioRotationInterval=%u,cpu=%u,hash=%u,logical=%u,physical=%u",
+ data_dev,
+ (seg->vdo_params.emulate_512_sectors == 0) ? 4096 : 512,
+ seg->vdo_params.use_read_cache ? "enabled" : "disabled",
+ seg->vdo_params.read_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
+ seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
+ seg->vdo_params.block_map_period,
+ (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
+ (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" : "auto", // policy
+ seg->vdo_name,
+ seg->vdo_params.ack_threads,
+ seg->vdo_params.bio_threads,
+ seg->vdo_params.bio_rotation,
+ seg->vdo_params.cpu_threads,
+ seg->vdo_params.hash_zone_threads,
+ seg->vdo_params.logical_threads,
+ seg->vdo_params.physical_threads);
+
+ return 1;
+}
+
static int _thin_emit_segment_line(struct dm_task *dmt,
struct load_segment *seg,
char *params, size_t paramsize)
@@ -2599,6 +2728,10 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
case SEG_STRIPED:
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
break;
+ case SEG_VDO:
+ if (!(r = _vdo_emit_segment_line(dmt, seg, params, paramsize)))
+ return_0;
+ break;
case SEG_CRYPT:
EMIT_PARAMS(pos, "%s%s%s%s%s %s %" PRIu64 " ", seg->cipher,
seg->chainmode ? "-" : "", seg->chainmode ?: "",
@@ -3893,3 +4026,32 @@ int dm_tree_node_add_cache_target_base(struct dm_tree_node *node,
policy_name, policy_settings, data_block_size);
}
#endif
+
+int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
+ uint64_t size,
+ const char *data_uuid,
+ const struct dm_vdo_target_params *vtp)
+{
+ struct load_segment *seg;
+
+ if (!(seg = _add_segment(node, SEG_VDO, size)))
+ return_0;
+
+ if (!(seg->vdo_data = dm_tree_find_node_by_uuid(node->dtree, data_uuid))) {
+ log_error("Missing VDO's data uuid %s.", data_uuid);
+ return 0;
+ }
+
+ if (!dm_vdo_validate_target_params(vtp, size))
+ return_0;
+
+ if (!_link_tree_nodes(node, seg->vdo_data))
+ return_0;
+
+ seg->vdo_params = *vtp;
+ seg->vdo_name = node->name;
+
+ node->props.send_messages = 2;
+
+ return 1;
+}
diff --git a/device_mapper/vdo/target.h b/device_mapper/vdo/target.h
index 3d8722b..c597491 100644
--- a/device_mapper/vdo/target.h
+++ b/device_mapper/vdo/target.h
@@ -66,6 +66,46 @@ struct dm_pool;
bool dm_vdo_status_parse(struct dm_pool *mem, const char *input,
struct dm_vdo_status_parse_result *result);
+enum dm_vdo_write_policy {
+ DM_VDO_WRITE_POLICY_AUTO = 0,
+ DM_VDO_WRITE_POLICY_SYNC,
+ DM_VDO_WRITE_POLICY_ASYNC
+};
+
+// FIXME: review whether we should use the createParams from the userlib
+struct dm_vdo_target_params {
+ uint32_t block_map_cache_size_mb;
+ uint32_t block_map_period;
+
+ uint32_t check_point_frequency;
+ uint32_t index_memory_size_mb;
+
+ uint32_t read_cache_size_mb;
+
+ uint32_t slab_size_mb;
+
+ // threads
+ uint32_t ack_threads;
+ uint32_t bio_threads;
+ uint32_t bio_rotation;
+ uint32_t cpu_threads;
+ uint32_t hash_zone_threads;
+ uint32_t logical_threads;
+ uint32_t physical_threads;
+
+ bool use_compression;
+ bool use_deduplication;
+ bool emulate_512_sectors;
+ bool use_sparse_index;
+ bool use_read_cache;
+
+ // write policy
+ enum dm_vdo_write_policy write_policy;
+};
+
+bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
+ uint64_t vdo_size);
+
//----------------------------------------------------------------
#endif
diff --git a/device_mapper/vdo/vdo_target.c b/device_mapper/vdo/vdo_target.c
new file mode 100644
index 0000000..c488023
--- /dev/null
+++ b/device_mapper/vdo/vdo_target.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "device_mapper/misc/dmlib.h"
+#include "device_mapper/all.h"
+
+#include "vdo_limits.h"
+#include "target.h"
+
+bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
+ uint64_t vdo_size)
+{
+ bool valid = true;
+
+ if ((vtp->block_map_cache_size_mb < DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB) ||
+ (vtp->block_map_cache_size_mb > DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB)) {
+ log_error("VDO block map cache size %u out of range.",
+ vtp->block_map_cache_size_mb);
+ valid = false;
+ }
+
+ if ((vtp->index_memory_size_mb < DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB) ||
+ (vtp->index_memory_size_mb > DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB)) {
+ log_error("VDO index memory size %u out of range.",
+ vtp->index_memory_size_mb);
+ valid = false;
+ }
+
+ if (vtp->read_cache_size_mb > DM_VDO_READ_CACHE_SIZE_MAXIMUM_MB) {
+ log_error("VDO read cache size %u out of range.",
+ vtp->read_cache_size_mb);
+ valid = false;
+ }
+
+ if ((vtp->slab_size_mb < DM_VDO_SLAB_SIZE_MINIMUM_MB) ||
+ (vtp->slab_size_mb > DM_VDO_SLAB_SIZE_MAXIMUM_MB)) {
+ log_error("VDO slab size %u out of range.",
+ vtp->slab_size_mb);
+ valid = false;
+ }
+
+ if (vtp->ack_threads > DM_VDO_ACK_THREADS_MAXIMUM) {
+ log_error("VDO ack threads %u out of range.", vtp->ack_threads);
+ valid = false;
+ }
+
+ if ((vtp->bio_threads < DM_VDO_BIO_THREADS_MINIMUM) ||
+ (vtp->bio_threads > DM_VDO_BIO_THREADS_MAXIMUM)) {
+ log_error("VDO bio threads %u out of range.", vtp->bio_threads);
+ valid = false;
+ }
+
+ if ((vtp->bio_rotation < DM_VDO_BIO_ROTATION_MINIMUM) ||
+ (vtp->bio_rotation > DM_VDO_BIO_ROTATION_MAXIMUM)) {
+ log_error("VDO bio rotation %u out of range.", vtp->bio_rotation);
+ valid = false;
+ }
+
+ if ((vtp->cpu_threads < DM_VDO_CPU_THREADS_MINIMUM) ||
+ (vtp->cpu_threads > DM_VDO_CPU_THREADS_MAXIMUM)) {
+ log_error("VDO cpu threads %u out of range.", vtp->cpu_threads);
+ valid = false;
+ }
+
+ if (vtp->hash_zone_threads > DM_VDO_HASH_ZONE_THREADS_MAXIMUM) {
+ log_error("VDO hash zone threads %u out of range.", vtp->hash_zone_threads);
+ valid = false;
+ }
+
+ if (vtp->logical_threads > DM_VDO_LOGICAL_THREADS_MAXIMUM) {
+ log_error("VDO logical threads %u out of range.", vtp->logical_threads);
+ valid = false;
+ }
+
+ if (vtp->physical_threads > DM_VDO_PHYSICAL_THREADS_MAXIMUM) {
+ log_error("VDO physical threads %u out of range.", vtp->physical_threads);
+ valid = false;
+ }
+
+ switch (vtp->write_policy) {
+ case DM_VDO_WRITE_POLICY_SYNC:
+ case DM_VDO_WRITE_POLICY_ASYNC:
+ case DM_VDO_WRITE_POLICY_AUTO:
+ break;
+ default:
+ log_error(INTERNAL_ERROR "VDO write policy %u is unknown.", vtp->write_policy);
+ valid = false;
+ }
+
+ if ((vtp->hash_zone_threads ||
+ vtp->logical_threads ||
+ vtp->physical_threads) &&
+ (!vtp->hash_zone_threads ||
+ !vtp->logical_threads ||
+ !vtp->physical_threads)) {
+ log_error("Value of vdo_hash_zone_threads(%u), vdo_logical_threads(%u), "
+ "vdo_physical_threads(%u) must be all zero or all non-zero.",
+ vtp->hash_zone_threads, vtp->logical_threads, vtp->physical_threads);
+ valid = false;
+ }
+
+ if (vdo_size >= (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) {
+ log_error("VDO logical size is by " FMTu64 "KiB bigger then limit " FMTu64 "TiB.",
+ (vdo_size - (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) / 2,
+ DM_VDO_LOGICAL_SIZE_MAXIMUM_MB / UINT64_C(1024) / UINT64_C(1024));
+ valid = false;
+ }
+
+ return valid;
+}
5 years, 9 months
master - lib: new vdo segment configurable options
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0d9a4c69896137f1b44...
Commit: 0d9a4c69896137f1b440ec6da187387f6394d1fb
Parent: 4a90b0c4c92564adb1569824f22dc0d9a1badf5e
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jun 29 11:09:03 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
lib: new vdo segment configurable options
Configurable for vdo segment with their default values.
Also specify their ranges with minimal and maximal values.
---
conf/example.conf.in | 154 ++++++++++++++++++++++++++++++++++++++++
device_mapper/vdo/vdo_limits.h | 60 ++++++++++++++++
lib/config/config_settings.h | 115 +++++++++++++++++++++++++++++-
lib/config/defaults.h | 33 +++++++++
4 files changed, 361 insertions(+), 1 deletions(-)
diff --git a/conf/example.conf.in b/conf/example.conf.in
index 83f9f42..f2bb77b 100644
--- a/conf/example.conf.in
+++ b/conf/example.conf.in
@@ -488,6 +488,149 @@ allocation {
# Default physical extent size in KiB to use for new VGs.
# This configuration option has an automatic default value.
# physical_extent_size = 4096
+
+ # Configuration option allocation/vdo_use_compression.
+ # Enables or disables compression when creating a VDO volume.
+ # Compression may be disabled if necessary to maximize performance
+ # or to speed processing of data that is unlikely to compress.
+ # This configuration option has an automatic default value.
+ # vdo_use_compression = 1
+
+ # Configuration option allocation/vdo_use_deduplication.
+ # Enables or disables deduplication when creating a VDO volume.
+ # Deduplication may be disabled in instances where data is not expected
+ # to have good deduplication rates but compression is still desired.
+ # This configuration option has an automatic default value.
+ # vdo_use_deduplication = 1
+
+ # Configuration option allocation/vdo_emulate_512_sectors.
+ # Specifies that the VDO volume is to emulate a 512 byte block device.
+ # This configuration option has an automatic default value.
+ # vdo_emulate_512_sectors = 0
+
+ # Configuration option allocation/vdo_block_map_cache_size_mb.
+ # Specifies the amount of memory in MiB allocated for caching block map
+ # pages for VDO volume. The value must be a multiple of 4096 and must be
+ # at least 128MiB and less than 16TiB. The cache must be at least 16MiB
+ # per logical thread. Note that there is a memory overhead of 15%.
+ # This configuration option has an automatic default value.
+ # vdo_block_map_cache_size_mb = 128
+
+ # Configuration option allocation/vdo_block_map_period.
+ # Tunes the quantity of block map updates that can accumulate
+ # before cache pages are flushed to disk. The value must be
+ # at least 1 and less then 16380.
+ # A lower value means shorter recovery time but lower performance.
+ # This configuration option has an automatic default value.
+ # vdo_block_map_period = 16380
+
+ # Configuration option allocation/vdo_check_point_frequency.
+ # The default check point frequency for VDO volume.
+ # This configuration option has an automatic default value.
+ # vdo_check_point_frequency = 0
+
+ # Configuration option allocation/vdo_use_sparse_index.
+ # Enables sparse indexing for VDO volume.
+ # This configuration option has an automatic default value.
+ # vdo_use_sparse_index = 0
+
+ # Configuration option allocation/vdo_index_memory_size_mb.
+ # Specifies the amount of index memory in MiB for VDO volume.
+ # The value must be at least 256MiB and at most 1TiB.
+ # This configuration option has an automatic default value.
+ # vdo_index_memory_size_mb = 256
+
+ # Configuration option allocation/vdo_use_read_cache.
+ # Enables or disables the read cache within the VDO volume.
+ # The cache should be enabled if write workloads are expected
+ # to have high levels of deduplication, or for read intensive
+ # workloads of highly compressible data.
+ # This configuration option has an automatic default value.
+ # vdo_use_read_cache = 0
+
+ # Configuration option allocation/vdo_read_cache_size_mb.
+ # Specifies the extra VDO volume read cache size in MiB.
+ # This space is in addition to a system-defined minimum.
+ # The value must be less then 16TiB and 1.12 MiB of memory
+ # will be used per MiB of read cache specified, per bio thread.
+ # This configuration option has an automatic default value.
+ # vdo_read_cache_size_mb = 0
+
+ # Configuration option allocation/vdo_slab_size_mb.
+ # Specifies the size in MiB of the increment by which a VDO is grown.
+ # Using a smaller size constrains the total maximum physical size
+ # that can be accommodated. Must be a power of two between 128MiB and 32GiB.
+ # This configuration option has an automatic default value.
+ # vdo_slab_size_mb = 2048
+
+ # Configuration option allocation/vdo_ack_threads.
+ # Specifies the number of threads to use for acknowledging
+ # completion of requested VDO I/O operations.
+ # The value must be at in range [0..100].
+ # This configuration option has an automatic default value.
+ # vdo_ack_threads = 1
+
+ # Configuration option allocation/vdo_bio_threads.
+ # Specifies the number of threads to use for submitting I/O
+ # operations to the storage device of VDO volume.
+ # The value must be in range [1..100]
+ # Each additional thread after the first will use an additional 18MiB of RAM,
+ # plus 1.12 MiB of RAM per megabyte of configured read cache size.
+ # This configuration option has an automatic default value.
+ # vdo_bio_threads = 1
+
+ # Configuration option allocation/vdo_bio_rotation.
+ # Specifies the number of I/O operations to enqueue for each bio-submission
+ # thread before directing work to the next. The value must be in range [1..1024].
+ # This configuration option has an automatic default value.
+ # vdo_bio_rotation = 64
+
+ # Configuration option allocation/vdo_cpu_threads.
+ # Specifies the number of threads to use for CPU-intensive work such as
+ # hashing or compression for VDO volume. The value must be in range [1..100]
+ # This configuration option has an automatic default value.
+ # vdo_cpu_threads = 2
+
+ # Configuration option allocation/vdo_hash_zone_threads.
+ # Specifies the number of threads across which to subdivide parts of the VDO
+ # processing based on the hash value computed from the block data.
+ # The value must be at in range [0..100].
+ # vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
+ # either all zero or all non-zero.
+ # This configuration option has an automatic default value.
+ # vdo_hash_zone_threads = 1
+
+ # Configuration option allocation/vdo_logical_threads.
+ # Specifies the number of threads across which to subdivide parts of the VDO
+ # processing based on the hash value computed from the block data.
+ # A logical thread count of 9 or more will require explicitly specifying
+ # a sufficiently large block map cache size, as well.
+ # The value must be in range [0..100].
+ # vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
+ # either all zero or all non-zero.
+ # This configuration option has an automatic default value.
+ # vdo_logical_threads = 1
+
+ # Configuration option allocation/vdo_physical_threads.
+ # Specifies the number of threads across which to subdivide parts of the VDO
+ # processing based on physical block addresses.
+ # Each additional thread after the first will use an additional 10MiB of RAM.
+ # The value must be in range [0..16].
+ # vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
+ # either all zero or all non-zero.
+ # This configuration option has an automatic default value.
+ # vdo_physical_threads = 1
+
+ # Configuration option allocation/vdo_write_policy.
+ # Specifies the write policy:
+ # auto - VDO will check the storage device and determine whether it supports flushes.
+ # If it does, VDO will run in async mode, otherwise it will run in sync mode.
+ # sync - Writes are acknowledged only after data is stably written.
+ # This policy is not supported if the underlying storage is not also synchronous.
+ # async - Writes are acknowledged after data has been cached for writing to stable storage.
+ # Data which has not been flushed is not guaranteed to persist in this mode.
+ # This configuration option has an automatic default value.
+ # vdo_write_policy = "auto"
}
# Configuration section log.
@@ -1006,6 +1149,17 @@ global {
# This configuration option has an automatic default value.
# cache_repair_options = [ "" ]
+ # Configuration option global/vdo_format_executable.
+ # The full path to the vdoformat command.
+ # LVM uses this command to initial data volume for VDO type logical volume
+ # This configuration option has an automatic default value.
+ # vdo_format_executable = "@VDO_FORMAT_CMD@"
+
+ # Configuration option global/vdo_format_options.
+ # List of options passed added to standard vdoformat command.
+ # This configuration option has an automatic default value.
+ # vdo_format_options = [ "" ]
+
# Configuration option global/fsadm_executable.
# The full path to the fsadm command.
# LVM uses this command to help with lvresize -r operations.
diff --git a/device_mapper/vdo/vdo_limits.h b/device_mapper/vdo/vdo_limits.h
new file mode 100644
index 0000000..40cf204
--- /dev/null
+++ b/device_mapper/vdo/vdo_limits.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DEVICE_MAPPER_VDO_LIMITS_H
+#define DEVICE_MAPPER_VDO_LIMITS_H
+
+#define DM_VDO_BLOCK_SIZE UINT64_C(8) // 4KiB in sectors
+
+#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB (128) // 128MiB
+#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
+#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_PER_LOGICAL_THREAD (4096 * DM_VDO_BLOCK_SIZE_KB)
+
+#define DM_VDO_BLOCK_MAP_PERIOD_MINIMUM 1
+#define DM_VDO_BLOCK_MAP_PERIOD_MAXIMUM (16380)
+
+#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB (256) // 0.25 GiB
+#define DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB (1024 * 1024 * 1024) // 1TiB
+
+//#define DM_VDO_READ_CACHE_SIZE_MINIMUM_MB (0)
+#define DM_VDO_READ_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
+
+#define DM_VDO_SLAB_SIZE_MINIMUM_MB (128) // 128MiB
+#define DM_VDO_SLAB_SIZE_MAXIMUM_MB (32 * 1024) // 32GiB
+
+//#define DM_VDO_LOGICAL_SIZE_MINIMUM_MB (0)
+#define DM_VDO_LOGICAL_SIZE_MAXIMUM_MB (UINT64_C(4) * 1024 * 1024 * 1024) // 4PiB
+
+//#define DM_VDO_ACK_THREADS_MINIMUM (0)
+#define DM_VDO_ACK_THREADS_MAXIMUM (100)
+
+#define DM_VDO_BIO_THREADS_MINIMUM (1)
+#define DM_VDO_BIO_THREADS_MAXIMUM (100)
+
+#define DM_VDO_BIO_ROTATION_MINIMUM (1)
+#define DM_VDO_BIO_ROTATION_MAXIMUM (1024)
+
+#define DM_VDO_CPU_THREADS_MINIMUM (1)
+#define DM_VDO_CPU_THREADS_MAXIMUM (100)
+
+//#define DM_VDO_HASH_ZONE_THREADS_MINIMUM (0)
+#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM (100)
+
+//#define DM_VDO_LOGICAL_THREADS_MINIMUM (0)
+#define DM_VDO_LOGICAL_THREADS_MAXIMUM (100)
+
+//#define DM_VDO_PHYSICAL_THREADS_MINIMUM (0)
+#define DM_VDO_PHYSICAL_THREADS_MAXIMUM (16)
+
+#endif // DEVICE_MAPPER_VDO_LIMITS_H
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index 7cb266c..9026c2d 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -607,6 +607,112 @@ cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocat
cfg(allocation_physical_extent_size_CFG, "physical_extent_size", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_EXTENT_SIZE, vsn(2, 2, 112), NULL, 0, NULL,
"Default physical extent size in KiB to use for new VGs.\n")
+#define VDO_1ST_VSN vsn(3, 0, 0)
+cfg(allocation_vdo_use_compression_CFG, "vdo_use_compression", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_COMPRESSION, VDO_1ST_VSN, NULL, 0, NULL,
+ "Enables or disables compression when creating a VDO volume.\n"
+ "Compression may be disabled if necessary to maximize performance\n"
+ "or to speed processing of data that is unlikely to compress.\n")
+
+cfg(allocation_vdo_use_deduplication_CFG, "vdo_use_deduplication", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_DEDUPLICATION, VDO_1ST_VSN, NULL, 0, NULL,
+ "Enables or disables deduplication when creating a VDO volume.\n"
+ "Deduplication may be disabled in instances where data is not expected\n"
+ "to have good deduplication rates but compression is still desired.")
+
+cfg(allocation_vdo_emulate_512_sectors_CFG, "vdo_emulate_512_sectors", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_EMULATE_512_SECTORS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies that the VDO volume is to emulate a 512 byte block device.\n")
+
+cfg(allocation_vdo_block_map_cache_size_mb_CFG, "vdo_block_map_cache_size_mb", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BLOCK_MAP_CACHE_SIZE_MB, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the amount of memory in MiB allocated for caching block map\n"
+ "pages for VDO volume. The value must be a multiple of 4096 and must be\n"
+ "at least 128MiB and less than 16TiB. The cache must be at least 16MiB\n"
+ "per logical thread. Note that there is a memory overhead of 15%.\n")
+
+cfg(allocation_vdo_block_map_period_CFG, "vdo_block_map_period", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BLOCK_MAP_PERIOD, VDO_1ST_VSN, NULL, 0, NULL,
+ "Tunes the quantity of block map updates that can accumulate\n"
+ "before cache pages are flushed to disk. The value must be\n"
+ "at least 1 and less then 16380.\n"
+ "A lower value means shorter recovery time but lower performance.\n")
+
+cfg(allocation_vdo_check_point_frequency_CFG, "vdo_check_point_frequency", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CHECK_POINT_FREQUENCY, VDO_1ST_VSN, NULL, 0, NULL,
+ "The default check point frequency for VDO volume.\n")
+
+cfg(allocation_vdo_use_sparse_index_CFG, "vdo_use_sparse_index", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_SPARSE_INDEX, VDO_1ST_VSN, NULL, 0, NULL,
+ "Enables sparse indexing for VDO volume.\n")
+
+cfg(allocation_vdo_index_memory_size_mb_CFG, "vdo_index_memory_size_mb", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_INDEX_MEMORY_SIZE_MB, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the amount of index memory in MiB for VDO volume.\n"
+ "The value must be at least 256MiB and at most 1TiB.\n")
+
+cfg(allocation_vdo_use_read_cache_CFG, "vdo_use_read_cache", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_READ_CACHE, VDO_1ST_VSN, NULL, 0, NULL,
+ "Enables or disables the read cache within the VDO volume.\n"
+ "The cache should be enabled if write workloads are expected\n"
+ "to have high levels of deduplication, or for read intensive\n"
+ "workloads of highly compressible data.\n")
+
+cfg(allocation_vdo_read_cache_size_mb_CFG, "vdo_read_cache_size_mb", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_READ_CACHE_SIZE_MB, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the extra VDO volume read cache size in MiB.\n"
+ "This space is in addition to a system-defined minimum.\n"
+ "The value must be less then 16TiB and 1.12 MiB of memory\n"
+ "will be used per MiB of read cache specified, per bio thread.\n")
+
+cfg(allocation_vdo_slab_size_mb_CFG, "vdo_slab_size_mb", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_SLAB_SIZE_MB, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the size in MiB of the increment by which a VDO is grown.\n"
+ "Using a smaller size constrains the total maximum physical size\n"
+ "that can be accommodated. Must be a power of two between 128MiB and 32GiB.\n")
+
+cfg(allocation_vdo_ack_threads_CFG, "vdo_ack_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_ACK_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of threads to use for acknowledging\n"
+ "completion of requested VDO I/O operations.\n"
+ "The value must be at in range [0..100].\n")
+
+cfg(allocation_vdo_bio_threads_CFG, "vdo_bio_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BIO_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of threads to use for submitting I/O\n"
+ "operations to the storage device of VDO volume.\n"
+ "The value must be in range [1..100]\n"
+ "Each additional thread after the first will use an additional 18MiB of RAM,\n"
+ "plus 1.12 MiB of RAM per megabyte of configured read cache size.\n")
+
+cfg(allocation_vdo_bio_rotation_CFG, "vdo_bio_rotation", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BIO_ROTATION, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of I/O operations to enqueue for each bio-submission\n"
+ "thread before directing work to the next. The value must be in range [1..1024].\n")
+
+cfg(allocation_vdo_cpu_threads_CFG, "vdo_cpu_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CPU_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of threads to use for CPU-intensive work such as\n"
+ "hashing or compression for VDO volume. The value must be in range [1..100]\n")
+
+cfg(allocation_vdo_hash_zone_threads_CFG, "vdo_hash_zone_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_HASH_ZONE_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of threads across which to subdivide parts of the VDO\n"
+ "processing based on the hash value computed from the block data.\n"
+ "The value must be at in range [0..100].\n"
+ "vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
+ "either all zero or all non-zero.")
+
+cfg(allocation_vdo_logical_threads_CFG, "vdo_logical_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_LOGICAL_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of threads across which to subdivide parts of the VDO\n"
+ "processing based on the hash value computed from the block data.\n"
+ "A logical thread count of 9 or more will require explicitly specifying\n"
+ "a sufficiently large block map cache size, as well.\n"
+ "The value must be in range [0..100].\n"
+ "vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
+ "either all zero or all non-zero.\n")
+
+cfg(allocation_vdo_physical_threads_CFG, "vdo_physical_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_PHYSICAL_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the number of threads across which to subdivide parts of the VDO\n"
+ "processing based on physical block addresses.\n"
+ "Each additional thread after the first will use an additional 10MiB of RAM.\n"
+ "The value must be in range [0..16].\n"
+ "vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
+ "either all zero or all non-zero.\n")
+
+cfg(allocation_vdo_write_policy_CFG, "vdo_write_policy", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_VDO_WRITE_POLICY, VDO_1ST_VSN, NULL, 0, NULL,
+ "Specifies the write policy:\n"
+ "auto - VDO will check the storage device and determine whether it supports flushes.\n"
+ " If it does, VDO will run in async mode, otherwise it will run in sync mode.\n"
+ "sync - Writes are acknowledged only after data is stably written.\n"
+ " This policy is not supported if the underlying storage is not also synchronous.\n"
+ "async - Writes are acknowledged after data has been cached for writing to stable storage.\n"
+ " Data which has not been flushed is not guaranteed to persist in this mode.\n")
+
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
"Enable or disable LVM log reporting.\n"
"If enabled, LVM will collect a log of operations, messages,\n"
@@ -1019,6 +1125,13 @@ cfg_array(global_cache_check_options_CFG, "cache_check_options", global_CFG_SECT
cfg_array(global_cache_repair_options_CFG, "cache_repair_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG, vsn(2, 2, 108), NULL, 0, NULL,
"List of options passed to the cache_repair command.\n")
+cfg(global_vdo_format_executable_CFG, "vdo_format_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, VDO_FORMAT_CMD, VDO_1ST_VSN, "@VDO_FORMAT_CMD@", 0, NULL,
+ "The full path to the vdoformat command.\n"
+ "LVM uses this command to initial data volume for VDO type logical volume\n")
+
+cfg_array(global_vdo_format_options_CFG, "vdo_format_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_VDO_FORMAT_OPTIONS_CONFIG, VDO_1ST_VSN, NULL, 0, NULL,
+ "List of options passed added to standard vdoformat command.\n")
+
cfg(global_fsadm_executable_CFG, "fsadm_executable", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_FSADM_PATH, vsn(2, 2, 170), "@FSADM_PATH@", 0, NULL,
"The full path to the fsadm command.\n"
"LVM uses this command to help with lvresize -r operations.\n")
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 084d365..2d70f53 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -16,6 +16,8 @@
#ifndef _LVM_DEFAULTS_H
#define _LVM_DEFAULTS_H
+#include "device_mapper/vdo/vdo_limits.h"
+
#define DEFAULT_PE_ALIGN 2048
#define DEFAULT_PE_ALIGN_OLD 128
@@ -134,6 +136,37 @@
#define DEFAULT_CACHE_METADATA_FORMAT CACHE_METADATA_FORMAT_UNSELECTED /* Autodetect */
#define DEFAULT_CACHE_MODE "writethrough"
+
+/* VDO defaults */
+#define DEFAULT_VDO_USE_COMPRESSION (true)
+#define DEFAULT_VDO_USE_DEDUPLICATION (true)
+#define DEFAULT_VDO_EMULATE_512_SECTORS (false)
+#define DEFAULT_VDO_BLOCK_MAP_CACHE_SIZE_MB (DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB)
+#define DEFAULT_VDO_BLOCK_MAP_PERIOD (DM_VDO_BLOCK_MAP_PERIOD_MAXIMUM)
+#define DEFAULT_VDO_USE_SPARSE_INDEX (false)
+#define DEFAULT_VDO_CHECK_POINT_FREQUENCY (0)
+#define DEFAULT_VDO_INDEX_MEMORY_SIZE_MB (DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB)
+#define DEFAULT_VDO_USE_READ_CACHE (false)
+#define DEFAULT_VDO_READ_CACHE_SIZE_MB (0)
+#define DEFAULT_VDO_SLAB_SIZE_MB (2 * 1024) // 2GiB ... 19 slabbits
+#define DEFAULT_VDO_ACK_THREADS (1)
+#define DEFAULT_VDO_BIO_THREADS (1)
+#define DEFAULT_VDO_BIO_ROTATION (64)
+#define DEFAULT_VDO_CPU_THREADS (2)
+#define DEFAULT_VDO_HASH_ZONE_THREADS (1)
+#define DEFAULT_VDO_LOGICAL_THREADS (1)
+#define DEFAULT_VDO_PHYSICAL_THREADS (1)
+#define DEFAULT_VDO_WRITE_POLICY "auto"
+
+#define DEFAULT_VDO_FORMAT_OPTIONS_CONFIG "#S" ""
+/*
+ * VDO pool will reverve some sectors in the front and the back of pool device to avoid
+ * seeing same device twice in the system.
+ */
+#define DEFAULT_VDO_POOL_HEADER_SIZE (1024) // 512KiB
+
+
+
#define DEFAULT_FSADM_PATH FSADM_PATH
#define DEFAULT_UMASK 0077
5 years, 9 months
master - build: add vdo configuration option --with-vdo=
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4a90b0c4c92564adb15...
Commit: 4a90b0c4c92564adb1569824f22dc0d9a1badf5e
Parent: 2e05f6018bc3cbc8104ea53fb8a3e041ef5f899a
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jun 29 13:38:18 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
build: add vdo configuration option --with-vdo=
Checks whether VDO support is enabled.
Detects presence of 'vdoformat' tool which is required for to format VDO pool.
ATM build of VDO is NOT automatically enabled (None is default).
To enable build of LVM with VDO support use:
configure --with-vdo=internal
TODO: Maybe future version may switch to link some small VDO library for formating
(would require linking and package dependency).
---
configure | 172 ++++++++++++++++++++++++++++++++++++++++++++++++
configure.ac | 54 +++++++++++++++
device_mapper/Makefile | 3 +
include/configure.h.in | 6 ++
make.tmpl.in | 1 +
5 files changed, 236 insertions(+), 0 deletions(-)
diff --git a/configure b/configure
index fc5783d..a96de76 100755
--- a/configure
+++ b/configure
@@ -641,6 +641,9 @@ LVMPOLLD_PIDFILE
LVMETAD_PIDFILE
DMEVENTD_PIDFILE
WRITE_INSTALL
+VDO_LIB
+VDO_INCLUDE
+VDO
VALGRIND_POOL
USRSBINDIR
SILENT_RULES
@@ -791,6 +794,7 @@ PKGCONFIGINIT_CFLAGS
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
+VDO_FORMAT_CMD
CACHE_RESTORE_CMD
CACHE_REPAIR_CMD
CACHE_DUMP_CMD
@@ -912,6 +916,8 @@ with_cache_dump
with_cache_repair
with_cache_restore
enable_cache_check_needs_check
+with_vdo
+with_vdo_format
enable_readline
enable_realtime
enable_ocf
@@ -1708,6 +1714,8 @@ Optional Packages:
cache_repair tool: [autodetect]
--with-cache-restore=PATH
cache_restore tool: [autodetect]
+ --with-vdo=TYPE vdo support: internal/none [internal]
+ --with-vdo-format=PATH vdoformat tool: [autodetect]
--with-ocfdir=DIR install OCF files in
[PREFIX/lib/ocf/resource.d/lvm2]
--with-default-pid-dir=PID_DIR
@@ -9545,6 +9553,165 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include vdo" >&5
+$as_echo_n "checking whether to include vdo... " >&6; }
+
+# Check whether --with-vdo was given.
+if test "${with_vdo+set}" = set; then :
+ withval=$with_vdo; VDO=$withval
+else
+ VDO="none"
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $VDO" >&5
+$as_echo "$VDO" >&6; }
+
+
+# Check whether --with-vdo-format was given.
+if test "${with_vdo_format+set}" = set; then :
+ withval=$with_vdo_format; VDO_FORMAT_CMD=$withval
+else
+ VDO_FORMAT_CMD="autodetect"
+fi
+
+case "$VDO" in
+ none) ;;
+ internal)
+
+$as_echo "#define VDO_INTERNAL 1" >>confdefs.h
+
+ if test "$VDO_FORMAT_CMD" = "autodetect"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}vdoformat", so it can be a program name with args.
+set dummy ${ac_tool_prefix}vdoformat; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_VDO_FORMAT_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $VDO_FORMAT_CMD in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_VDO_FORMAT_CMD="$VDO_FORMAT_CMD" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_VDO_FORMAT_CMD="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+VDO_FORMAT_CMD=$ac_cv_path_VDO_FORMAT_CMD
+if test -n "$VDO_FORMAT_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VDO_FORMAT_CMD" >&5
+$as_echo "$VDO_FORMAT_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_VDO_FORMAT_CMD"; then
+ ac_pt_VDO_FORMAT_CMD=$VDO_FORMAT_CMD
+ # Extract the first word of "vdoformat", so it can be a program name with args.
+set dummy vdoformat; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_VDO_FORMAT_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_VDO_FORMAT_CMD in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_VDO_FORMAT_CMD="$ac_pt_VDO_FORMAT_CMD" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_VDO_FORMAT_CMD="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_VDO_FORMAT_CMD=$ac_cv_path_ac_pt_VDO_FORMAT_CMD
+if test -n "$ac_pt_VDO_FORMAT_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_VDO_FORMAT_CMD" >&5
+$as_echo "$ac_pt_VDO_FORMAT_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_VDO_FORMAT_CMD" = x; then
+ VDO_FORMAT_CMD=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ VDO_FORMAT_CMD=$ac_pt_VDO_FORMAT_CMD
+ fi
+else
+ VDO_FORMAT_CMD="$ac_cv_path_VDO_FORMAT_CMD"
+fi
+
+ if test -z "$VDO_FORMAT_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: vdoformat not found in path $PATH" >&5
+$as_echo "$as_me: WARNING: vdoformat not found in path $PATH" >&2;}
+ VDO_FORMAT_CMD=/usr/bin/vdoformat
+ VDO_CONFIGURE_WARN=y
+ fi
+ fi
+ ;;
+ *) as_fn_error $? "--with-vdo parameter invalid" "$LINENO" 5 ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define VDO_FORMAT_CMD "$VDO_FORMAT_CMD"
+_ACEOF
+
+#
+# Do we need to use the API??
+# Do we want to link lvm2 with a big library for vdoformating ?
+#
+#AC_ARG_WITH(vdo-include,
+# AC_HELP_STRING([--with-vdo-include=PATH],
+# [vdo support: Path to utils headers: [/usr/include/vdo/utils]]),
+# VDO_INCLUDE=$withval, VDO_INCLUDE="/usr/include/vdo/utils")
+#AC_MSG_RESULT($VDO_INCLUDE)
+#
+#AC_ARG_WITH(vdo-lib,
+# AC_HELP_STRING([--with-vdo-lib=PATH],
+# [vdo support: Path to utils lib: [/usr/lib]]),
+# VDO_LIB=$withval, VDO_LIB="/usr/lib")
+#AC_MSG_RESULT($VDO_LIB)
################################################################################
# Check whether --enable-readline was given.
@@ -15043,6 +15210,11 @@ if test -n "$CACHE_CHECK_VERSION_WARN"; then :
$as_echo "$as_me: WARNING: You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2" >&2;}
fi
+if test -n "$VDO_CONFIGURE_WARN"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!" >&5
+$as_echo "$as_me: WARNING: unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!" >&2;}
+fi
+
if test "$ODIRECT" != yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: O_DIRECT disabled: low-memory pvmove may lock up" >&5
diff --git a/configure.ac b/configure.ac
index 21ff52c..ab0c770 100644
--- a/configure.ac
+++ b/configure.ac
@@ -592,6 +592,53 @@ AC_DEFINE_UNQUOTED([CACHE_REPAIR_CMD], ["$CACHE_REPAIR_CMD"],
AC_DEFINE_UNQUOTED([CACHE_RESTORE_CMD], ["$CACHE_RESTORE_CMD"],
[The path to 'cache_restore', if available.])
+################################################################################
+dnl -- cache inclusion type
+AC_MSG_CHECKING(whether to include vdo)
+AC_ARG_WITH(vdo,
+ AC_HELP_STRING([--with-vdo=TYPE],
+ [vdo support: internal/none [internal]]),
+ VDO=$withval, VDO="none")
+
+AC_MSG_RESULT($VDO)
+
+AC_ARG_WITH(vdo-format,
+ AC_HELP_STRING([--with-vdo-format=PATH],
+ [vdoformat tool: [autodetect]]),
+ VDO_FORMAT_CMD=$withval, VDO_FORMAT_CMD="autodetect")
+case "$VDO" in
+ none) ;;
+ internal)
+ AC_DEFINE([VDO_INTERNAL], 1, [Define to 1 to include built-in support for vdo.])
+ if test "$VDO_FORMAT_CMD" = "autodetect"; then
+ AC_PATH_TOOL(VDO_FORMAT_CMD, vdoformat, [], [$PATH])
+ if test -z "$VDO_FORMAT_CMD"; then
+ AC_MSG_WARN([vdoformat not found in path $PATH])
+ VDO_FORMAT_CMD=/usr/bin/vdoformat
+ VDO_CONFIGURE_WARN=y
+ fi
+ fi
+ ;;
+ *) AC_MSG_ERROR([--with-vdo parameter invalid]) ;;
+esac
+
+AC_DEFINE_UNQUOTED([VDO_FORMAT_CMD], ["$VDO_FORMAT_CMD"],
+ [The path to 'vdoformat', if available.])
+#
+# Do we need to use the API??
+# Do we want to link lvm2 with a big library for vdoformating ?
+#
+#AC_ARG_WITH(vdo-include,
+# AC_HELP_STRING([--with-vdo-include=PATH],
+# [vdo support: Path to utils headers: [/usr/include/vdo/utils]]),
+# VDO_INCLUDE=$withval, VDO_INCLUDE="/usr/include/vdo/utils")
+#AC_MSG_RESULT($VDO_INCLUDE)
+#
+#AC_ARG_WITH(vdo-lib,
+# AC_HELP_STRING([--with-vdo-lib=PATH],
+# [vdo support: Path to utils lib: [/usr/lib]]),
+# VDO_LIB=$withval, VDO_LIB="/usr/lib")
+#AC_MSG_RESULT($VDO_LIB)
################################################################################
dnl -- Disable readline
@@ -1739,6 +1786,10 @@ AC_SUBST(USE_TRACKING)
AC_SUBST(SILENT_RULES)
AC_SUBST(USRSBINDIR)
AC_SUBST(VALGRIND_POOL)
+AC_SUBST(VDO)
+AC_SUBST(VDO_FORMAT_CMD)
+AC_SUBST(VDO_INCLUDE)
+AC_SUBST(VDO_LIB)
AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE)
AC_SUBST(LVMETAD_PIDFILE)
@@ -1840,6 +1891,9 @@ AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
[AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
+AS_IF([test -n "$VDO_CONFIGURE_WARN"],
+ [AC_MSG_WARN([unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!])])
+
AS_IF([test "$ODIRECT" != yes],
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
diff --git a/device_mapper/Makefile b/device_mapper/Makefile
index 0a06a8b..30717b6 100644
--- a/device_mapper/Makefile
+++ b/device_mapper/Makefile
@@ -30,6 +30,9 @@ DEVICE_MAPPER_DEPENDS=$(addprefix $(top_builddir)/,$(subst .c,.d,$(DEVICE_MAPPER
DEVICE_MAPPER_OBJECTS=$(addprefix $(top_builddir)/,$(subst .c,.o,$(DEVICE_MAPPER_SOURCE)))
CLEAN_TARGETS+=$(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS)
+#$(DEVICE_MAPPER_DEPENDS): INCLUDES+=$(VDO_INCLUDES)
+#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
+
ifeq ("$(USE_TRACKING)","yes")
ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
help check check_local check_cluster check_lvmetad check_lvmpolld))
diff --git a/include/configure.h.in b/include/configure.h.in
index 50e35f7..f68b092 100644
--- a/include/configure.h.in
+++ b/include/configure.h.in
@@ -672,6 +672,12 @@
/* Enable a valgrind aware build of pool */
#undef VALGRIND_POOL
+/* The path to 'vdoformat', if available. */
+#undef VDO_FORMAT_CMD
+
+/* Define to 1 to include built-in support for vdo. */
+#undef VDO_INTERNAL
+
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
diff --git a/make.tmpl.in b/make.tmpl.in
index dcdc093..a6642f2 100644
--- a/make.tmpl.in
+++ b/make.tmpl.in
@@ -311,6 +311,7 @@ LIB_VERSION_APP := $(shell $(AWK) -F '[(). ]' '{printf "%s.%s",$$1,$$4}' $(top_s
INCLUDES += -I$(top_srcdir) -I$(srcdir) -I$(top_builddir)/include
+#VDO_INCLUDES=-I@VDO_INCLUDE@
DEPS = $(top_builddir)/make.tmpl $(top_srcdir)/VERSION \
$(top_builddir)/Makefile
5 years, 9 months
master - dmeventd: base vdo plugin
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=80e6097ea6bc5654830...
Commit: 80e6097ea6bc56548304185715f04e8eaca2da48
Parent: b98846998b7719360e9d41f83a24101c8389bc70
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Jul 9 11:41:26 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:32 2018 +0200
dmeventd: base vdo plugin
Introduce VDO plugin for monitoring VDO devices.
This plugin can be used also by other users, as plugin checks
for UUID prefix 'LVM-' and run lvm actions only on those
devices.
Non LVM- device are only monitored and log warnings
when usage threshold reaches 80%.
---
WHATS_NEW_DM | 1 +
configure | 3 +-
configure.ac | 1 +
daemons/dmeventd/libdevmapper-event.c | 1 +
daemons/dmeventd/plugins/Makefile.in | 9 +-
daemons/dmeventd/plugins/vdo/.exported_symbols | 3 +
daemons/dmeventd/plugins/vdo/Makefile.in | 36 ++
daemons/dmeventd/plugins/vdo/dmeventd_vdo.c | 406 ++++++++++++++++++++++++
8 files changed, 453 insertions(+), 7 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 7a94016..ac4868c 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.147 -
====================================
+ Add vdo plugin for monitoring VDO devices.
Version 1.02.147-rc1 - 24th May 2018
====================================
diff --git a/configure b/configure
index deaa8e9..fc5783d 100755
--- a/configure
+++ b/configure
@@ -13672,7 +13672,7 @@ _ACEOF
################################################################################
-ac_config_files="$ac_config_files Makefile make.tmpl libdm/make.tmpl daemons/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/Makefile lib/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/dm-tools/Makefile libdm/libdevmapper.pc man/Makefile po/Makefile scripts/blkdeactivate.sh scripts
/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile tools/Makefile udev/Makefile"
+ac_config_files="$ac_config_files Makefile make.tmpl libdm/make.tmpl daemons/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmeventd/plugins/vdo/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/Makefile lib/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/dm-tools/Makefile libdm/libdevmapper.pc man/Makefile po/Mak
efile scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile tools/Makefile udev/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -14380,6 +14380,7 @@ do
"daemons/dmeventd/plugins/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/mirror/Makefile" ;;
"daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;;
"daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;;
+ "daemons/dmeventd/plugins/vdo/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/vdo/Makefile" ;;
"daemons/lvmdbusd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/Makefile" ;;
"daemons/lvmdbusd/lvmdbusd") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/lvmdbusd" ;;
"daemons/lvmdbusd/lvmdb.py") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/lvmdb.py" ;;
diff --git a/configure.ac b/configure.ac
index 699bbb6..21ff52c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1775,6 +1775,7 @@ daemons/dmeventd/plugins/raid/Makefile
daemons/dmeventd/plugins/mirror/Makefile
daemons/dmeventd/plugins/snapshot/Makefile
daemons/dmeventd/plugins/thin/Makefile
+daemons/dmeventd/plugins/vdo/Makefile
daemons/lvmdbusd/Makefile
daemons/lvmdbusd/lvmdbusd
daemons/lvmdbusd/lvmdb.py
diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c
index e58a0ce..1c4607a 100644
--- a/daemons/dmeventd/libdevmapper-event.c
+++ b/daemons/dmeventd/libdevmapper-event.c
@@ -648,6 +648,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
uuid = dm_task_get_uuid(dmt);
if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") &&
+ !strstr(dmevh->dso, "libdevmapper-event-lvm2vdo.so") &&
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
diff --git a/daemons/dmeventd/plugins/Makefile.in b/daemons/dmeventd/plugins/Makefile.in
index 27edf55..951dd2b 100644
--- a/daemons/dmeventd/plugins/Makefile.in
+++ b/daemons/dmeventd/plugins/Makefile.in
@@ -1,6 +1,6 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -16,11 +16,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
-SUBDIRS += lvm2 snapshot raid thin mirror
-
-ifeq ($(MAKECMDGOALS),distclean)
- SUBDIRS = lvm2 mirror snapshot raid thin
-endif
+SUBDIRS += lvm2 snapshot raid thin mirror vdo
include $(top_builddir)/make.tmpl
@@ -28,3 +24,4 @@ snapshot: lvm2
mirror: lvm2
raid: lvm2
thin: lvm2
+vdo: lvm2
diff --git a/daemons/dmeventd/plugins/vdo/.exported_symbols b/daemons/dmeventd/plugins/vdo/.exported_symbols
new file mode 100644
index 0000000..b88c705
--- /dev/null
+++ b/daemons/dmeventd/plugins/vdo/.exported_symbols
@@ -0,0 +1,3 @@
+process_event
+register_device
+unregister_device
diff --git a/daemons/dmeventd/plugins/vdo/Makefile.in b/daemons/dmeventd/plugins/vdo/Makefile.in
new file mode 100644
index 0000000..bda738a
--- /dev/null
+++ b/daemons/dmeventd/plugins/vdo/Makefile.in
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
+CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
+
+SOURCES = dmeventd_vdo.c
+
+LIB_NAME = libdevmapper-event-lvm2vdo
+LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
+LIB_VERSION = $(LIB_VERSION_LVM)
+
+CFLOW_LIST = $(SOURCES)
+CFLOW_LIST_TARGET = $(LIB_NAME).cflow
+
+include $(top_builddir)/make.tmpl
+
+LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
+
+install_lvm2: install_dm_plugin
+
+install: install_lvm2
diff --git a/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
new file mode 100644
index 0000000..d77ca79
--- /dev/null
+++ b/daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "lib/misc/lib.h"
+#include "dmeventd_lvm.h"
+#include "daemons/dmeventd/libdevmapper-event.h"
+#include "device_mapper/vdo/target.h"
+
+#include <sys/wait.h>
+#include <stdarg.h>
+
+/* First warning when VDO pool is 80% full. */
+#define WARNING_THRESH (DM_PERCENT_1 * 80)
+/* Run a check every 5%. */
+#define CHECK_STEP (DM_PERCENT_1 * 5)
+/* Do not bother checking VDO pool is less than 50% full. */
+#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
+
+#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */
+
+#define VDO_DEBUG 0
+
+struct dso_state {
+ struct dm_pool *mem;
+ int percent_check;
+ int percent;
+ uint64_t known_data_size;
+ unsigned fails;
+ unsigned max_fails;
+ int restore_sigset;
+ sigset_t old_sigset;
+ pid_t pid;
+ char *argv[3];
+ const char *cmd_str;
+ const char *name;
+};
+
+DM_EVENT_LOG_FN("vdo")
+
+static int _run_command(struct dso_state *state)
+{
+ char val[16];
+ int i;
+
+ /* Mark for possible lvm2 command we are running from dmeventd
+ * lvm2 will not try to talk back to dmeventd while processing it */
+ (void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1);
+
+ if (state->percent) {
+ /* Prepare some known data to env vars for easy use */
+ if (dm_snprintf(val, sizeof(val), "%d",
+ state->percent / DM_PERCENT_1) != -1)
+ (void) setenv("DMEVENTD_VDO_POOL", val, 1);
+ } else {
+ /* For an error event it's for a user to check status and decide */
+ log_debug("Error event processing.");
+ }
+
+ log_verbose("Executing command: %s", state->cmd_str);
+
+ /* TODO:
+ * Support parallel run of 'task' and it's waitpid maintainence
+ * ATM we can't handle signaling of SIGALRM
+ * as signalling is not allowed while 'process_event()' is running
+ */
+ if (!(state->pid = fork())) {
+ /* child */
+ (void) close(0);
+ for (i = 3; i < 255; ++i) (void) close(i);
+ execvp(state->argv[0], state->argv);
+ _exit(errno);
+ } else if (state->pid == -1) {
+ log_error("Can't fork command %s.", state->cmd_str);
+ state->fails = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _use_policy(struct dm_task *dmt, struct dso_state *state)
+{
+#if VDO_DEBUG
+ log_debug("dmeventd executes: %s.", state->cmd_str);
+#endif
+ if (state->argv[0])
+ return _run_command(state);
+
+ if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
+ log_error("Failed command for %s.", dm_task_get_name(dmt));
+ state->fails = 1;
+ return 0;
+ }
+
+ state->fails = 0;
+
+ return 1;
+}
+
+/* Check if executed command has finished
+ * Only 1 command may run */
+static int _wait_for_pid(struct dso_state *state)
+{
+ int status = 0;
+
+ if (state->pid == -1)
+ return 1;
+
+ if (!waitpid(state->pid, &status, WNOHANG))
+ return 0;
+
+ /* Wait for finish */
+ if (WIFEXITED(status)) {
+ log_verbose("Child %d exited with status %d.",
+ state->pid, WEXITSTATUS(status));
+ state->fails = WEXITSTATUS(status) ? 1 : 0;
+ } else {
+ if (WIFSIGNALED(status))
+ log_verbose("Child %d was terminated with status %d.",
+ state->pid, WTERMSIG(status));
+ state->fails = 1;
+ }
+
+ state->pid = -1;
+
+ return 1;
+}
+
+void process_event(struct dm_task *dmt,
+ enum dm_event_mask event __attribute__((unused)),
+ void **user)
+{
+ const char *device = dm_task_get_name(dmt);
+ struct dso_state *state = *user;
+ void *next = NULL;
+ uint64_t start, length;
+ char *target_type = NULL;
+ char *params;
+ int needs_policy = 0;
+ struct dm_task *new_dmt = NULL;
+ struct dm_vdo_status_parse_result vdop = { .status = NULL };
+
+#if VDO_DEBUG
+ log_debug("Watch for VDO %s:%.2f%%.", state->name,
+ dm_percent_to_round_float(state->percent_check, 2));
+#endif
+ if (!_wait_for_pid(state)) {
+ log_warn("WARNING: Skipping event, child %d is still running (%s).",
+ state->pid, state->cmd_str);
+ return;
+ }
+
+ if (event & DM_EVENT_DEVICE_ERROR) {
+#if VDO_DEBUG
+ log_debug("VDO event error.");
+#endif
+ /* Error -> no need to check and do instant resize */
+ state->percent = 0;
+ if (_use_policy(dmt, state))
+ goto out;
+
+ stack;
+
+ if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
+ goto_out;
+
+ if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
+ goto_out;
+
+ /* Non-blocking status read */
+ if (!dm_task_no_flush(new_dmt))
+ log_warn("WARNING: Can't set no_flush for dm status.");
+
+ if (!dm_task_run(new_dmt))
+ goto_out;
+
+ dmt = new_dmt;
+ }
+
+ dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
+
+ if (!target_type || (strcmp(target_type, "vdo") != 0)) {
+ log_error("Invalid target type.");
+ goto out;
+ }
+
+ if (!dm_vdo_status_parse(state->mem, params, &vdop)) {
+ log_error("Failed to parse status.");
+ goto out;
+ }
+
+ state->percent = dm_make_percent(vdop.status->used_blocks,
+ vdop.status->total_blocks);
+
+#if VDO_DEBUG
+ log_debug("VDO %s status %.2f%% " FMTu64 "/" FMTu64 ".",
+ state->name, dm_percent_to_round_float(state->percent, 2),
+ vdop.status->used_blocks, vdop.status->total_blocks);
+#endif
+
+ /* VDO pool size had changed. Clear the threshold. */
+ if (state->known_data_size != vdop.status->total_blocks) {
+ state->percent_check = CHECK_MINIMUM;
+ state->known_data_size = vdop.status->total_blocks;
+ state->fails = 0;
+ }
+
+ /*
+ * Trigger action when threshold boundary is exceeded.
+ * Report 80% threshold warning when it's used above 80%.
+ * Only 100% is exception as it cannot be surpased so policy
+ * action is called for: >50%, >55% ... >95%, 100%
+ */
+ if ((state->percent > WARNING_THRESH) &&
+ (state->percent > state->percent_check))
+ log_warn("WARNING: VDO %s %s is now %.2f%% full.",
+ state->name, device,
+ dm_percent_to_round_float(state->percent, 2));
+ if (state->percent > CHECK_MINIMUM) {
+ /* Run action when usage raised more than CHECK_STEP since the last time */
+ if (state->percent > state->percent_check)
+ needs_policy = 1;
+ state->percent_check = (state->percent / CHECK_STEP + 1) * CHECK_STEP;
+ if (state->percent_check == DM_PERCENT_100)
+ state->percent_check--; /* Can't get bigger then 100% */
+ } else
+ state->percent_check = CHECK_MINIMUM;
+
+ /* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
+ * Avoids too high number of error retries, yet shows some status messages in log regularly.
+ * i.e. PV could have been pvmoved and VG/LV was locked for a while...
+ */
+ if (state->fails) {
+ if (state->fails++ <= state->max_fails) {
+ log_debug("Postponing frequently failing policy (%u <= %u).",
+ state->fails - 1, state->max_fails);
+ return;
+ }
+ if (state->max_fails < MAX_FAILS)
+ state->max_fails <<= 1;
+ state->fails = needs_policy = 1; /* Retry failing command */
+ } else
+ state->max_fails = 1; /* Reset on success */
+
+ /* FIXME: ATM nothing can be done, drop 0, once it becomes useful */
+ if (0 && needs_policy)
+ _use_policy(dmt, state);
+out:
+ if (vdop.status)
+ dm_pool_free(state->mem, vdop.status);
+
+ if (new_dmt)
+ dm_task_destroy(new_dmt);
+}
+
+/* Handle SIGCHLD for a thread */
+static void _sig_child(int signum __attribute__((unused)))
+{
+ /* empty SIG_IGN */;
+}
+
+/* Setup handler for SIGCHLD when executing external command
+ * to get quick 'waitpid()' reaction
+ * It will interrupt syscall just like SIGALRM and
+ * invoke process_event().
+ */
+static void _init_thread_signals(struct dso_state *state)
+{
+ struct sigaction act = { .sa_handler = _sig_child };
+ sigset_t my_sigset;
+
+ sigemptyset(&my_sigset);
+
+ if (sigaction(SIGCHLD, &act, NULL))
+ log_warn("WARNING: Failed to set SIGCHLD action.");
+ else if (sigaddset(&my_sigset, SIGCHLD))
+ log_warn("WARNING: Failed to add SIGCHLD to set.");
+ else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
+ log_warn("WARNING: Failed to unblock SIGCHLD.");
+ else
+ state->restore_sigset = 1;
+}
+
+static void _restore_thread_signals(struct dso_state *state)
+{
+ if (state->restore_sigset &&
+ pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
+ log_warn("WARNING: Failed to block SIGCHLD.");
+}
+
+int register_device(const char *device,
+ const char *uuid,
+ int major __attribute__((unused)),
+ int minor __attribute__((unused)),
+ void **user)
+{
+ struct dso_state *state;
+ const char *cmd;
+ char *str;
+ char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
+ const char *name = "pool";
+
+ if (!dmeventd_lvm2_init_with_pool("vdo_pool_state", state))
+ goto_bad;
+
+ state->cmd_str = "";
+
+ /* Search for command for LVM- prefixed devices only */
+ cmd = (strncmp(uuid, "LVM-", 4) == 0) ? "_dmeventd_vdo_command" : "";
+
+ if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str), cmd, device))
+ goto_bad;
+
+ if (strncmp(cmd_str, "lvm ", 4) == 0) {
+ if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
+ log_error("Failed to copy lvm VDO command.");
+ goto bad;
+ }
+ } else if (cmd_str[0] == '/') {
+ if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
+ log_error("Failed to copy VDO command.");
+ goto bad;
+ }
+
+ /* Find last space before 'vg/lv' */
+ if (!(str = strrchr(state->cmd_str, ' ')))
+ goto inval;
+
+ if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
+ str - state->cmd_str))) {
+ log_error("Failed to copy command.");
+ goto bad;
+ }
+
+ state->argv[1] = str + 1; /* 1 argument - vg/lv */
+ _init_thread_signals(state);
+ } else if (cmd[0] == 0) {
+ state->name = "volume"; /* What to use with 'others?' */
+ } else/* Unuspported command format */
+ goto inval;
+
+ state->pid = -1;
+ state->name = name;
+ *user = state;
+
+ log_info("Monitoring VDO %s %s.", name, device);
+
+ return 1;
+inval:
+ log_error("Invalid command for monitoring: %s.", cmd_str);
+bad:
+ log_error("Failed to monitor VDO %s %s.", name, device);
+
+ if (state)
+ dmeventd_lvm2_exit_with_pool(state);
+
+ return 0;
+}
+
+int unregister_device(const char *device,
+ const char *uuid __attribute__((unused)),
+ int major __attribute__((unused)),
+ int minor __attribute__((unused)),
+ void **user)
+{
+ struct dso_state *state = *user;
+ const char *name = state->name;
+ int i;
+
+ for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
+ if (i == 0)
+ /* Give it 2 seconds, then try to terminate & kill it */
+ log_verbose("Child %d still not finished (%s) waiting.",
+ state->pid, state->cmd_str);
+ else if (i == 3) {
+ log_warn("WARNING: Terminating child %d.", state->pid);
+ kill(state->pid, SIGINT);
+ kill(state->pid, SIGTERM);
+ } else if (i == 5) {
+ log_warn("WARNING: Killing child %d.", state->pid);
+ kill(state->pid, SIGKILL);
+ }
+ sleep(1);
+ }
+
+ if (state->pid != -1)
+ log_warn("WARNING: Cannot kill child %d!", state->pid);
+
+ _restore_thread_signals(state);
+
+ dmeventd_lvm2_exit_with_pool(state);
+ log_info("No longer monitoring VDO %s %s.", name, device);
+
+ return 1;
+}
5 years, 9 months
master - activate: kvdo modprobe workaround
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=2e05f6018bc3cbc8104...
Commit: 2e05f6018bc3cbc8104ea53fb8a3e041ef5f899a
Parent: 80e6097ea6bc56548304185715f04e8eaca2da48
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jun 29 11:02:24 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 15:28:35 2018 +0200
activate: kvdo modprobe workaround
To support autoloading of VDO dm target driver loading of 'kvdo'
kernel module is needed - ATM it's not using 'dm-vdo' name.
So to support this strange name - add temporarily solution to
autoload kvdo kernel module in this case.
---
lib/activate/activate.c | 6 ++++++
lib/activate/activate.h | 1 +
2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 8f4462a..4facb7c 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -585,6 +585,12 @@ int module_present(struct cmd_context *cmd, const char *target_name)
}
#ifdef MODPROBE_CMD
+ if (strcmp(target_name, MODULE_NAME_VDO) == 0) {
+ argv[1] = target_name; /* ATM kvdo is without dm- prefix */
+ if ((ret = exec_cmd(cmd, argv, NULL, 0)))
+ return ret;
+ }
+
if (dm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) {
log_error("module_present module name too long: %s",
target_name);
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
index 2f0b0a0..5d77f40 100644
--- a/lib/activate/activate.h
+++ b/lib/activate/activate.h
@@ -271,6 +271,7 @@ void fs_unlock(void);
#define MODULE_NAME_MIRROR TARGET_NAME_MIRROR
#define MODULE_NAME_SNAPSHOT TARGET_NAME_SNAPSHOT
#define MODULE_NAME_RAID TARGET_NAME_RAID
+#define MODULE_NAME_VDO "kvdo" /* does NOT use dm- prefix */
#define MODULE_NAME_ZERO TARGET_NAME_ZERO
#endif
5 years, 9 months
master - build: not yet merged
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=b98846998b7719360e9...
Commit: b98846998b7719360e9d41f83a24101c8389bc70
Parent: 5f3eff8eaecdb6e8f97b3904d5c43d36700709f3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Jul 9 10:37:39 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 10:37:39 2018 +0200
build: not yet merged
status.c will get linked with VDO support.
---
test/unit/Makefile | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/test/unit/Makefile b/test/unit/Makefile
index aeed2d7..c2f992b 100644
--- a/test/unit/Makefile
+++ b/test/unit/Makefile
@@ -11,6 +11,8 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
UNIT_SOURCE=\
+ device_mapper/vdo/status.c \
+ \
test/unit/activation-generator_t.c \
test/unit/bcache_t.c \
test/unit/bcache_utils_t.c \
5 years, 9 months
master - build: unit test Makefile update
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4a64bb9573bb3c54cfa...
Commit: 4a64bb9573bb3c54cfac0b4f588cd80dba01d60d
Parent: 5cf0923e1840375d23c4fd6035b919613ce6573b
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Jul 9 10:05:19 2018 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Jul 9 10:30:34 2018 +0200
build: unit test Makefile update
Update makefile to link with more libs since now whole liblvm-internal.a
is linked-in and this library has futher dependencies.
Avoid including deps for run-unit-test.
Drop linking separate status.c as it's already linked via internal libs.
---
test/unit/Makefile | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/test/unit/Makefile b/test/unit/Makefile
index 6fb6401..aeed2d7 100644
--- a/test/unit/Makefile
+++ b/test/unit/Makefile
@@ -11,8 +11,6 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
UNIT_SOURCE=\
- device_mapper/vdo/status.c \
- \
test/unit/activation-generator_t.c \
test/unit/bcache_t.c \
test/unit/bcache_utils_t.c \
@@ -36,7 +34,7 @@ CLEAN_TARGETS+=$(UNIT_DEPENDS) $(UNIT_OBJECTS)
test/unit/unit-test: $(UNIT_OBJECTS) lib/liblvm-internal.a libdaemon/client/libdaemonclient.a $(INTERNAL_LIBS)
@echo " [LD] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) \
- -o $@ $+ $(LIBS) -lm -ldl -laio
+ -o $@ $+ $(LIBS) $(DMEVENT_LIBS) $(SYSTEMD_LIBS) -lm -ldl -laio
.PHONEY: run-unit-test
run-unit-test: test/unit/unit-test
@@ -45,7 +43,7 @@ run-unit-test: test/unit/unit-test
ifeq ("$(USE_TRACKING)","yes")
ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
- help check check_local check_cluster check_lvmetad check_lvmpolld))
+ help check check_local check_cluster check_lvmetad check_lvmpolld run-unit-test))
-include $(UNIT_DEPENDS)
endif
endif
5 years, 9 months