1
0
mirror of git://sourceware.org/git/lvm2.git synced 2026-02-01 00:32:46 +03:00

Compare commits

..

2 Commits

Author SHA1 Message Date
David Teigland
f1adf8944d locking: use lock file timestamps to detect vg changes
A reporting command that is run concurrently with another
command modifying a VG may report either the old or new
VG state.  This flexibility means the reporting command
could be optimized to report metadata that was read prior
to taking the VG lock.

Using lock file timestamps, that window can be closed so
that metadata reported is always consistent with the held
VG lock.  In some cases, this additional consistency will
avoid warnings that could be produced when the command
compares the metadata with the dm kernel state.

The end result is that the optimization is used (to read
disks only once) and the reported metadata is consistent
with the dm kernel state, even if a concurrent command
is making changes.

A reporting command will now save the VG lock file
timestamps prior to scanning disks.  The VG metadata that
is read while scanning disks is saved in memory.

After the scan, when reporting each VG, the command will
lock the VG, and then check the lock file timestamp again.
If the timestamp is unchanged, then the metadata saved
from the scan is unchanged and is reused to report the VG.
If the timestamp has changed, then another command has
modified the metadata since the scan, and the metadata is
reread from disk prior to reporting it.

Changes to lock file handling to support this:
- lock files are no longer unlinked and recreated by every
  lvm command, but are left in place.
- a command modifying a VG (holding an exclusive flock)
  will update the lock file timestamp before unlocking it.
2019-11-20 14:37:40 -06:00
David Teigland
7474440d3b lvs: disable scanning optimization
The scanning optimization can produce warnings from
'lvs' when run concurrently with commands modifying LVs,
so disable the optimization until it can be improved.

Without the scanning optimization, lvs will always
read all PVs twice:

1. read metadata from all PVs, saving it in memory
2. for each VG
3. lock VG
4. reread metadata from all PVs in VG, replacing metadata
   saved from step 1
5. run command on VG
6. unlock VG

The optimization would usually cause step 4 to be skipped,
and PVs would be read only once.

Running the command in step 5 using metadata that was not
read under the VG lock is usually fine, except for the
fact that lvs attempts to validate the metadata by comparing
it to current dm state.  If other commands are modifying dm
state while lvs is running, lvs may see differences between
metadata from step 1 and dm state checked during step 5,
and print warnings.

(A better fix may be to detect the concurrent change and
fall back to rereading metadata in step 4 only when needed.)
2019-11-19 10:56:12 -06:00
29 changed files with 286 additions and 1300 deletions

View File

@@ -392,15 +392,6 @@ struct dm_status_writecache {
int dm_get_status_writecache(struct dm_pool *mem, const char *params,
struct dm_status_writecache **status);
struct dm_status_integrity {
uint64_t number_of_mismatches;
uint64_t provided_data_sectors;
uint64_t recalc_sector;
};
int dm_get_status_integrity(struct dm_pool *mem, const char *params,
struct dm_status_integrity **status);
/*
* Parse params from STATUS call for snapshot target
*
@@ -979,35 +970,6 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
uint32_t writecache_block_size,
struct writecache_settings *settings);
struct integrity_settings {
char mode[8];
uint32_t tag_size;
const char *internal_hash;
uint32_t journal_sectors;
uint32_t interleave_sectors;
uint32_t buffer_sectors;
uint32_t journal_watermark;
uint32_t commit_time;
uint32_t block_size;
uint32_t bitmap_flush_interval;
uint64_t sectors_per_bit;
unsigned journal_sectors_set:1;
unsigned interleave_sectors_set:1;
unsigned buffer_sectors_set:1;
unsigned journal_watermark_set:1;
unsigned commit_time_set:1;
unsigned block_size_set:1;
unsigned bitmap_flush_interval_set:1;
unsigned sectors_per_bit_set:1;
};
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
uint64_t size,
const char *origin_uuid,
const char *meta_uuid,
struct integrity_settings *settings);
/*
* VDO target

View File

@@ -38,7 +38,6 @@ enum {
SEG_STRIPED,
SEG_ZERO,
SEG_WRITECACHE,
SEG_INTEGRITY,
SEG_THIN_POOL,
SEG_THIN,
SEG_VDO,
@@ -79,7 +78,6 @@ static const struct {
{ SEG_STRIPED, "striped" },
{ SEG_ZERO, "zero"},
{ SEG_WRITECACHE, "writecache"},
{ SEG_INTEGRITY, "integrity"},
{ SEG_THIN_POOL, "thin-pool"},
{ SEG_THIN, "thin"},
{ SEG_VDO, "vdo" },
@@ -223,10 +221,6 @@ struct load_segment {
int writecache_pmem; /* writecache, 1 if pmem, 0 if ssd */
uint32_t writecache_block_size; /* writecache, in bytes */
struct writecache_settings writecache_settings; /* writecache */
uint64_t integrity_data_sectors; /* integrity (provided_data_sectors) */
struct dm_tree_node *integrity_meta_node; /* integrity */
struct integrity_settings integrity_settings; /* integrity */
};
/* Per-device properties */
@@ -2711,82 +2705,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
return 1;
}
static int _integrity_emit_segment_line(struct dm_task *dmt,
struct load_segment *seg,
char *params, size_t paramsize)
{
struct integrity_settings *set = &seg->integrity_settings;
int pos = 0;
int count;
char origin_dev[DM_FORMAT_DEV_BUFSIZE];
char meta_dev[DM_FORMAT_DEV_BUFSIZE];
if (!_build_dev_string(origin_dev, sizeof(origin_dev), seg->origin))
return_0;
if (seg->integrity_meta_node &&
!_build_dev_string(meta_dev, sizeof(meta_dev), seg->integrity_meta_node))
return_0;
count = 1; /* for internal_hash which we always pass in */
if (seg->integrity_meta_node)
count++;
if (set->journal_sectors_set)
count++;
if (set->interleave_sectors_set)
count++;
if (set->buffer_sectors_set)
count++;
if (set->journal_watermark_set)
count++;
if (set->commit_time_set)
count++;
if (set->block_size_set)
count++;
if (set->bitmap_flush_interval_set)
count++;
if (set->sectors_per_bit_set)
count++;
EMIT_PARAMS(pos, "%s 0 %u %s %d internal_hash:%s",
origin_dev,
set->tag_size,
set->mode,
count,
set->internal_hash);
if (seg->integrity_meta_node)
EMIT_PARAMS(pos, " meta_device:%s", meta_dev);
if (set->journal_sectors_set)
EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
if (set->interleave_sectors_set)
EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors);
if (set->buffer_sectors_set)
EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors);
if (set->journal_watermark_set)
EMIT_PARAMS(pos, " journal_watermark:%u", set->journal_watermark);
if (set->commit_time_set)
EMIT_PARAMS(pos, " commit_time:%u", set->commit_time);
if (set->block_size_set)
EMIT_PARAMS(pos, " block_size:%u", set->block_size);
if (set->bitmap_flush_interval_set)
EMIT_PARAMS(pos, " bitmap_flush_interval:%u", set->bitmap_flush_interval);
if (set->sectors_per_bit_set)
EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
return 1;
}
static int _thin_pool_emit_segment_line(struct dm_task *dmt,
struct load_segment *seg,
char *params, size_t paramsize)
@@ -2971,10 +2889,6 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
if (!_writecache_emit_segment_line(dmt, seg, params, paramsize))
return_0;
break;
case SEG_INTEGRITY:
if (!_integrity_emit_segment_line(dmt, seg, params, paramsize))
return_0;
break;
}
switch(seg->type) {
@@ -2987,7 +2901,6 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
case SEG_THIN:
case SEG_CACHE:
case SEG_WRITECACHE:
case SEG_INTEGRITY:
break;
case SEG_CRYPT:
case SEG_LINEAR:
@@ -3825,39 +3738,6 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
return 1;
}
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
uint64_t size,
const char *origin_uuid,
const char *meta_uuid,
struct integrity_settings *settings)
{
struct load_segment *seg;
if (!(seg = _add_segment(node, SEG_INTEGRITY, size)))
return_0;
if (meta_uuid) {
if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) {
log_error("Missing integrity's meta uuid %s.", meta_uuid);
return 0;
}
if (!_link_tree_nodes(node, seg->integrity_meta_node))
return_0;
}
if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
log_error("Missing integrity's origin uuid %s.", origin_uuid);
return 0;
}
if (!_link_tree_nodes(node, seg->origin))
return_0;
memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
return 1;
}
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
uint64_t size,
const char *rlog_uuid,

