mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
9a371639fc
Move _features[] structure from .data.rel.ro to .rodata.
645 lines
19 KiB
C
645 lines
19 KiB
C
/*
|
|
* Copyright (C) 2018-2022 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 "lib/mm/memlock.h"
|
|
#include "base/memory/zalloc.h"
|
|
|
|
static const char _vdo_module[] = MODULE_NAME_VDO;
|
|
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 void _vdo_display(const struct lv_segment *seg)
|
|
{
|
|
display_stripe(seg, 0, " ");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static void _vdo_pool_display(const struct lv_segment *seg)
|
|
{
|
|
struct cmd_context *cmd = seg->lv->vg->cmd;
|
|
const struct dm_vdo_target_params *vtp = &seg->vdo_params;
|
|
|
|
log_print(" Virtual size\t%s", display_size(cmd, get_vdo_pool_virtual_size(seg)));
|
|
log_print(" Header size\t\t%s", display_size(cmd, seg->vdo_pool_header_size));
|
|
|
|
_print_yes_no("Compression\t", vtp->use_compression);
|
|
_print_yes_no("Deduplication", vtp->use_deduplication);
|
|
_print_yes_no("Metadata hints", vtp->use_metadata_hints);
|
|
|
|
log_print(" Minimum IO size\t%s",
|
|
display_size(cmd, vtp->minimum_io_size));
|
|
log_print(" Block map cache sz\t%s",
|
|
display_size(cmd, vtp->block_map_cache_size_mb * UINT64_C(2 * 1024)));
|
|
log_print(" Block map era length %u", vtp->block_map_era_length);
|
|
|
|
_print_yes_no("Sparse index", vtp->use_sparse_index);
|
|
|
|
log_print(" Index memory size\t%s",
|
|
display_size(cmd, vtp->index_memory_size_mb * UINT64_C(2 * 1024)));
|
|
|
|
log_print(" Slab size\t\t%s",
|
|
display_size(cmd, vtp->slab_size_mb * UINT64_C(2 * 1024)));
|
|
|
|
log_print(" # Ack threads\t%u", (unsigned) vtp->ack_threads);
|
|
log_print(" # Bio threads\t%u", (unsigned) vtp->bio_threads);
|
|
log_print(" Bio rotation\t%u", (unsigned) vtp->bio_rotation);
|
|
log_print(" # CPU threads\t%u", (unsigned) vtp->cpu_threads);
|
|
log_print(" # Hash zone threads\t%u", (unsigned) vtp->hash_zone_threads);
|
|
log_print(" # Logical threads\t%u", (unsigned) vtp->logical_threads);
|
|
log_print(" # Physical threads\t%u", (unsigned) vtp->physical_threads);
|
|
log_print(" Max discard\t\t%u", (unsigned) vtp->max_discard);
|
|
log_print(" Write policy\t%s", get_vdo_write_policy_name(vtp->write_policy));
|
|
}
|
|
|
|
/* 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, "use_metadata_hints", &vtp->use_metadata_hints))
|
|
return_0;
|
|
|
|
if (!dm_config_get_uint32(n, "minimum_io_size", &vtp->minimum_io_size))
|
|
return _bad_field("minimum_io_size");
|
|
vtp->minimum_io_size >>= SECTOR_SHIFT; // keep in sectors, while metadata uses bytes
|
|
|
|
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_era_length", &vtp->block_map_era_length))
|
|
return _bad_field("block_map_era_length");
|
|
|
|
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 (!dm_config_get_uint32(n, "max_discard", &vtp->max_discard))
|
|
return _bad_field("max_discard");
|
|
|
|
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 (dm_config_has_node(n, "write_policy")) {
|
|
if (!(str = dm_config_find_str(n, "write_policy", NULL)) ||
|
|
!set_vdo_write_policy(&vtp->write_policy, str))
|
|
return _bad_field("write_policy");
|
|
} else
|
|
vtp->write_policy = DM_VDO_WRITE_POLICY_AUTO;
|
|
|
|
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",
|
|
seg->vdo_pool_header_size);
|
|
outsize(f, seg->vdo_pool_virtual_extents * (uint64_t) seg->lv->vg->extent_size,
|
|
"virtual_extents = %u", 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->use_metadata_hints)
|
|
outf(f, "use_metadata_hints = 1");
|
|
|
|
outf(f, "minimum_io_size = %u", (vtp->minimum_io_size << SECTOR_SHIFT));
|
|
|
|
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_era_length = %u", vtp->block_map_era_length);
|
|
|
|
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);
|
|
|
|
outf(f, "max_discard = %u", vtp->max_discard);
|
|
|
|
// TODO - conditionally
|
|
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);
|
|
|
|
if (vtp->write_policy != DM_VDO_WRITE_POLICY_AUTO)
|
|
outf(f, "write_policy = %s", get_vdo_write_policy_name(vtp->write_policy));
|
|
|
|
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_check(struct cmd_context *cmd, const struct lv_segment *seg)
|
|
{
|
|
|
|
struct vdo_pool_size_config cfg = { 0 };
|
|
|
|
if (!lv_vdo_pool_size_config(seg->lv, &cfg))
|
|
return_0;
|
|
|
|
/* Check if we are just adding more size to the already running vdo pool */
|
|
if (seg->lv->size >= cfg.physical_size)
|
|
cfg.physical_size = seg->lv->size - cfg.physical_size;
|
|
if (get_vdo_pool_virtual_size(seg) >= cfg.virtual_size)
|
|
cfg.virtual_size = get_vdo_pool_virtual_size(seg) - cfg.virtual_size;
|
|
if (seg->vdo_params.block_map_cache_size_mb >= cfg.block_map_cache_size_mb)
|
|
cfg.block_map_cache_size_mb = seg->vdo_params.block_map_cache_size_mb - cfg.block_map_cache_size_mb;
|
|
if (seg->vdo_params.index_memory_size_mb >= cfg.index_memory_size_mb)
|
|
cfg.index_memory_size_mb = seg->vdo_params.index_memory_size_mb - cfg.index_memory_size_mb;
|
|
|
|
return check_vdo_constrains(cmd, &cfg);
|
|
}
|
|
|
|
static int _vdo_pool_add_target_line(struct dev_manager *dm,
|
|
struct dm_pool *mem,
|
|
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_name, *data_uuid;
|
|
unsigned attrs = 0;
|
|
|
|
if (seg->segtype->ops->target_present)
|
|
seg->segtype->ops->target_present(cmd, NULL, &attrs);
|
|
|
|
if (!seg_is_vdo_pool(seg)) {
|
|
log_error(INTERNAL_ERROR "Passed segment is not VDO pool.");
|
|
return 0;
|
|
}
|
|
|
|
if (!critical_section() && !_vdo_check(cmd, seg))
|
|
return_0;
|
|
|
|
if (!(vdo_pool_name = dm_build_dm_name(mem, seg->lv->vg->name, seg->lv->name, lv_layer(seg->lv))))
|
|
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),
|
|
!(attrs & VDO_FEATURE_VERSION4) ? 2 : 4,
|
|
vdo_pool_name, data_uuid, seg_lv(seg, 0)->size,
|
|
&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)
|
|
{
|
|
/* List of features with their kernel target version */
|
|
static const struct feature {
|
|
uint16_t maj;
|
|
uint16_t min;
|
|
uint16_t patchlevel;
|
|
uint16_t vdo_feature;
|
|
const char feature[24];
|
|
} _features[] = {
|
|
{ 6, 2, 3, VDO_FEATURE_ONLINE_RENAME, "online_rename" },
|
|
{ 8, 2, 0, VDO_FEATURE_VERSION4, "version4" },
|
|
};
|
|
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;
|
|
const struct dm_config_node *cn;
|
|
const struct dm_config_value *cv;
|
|
const char *str;
|
|
|
|
if (!activation())
|
|
return 0;
|
|
|
|
if (!_vdo_checked) {
|
|
_vdo_checked = 1;
|
|
|
|
if (!target_present_version(cmd, TARGET_NAME_VDO, 1,
|
|
&maj, &min, &patchlevel))
|
|
return 0;
|
|
|
|
if (maj < 6 || (maj == 6 && min < 2)) {
|
|
log_warn("WARNING: Target %s version %u.%u.%u is too old.",
|
|
_vdo_module, 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)) ||
|
|
((maj == _features[i].maj) && (min == _features[i].min) && (patchlevel >= _features[i].patchlevel)))
|
|
_vdo_attrs |= _features[i].vdo_feature;
|
|
else
|
|
log_very_verbose("Target %s does not support %s.",
|
|
_vdo_module,
|
|
_features[i].feature);
|
|
}
|
|
|
|
if (attributes) {
|
|
if (!_feature_mask) {
|
|
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
|
|
if ((cn = find_config_tree_array(cmd, global_vdo_disabled_features_CFG, NULL))) {
|
|
for (cv = cn->v; cv; cv = cv->next) {
|
|
if (cv->type != DM_CFG_STRING) {
|
|
log_warn("WARNING: Ignoring invalid string in config file %s.",
|
|
_lvmconf);
|
|
continue;
|
|
}
|
|
str = cv->v.str;
|
|
if (!*str)
|
|
continue;
|
|
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
|
if (strcasecmp(str, _features[i].feature) == 0)
|
|
_feature_mask |= _features[i].vdo_feature;
|
|
}
|
|
}
|
|
_feature_mask = ~_feature_mask;
|
|
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
|
if ((_vdo_attrs & _features[i].vdo_feature) &&
|
|
!(_feature_mask & _features[i].vdo_feature))
|
|
log_very_verbose("Target %s %s support disabled by %s.",
|
|
_vdo_module,
|
|
_features[i].feature, _lvmconf);
|
|
}
|
|
*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, _vdo_module)) {
|
|
log_error("String list allocation failed for VDO module.");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
# ifdef DMEVENTD
|
|
/* FIXME Cache this */
|
|
static int _vdo_pool_target_registered(struct lv_segment *seg, int *pending, int *monitored)
|
|
{
|
|
return target_registered_with_dmeventd(seg->lv->vg->cmd,
|
|
seg->segtype->dso,
|
|
seg->lv, pending, monitored);
|
|
}
|
|
|
|
/* FIXME This gets run while suspended and performs banned operations. */
|
|
static int _vdo_pool_target_set_events(struct lv_segment *seg, int evmask, int set)
|
|
{
|
|
/* FIXME Make timeout (10) configurable */
|
|
return target_register_events(seg->lv->vg->cmd,
|
|
seg->segtype->dso,
|
|
seg->lv, evmask, set, 10);
|
|
}
|
|
|
|
static int _vdo_pool_target_register_events(struct lv_segment *seg,
|
|
int events)
|
|
{
|
|
return _vdo_pool_target_set_events(seg, events, 1);
|
|
}
|
|
|
|
static int _vdo_pool_target_unregister_events(struct lv_segment *seg,
|
|
int events)
|
|
{
|
|
return _vdo_pool_target_set_events(seg, events, 0);
|
|
}
|
|
|
|
# endif /* DMEVENTD */
|
|
#endif
|
|
|
|
/* reused as _vdo_destroy */
|
|
static void _vdo_pool_destroy(struct segment_type *segtype)
|
|
{
|
|
free((void *)segtype->dso);
|
|
free((void *)segtype);
|
|
}
|
|
|
|
static const struct segtype_handler _vdo_ops = {
|
|
.name = _vdo_name,
|
|
.display = _vdo_display,
|
|
.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 const struct segtype_handler _vdo_pool_ops = {
|
|
.name = _vdo_pool_name,
|
|
.display = _vdo_pool_display,
|
|
.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,
|
|
|
|
# ifdef DMEVENTD
|
|
.target_monitored = _vdo_pool_target_registered,
|
|
.target_monitor_events = _vdo_pool_target_register_events,
|
|
.target_unmonitor_events = _vdo_pool_target_unregister_events,
|
|
# endif /* DMEVENTD */
|
|
#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;
|
|
#ifdef DEVMAPPER_SUPPORT
|
|
# ifdef DMEVENTD
|
|
pool_segtype->dso = get_monitor_dso_path(cmd, dmeventd_vdo_library_CFG);
|
|
if (pool_segtype->dso)
|
|
pool_segtype->flags |= SEG_MONITORED;
|
|
# endif /* DMEVENTD */
|
|
#endif
|
|
|
|
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;
|
|
}
|