View File

@@ -380,35 +380,6 @@ int dm_get_status_writecache(struct dm_pool *mem, const char *params,
return 1;
}
int dm_get_status_integrity(struct dm_pool *mem, const char *params,
struct dm_status_integrity **status)
{
struct dm_status_integrity *s;
char recalc_str[8];
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_integrity))))
return_0;
memset(recalc_str, 0, sizeof(recalc_str));
if (sscanf(params, "%llu %llu %s",
(unsigned long long *)&s->number_of_mismatches,
(unsigned long long *)&s->provided_data_sectors,
recalc_str) != 3) {
log_error("Failed to parse integrity params: %s.", params);
dm_pool_free(mem, s);
return 0;
}
if (recalc_str[0] == '-')
s->recalc_sector = 0;
else
s->recalc_sector = strtoull(recalc_str, NULL, 0);
*status = s;
return 1;
}
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s)
{
int pos;

View File

@@ -20,7 +20,6 @@ SOURCES =\
activate/activate.c \
cache/lvmcache.c \
writecache/writecache.c \
integrity/integrity.c \
cache_segtype/cache.c \
commands/toolcontext.c \
config/config.c \
@@ -68,7 +67,6 @@ SOURCES =\
log/log.c \
metadata/cache_manip.c \
metadata/writecache_manip.c \
metadata/integrity_manip.c \
metadata/lv.c \
metadata/lv_manip.c \
metadata/merge.c \

View File

@@ -2870,7 +2870,6 @@ int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
{
const struct logical_volume *active_lv;
const struct logical_volume *lv_use;
int ret;
/*
@@ -2889,30 +2888,19 @@ int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
goto out;
}
if (lv->status & LV_UNCOMMITTED)
lv_use = lv;
else
lv_use = lv_committed(lv);
ret = lv_activate_with_filter(cmd, NULL, 0,
(lv->status & LV_NOSCAN) ? 1 : 0,
(lv->status & LV_TEMPORARY) ? 1 : 0,
lv_use);
lv_committed(lv));
out:
return ret;
}
int deactivate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
{
const struct logical_volume *lv_use;
int ret;
if (lv->status & LV_UNCOMMITTED)
lv_use = lv;
else
lv_use = lv_committed(lv);
ret = lv_deactivate(cmd, NULL, lv_use);
ret = lv_deactivate(cmd, NULL, lv_committed(lv));
return ret;
}

View File

@@ -39,7 +39,6 @@ typedef enum {
SEG_STATUS_THIN_POOL,
SEG_STATUS_VDO_POOL,
SEG_STATUS_WRITECACHE,
SEG_STATUS_INTEGRITY,
SEG_STATUS_UNKNOWN
} lv_seg_status_type_t;
@@ -54,7 +53,6 @@ struct lv_seg_status {
struct dm_status_thin *thin;
struct dm_status_thin_pool *thin_pool;
struct dm_status_writecache *writecache;
struct dm_status_integrity *integrity;
struct lv_status_vdo vdo_pool;
};
};
@@ -262,7 +260,6 @@ void fs_unlock(void);
#define TARGET_NAME_CACHE "cache"
#define TARGET_NAME_WRITECACHE "writecache"
#define TARGET_NAME_INTEGRITY "integrity"
#define TARGET_NAME_ERROR "error"
#define TARGET_NAME_ERROR_OLD "erro" /* Truncated in older kernels */
#define TARGET_NAME_LINEAR "linear"
@@ -280,7 +277,6 @@ void fs_unlock(void);
#define MODULE_NAME_CLUSTERED_MIRROR "clog"
#define MODULE_NAME_CACHE TARGET_NAME_CACHE
#define MODULE_NAME_WRITECACHE TARGET_NAME_WRITECACHE
#define MODULE_NAME_INTEGRITY TARGET_NAME_INTEGRITY
#define MODULE_NAME_ERROR TARGET_NAME_ERROR
#define MODULE_NAME_LOG_CLUSTERED "log-clustered"
#define MODULE_NAME_LOG_USERSPACE "log-userspace"

View File

@@ -222,10 +222,6 @@ static int _get_segment_status_from_target_params(const char *target_name,
if (!dm_get_status_writecache(seg_status->mem, params, &(seg_status->writecache)))
return_0;
seg_status->type = SEG_STATUS_WRITECACHE;
} else if (segtype_is_integrity(segtype)) {
if (!dm_get_status_integrity(seg_status->mem, params, &(seg_status->integrity)))
return_0;
seg_status->type = SEG_STATUS_INTEGRITY;
} else
/*
* TODO: Add support for other segment types too!
@@ -303,9 +299,6 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
if (lv_is_vdo_pool(seg_status->seg->lv))
length = get_vdo_pool_virtual_size(seg_status->seg);
if (lv_is_integrity(seg_status->seg->lv))
length = seg_status->seg->integrity_data_sectors;
do {
target = dm_get_next_target(dmt, target, &target_start,
&target_length, &target_name, &target_params);
@@ -2627,10 +2620,6 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if (!_add_lv_to_dtree(dm, dtree, seg->writecache, dm->activation ? origin_only : 1))
return_0;
}
if (seg->integrity_meta_dev && seg_is_integrity(seg)) {
if (!_add_lv_to_dtree(dm, dtree, seg->integrity_meta_dev, dm->activation ? origin_only : 1))
return_0;
}
if (seg->pool_lv &&
(lv_is_cache_pool(seg->pool_lv) || lv_is_cache_vol(seg->pool_lv) || dm->track_external_lv_deps) &&
/* When activating and not origin_only detect linear 'overlay' over pool */
@@ -3087,11 +3076,6 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
lv_layer(seg->writecache)))
return_0;
if (seg->integrity_meta_dev && !laopts->origin_only &&
!_add_new_lv_to_dtree(dm, dtree, seg->integrity_meta_dev, laopts,
lv_layer(seg->integrity_meta_dev)))
return_0;
/* Add any LVs used by this segment */
for (s = 0; s < seg->area_count; ++s) {
if ((seg_type(seg, s) == AREA_LV) &&

View File

@@ -1362,9 +1362,6 @@ static int _init_segtypes(struct cmd_context *cmd)
return 0;
#endif
if (!init_integrity_segtypes(cmd, &seglib))
return 0;
return 1;
}

View File

@@ -104,10 +104,8 @@ static const struct flag _lv_flags[] = {
{LV_VDO_POOL, NULL, 0},
{LV_VDO_POOL_DATA, NULL, 0},
{WRITECACHE, NULL, 0},
{INTEGRITY, NULL, 0},
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
{LV_REMOVED, NULL, 0},
{LV_UNCOMMITTED, NULL, 0},
{0, NULL, 0}
};

View File

@@ -1,325 +0,0 @@
/*
* Copyright (C) 2013-2016 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 "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/metadata/segtype.h"
#include "lib/display/display.h"
#include "lib/format_text/text_export.h"
#include "lib/config/config.h"
#include "lib/datastruct/str_list.h"
#include "lib/misc/lvm-string.h"
#include "lib/activate/activate.h"
#include "lib/metadata/metadata.h"
#include "lib/metadata/lv_alloc.h"
#include "lib/config/defaults.h"
#define SEG_LOG_ERROR(t, p...) \
log_error(t " segment %s of logical volume %s.", ## p, \
dm_config_parent_name(sn), seg->lv->name), 0;
static void _integrity_display(const struct lv_segment *seg)
{
/* TODO: lvdisplay segments */
}
static int _integrity_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
{
struct integrity_settings *set;
struct logical_volume *origin_lv = NULL;
struct logical_volume *meta_lv = NULL;
const char *origin_name = NULL;
const char *meta_dev = NULL;
const char *mode = NULL;
const char *hash = NULL;
memset(&seg->integrity_settings, 0, sizeof(struct integrity_settings));
set = &seg->integrity_settings;
/* origin always set */
if (!dm_config_has_node(sn, "origin"))
return SEG_LOG_ERROR("origin not specified in");
if (!dm_config_get_str(sn, "origin", &origin_name))
return SEG_LOG_ERROR("origin must be a string in");
if (!(origin_lv = find_lv(seg->lv->vg, origin_name)))
return SEG_LOG_ERROR("Unknown LV specified for integrity origin %s in", origin_name);
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
return_0;
/* data_sectors always set */
if (!dm_config_get_uint64(sn, "data_sectors", &seg->integrity_data_sectors))
return SEG_LOG_ERROR("integrity data_sectors must be set in");
/* mode always set */
if (!dm_config_get_str(sn, "mode", &mode))
return SEG_LOG_ERROR("integrity mode must be set in");
if (strlen(mode) > 7)
return SEG_LOG_ERROR("integrity mode invalid in");
strncpy(set->mode, mode, 7);
/* tag_size always set */
if (!dm_config_get_uint32(sn, "tag_size", &set->tag_size))
return SEG_LOG_ERROR("integrity tag_size must be set in");
/* internal_hash always set */
if (!dm_config_get_str(sn, "internal_hash", &hash))
return SEG_LOG_ERROR("integrity internal_hash must be set in");
if (!(set->internal_hash = strdup(hash)))
return SEG_LOG_ERROR("integrity internal_hash failed to be set in");
/* meta_dev optional */
if (dm_config_has_node(sn, "meta_dev")) {
if (!dm_config_get_str(sn, "meta_dev", &meta_dev))
return SEG_LOG_ERROR("meta_dev must be a string in");
if (!(meta_lv = find_lv(seg->lv->vg, meta_dev)))
return SEG_LOG_ERROR("Unknown logical volume %s specified for integrity in", meta_dev);
}
/* the rest are optional */
if (dm_config_has_node(sn, "journal_sectors")) {
if (!dm_config_get_uint32(sn, "journal_sectors", &set->journal_sectors))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->journal_sectors_set = 1;
}
if (dm_config_has_node(sn, "interleave_sectors")) {
if (!dm_config_get_uint32(sn, "interleave_sectors", &set->interleave_sectors))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->interleave_sectors_set = 1;
}
if (dm_config_has_node(sn, "buffer_sectors")) {
if (!dm_config_get_uint32(sn, "buffer_sectors", &set->buffer_sectors))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->buffer_sectors_set = 1;
}
if (dm_config_has_node(sn, "journal_watermark")) {
if (!dm_config_get_uint32(sn, "journal_watermark", &set->journal_watermark))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->journal_watermark_set = 1;
}
if (dm_config_has_node(sn, "commit_time")) {
if (!dm_config_get_uint32(sn, "commit_time", &set->commit_time))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->commit_time_set = 1;
}
if (dm_config_has_node(sn, "block_size")) {
if (!dm_config_get_uint32(sn, "block_size", &set->block_size))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->block_size_set = 1;
}
if (dm_config_has_node(sn, "bitmap_flush_interval")) {
if (!dm_config_get_uint32(sn, "bitmap_flush_interval", &set->bitmap_flush_interval))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->bitmap_flush_interval_set = 1;
}
if (dm_config_has_node(sn, "sectors_per_bit")) {
if (!dm_config_get_uint64(sn, "sectors_per_bit", &set->sectors_per_bit))
return SEG_LOG_ERROR("Unknown integrity_setting in");
set->sectors_per_bit_set = 1;
}
seg->origin = origin_lv;
seg->integrity_meta_dev = meta_lv;
seg->lv->status |= INTEGRITY;
if (meta_lv && !add_seg_to_segs_using_this_lv(meta_lv, seg))
return_0;
return 1;
}
static int _integrity_text_import_area_count(const struct dm_config_node *sn,
uint32_t *area_count)
{
*area_count = 1;
return 1;
}
static int _integrity_text_export(const struct lv_segment *seg,
struct formatter *f)
{
const struct integrity_settings *set = &seg->integrity_settings;
outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name);
outf(f, "data_sectors = %llu", (unsigned long long)seg->integrity_data_sectors);
outf(f, "mode = \"%s\"", set->mode);
outf(f, "tag_size = %u", set->tag_size);
outf(f, "internal_hash = \"%s\"", set->internal_hash);
if (seg->integrity_meta_dev)
outf(f, "meta_dev = \"%s\"", seg->integrity_meta_dev->name);
if (set->journal_sectors_set)
outf(f, "journal_sectors = %u", set->journal_sectors);
if (set->interleave_sectors_set)
outf(f, "interleave_sectors = %u", set->interleave_sectors);
if (set->buffer_sectors_set)
outf(f, "buffer_sectors = %u", set->buffer_sectors);
if (set->journal_watermark_set)
outf(f, "journal_watermark = %u", set->journal_watermark);
if (set->commit_time_set)
outf(f, "commit_time = %u", set->commit_time);
if (set->block_size_set)
outf(f, "block_size = %u", set->block_size);
if (set->bitmap_flush_interval)
outf(f, "bitmap_flush_interval = %u", set->bitmap_flush_interval);
if (set->sectors_per_bit)
outf(f, "sectors_per_bit = %llu", (unsigned long long)set->sectors_per_bit);
return 1;
}
static void _destroy(struct segment_type *segtype)
{
free((void *) segtype);
}
#ifdef DEVMAPPER_SUPPORT
static int _target_present(struct cmd_context *cmd,
const struct lv_segment *seg __attribute__((unused)),
unsigned *attributes __attribute__((unused)))
{
static int _integrity_checked = 0;
static int _integrity_present = 0;
if (!activation())
return 0;
if (!_integrity_checked) {
_integrity_checked = 1;
_integrity_present = target_present(cmd, TARGET_NAME_INTEGRITY, 0);
}
return _integrity_present;
}
static int _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_INTEGRITY)) {
log_error("String list allocation failed for integrity module.");
return 0;
}
return 1;
}
#endif /* DEVMAPPER_SUPPORT */
#ifdef DEVMAPPER_SUPPORT
static int _integrity_add_target_line(struct dev_manager *dm,
struct dm_pool *mem,
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 *origin_uuid;
char *meta_uuid = NULL;
if (!seg_is_integrity(seg)) {
log_error(INTERNAL_ERROR "Passed segment is not integrity.");
return 0;
}
if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0), NULL)))
return_0;
if (seg->integrity_meta_dev) {
if (!(meta_uuid = build_dm_uuid(mem, seg->integrity_meta_dev, NULL)))
return_0;
}
if (!seg->integrity_data_sectors) {
log_error("_integrity_add_target_line zero size");
return_0;
}
if (!dm_tree_node_add_integrity_target(node, seg->integrity_data_sectors,
origin_uuid, meta_uuid,
&seg->integrity_settings))
return_0;
return 1;
}
#endif /* DEVMAPPER_SUPPORT */
static struct segtype_handler _integrity_ops = {
.display = _integrity_display,
.text_import = _integrity_text_import,
.text_import_area_count = _integrity_text_import_area_count,
.text_export = _integrity_text_export,
#ifdef DEVMAPPER_SUPPORT
.add_target_line = _integrity_add_target_line,
.target_present = _target_present,
.modules_needed = _modules_needed,
#endif
.destroy = _destroy,
};
int init_integrity_segtypes(struct cmd_context *cmd,
struct segtype_library *seglib)
{
struct segment_type *segtype = zalloc(sizeof(*segtype));
if (!segtype) {
log_error("Failed to allocate memory for integrity segtype");
return 0;
}
segtype->name = SEG_TYPE_NAME_INTEGRITY;
segtype->flags = SEG_INTEGRITY;
segtype->ops = &_integrity_ops;
if (!lvm_register_segtype(seglib, segtype))
return_0;
log_very_verbose("Initialised segtype: %s", segtype->name);
return 1;
}

View File

@@ -1045,6 +1045,15 @@ int label_scan(struct cmd_context *cmd)
*/
_prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
/*
* Read and save the timestamps from VG lock files. The lock file
* timestamp is updated when a command releases an exclusive lock
* (indicating it has changed the VG.) So, the timestamps can be
* checked later to detect if another command has changed the VG since
* our label scan.
*/
file_lock_save_times(cmd);
/*
* Do the main scan.
*/

View File

@@ -26,12 +26,14 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <dirent.h>
static char _lock_dir[PATH_MAX];
static void _fin_file_locking(void)
{
release_flocks(1);
free_flocks();
}
static void _reset_file_locking(void)
@@ -50,11 +52,12 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
log_error("Too long locking filename %s/P_%s.", _lock_dir, resource + 1);
return 0;
}
} else
} else {
if (dm_snprintf(lockfile, sizeof(lockfile), "%s/V_%s", _lock_dir, resource) < 0) {
log_error("Too long locking filename %s/V_%s.", _lock_dir, resource);
return 0;
}
}
if (!lock_file(lockfile, flags))
return_0;
@@ -95,3 +98,72 @@ int init_file_locking(struct locking_type *locking, struct cmd_context *cmd,
return 1;
}
/*
* For each file in locking_dir with V_ and no aux,
* stat and save the file time.
*/
void file_lock_save_times(struct cmd_context *cmd)
{
char lockfile[PATH_MAX];
DIR *dir;
struct dirent *de;
char *aux;
if (!(dir = opendir(_lock_dir)))
return;
while ((de = readdir(dir))) {
if (de->d_name[0] != 'V')
continue;
if ((aux = strchr(de->d_name, ':'))) {
if (!strncmp(aux, ":aux", 4))
continue;
}
if (dm_snprintf(lockfile, sizeof(lockfile), "%s/%s", _lock_dir, de->d_name) < 0)
continue;
lock_file_time_init(lockfile);
}
closedir(dir);
}
/*
* Check if the file lock timestamp is unchanged from when it was saved by
* file_lock_save_times. Return true if unchanged. Return false if the
* timestamp is different, or if there's no info to know.
*/
bool file_lock_time_unchanged(struct cmd_context *cmd, const char *resource)
{
char lockfile[PATH_MAX];
/* shouldn't be used with this function */
if (!strcmp(resource, VG_GLOBAL))
return false;
if (dm_snprintf(lockfile, sizeof(lockfile), "%s/V_%s", _lock_dir, resource) < 0) {
log_error("Too long locking filename %s/V_%s.", _lock_dir, resource);
return false;
}
return lock_file_time_unchanged(lockfile);
}
void file_lock_remove_on_unlock(struct cmd_context *cmd, const char *resource)
{
char lockfile[PATH_MAX];
/* shouldn't be used with this function */
if (!strcmp(resource, VG_GLOBAL))
return;
if (dm_snprintf(lockfile, sizeof(lockfile), "%s/V_%s", _lock_dir, resource) < 0) {
log_error("Too long locking filename %s/V_%s.", _lock_dir, resource);
return;
}
lock_file_remove_on_unlock(lockfile);
}

View File

@@ -78,4 +78,8 @@ int lockf_global_convert(struct cmd_context *cmd, const char *mode);
int lock_global(struct cmd_context *cmd, const char *mode);
int lock_global_convert(struct cmd_context *cmd, const char *mode);
void file_lock_save_times(struct cmd_context *cmd);
bool file_lock_time_unchanged(struct cmd_context *cmd, const char *resource);
void file_lock_remove_on_unlock(struct cmd_context *cmd, const char *resource);
#endif

View File

@@ -1,296 +0,0 @@
/*
* Copyright (C) 2014-2015 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/activate/dev_manager.h"
#define DEFAULT_TAG_SIZE 4 /* bytes */
#define DEFAULT_MODE 'B'
#define DEFAULT_INTERNAL_HASH "crc32c"
#define ONE_MB_IN_BYTES 1048576
/*
* The user wants external metadata, but did not specify an existing
* LV to hold metadata, so create an LV for metadata. Save it in
* lp->integrity_meta_lv and it will be passed to lv_add_integrity().
*/
int lv_create_integrity_metadata(struct cmd_context *cmd,
struct volume_group *vg,
struct lvcreate_params *lp)
{
char metaname[NAME_LEN];
uint32_t extent_bytes;
struct logical_volume *lv;
struct lvcreate_params lp_meta = {
.activate = CHANGE_AN,
.alloc = ALLOC_INHERIT,
.major = -1,
.minor = -1,
.permission = LVM_READ | LVM_WRITE,
.pvh = &vg->pvs,
.read_ahead = DM_READ_AHEAD_NONE,
.stripes = 1,
.vg_name = vg->name,
.zero = 0,
.wipe_signatures = 0,
};
if (dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) {
log_error("Failed to create metadata LV name.");
return 0;
}
if (!(lp_meta.lv_name = strdup(metaname)))
return_0;
/* TODO: set pvh per command line */
/* TODO: scale size according to LV size. */
extent_bytes = vg->extent_size * SECTOR_SIZE;
lp_meta.extents = (4 * ONE_MB_IN_BYTES) / extent_bytes;
log_debug("Creating integrity metadata LV with %u extents", lp_meta.extents);
dm_list_init(&lp_meta.tags);
if (!(lp_meta.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
if (!(lv = lv_create_single(vg, &lp_meta))) {
log_error("Failed to create integrity metadata LV");
return 0;
}
lp->integrity_meta_lv = lv;
return 1;
}
static int _get_provided_data_sectors(struct logical_volume *lv, uint64_t *provided_data_sectors)
{
struct lv_with_info_and_seg_status status;
memset(&status, 0, sizeof(status));
status.seg_status.type = SEG_STATUS_NONE;
status.seg_status.seg = first_seg(lv);
/* FIXME: why reporter_pool? */
if (!(status.seg_status.mem = dm_pool_create("reporter_pool", 1024))) {
log_error("Failed to get mem for LV status.");
return 0;
}
if (!lv_info_with_seg_status(lv->vg->cmd, first_seg(lv), &status, 1, 1)) {
log_error("Failed to get device mapper status for %s", display_lvname(lv));
goto fail;
}
if (!status.info.exists) {
log_error("No device mapper info exists for %s", display_lvname(lv));
goto fail;
}
if (status.seg_status.type != SEG_STATUS_INTEGRITY) {
log_error("Invalid device mapper status type (%d) for %s",
(uint32_t)status.seg_status.type, display_lvname(lv));
goto fail;
}
*provided_data_sectors = status.seg_status.integrity->provided_data_sectors;
dm_pool_destroy(status.seg_status.mem);
return 1;
fail:
dm_pool_destroy(status.seg_status.mem);
return 0;
}
int lv_add_integrity(struct logical_volume *lv, const char *arg,
struct logical_volume *meta_lv_created,
const char *meta_name,
struct integrity_settings *settings)
{
struct cmd_context *cmd = lv->vg->cmd;
struct volume_group *vg = lv->vg;
struct integrity_settings *set;
struct logical_volume *lv_orig;
struct logical_volume *meta_lv = NULL;
const struct segment_type *segtype;
struct lv_segment *seg;
uint32_t orig_seg_len; /* extents */
int ret;
seg = first_seg(lv);
orig_seg_len = seg->len;
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
return_0;
/*
* "lv_orig" is a new LV with new id, but with the segments from "lv".
* "lv" keeps the existing name and id, but gets a new integrity segment,
* in place of the segments that were moved to lv_orig.
*/
if (!(lv_orig = insert_layer_for_lv(cmd, lv, INTEGRITY, "_iorig")))
return_0;
seg = first_seg(lv);
seg->segtype = segtype;
lv->status |= INTEGRITY;
memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
set = &seg->integrity_settings;
if (!set->mode[0])
set->mode[0] = DEFAULT_MODE;
if (!set->tag_size)
set->tag_size = DEFAULT_TAG_SIZE;
if (!set->internal_hash)
set->internal_hash = DEFAULT_INTERNAL_HASH;
/*
* --integrity <arg> is y|external|internal
*/
if (!arg)
arg = "external";
if (!strcmp(arg, "none")) {
log_error("Invalid --integrity arg for lvcreate.");
return 0;
}
if (!strcmp(arg, "internal") && meta_name) {
log_error("Internal integrity cannot be used with integritymetadata option.");
return 0;
}
if (meta_lv_created)
meta_lv = meta_lv_created;
else if (meta_name) {
if (!(meta_lv = find_lv(vg, meta_name))) {
log_error("LV %s not found.", meta_name);
return_0;
}
}
/*
* When not using a meta_dev, dm-integrity needs to tell us what the
* usable size of the LV is, which is the dev size minus the integrity
* overhead. To find that, we need to do a special, temporary activation
* of the new LV, specifying a dm dev size of 1, then check the dm dev
* status field provided_data_sectors, which is the actual size of the
* LV. We need to include provided_data_sectors in the metadata for the
* new LV, and use this as the dm dev size for normal LV activation.
*
* When using a meta_dev, the dm dev size is the size of the data
* device. The necessary size of the meta_dev for the given data
* device needs to be estimated.
*/
if (meta_lv) {
struct wipe_params wipe;
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local devices.");
return 0;
}
log_verbose("Zeroing LV for integrity metadata");
if (!lv_is_active(meta_lv)) {
if (!activate_lv(cmd, meta_lv)) {
log_error("Failed to activate LV %s to zero", display_lvname(meta_lv));
return 0;
}
}
memset(&wipe, 0, sizeof(wipe));
wipe.do_zero = 1;
wipe.zero_sectors = 1;
if (!wipe_lv(meta_lv, wipe)) {
log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv));
return 0;
}
if (!deactivate_lv(cmd, meta_lv)) {
log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
return 0;
}
/* orig_seg_len and extent_size are both in sectors */
seg->integrity_data_sectors = (orig_seg_len * vg->extent_size);
seg->integrity_meta_dev = meta_lv;
lv_set_hidden(meta_lv);
/* TODO: give meta_lv a suffix? e.g. _imeta */
ret = 1;
} else {
/* dm-integrity wants temp/fake size of 1 to report usable size */
seg->integrity_data_sectors = 1;
lv->status |= LV_TEMPORARY;
lv->status |= LV_NOSCAN;
lv->status |= LV_UNCOMMITTED;
log_debug("Activating temporary integrity LV to get data sectors.");
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate temporary integrity.");
ret = 0;
goto out;
}
if (!_get_provided_data_sectors(lv, &seg->integrity_data_sectors)) {
log_error("Failed to get data sectors from dm-integrity");
ret = 0;
} else {
log_debug("Found integrity provided_data_sectors %llu", (unsigned long long)seg->integrity_data_sectors);
ret = 1;
}
lv->status |= LV_UNCOMMITTED;
if (!deactivate_lv(cmd, lv)) {
log_error("Failed to deactivate temporary integrity.");
ret = 0;
}
lv->status &= ~LV_UNCOMMITTED;
lv->status &= ~LV_NOSCAN;
lv->status &= ~LV_TEMPORARY;
}
log_debug("Write VG with integrity added to LV");
if (!vg_write(vg) || !vg_commit(vg))
ret = 0;
out:
return ret;
}

View File

@@ -585,8 +585,6 @@ struct logical_volume *lv_origin_lv(const struct logical_volume *lv)
origin = first_seg(lv)->external_lv;
else if (lv_is_writecache(lv) && first_seg(lv)->origin)
origin = first_seg(lv)->origin;
else if (lv_is_integrity(lv) && first_seg(lv)->origin)
origin = first_seg(lv)->origin;
return origin;
}

View File

@@ -1457,15 +1457,6 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
return_0;
}
if (delete && seg_is_integrity(seg)) {
/* Remove integrity origin in addition to integrity layer. */
if (!lv_remove(seg_lv(seg, 0)))
return_0;
/* Remove integrity metadata. */
if (seg->integrity_meta_dev && !lv_remove(seg->integrity_meta_dev))
return_0;
}
if ((pool_lv = seg->pool_lv)) {
if (!detach_pool_lv(seg))
return_0;
@@ -5663,11 +5654,6 @@ int lv_resize(struct logical_volume *lv,
return 0;
}
if (lv_is_integrity(lv)) {
log_error("Resize not yet allowed on LVs with integrity.");
return 0;
}
if (!_lvresize_check(lv, lp))
return_0;
@@ -7424,12 +7410,6 @@ int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
return 1;
}
/* FIXME: copied from label.c */
#define BCACHE_BLOCK_SIZE_IN_SECTORS 256 /* 256*512 = 128K */
#define BCACHE_BLOCK_SIZE_IN_BYTES 131072
#define ONE_MB_IN_BYTES 1048576
#define ONE_MB_IN_SECTORS 2048 /* 2048 * 512 = 1048576 */
/*
* Initialize the LV with 'value'.
*/
@@ -7488,44 +7468,7 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
stack;
}
if (wp.do_zero && !wp.zero_value && (wp.zero_sectors >= ONE_MB_IN_SECTORS)) {
uint64_t off = 0, i = 0, j = 0;
uint64_t zero_bytes;
uint32_t extra_bytes;
zero_bytes = wp.zero_sectors * 512;
if ((extra_bytes = (zero_bytes % ONE_MB_IN_BYTES)))
zero_bytes -= extra_bytes;
log_print("Zeroing %llu MiB...", (unsigned long long)(zero_bytes / ONE_MB_IN_BYTES));
/*
* Write 1MiB at a time to avoid going over bcache size.
* Then write 128KiB at a time to cover remaining dev size.
*/
for (i = 0; i < (zero_bytes / ONE_MB_IN_BYTES); i++) {
off = i * ONE_MB_IN_BYTES;
if (!dev_write_zeros(dev, off, (size_t)ONE_MB_IN_BYTES))
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
}
if (extra_bytes) {
log_warn("Zeroing %u bytes at %llu...", extra_bytes, (unsigned long long)off);
for (j = 0; j < (extra_bytes / BCACHE_BLOCK_SIZE_IN_BYTES); j++) {
off = i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES;
if (!dev_write_zeros(dev, off, (size_t)BCACHE_BLOCK_SIZE_IN_BYTES))
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
}
}
/* FIXME: bcache can't write partial block yet */
if ((extra_bytes = (wp.zero_sectors * 512) - (i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES)))
log_warn("WARNING: last %llu bytes not zeroed.", (unsigned long long)extra_bytes);
} else if (wp.do_zero) {
if (wp.do_zero) {
zero_sectors = wp.zero_sectors ? : UINT64_C(4096) >> SECTOR_SHIFT;
if (zero_sectors > lv->size)
@@ -7736,15 +7679,6 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
first_seg(first_seg(lv)->pool_lv)->zero_new_blocks))
return 0;
/*
* dm-integrity requires the first sector (integrity superblock) to be
* zero when creating a new integrity device.
* TODO: print a warning or error if the user specifically
* asks for no wiping or zeroing?
*/
if (seg_is_integrity(lp))
return 1;
/* Cannot zero read-only volume */
if ((lv->status & LVM_WRITE) &&
(lp->zero || lp->wipe_signatures))
@@ -8000,18 +7934,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
/* FIXME Eventually support raid/mirrors with -m */
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
} else if (seg_is_integrity(lp)) {
/*
* TODO: if using internal metadata, estimate the amount of metadata
* that will be needed, and add this to the amount of PV space being
* allocated so that the usable LV size is what the user requested.
* Or, just request an extra extent_size bytes, then round the
* provided_data_sectors down to be an extent_size multiple.
*/
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
} else if (seg_is_mirrored(lp) || (seg_is_raid(lp) && !seg_is_any_raid0(lp))) {
if (!(lp->region_size = adjusted_mirror_region_size(vg->cmd,
vg->extent_size,
@@ -8355,19 +8277,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
goto revert_new_lv;
}
lv->status &= ~LV_TEMPORARY;
} else if (seg_is_integrity(lp)) {
/*
* Activate the new origin LV so it can be zeroed/wiped
* below before adding integrity.
*/
lv->status |= LV_TEMPORARY;
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate new LV for wiping.");
goto revert_new_lv;
}
lv->status &= ~LV_TEMPORARY;
} else if (!lv_active_change(cmd, lv, lp->activate)) {
log_error("Failed to activate new LV %s.", display_lvname(lv));
goto deactivate_and_revert_new_lv;
@@ -8387,55 +8296,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
if (seg_is_integrity(lp)) {
struct wipe_params wipe;
log_verbose("Adding integrity to new LV");
/* Origin is active from zeroing, deactivate to add integrity. */
if (!deactivate_lv(cmd, lv)) {
log_error("Failed to deactivate LV to add integrity");
goto revert_new_lv;
}
if (!lv_add_integrity(lv, lp->integrity_arg, lp->integrity_meta_lv,
lp->integrity_meta_name, &lp->integrity_settings))
goto revert_new_lv;
backup(vg);
/*
* This zeroing is for the final integrity LV, which
* initializes the integrity metadata (checksums). It's
* different from zeroing the first sector of the integrity
* origin or integrity metadata.
*/
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate LV to zero integrity.");
goto out;
}
memset(&wipe, 0, sizeof(wipe));
wipe.do_zero = 1;
wipe.zero_sectors = first_seg(lv)->integrity_data_sectors;
log_print("Zeroing integrity checksums (%llu sectors) on LV %s",
(unsigned long long)wipe.zero_sectors, display_lvname(lv));
if (!wipe_lv(lv, wipe))
log_error("Failed to zero integrity metadata.");
/* If the final requested state is inactive, then deactivate LV. */
if (!lv_active_change(cmd, lv, lp->activate)) {
log_error("Failed to activate new LV %s.", display_lvname(lv));
goto deactivate_and_revert_new_lv;
}
goto out;
}
if (seg_is_vdo_pool(lp)) {
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents)) {
stack;

View File

@@ -742,8 +742,6 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
seg_found++;
if (seg->metadata_lv == lv || seg->pool_lv == lv || seg->writecache == lv)
seg_found++;
if (seg->integrity_meta_dev == lv)
seg_found++;
if (seg_is_thin_volume(seg) && (seg->origin == lv || seg->external_lv == lv))
seg_found++;

View File

@@ -84,14 +84,12 @@
#define CONVERTING UINT64_C(0x0000000000400000) /* LV */
#define MISSING_PV UINT64_C(0x0000000000800000) /* PV */
#define INTEGRITY UINT64_C(0x0000000000800000) /* LV - Internal use only */
#define PV_MOVED_VG UINT64_C(0x4000000000000000) /* PV - Moved to a new VG */
#define PARTIAL_LV UINT64_C(0x0000000001000000) /* LV - derived flag, not
written out in metadata*/
//#define POSTORDER_FLAG UINT64_C(0x0000000002000000) /* Not real flags, reserved for
//#define POSTORDER_OPEN_FLAG UINT64_C(0x0000000004000000) temporary use inside vg_read_internal. */
#define LV_UNCOMMITTED UINT64_C(0x0000000002000000)
#define VIRTUAL_ORIGIN UINT64_C(0x0000000008000000) /* LV - internal use only */
#define MERGING UINT64_C(0x0000000010000000) /* LV SEG */
@@ -263,7 +261,6 @@
#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_writecache(lv) (((lv)->status & WRITECACHE) ? 1 : 0)
#define lv_is_integrity(lv) (((lv)->status & INTEGRITY) ? 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)
@@ -522,10 +519,6 @@ struct lv_segment {
uint32_t writecache_block_size; /* For writecache */
struct writecache_settings writecache_settings; /* For writecache */
uint64_t integrity_data_sectors;
struct logical_volume *integrity_meta_dev;
struct integrity_settings integrity_settings;
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 */
@@ -999,11 +992,6 @@ struct lvcreate_params {
alloc_policy_t alloc; /* all */
struct dm_vdo_target_params vdo_params; /* vdo */
const char *integrity_arg;
const char *integrity_meta_name; /* external LV is user-specified */
struct logical_volume *integrity_meta_lv; /* external LV we create */
struct integrity_settings integrity_settings;
struct dm_list tags; /* all */
int yes;
@@ -1397,12 +1385,4 @@ int vg_is_foreign(struct volume_group *vg);
void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
int lv_add_integrity(struct logical_volume *lv, const char *arg,
struct logical_volume *meta_lv_created,
const char *meta_name, struct integrity_settings *settings);
int lv_create_integrity_metadata(struct cmd_context *cmd,
struct volume_group *vg,
struct lvcreate_params *lp);
#endif

View File

@@ -4586,6 +4586,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
struct device *mda_dev, *dev_ret, *dev;
struct cached_vg_fmtdata *vg_fmtdata = NULL; /* Additional format-specific data about the vg */
struct pv_list *pvl;
const char *rescan_reason = NULL;
int found_old_metadata = 0;
int found_md_component = 0;
unsigned use_previous_vg;
@@ -4622,16 +4623,27 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
*
* The devs in the VG may be persistently inconsistent due to some
* previous problem. In this case, rescanning the labels here will
* find the same inconsistency. The VG repair (mistakenly done by
* vg_read below) is supposed to fix that.
* find the same inconsistency.
*
* FIXME: sort out the usage of the global lock (which is mixed up
* with the orphan lock), and when we can tell that the global
* lock is taken prior to the label scan, and still held here,
* we can also skip the rescan in that case.
* Even though it's acceptable to report old metadata that was scanned
* prior to taking the VG lock, we can actually detect the rare case
* when another command has written the metadata between the time of
* our scan and us acquiring the VG lock. We save the VG lock file
* timestamp prior to scan, then check it again aftrr taking the VG
* lock (file_lock_time_unchanged). If the timestamp is different, it
* means that another command has written the metadata since our scan,
* and we rescan it here to report the latest metadata.
*/
if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
log_debug_metadata("Rescanning devices for %s %s", vgname, writing ? "rw" : "");
if (!cmd->can_use_one_scan)
rescan_reason = "disabled";
else if (lvmcache_scan_mismatch(cmd, vgname, vgid))
rescan_reason = "mismatch";
else if (!file_lock_time_unchanged(cmd, vgname))
rescan_reason = "changed";
if (rescan_reason) {
log_debug_metadata("Rescanning devices for %s %s (%s)", vgname, writing ? "rw" : "", rescan_reason);
if (writing)
lvmcache_label_rescan_vg_rw(cmd, vgname, vgid);
else

View File

@@ -67,7 +67,6 @@ struct dev_manager;
#define SEG_RAID6_N_6 (1ULL << 35)
#define SEG_RAID6 SEG_RAID6_ZR
#define SEG_WRITECACHE (1ULL << 36)
#define SEG_INTEGRITY (1ULL << 37)
#define SEG_STRIPED_TARGET (1ULL << 39)
#define SEG_LINEAR_TARGET (1ULL << 40)
@@ -85,7 +84,6 @@ struct dev_manager;
#define SEG_TYPE_NAME_CACHE "cache"
#define SEG_TYPE_NAME_CACHE_POOL "cache-pool"
#define SEG_TYPE_NAME_WRITECACHE "writecache"
#define SEG_TYPE_NAME_INTEGRITY "integrity"
#define SEG_TYPE_NAME_ERROR "error"
#define SEG_TYPE_NAME_FREE "free"
#define SEG_TYPE_NAME_ZERO "zero"
@@ -119,7 +117,6 @@ struct dev_manager;
#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0)
#define segtype_is_cache_pool(segtype) ((segtype)->flags & SEG_CACHE_POOL ? 1 : 0)
#define segtype_is_writecache(segtype) ((segtype)->flags & SEG_WRITECACHE ? 1 : 0)
#define segtype_is_integrity(segtype) ((segtype)->flags & SEG_INTEGRITY ? 1 : 0)
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
#define segtype_is_mirror(segtype) ((segtype)->flags & SEG_MIRROR ? 1 : 0)
#define segtype_is_pool(segtype) ((segtype)->flags & (SEG_CACHE_POOL | SEG_THIN_POOL) ? 1 : 0)
@@ -182,7 +179,6 @@ struct dev_manager;
#define seg_is_cache(seg) segtype_is_cache((seg)->segtype)
#define seg_is_cache_pool(seg) segtype_is_cache_pool((seg)->segtype)
#define seg_is_writecache(seg) segtype_is_writecache((seg)->segtype)
#define seg_is_integrity(seg) segtype_is_integrity((seg)->segtype)
#define seg_is_used_cache_pool(seg) (seg_is_cache_pool(seg) && (!dm_list_empty(&(seg->lv)->segs_using_this_lv)))
#define seg_is_linear(seg) (seg_is_striped(seg) && ((seg)->area_count == 1))
#define seg_is_mirror(seg) segtype_is_mirror((seg)->segtype)
@@ -351,8 +347,6 @@ int init_vdo_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
int init_writecache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
int init_integrity_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
#define CACHE_FEATURE_POLICY_MQ (1U << 0)
#define CACHE_FEATURE_POLICY_SMQ (1U << 1)
#define CACHE_FEATURE_METADATA2 (1U << 2)

View File

@@ -25,36 +25,16 @@
struct lock_list {
struct dm_list list;
int lf;
unsigned ex:1;
unsigned remove_on_unlock:1;
char *res;
struct timespec save_time;
};
static struct dm_list _lock_list;
static int _prioritise_write_locks;
/* Drop lock known to be shared with another file descriptor. */
static void _drop_shared_flock(const char *file, int fd)
{
log_debug_locking("_drop_shared_flock %s.", file);
if (close(fd) < 0)
log_sys_debug("close", file);
}
static void _undo_flock(const char *file, int fd)
{
struct stat buf1, buf2;
log_debug_locking("_undo_flock %s", file);
if (!flock(fd, LOCK_NB | LOCK_EX) &&
!stat(file, &buf1) &&
!fstat(fd, &buf2) &&
is_same_inode(buf1, buf2))
if (unlink(file))
log_sys_debug("unlink", file);
if (close(fd) < 0)
log_sys_debug("close", file);
}
#define AUX_LOCK_SUFFIX ":aux"
static struct lock_list *_get_lock_list_entry(const char *file)
{
@@ -70,6 +50,19 @@ static struct lock_list *_get_lock_list_entry(const char *file)
return NULL;
}
static void _unlink_aux(const char *file)
{
char aux_path[PATH_MAX];
if (dm_snprintf(aux_path, sizeof(aux_path), "%s%s", file, AUX_LOCK_SUFFIX) < 0) {
stack;
return;
}
if (unlink(aux_path))
log_sys_debug("unlink", aux_path);
}
static int _release_lock(const char *file, int unlock)
{
struct lock_list *ll;
@@ -78,18 +71,54 @@ static int _release_lock(const char *file, int unlock)
dm_list_iterate_safe(llh, llt, &_lock_list) {
ll = dm_list_item(llh, struct lock_list);
if (ll->lf < 0)
continue;
if (!file || !strcmp(ll->res, file)) {
dm_list_del(llh);
/*
* When a VG is being removed, and the flock is still
* held for the VG, it sets the remove_on_unlock flag,
* so that when the flock is unlocked, the lock file is
* then also removed.
*/
if (file && unlock && ll->remove_on_unlock) {
log_debug("Unlocking %s and removing", ll->res);
if (_prioritise_write_locks)
_unlink_aux(ll->res);
if (flock(ll->lf, LOCK_NB | LOCK_UN))
log_sys_debug("flock", ll->res);
if (unlink(ll->res))
log_sys_debug("unlink", ll->res);
if (close(ll->lf) < 0)
log_sys_debug("close", ll->res);
dm_list_del(&ll->list);
free(ll->res);
free(ll);
return 1;
}
/*
* Update the lock file timestamp when unlocking an
* exclusive flock. Other commands may use the
* timestamp change to detect that the VG was changed.
*/
if (file && unlock && ll->ex) {
if (futimens(ll->lf, NULL) < 0)
log_debug("lock file %s time update error %d", file, errno);
}
if (unlock) {
log_very_verbose("Unlocking %s", ll->res);
if (flock(ll->lf, LOCK_NB | LOCK_UN))
log_sys_debug("flock", ll->res);
_undo_flock(ll->res, ll->lf);
} else
_drop_shared_flock(ll->res, ll->lf);
}
free(ll->res);
free(llh);
if (close(ll->lf) < 0)
log_sys_debug("close", ll->res);
ll->lf = -1;
if (file)
return 1;
@@ -154,8 +183,6 @@ static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock
return_0;
}
#define AUX_LOCK_SUFFIX ":aux"
static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock)
{
int r, fd_aux = -1;
@@ -167,9 +194,11 @@ static int _do_write_priority_flock(const char *file, int *fd, int operation, ui
if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
if (operation == LOCK_EX) {
r = _do_flock(file, fd, operation, nonblock);
_undo_flock(file_aux, fd_aux);
if (close(fd_aux) < 0)
log_sys_debug("close", file_aux);
} else {
_undo_flock(file_aux, fd_aux);
if (close(fd_aux) < 0)
log_sys_debug("close", file_aux);
r = _do_flock(file, fd, operation, nonblock);
}
}
@@ -183,6 +212,7 @@ int lock_file(const char *file, uint32_t flags)
uint32_t nonblock = flags & LCK_NONBLOCK;
uint32_t convert = flags & LCK_CONVERT;
int r;
int ex = 0;
struct lock_list *ll;
char state;
@@ -194,6 +224,7 @@ int lock_file(const char *file, uint32_t flags)
case LCK_WRITE:
operation = LOCK_EX;
state = 'W';
ex = 1;
break;
case LCK_UNLOCK:
return _release_lock(file, 1);
@@ -210,22 +241,27 @@ int lock_file(const char *file, uint32_t flags)
log_very_verbose("Locking %s %c%c convert", ll->res, state,
nonblock ? ' ' : 'B');
r = flock(ll->lf, operation);
if (!r)
if (!r) {
ll->ex = ex;
return 1;
}
log_error("Failed to convert flock on %s %d", file, errno);
return 0;
}
if (!(ll = malloc(sizeof(struct lock_list))))
return_0;
if (!(ll = _get_lock_list_entry(file))) {
if (!(ll = zalloc(sizeof(struct lock_list))))
return_0;
if (!(ll->res = strdup(file))) {
free(ll);
return_0;
if (!(ll->res = strdup(file))) {
free(ll);
return_0;
}
ll->lf = -1;
dm_list_add(&_lock_list, &ll->list);
}
ll->lf = -1;
log_very_verbose("Locking %s %c%c", ll->res, state,
nonblock ? ' ' : 'B');
@@ -237,12 +273,9 @@ int lock_file(const char *file, uint32_t flags)
(void) dm_prepare_selinux_context(NULL, 0);
if (r)
dm_list_add(&_lock_list, &ll->list);
else {
free(ll->res);
free(ll);
ll->ex = ex;
else
stack;
}
return r;
}
@@ -254,3 +287,93 @@ void init_flock(struct cmd_context *cmd)
_prioritise_write_locks =
find_config_tree_bool(cmd, global_prioritise_write_locks_CFG, NULL);
}
void free_flocks(void)
{
struct lock_list *ll, *ll2;
dm_list_iterate_items_safe(ll, ll2, &_lock_list) {
dm_list_del(&ll->list);
free(ll->res);
free(ll);
}
}
/*
* Save the lock file timestamps prior to scanning, so that the timestamps can
* be checked later (lock_file_time_unchanged) to see if the VG has been
* changed.
*/
void lock_file_time_init(const char *file)
{
struct lock_list *ll;
struct stat buf;
if (stat(file, &buf) < 0)
return;
if (!(ll = _get_lock_list_entry(file))) {
if (!(ll = zalloc(sizeof(struct lock_list))))
return;
if (!(ll->res = strdup(file))) {
free(ll);
return;
}
ll->lf = -1;
ll->save_time = buf.st_mtim;
dm_list_add(&_lock_list, &ll->list);
}
}
/*
* Check if a lock file timestamp has been changed (by other command) since we
* saved it (lock_file_time_init). Another command may have updated the lock
* file timestamp when releasing an ex flock (futimens above.)
*/
bool lock_file_time_unchanged(const char *file)
{
struct lock_list *ll;
struct stat buf;
struct timespec *prev, *now;
if (stat(file, &buf) < 0) {
log_debug("lock_file_time_unchanged no file %s", file);
return false;
}
if (!(ll = _get_lock_list_entry(file))) {
log_debug("lock_file_time_unchanged no list item %s", file);
return false;
}
prev = &ll->save_time;
now = &buf.st_mtim;
if ((now->tv_sec == prev->tv_sec) && (now->tv_nsec == prev->tv_nsec)) {
log_debug("lock file %s unchanged from %llu.%llu", file,
(unsigned long long)prev->tv_sec,
(unsigned long long)prev->tv_nsec);
return true;
}
log_debug("lock file %s changed from %llu.%llu to %llu.%llu", file,
(unsigned long long)prev->tv_sec,
(unsigned long long)prev->tv_nsec,
(unsigned long long)now->tv_sec,
(unsigned long long)now->tv_nsec);
return false;
}
void lock_file_remove_on_unlock(const char *file)
{
struct lock_list *ll;
if ((ll = _get_lock_list_entry(file)))
ll->remove_on_unlock = 1;
}

View File

@@ -16,7 +16,12 @@
#define _LVM_FLOCK_H
void init_flock(struct cmd_context *cmd);
void free_flocks(void);
int lock_file(const char *file, uint32_t flags);
void release_flocks(int unlock);
void lock_file_time_init(const char *file);
bool lock_file_time_unchanged(const char *file);
void lock_file_remove_on_unlock(const char *file);
#endif /* _LVM_FLOCK_H */

View File

@@ -272,15 +272,6 @@ arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0,
"and \\fBdiff\\fP types include unsupported settings in their output by default,\n"
"all the other types ignore unsupported settings.\n")
arg(integrity_ARG, '\0', "integrity", string_VAL, 0, 0,
"Controls if integrity metadata should be stored and checked for an LV.\n")
arg(integritymetadata_ARG, '\0', "integritymetadata", lv_VAL, 0, 0,
"The name of an LV to hold integrity metadata.\n")
arg(integritysettings_ARG, '\0', "integritysettings", string_VAL, ARG_GROUPABLE, 0,
"Set dm-integrity parameters.\n")
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
"By default the PV is labelled with an LVM2 identifier in its second\n"
"sector (sector 1). This lets you use a different sector near the\n"

View File

@@ -1269,20 +1269,6 @@ FLAGS: SECONDARY_SYNTAX
---
lvcreate --type integrity --size SizeMB VG
OO: --integrity String, --integritymetadata LV, --integritysettings String, OO_LVCREATE
OP: PV ...
ID: lvcreate_integrity
DESC: Create a LV with integrity.
lvcreate --integrity String --size SizeMB VG
OO: --type integrity, --integritymetadata LV, --integritysettings String, OO_LVCREATE
OP: PV ...
ID: lvcreate_integrity
DESC: Create a LV with integrity (infers --type integrity).
---
lvdisplay
OO: --aligned, --all, --binary, --colon, --columns,
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,

View File

@@ -34,6 +34,5 @@ lvt(raid10_LVT, "raid10", NULL)
lvt(error_LVT, "error", NULL)
lvt(zero_LVT, "zero", NULL)
lvt(writecache_LVT, "writecache", NULL)
lvt(integrity_LVT, "integrity", NULL)
lvt(LVT_COUNT, "", NULL)

View File

@@ -785,8 +785,6 @@ static int _lvcreate_params(struct cmd_context *cmd,
mirror_default_cfg = (arg_uint_value(cmd, stripes_ARG, 1) > 1)
? global_raid10_segtype_default_CFG : global_mirror_segtype_default_CFG;
segtype_str = find_config_tree_str(cmd, mirror_default_cfg, NULL);
} else if (arg_is_set(cmd, integrity_ARG)) {
segtype_str = SEG_TYPE_NAME_INTEGRITY;
} else
segtype_str = SEG_TYPE_NAME_STRIPED;
@@ -1220,11 +1218,6 @@ static int _lvcreate_params(struct cmd_context *cmd,
}
}
if (seg_is_integrity(lp)) {
if (!get_integrity_options(cmd, &lp->integrity_arg, &lp->integrity_meta_name, &lp->integrity_settings))
return 0;
}
lcp->pv_count = argc;
lcp->pvs = argv;
@@ -1709,24 +1702,6 @@ static int _lvcreate_single(struct cmd_context *cmd, const char *vg_name,
lp->pool_name ? : "with generated name", lp->vg_name, lp->segtype->name);
}
/*
* Create an LV to hold integrity metadata when:
*
* . The user wants external (not internal) metadata. External
* is indicated by: no option set (external is default), or
* --integrity y|external.
*
* . The user did not specify an existing metadata LV with
* --integritymetadata, saved as lp->integrity_meta_name.
*/
if (seg_is_integrity(lp) && !lp->integrity_meta_name &&
(!lp->integrity_arg ||
!strcmp(lp->integrity_arg, "external") ||
!strcmp(lp->integrity_arg, "y"))) {
if (!lv_create_integrity_metadata(cmd, vg, lp))
goto_out;
}
if (vg->lock_type && !strcmp(vg->lock_type, "sanlock")) {
if (!handle_sanlock_lv(cmd, vg)) {
log_error("No space for sanlock lock, extend the internal lvmlock LV.");

View File

@@ -1414,174 +1414,6 @@ out:
return ok;
}
static int _get_one_integrity_setting(struct cmd_context *cmd, struct integrity_settings *settings,
char *key, char *val)
{
if (!strncmp(key, "mode", strlen("mode"))) {
if (*val == 'D')
settings->mode[0] = 'D';
else if (*val == 'J')
settings->mode[0] = 'J';
else if (*val == 'B')
settings->mode[0] = 'B';
else if (*val == 'R')
settings->mode[0] = 'R';
else
goto_bad;
/* lvm assigns a default if the user doesn't. */
return 1;
}
if (!strncmp(key, "tag_size", strlen("tag_size"))) {
if (sscanf(val, "%u", &settings->tag_size) != 1)
goto_bad;
/* lvm assigns a default if the user doesn't. */
return 1;
}
if (!strncmp(key, "internal_hash", strlen("internal_hash"))) {
if (!(settings->internal_hash = strdup(val)))
goto_bad;
/* lvm assigns a default if the user doesn't. */
return 1;
}
/*
* For the following settings, lvm does not set a default value if the
* user does not specify their own value, and lets dm-integrity use its
* own default.
*/
if (!strncmp(key, "journal_sectors", strlen("journal_sectors"))) {
if (sscanf(val, "%u", &settings->journal_sectors) != 1)
goto_bad;
settings->journal_sectors_set = 1;
return 1;
}
if (!strncmp(key, "interleave_sectors", strlen("interleave_sectors"))) {
if (sscanf(val, "%u", &settings->interleave_sectors) != 1)
goto_bad;
settings->interleave_sectors_set = 1;
return 1;
}
if (!strncmp(key, "buffer_sectors", strlen("buffer_sectors"))) {
if (sscanf(val, "%u", &settings->buffer_sectors) != 1)
goto_bad;
settings->buffer_sectors_set = 1;
return 1;
}
if (!strncmp(key, "journal_watermark", strlen("journal_watermark"))) {
if (sscanf(val, "%u", &settings->journal_watermark) != 1)
goto_bad;
settings->journal_watermark_set = 1;
return 1;
}
if (!strncmp(key, "commit_time", strlen("commit_time"))) {
if (sscanf(val, "%u", &settings->commit_time) != 1)
goto_bad;
settings->commit_time_set = 1;
return 1;
}
if (!strncmp(key, "block_size", strlen("block_size"))) {
if (sscanf(val, "%u", &settings->block_size) != 1)
goto_bad;
settings->block_size_set = 1;
return 1;
}
if (!strncmp(key, "bitmap_flush_interval", strlen("bitmap_flush_interval"))) {
if (sscanf(val, "%u", &settings->bitmap_flush_interval) != 1)
goto_bad;
settings->bitmap_flush_interval_set = 1;
return 1;
}
if (!strncmp(key, "sectors_per_bit", strlen("sectors_per_bit"))) {
if (sscanf(val, "%llu", (unsigned long long *)&settings->sectors_per_bit) != 1)
goto_bad;
settings->sectors_per_bit_set = 1;
return 1;
}
log_error("Unknown setting: %s", key);
return 0;
bad:
log_error("Invalid setting: %s", key);
return 0;
}
static int _get_integrity_settings(struct cmd_context *cmd, struct integrity_settings *settings)
{
struct arg_value_group_list *group;
const char *str;
char key[64];
char val[64];
int num;
int pos;
/*
* "grouped" means that multiple --integritysettings options can be used.
* Each option is also allowed to contain multiple key = val pairs.
*/
dm_list_iterate_items(group, &cmd->arg_value_groups) {
if (!grouped_arg_is_set(group->arg_values, integritysettings_ARG))
continue;
if (!(str = grouped_arg_str_value(group->arg_values, integritysettings_ARG, NULL)))
break;
pos = 0;
while (pos < strlen(str)) {
/* scan for "key1=val1 key2 = val2 key3= val3" */
memset(key, 0, sizeof(key));
memset(val, 0, sizeof(val));
if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
log_error("Invalid setting at: %s", str+pos);
return 0;
}
pos += num;
if (!_get_one_integrity_setting(cmd, settings, key, val))
return_0;
}
}
return 1;
}
int get_integrity_options(struct cmd_context *cmd, const char **arg, const char **meta_name,
struct integrity_settings *set)
{
*arg = NULL;
*meta_name = NULL;
memset(set, 0, sizeof(struct integrity_settings));
if (arg_is_set(cmd, integrity_ARG))
*arg = arg_str_value(cmd, integrity_ARG, NULL);
if (arg_is_set(cmd, integritymetadata_ARG))
*meta_name = arg_str_value(cmd, integritymetadata_ARG, NULL);
if (arg_is_set(cmd, integritysettings_ARG)) {
if (!_get_integrity_settings(cmd, set))
return_0;
}
return 1;
}
/* FIXME move to lib */
static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
{
@@ -2747,8 +2579,6 @@ static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int l
return seg_is_raid10(seg);
case writecache_LVT:
return seg_is_writecache(seg);
case integrity_LVT:
return seg_is_integrity(seg);
case error_LVT:
return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR);
case zero_LVT:
@@ -2807,8 +2637,6 @@ int get_lvt_enum(struct logical_volume *lv)
return raid10_LVT;
if (seg_is_writecache(seg))
return writecache_LVT;
if (seg_is_integrity(seg))
return integrity_LVT;
if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR))
return error_LVT;

View File

@@ -233,9 +233,6 @@ struct lv_prop *get_lv_prop(int lvp_enum);
struct lv_type *get_lv_type(int lvt_enum);
struct command *get_command(int cmd_enum);
int get_integrity_options(struct cmd_context *cmd, const char **arg, const char **meta_name,
struct integrity_settings *set);
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv);

View File

@@ -78,6 +78,8 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
lockd_free_vg_final(cmd, vg);
file_lock_remove_on_unlock(cmd, vg->name);
return ECMD_PROCESSED;
}