mirror of
git://sourceware.org/git/lvm2.git
synced 2026-01-02 20:32:47 +03:00
Compare commits
76 Commits
dev-dct-ca
...
dev-dct-in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf16309c35 | ||
|
|
2173bdb821 | ||
|
|
2da6f01c15 | ||
|
|
4a52855899 | ||
|
|
611d4107a4 | ||
|
|
3b6defcf1f | ||
|
|
8ab1d489f3 | ||
|
|
89d839e541 | ||
|
|
abc0a8faba | ||
|
|
5555765cfc | ||
|
|
cff16b062b | ||
|
|
e70d5d470c | ||
|
|
4353823306 | ||
|
|
df0bc5081c | ||
|
|
338f4df54b | ||
|
|
3f381784f2 | ||
|
|
ec71df6fec | ||
|
|
91f91b80f1 | ||
|
|
3d7f755674 | ||
|
|
0a7495e680 | ||
|
|
5a88b2ce7f | ||
|
|
3145a85583 | ||
|
|
2e0f273008 | ||
|
|
d051e899a5 | ||
|
|
9cf08836ef | ||
|
|
53126ceada | ||
|
|
94076245df | ||
|
|
74ad2cd76f | ||
|
|
13c629fb78 | ||
|
|
39bd9b111b | ||
|
|
4485b8edca | ||
|
|
657d42e879 | ||
|
|
595aa1d452 | ||
|
|
98a8099da9 | ||
|
|
b400353c71 | ||
|
|
a61272a6f0 | ||
|
|
0c1316cda8 | ||
|
|
56a295f78c | ||
|
|
29db9c6325 | ||
|
|
2037476008 | ||
|
|
1c9b36618e | ||
|
|
bbd8badaef | ||
|
|
b690258518 | ||
|
|
4757ce4c2a | ||
|
|
1e669ab315 | ||
|
|
7474440d3b | ||
|
|
f88f7c0fdc | ||
|
|
496c368528 | ||
|
|
dccc50f6f6 | ||
|
|
7ea71a9eb9 | ||
|
|
31a862a6be | ||
|
|
91df257b53 | ||
|
|
e92d3bd1f7 | ||
|
|
14e01d6316 | ||
|
|
1760b96368 | ||
|
|
9af1d63b4d | ||
|
|
33c1d2e921 | ||
|
|
ad0343d8cb | ||
|
|
9ee3af7efc | ||
|
|
cbabdf2fca | ||
|
|
1da5fd8226 | ||
|
|
61a483a654 | ||
|
|
c38be06531 | ||
|
|
1349a52626 | ||
|
|
219fe72359 | ||
|
|
d4d82dbb70 | ||
|
|
70fb31b5d6 | ||
|
|
1f4968289c | ||
|
|
d67ce9e140 | ||
|
|
0bad3977df | ||
|
|
153e55c20e | ||
|
|
44bf9c9a6a | ||
|
|
82e6b820b8 | ||
|
|
43f149526d | ||
|
|
33c8e4de33 | ||
|
|
13c254fc05 |
@@ -1 +1 @@
|
||||
1.02.167-git (2019-10-23)
|
||||
1.02.169-git (2019-11-30)
|
||||
|
||||
10
WHATS_NEW
10
WHATS_NEW
@@ -1,7 +1,13 @@
|
||||
Version 2.03.07 -
|
||||
===================================
|
||||
Version 2.03.08 -
|
||||
====================================
|
||||
|
||||
Version 2.03.07 - 30th November 2019
|
||||
====================================
|
||||
Subcommand in vgck for repairing headers and metadata.
|
||||
Ensure minimum required region size on striped RaidLV creation.
|
||||
Fix resize of thin-pool with data and metadata of different segtype.
|
||||
Improve mirror type leg splitting.
|
||||
Improve error path handling in daemons on shutdown.
|
||||
Fix activation order when removing merged snapshot.
|
||||
Experimental VDO support for lvmdbusd.
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
Version 1.02.167 -
|
||||
====================================
|
||||
Version 1.02.169 -
|
||||
=====================================
|
||||
Enhance error messages for device creation.
|
||||
|
||||
Version 1.02.167 - 30th November 2019
|
||||
=====================================
|
||||
|
||||
Version 1.02.165 - 23rd October 2019
|
||||
====================================
|
||||
|
||||
@@ -1745,7 +1745,8 @@ static void _init_thread_signals(void)
|
||||
sigdelset(&my_sigset, SIGHUP);
|
||||
sigdelset(&my_sigset, SIGQUIT);
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
|
||||
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
|
||||
log_sys_error("pthread_sigmask", "SIG_BLOCK");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
/* Use parser from new device_mapper library */
|
||||
/*
|
||||
* Use parser from new device_mapper library.
|
||||
* Although during compilation we can see dm_vdo_status_parse()
|
||||
* in runtime we are linked agains systems libdm 'older' library
|
||||
* which does not provide this symbol and plugin fails to load
|
||||
*/
|
||||
#include "device_mapper/vdo/status.c"
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -392,6 +392,15 @@ 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
|
||||
*
|
||||
@@ -970,6 +979,36 @@ 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,
|
||||
int recalculate);
|
||||
|
||||
/*
|
||||
* VDO target
|
||||
|
||||
@@ -2012,7 +2012,8 @@ static int _sysfs_get_kernel_name(uint32_t major, uint32_t minor, char *buf, siz
|
||||
log_sys_error("readlink", sysfs_path);
|
||||
else {
|
||||
log_sys_debug("readlink", sysfs_path);
|
||||
return _sysfs_find_kernel_name(major, minor, buf, buf_size);
|
||||
r = _sysfs_find_kernel_name(major, minor, buf, buf_size);
|
||||
goto out;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
@@ -2033,6 +2034,7 @@ static int _sysfs_get_kernel_name(uint32_t major, uint32_t minor, char *buf, siz
|
||||
strcpy(buf, name);
|
||||
r = 1;
|
||||
bad:
|
||||
out:
|
||||
free(temp_buf);
|
||||
free(sysfs_path);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ enum {
|
||||
SEG_STRIPED,
|
||||
SEG_ZERO,
|
||||
SEG_WRITECACHE,
|
||||
SEG_INTEGRITY,
|
||||
SEG_THIN_POOL,
|
||||
SEG_THIN,
|
||||
SEG_VDO,
|
||||
@@ -78,6 +79,7 @@ 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" },
|
||||
@@ -221,6 +223,11 @@ 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 */
|
||||
int integrity_recalculate; /* integrity */
|
||||
};
|
||||
|
||||
/* Per-device properties */
|
||||
@@ -2705,6 +2712,88 @@ 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 (seg->integrity_recalculate)
|
||||
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 (seg->integrity_recalculate)
|
||||
EMIT_PARAMS(pos, " recalculate");
|
||||
|
||||
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)
|
||||
@@ -2889,6 +2978,10 @@ 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) {
|
||||
@@ -2901,6 +2994,7 @@ 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:
|
||||
@@ -3738,6 +3832,42 @@ 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,
|
||||
int recalculate)
|
||||
{
|
||||
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));
|
||||
|
||||
seg->integrity_recalculate = recalculate;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *rlog_uuid,
|
||||
|
||||
@@ -380,6 +380,35 @@ 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;
|
||||
|
||||
@@ -20,6 +20,7 @@ SOURCES =\
|
||||
activate/activate.c \
|
||||
cache/lvmcache.c \
|
||||
writecache/writecache.c \
|
||||
integrity/integrity.c \
|
||||
cache_segtype/cache.c \
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
@@ -67,6 +68,7 @@ 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 \
|
||||
|
||||
@@ -325,25 +325,11 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned or
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv, const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, int noscan,
|
||||
int temporary, const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
@@ -2413,7 +2399,7 @@ static int _lv_has_open_snapshots(const struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv)
|
||||
static int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv)
|
||||
{
|
||||
struct lvinfo info;
|
||||
static const struct lv_activate_opts laopts = { .skip_in_use = 1 };
|
||||
@@ -2609,34 +2595,6 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Activate LV */
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = { .exclusive = exclusive,
|
||||
.noscan = noscan,
|
||||
.temporary = temporary };
|
||||
|
||||
if (!_lv_activate(cmd, lvid_s, &laopts, 0, lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Activate LV only if it passes filter */
|
||||
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = { .exclusive = exclusive,
|
||||
.noscan = noscan,
|
||||
.temporary = temporary };
|
||||
|
||||
if (!_lv_activate(cmd, lvid_s, &laopts, 1, lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
@@ -2867,11 +2825,18 @@ int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
int activate_lv_opts(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts)
|
||||
{
|
||||
const struct logical_volume *active_lv;
|
||||
int ret;
|
||||
|
||||
if (lv->status & LV_NOSCAN)
|
||||
laopts->noscan = 1;
|
||||
|
||||
if (lv->status & LV_TEMPORARY)
|
||||
laopts->temporary = 1;
|
||||
|
||||
/*
|
||||
* When trying activating component LV, make sure none of sub component
|
||||
* LV or LVs that are using it are active.
|
||||
@@ -2888,14 +2853,18 @@ int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = lv_activate_with_filter(cmd, NULL, 0,
|
||||
(lv->status & LV_NOSCAN) ? 1 : 0,
|
||||
(lv->status & LV_TEMPORARY) ? 1 : 0,
|
||||
lv_committed(lv));
|
||||
ret = _lv_activate(cmd, NULL, laopts, 1, lv_committed(lv));
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = { 0 };
|
||||
|
||||
return activate_lv_opts(cmd, lv, &laopts);
|
||||
}
|
||||
|
||||
int deactivate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -39,6 +39,7 @@ typedef enum {
|
||||
SEG_STATUS_THIN_POOL,
|
||||
SEG_STATUS_VDO_POOL,
|
||||
SEG_STATUS_WRITECACHE,
|
||||
SEG_STATUS_INTEGRITY,
|
||||
SEG_STATUS_UNKNOWN
|
||||
} lv_seg_status_type_t;
|
||||
|
||||
@@ -53,6 +54,7 @@ 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;
|
||||
};
|
||||
};
|
||||
@@ -72,6 +74,7 @@ struct lv_activate_opts {
|
||||
int no_merging;
|
||||
int send_messages;
|
||||
int skip_in_use;
|
||||
int integrity_recalculate;
|
||||
unsigned revert;
|
||||
unsigned read_only;
|
||||
unsigned noscan; /* Mark this LV to avoid its scanning. This also
|
||||
@@ -122,9 +125,6 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
|
||||
unsigned origin_only, unsigned exclusive, unsigned revert, const struct logical_volume *lv);
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv);
|
||||
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv);
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv);
|
||||
|
||||
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
|
||||
@@ -132,6 +132,8 @@ int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv);
|
||||
|
||||
int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
int deactivate_lv(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
int activate_lv_opts(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts);
|
||||
int suspend_lv(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
int suspend_lv_origin(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
int resume_lv(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
@@ -260,6 +262,7 @@ 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"
|
||||
@@ -277,6 +280,7 @@ 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"
|
||||
|
||||
@@ -46,7 +46,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", "cvol", "tdata", "tmeta", "vdata", "vpool", NULL};
|
||||
const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "cvol", "tdata", "tmeta", "vdata", "vpool", "imeta", NULL};
|
||||
|
||||
struct dlid_list {
|
||||
struct dm_list list;
|
||||
@@ -222,6 +222,10 @@ 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!
|
||||
@@ -299,6 +303,9 @@ 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);
|
||||
@@ -2620,6 +2627,10 @@ 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 */
|
||||
@@ -3076,6 +3087,11 @@ 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) &&
|
||||
|
||||
54
lib/cache/lvmcache.c
vendored
54
lib/cache/lvmcache.c
vendored
@@ -21,7 +21,6 @@
|
||||
#include "lib/locking/locking.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/mm/memlock.h"
|
||||
#include "lib/datastruct/str_list.h"
|
||||
#include "lib/format_text/format-text.h"
|
||||
#include "lib/config/config.h"
|
||||
|
||||
@@ -239,6 +238,30 @@ void lvmcache_get_bad_mdas(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
void lvmcache_get_mdas(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid,
|
||||
struct dm_list *mda_list)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
struct mda_list *mdal;
|
||||
struct metadata_area *mda, *mda2;
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
|
||||
log_error(INTERNAL_ERROR "lvmcache_get_mdas no vginfo %s", vgname);
|
||||
return;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(info, &vginfo->infos) {
|
||||
dm_list_iterate_items_safe(mda, mda2, &info->mdas) {
|
||||
if (!(mdal = zalloc(sizeof(*mdal))))
|
||||
continue;
|
||||
mdal->mda = mda;
|
||||
dm_list_add(mda_list, &mdal->list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
|
||||
struct lvmcache_info *info)
|
||||
{
|
||||
@@ -1952,24 +1975,25 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller,
|
||||
|
||||
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
|
||||
|
||||
/*
|
||||
* Keep the existing PV/dev in lvmcache, and save the
|
||||
* new duplicate in the list of duplicates. After
|
||||
* scanning is complete, compare the duplicate devs
|
||||
* with those in lvmcache to check if one of the
|
||||
* duplicates is preferred and if so switch lvmcache to
|
||||
* use it.
|
||||
*/
|
||||
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
return_NULL;
|
||||
devl->dev = dev;
|
||||
|
||||
/* shouldn't happen */
|
||||
if (dev_in_device_list(dev, &_initial_duplicates))
|
||||
log_debug_cache("Initial duplicate already in list %s", dev_name(dev));
|
||||
else
|
||||
else {
|
||||
/*
|
||||
* Keep the existing PV/dev in lvmcache, and save the
|
||||
* new duplicate in the list of duplicates. After
|
||||
* scanning is complete, compare the duplicate devs
|
||||
* with those in lvmcache to check if one of the
|
||||
* duplicates is preferred and if so switch lvmcache to
|
||||
* use it.
|
||||
*/
|
||||
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
return_NULL;
|
||||
devl->dev = dev;
|
||||
|
||||
dm_list_add(&_initial_duplicates, &devl->list);
|
||||
}
|
||||
|
||||
if (is_duplicate)
|
||||
*is_duplicate = 1;
|
||||
|
||||
4
lib/cache/lvmcache.h
vendored
4
lib/cache/lvmcache.h
vendored
@@ -216,4 +216,8 @@ void lvmcache_get_bad_mdas(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid,
|
||||
struct dm_list *bad_mda_list);
|
||||
|
||||
void lvmcache_get_mdas(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid,
|
||||
struct dm_list *mda_list);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1362,6 +1362,9 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!init_integrity_segtypes(cmd, &seglib))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,21 @@ bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_invalidate_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||
{
|
||||
block_address bb, be;
|
||||
bool result = true;
|
||||
|
||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_invalidate(cache, fd, bb))
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
// Writing bytes and zeroing bytes are very similar, so we factor out
|
||||
|
||||
@@ -163,6 +163,7 @@ bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
|
||||
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data);
|
||||
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
|
||||
bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, uint8_t val);
|
||||
bool bcache_invalidate_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
|
||||
|
||||
void bcache_set_last_byte(struct bcache *cache, int fd, uint64_t offset, int sector_size);
|
||||
void bcache_unset_last_byte(struct bcache *cache, int fd);
|
||||
|
||||
@@ -1522,7 +1522,7 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
|
||||
sysfs_dir = dm_sysfs_dir();
|
||||
if (sysfs_dir && *sysfs_dir) {
|
||||
/* First check if dev is sysfs to avoid useless scan */
|
||||
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d",
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
|
||||
sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) {
|
||||
log_error("dm_snprintf partition failed.");
|
||||
return NULL;
|
||||
|
||||
@@ -42,7 +42,6 @@ int dev_is_pmem(struct device *dev)
|
||||
{
|
||||
FILE *fp;
|
||||
char path[PATH_MAX];
|
||||
char buffer[64];
|
||||
int is_pmem = 0;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/queue/dax",
|
||||
@@ -56,27 +55,16 @@ int dev_is_pmem(struct device *dev)
|
||||
if (!(fp = fopen(path, "r")))
|
||||
return 0;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
log_warn("Failed to read %s.", path);
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
return 0;
|
||||
} else if (sscanf(buffer, "%d", &is_pmem) != 1) {
|
||||
log_warn("Failed to parse %s '%s'.", path, buffer);
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
return 0;
|
||||
}
|
||||
if (fscanf(fp, "%d", &is_pmem) != 1)
|
||||
log_warn("Failed to parse DAX %s.", path);
|
||||
|
||||
if (is_pmem)
|
||||
log_debug("%s is pmem", dev_name(dev));
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
|
||||
if (is_pmem) {
|
||||
log_debug("%s is pmem", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return is_pmem ? 1 : 0;
|
||||
}
|
||||
|
||||
int dev_is_lv(struct device *dev)
|
||||
@@ -84,6 +72,7 @@ int dev_is_lv(struct device *dev)
|
||||
FILE *fp;
|
||||
char path[PATH_MAX];
|
||||
char buffer[64];
|
||||
int ret = 0;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/uuid",
|
||||
dm_sysfs_dir(),
|
||||
@@ -96,17 +85,15 @@ int dev_is_lv(struct device *dev)
|
||||
if (!(fp = fopen(path, "r")))
|
||||
return 0;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
if (!fgets(buffer, sizeof(buffer), fp))
|
||||
log_warn("Failed to read %s.", path);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
else if (!strncmp(buffer, "LVM-", 4))
|
||||
ret = 1;
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
|
||||
if (!strncmp(buffer, "LVM-", 4))
|
||||
return 1;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dev_types *create_dev_types(const char *proc_dir,
|
||||
|
||||
@@ -104,6 +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},
|
||||
{INTEGRITY_METADATA, NULL, 0},
|
||||
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
|
||||
{LV_REMOVED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
|
||||
@@ -277,7 +277,6 @@ static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
dev_set_last_byte(dev, start_byte + MDA_HEADER_SIZE);
|
||||
|
||||
if (!dev_write_bytes(dev, start_byte, MDA_HEADER_SIZE, mdah)) {
|
||||
dev_unset_last_byte(dev);
|
||||
log_error("Failed to write mda header to %s fd %d", dev_name(dev), dev->bcache_fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -342,7 +341,7 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
|
||||
* Don't try to check existing metadata
|
||||
* if given vgname is an empty string.
|
||||
*/
|
||||
if (!*vgname)
|
||||
if (!vgname || !*vgname)
|
||||
return rlocn;
|
||||
|
||||
/*
|
||||
@@ -532,29 +531,6 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
return vg;
|
||||
}
|
||||
|
||||
#define MAX_DESC_LEN 2048
|
||||
|
||||
static char *_build_desc_write(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
size_t len = strlen(cmd->cmd_line) + 32;
|
||||
char *desc;
|
||||
|
||||
if (len > MAX_DESC_LEN)
|
||||
len = MAX_DESC_LEN;
|
||||
|
||||
if (!(desc = zalloc(len)))
|
||||
return_NULL;
|
||||
|
||||
vg->write_count++;
|
||||
|
||||
if (vg->write_count == 1)
|
||||
dm_snprintf(desc, len, "Write from %s.", cmd->cmd_line);
|
||||
else
|
||||
dm_snprintf(desc, len, "Write[%u] from %s.", vg->write_count, cmd->cmd_line);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/*
|
||||
* VG metadata updates:
|
||||
*
|
||||
@@ -599,6 +575,7 @@ static char *_build_desc_write(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
char desc[2048];
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
|
||||
struct raw_locn *rlocn_old;
|
||||
@@ -673,12 +650,15 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
write_buf_size = fidtc->write_buf_size;
|
||||
new_size = fidtc->new_metadata_size;
|
||||
} else {
|
||||
char *desc = _build_desc_write(fid->fmt->cmd, vg);
|
||||
if (!vg->write_count++)
|
||||
(void) dm_snprintf(desc, sizeof(desc), "Write from %s.", vg->cmd->cmd_line);
|
||||
else
|
||||
(void) dm_snprintf(desc, sizeof(desc), "Write[%u] from %s.", vg->write_count, vg->cmd->cmd_line);
|
||||
|
||||
new_size = text_vg_export_raw(vg, desc, &write_buf, &write_buf_size);
|
||||
fidtc->write_buf = write_buf;
|
||||
fidtc->write_buf_size = write_buf_size;
|
||||
fidtc->new_metadata_size = new_size;
|
||||
free(desc);
|
||||
}
|
||||
|
||||
if (!new_size || !write_buf) {
|
||||
@@ -989,7 +969,6 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!dev_write_bytes(mdac->area.dev, write1_start, (size_t)write1_size, write_buf)) {
|
||||
log_error("Failed to write metadata to %s fd %d", devname, mdac->area.dev->bcache_fd);
|
||||
dev_unset_last_byte(mdac->area.dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1002,7 +981,6 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
if (!dev_write_bytes(mdac->area.dev, write2_start, write2_size,
|
||||
write_buf + new_size - new_wrap)) {
|
||||
log_error("Failed to write metadata wrap to %s fd %d", devname, mdac->area.dev->bcache_fd);
|
||||
dev_unset_last_byte(mdac->area.dev);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1529,6 +1507,7 @@ static int _vg_remove_file(struct format_instance *fid __attribute__((unused)),
|
||||
}
|
||||
|
||||
int read_metadata_location_summary(const struct format_type *fmt,
|
||||
struct metadata_area *mda,
|
||||
struct mda_header *mdah, int primary_mda, struct device_area *dev_area,
|
||||
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
|
||||
{
|
||||
@@ -1586,6 +1565,17 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to read the vg summary during label scan.
|
||||
* Save the text start location and checksum during scan. After the VG
|
||||
* lock is acquired in vg_read, we can reread the mda_header, and
|
||||
* compare rlocn->offset,checksum to what was saved during scan. If
|
||||
* unchanged, it means that the metadata was not changed between scan
|
||||
* and the read.
|
||||
*/
|
||||
mda->scan_text_offset = rlocn->offset;
|
||||
mda->scan_text_checksum = rlocn->checksum;
|
||||
|
||||
/*
|
||||
* When the current metadata wraps around the end of the metadata area
|
||||
* (so some is located at the end and some is located at the
|
||||
|
||||
@@ -47,11 +47,15 @@ enum pv_vg_lv_e {
|
||||
|
||||
struct text_vg_version_ops {
|
||||
int (*check_version) (const struct dm_config_tree * cf);
|
||||
struct volume_group *(*read_vg) (struct format_instance * fid,
|
||||
const struct dm_config_tree *cf,
|
||||
unsigned allow_lvmetad_extensions);
|
||||
|
||||
struct volume_group *(*read_vg) (struct cmd_context *cmd,
|
||||
const struct format_type *fmt,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft);
|
||||
|
||||
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
|
||||
time_t *when, char **desc);
|
||||
|
||||
int (*read_vgsummary) (const struct format_type *fmt,
|
||||
const struct dm_config_tree *cft,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "import-export.h"
|
||||
|
||||
/* FIXME Use tidier inclusion method */
|
||||
@@ -181,7 +182,7 @@ struct volume_group *text_read_metadata(struct format_instance *fid,
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
|
||||
if (!(vg = (*vsn)->read_vg(fid->fmt->cmd, fid->fmt, fid, cft)))
|
||||
goto_out;
|
||||
|
||||
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
|
||||
@@ -210,9 +211,9 @@ struct volume_group *text_read_metadata_file(struct format_instance *fid,
|
||||
when, desc);
|
||||
}
|
||||
|
||||
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
static struct volume_group *_import_vg_from_config_tree(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
unsigned allow_lvmetad_extensions)
|
||||
const struct dm_config_tree *cft)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct text_vg_version_ops **vsn;
|
||||
@@ -227,7 +228,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
|
||||
* The only path to this point uses cached vgmetadata,
|
||||
* so it can use cached PV state too.
|
||||
*/
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, allow_lvmetad_extensions)))
|
||||
if (!(vg = (*vsn)->read_vg(cmd, fid->fmt, fid, cft)))
|
||||
stack;
|
||||
else {
|
||||
set_pv_devices(fid, vg, NULL);
|
||||
@@ -243,8 +244,21 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid)
|
||||
struct volume_group *import_vg_from_config_tree(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft)
|
||||
{
|
||||
return _import_vg_from_config_tree(cft, fid, 0);
|
||||
return _import_vg_from_config_tree(cmd, fid, cft);
|
||||
}
|
||||
|
||||
struct volume_group *vg_from_config_tree(struct cmd_context *cmd, const struct dm_config_tree *cft)
|
||||
{
|
||||
static struct text_vg_version_ops *ops;
|
||||
|
||||
_init_text_import();
|
||||
|
||||
ops = _text_vsn_list[0];
|
||||
|
||||
return ops->read_vg(cmd, cmd->fmt, NULL, cft);
|
||||
}
|
||||
|
||||
|
||||
@@ -993,7 +993,7 @@ static int _read_lvsegs(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
static int _read_sections(struct cmd_context *cmd,
|
||||
struct format_type *fmt,
|
||||
const struct format_type *fmt,
|
||||
struct format_instance *fid,
|
||||
struct dm_pool *mem,
|
||||
const char *section, section_fn fn,
|
||||
@@ -1016,19 +1016,18 @@ static int _read_sections(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
for (n = n->child; n; n = n->sib) {
|
||||
if (!fn(cmd, fmt, fid, mem, vg, vgsummary, n, vgn, pv_hash, lv_hash))
|
||||
if (!fn(cmd, (struct format_type *)fmt, fid, mem, vg, vgsummary, n, vgn, pv_hash, lv_hash))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
const struct dm_config_tree *cft,
|
||||
unsigned allow_lvmetad_extensions)
|
||||
static struct volume_group *_read_vg(struct cmd_context *cmd,
|
||||
const struct format_type *fmt,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft)
|
||||
{
|
||||
struct cmd_context *cmd = fid->fmt->cmd;
|
||||
struct format_type *fmt = (struct format_type *)fid->fmt;
|
||||
struct dm_pool *mem;
|
||||
const struct dm_config_node *vgn;
|
||||
const struct dm_config_value *cv;
|
||||
@@ -1234,7 +1233,8 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
dm_hash_destroy(pv_hash);
|
||||
dm_hash_destroy(lv_hash);
|
||||
|
||||
vg_set_fid(vg, fid);
|
||||
if (fid)
|
||||
vg_set_fid(vg, fid);
|
||||
|
||||
/*
|
||||
* Finished.
|
||||
|
||||
@@ -104,7 +104,8 @@ struct mda_context {
|
||||
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
|
||||
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
|
||||
|
||||
int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
|
||||
int read_metadata_location_summary(const struct format_type *fmt,
|
||||
struct metadata_area *mda, struct mda_header *mdah, int primary_mda,
|
||||
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
|
||||
uint64_t *mda_free_sectors);
|
||||
|
||||
|
||||
@@ -332,14 +332,12 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
log_warn("WARNING: bad metadata header on %s at %llu.",
|
||||
dev_name(mdac->area.dev),
|
||||
(unsigned long long)mdac->area.start);
|
||||
if (mda)
|
||||
mda->header_start = mdac->area.start;
|
||||
mda->header_start = mdac->area.start;
|
||||
*bad_fields |= BAD_MDA_HEADER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mda)
|
||||
mda->header_start = mdah->start;
|
||||
mda->header_start = mdah->start;
|
||||
|
||||
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
|
||||
|
||||
@@ -351,7 +349,7 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
|
||||
if (!read_metadata_location_summary(fmt, mda, mdah, mda_is_primary(mda), &mdac->area,
|
||||
vgsummary, &mdac->free_sectors)) {
|
||||
if (vgsummary->zero_offset)
|
||||
return 1;
|
||||
|
||||
329
lib/integrity/integrity.c
Normal file
329
lib/integrity/integrity.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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)
|
||||
meta_lv->status |= INTEGRITY_METADATA;
|
||||
|
||||
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,
|
||||
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,
|
||||
laopts->integrity_recalculate))
|
||||
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;
|
||||
}
|
||||
@@ -638,7 +638,8 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
char devpath[PATH_MAX];
|
||||
FILE *fp;
|
||||
struct dev_iter *iter;
|
||||
struct hint *hint;
|
||||
struct hint hint;
|
||||
struct hint *alloc_hint;
|
||||
struct device *dev;
|
||||
char *split[HINT_LINE_WORDS];
|
||||
char *name, *pvid, *devn, *vgname, *p, *filter_str = NULL;
|
||||
@@ -662,11 +663,7 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
split[i] = NULL;
|
||||
|
||||
while (fgets(_hint_line, sizeof(_hint_line), fp)) {
|
||||
if (!(hint = zalloc(sizeof(struct hint)))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
if (_hint_line[0] == '#')
|
||||
continue;
|
||||
|
||||
@@ -704,13 +701,11 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
_filter_to_str(cmd, devices_global_filter_CFG, &filter_str);
|
||||
if (!filter_str || strcmp(filter_str, _hint_line + keylen)) {
|
||||
log_debug("ignore hints with different global_filter");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -719,23 +714,20 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
_filter_to_str(cmd, devices_filter_CFG, &filter_str);
|
||||
if (!filter_str || strcmp(filter_str, _hint_line + keylen)) {
|
||||
log_debug("ignore hints with different filter");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
keylen = strlen("scan_lvs:");
|
||||
if (!strncmp(_hint_line, "scan_lvs:", keylen)) {
|
||||
int scan_lvs = 0;
|
||||
sscanf(_hint_line + keylen, "%u", &scan_lvs);
|
||||
|
||||
if (scan_lvs != cmd->scan_lvs) {
|
||||
log_debug("ignore hints with different scan_lvs");
|
||||
if ((sscanf(_hint_line + keylen, "%u", &scan_lvs) != 1) ||
|
||||
scan_lvs != cmd->scan_lvs) {
|
||||
log_debug("ignore hints with different or unreadable scan_lvs");
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
@@ -744,7 +736,11 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
|
||||
keylen = strlen("devs_hash:");
|
||||
if (!strncmp(_hint_line, "devs_hash:", keylen)) {
|
||||
sscanf(_hint_line + keylen, "%u %u", &read_hash, &read_count);
|
||||
if (sscanf(_hint_line + keylen, "%u %u", &read_hash, &read_count) != 2) {
|
||||
log_debug("ignore hints with invalid devs_hash");
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -764,19 +760,28 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
vgname = split[3];
|
||||
|
||||
if (name && !strncmp(name, "scan:", 5))
|
||||
strncpy(hint->name, name+5, PATH_MAX);
|
||||
if (!dm_strncpy(hint.name, name + 5, sizeof(hint.name)))
|
||||
continue;
|
||||
|
||||
if (pvid && !strncmp(pvid, "pvid:", 5))
|
||||
strncpy(hint->pvid, pvid+5, ID_LEN);
|
||||
if (!dm_strncpy(hint.pvid, pvid + 5, sizeof(hint.pvid)))
|
||||
continue;
|
||||
|
||||
if (devn && sscanf(devn, "devn:%d:%d", &major, &minor) == 2)
|
||||
hint->devt = makedev(major, minor);
|
||||
hint.devt = makedev(major, minor);
|
||||
|
||||
if (vgname && (strlen(vgname) > 3) && (vgname[4] != '-'))
|
||||
strncpy(hint->vgname, vgname+3, NAME_LEN);
|
||||
if (!dm_strncpy(hint.vgname, vgname + 3, sizeof(hint.vgname)))
|
||||
continue;
|
||||
|
||||
log_debug("add hint %s %s %d:%d %s", hint->name, hint->pvid, major, minor, vgname);
|
||||
dm_list_add(hints, &hint->list);
|
||||
if (!(alloc_hint = malloc(sizeof(struct hint)))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
memcpy(alloc_hint, &hint, sizeof(hint));
|
||||
|
||||
log_debug("add hint %s %s %d:%d %s", hint.name, hint.pvid, major, minor, vgname);
|
||||
dm_list_add(hints, &alloc_hint->list);
|
||||
found++;
|
||||
}
|
||||
|
||||
@@ -911,13 +916,11 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
|
||||
_filter_to_str(cmd, devices_global_filter_CFG, &filter_str);
|
||||
fprintf(fp, "global_filter:%s\n", filter_str ?: "-");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
|
||||
_filter_to_str(cmd, devices_filter_CFG, &filter_str);
|
||||
fprintf(fp, "filter:%s\n", filter_str ?: "-");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
|
||||
fprintf(fp, "scan_lvs:%d\n", cmd->scan_lvs);
|
||||
|
||||
@@ -951,7 +954,6 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
* detect when the devices on the system change, which
|
||||
* invalidates the existing hints.
|
||||
*/
|
||||
memset(devpath, 0, sizeof(devpath));
|
||||
strncpy(devpath, dev_name(dev), PATH_MAX);
|
||||
hash = calc_crc(hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
count++;
|
||||
@@ -1179,7 +1181,8 @@ static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
|
||||
|
||||
if (!(st = strchr(arg, '/'))) {
|
||||
/* simple vgname */
|
||||
name = strdup(arg);
|
||||
if (!(name = strdup(arg)))
|
||||
return;
|
||||
goto check;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1190,8 @@ static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
|
||||
for (p = arg; p < st; p++)
|
||||
namebuf[i++] = *p;
|
||||
|
||||
name = strdup(namebuf);
|
||||
if (!(name = strdup(namebuf)))
|
||||
return;
|
||||
|
||||
check:
|
||||
/*
|
||||
@@ -1202,6 +1206,8 @@ check:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1261,8 +1267,9 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
*/
|
||||
if (_newhints_exists()) {
|
||||
log_debug("get_hints: newhints file");
|
||||
if (!_hints_exists())
|
||||
_touch_hints();
|
||||
if (!_hints_exists() && !_touch_hints())
|
||||
return 0;
|
||||
|
||||
if (!_lock_hints(cmd, LOCK_EX, NONBLOCK))
|
||||
return 0;
|
||||
/* create new hints after scan */
|
||||
@@ -1355,6 +1362,9 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
dm_list_size(devs_out), dm_list_size(devs_in));
|
||||
|
||||
dm_list_splice(hints_out, &hints_list);
|
||||
|
||||
free(vgname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/label/hints.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/format_text/format-text.h"
|
||||
#include "lib/format_text/layout.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -218,7 +220,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
|
||||
if (!dev_write_bytes(dev, offset, LABEL_SIZE, buf)) {
|
||||
log_debug_devs("Failed to write label to %s", dev_name(dev));
|
||||
r = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_unset_last_byte(dev);
|
||||
@@ -655,7 +657,6 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
int submit_count;
|
||||
int scan_failed;
|
||||
int is_lvm_device;
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
dm_list_init(&wait_devs);
|
||||
@@ -702,12 +703,11 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
|
||||
dm_list_iterate_items_safe(devl, devl2, &wait_devs) {
|
||||
bb = NULL;
|
||||
error = 0;
|
||||
scan_failed = 0;
|
||||
is_lvm_device = 0;
|
||||
|
||||
if (!bcache_get(scan_bcache, devl->dev->bcache_fd, 0, 0, &bb)) {
|
||||
log_debug_devs("Scan failed to read %s error %d.", dev_name(devl->dev), error);
|
||||
log_debug_devs("Scan failed to read %s.", dev_name(devl->dev));
|
||||
scan_failed = 1;
|
||||
scan_read_errors++;
|
||||
scan_failed_count++;
|
||||
@@ -921,6 +921,74 @@ static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_d
|
||||
#endif
|
||||
}
|
||||
|
||||
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out)
|
||||
{
|
||||
char buf[LABEL_SIZE] __attribute__((aligned(8)));
|
||||
struct dm_list devs;
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
struct pv_header *pvh;
|
||||
int ret = 0;
|
||||
|
||||
dm_list_init(&devs);
|
||||
|
||||
dev_cache_scan();
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter, 0))) {
|
||||
log_error("Scanning failed to get devices.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_devs("Filtering devices to scan");
|
||||
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
continue;
|
||||
devl->dev = dev;
|
||||
dm_list_add(&devs, &devl->list);
|
||||
};
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
if (!scan_bcache) {
|
||||
if (!_setup_bcache())
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_debug_devs("Reading labels for pvid");
|
||||
|
||||
dm_list_iterate_items(devl, &devs) {
|
||||
dev = devl->dev;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (!label_scan_open(dev))
|
||||
continue;
|
||||
|
||||
if (!dev_read_bytes(dev, 512, LABEL_SIZE, buf)) {
|
||||
_scan_dev_close(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pvh = (struct pv_header *)(buf + 32);
|
||||
|
||||
if (!memcmp(pvh->pv_uuid, pvid, ID_LEN)) {
|
||||
*dev_out = devl->dev;
|
||||
_scan_dev_close(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
ret = 1;
|
||||
out:
|
||||
dm_list_iterate_items_safe(devl, devl2, &devs) {
|
||||
dm_list_del(&devl->list);
|
||||
free(devl);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan devices on the system to discover which are LVM devices.
|
||||
* Info about the LVM devices (PVs) is saved in lvmcache in a
|
||||
@@ -1451,6 +1519,7 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
if (!bcache_write_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
@@ -1458,12 +1527,18 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
if (!bcache_flush(scan_bcache)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
|
||||
{
|
||||
return bcache_invalidate_bytes(scan_bcache, dev->bcache_fd, start, len);
|
||||
}
|
||||
|
||||
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len)
|
||||
{
|
||||
if (test_mode())
|
||||
|
||||
@@ -118,6 +118,8 @@ int label_scan_open(struct device *dev);
|
||||
int label_scan_open_excl(struct device *dev);
|
||||
int label_scan_open_rw(struct device *dev);
|
||||
|
||||
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out);
|
||||
|
||||
/*
|
||||
* Wrappers around bcache equivalents.
|
||||
* (these make it easier to disable bcache and revert to direct rw if needed)
|
||||
@@ -126,6 +128,7 @@ bool dev_read_bytes(struct device *dev, uint64_t start, size_t len, void *data);
|
||||
bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data);
|
||||
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
|
||||
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
|
||||
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len);
|
||||
void dev_set_last_byte(struct device *dev, uint64_t offset);
|
||||
void dev_unset_last_byte(struct device *dev);
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ int sync_local_dev_names(struct cmd_context* cmd)
|
||||
* an explicitly acquired ex global lock to sh in process_each.
|
||||
*/
|
||||
|
||||
static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
|
||||
static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert, int nonblock)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
int ret;
|
||||
@@ -346,6 +346,9 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
|
||||
if (convert)
|
||||
flags |= LCK_CONVERT;
|
||||
|
||||
if (nonblock)
|
||||
flags |= LCK_NONBLOCK;
|
||||
|
||||
if (!strcmp(mode, "ex")) {
|
||||
flags |= LCK_WRITE;
|
||||
|
||||
@@ -379,7 +382,7 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
|
||||
|
||||
int lockf_global(struct cmd_context *cmd, const char *mode)
|
||||
{
|
||||
return _lockf_global(cmd, mode, 0);
|
||||
return _lockf_global(cmd, mode, 0, 0);
|
||||
}
|
||||
|
||||
int lockf_global_convert(struct cmd_context *cmd, const char *mode)
|
||||
@@ -388,7 +391,12 @@ int lockf_global_convert(struct cmd_context *cmd, const char *mode)
|
||||
if (cmd->lockf_global_ex && !strcmp(mode, "ex"))
|
||||
return 1;
|
||||
|
||||
return _lockf_global(cmd, mode, 1);
|
||||
return _lockf_global(cmd, mode, 1, 0);
|
||||
}
|
||||
|
||||
int lockf_global_nonblock(struct cmd_context *cmd, const char *mode)
|
||||
{
|
||||
return _lockf_global(cmd, mode, 0, 1);
|
||||
}
|
||||
|
||||
int lock_global(struct cmd_context *cmd, const char *mode)
|
||||
|
||||
@@ -75,6 +75,7 @@ int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusiv
|
||||
|
||||
int lockf_global(struct cmd_context *cmd, const char *mode);
|
||||
int lockf_global_convert(struct cmd_context *cmd, const char *mode);
|
||||
int lockf_global_nonblock(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);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "lib/config/defaults.h"
|
||||
#include "lib/metadata/lv_alloc.h"
|
||||
#include "lib/misc/lvm-signal.h"
|
||||
#include "lib/activate/dev_manager.h"
|
||||
|
||||
/* https://github.com/jthornber/thin-provisioning-tools/blob/master/caching/cache_metadata_size.cc */
|
||||
#define DM_TRANSACTION_OVERHEAD 4096 /* KiB */
|
||||
|
||||
738
lib/metadata/integrity_manip.c
Normal file
738
lib/metadata/integrity_manip.c
Normal file
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
int lv_is_integrity_origin(const struct logical_volume *lv)
|
||||
{
|
||||
struct seg_list *sl;
|
||||
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
if (!sl->seg || !sl->seg->lv || !sl->seg->origin)
|
||||
continue;
|
||||
if (lv_is_integrity(sl->seg->lv) && (sl->seg->origin == lv))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Every 500M of data needs 4M of metadata.
|
||||
* (From trial and error testing.)
|
||||
*/
|
||||
static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
|
||||
{
|
||||
return ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES);
|
||||
}
|
||||
|
||||
/*
|
||||
* The user wants external metadata, but did not specify an existing
|
||||
* LV to hold metadata, so create an LV for metadata.
|
||||
*/
|
||||
static int _lv_create_integrity_metadata(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct lvcreate_params *lp,
|
||||
struct logical_volume **meta_lv)
|
||||
{
|
||||
char metaname[NAME_LEN];
|
||||
uint64_t lv_size_bytes, meta_bytes, meta_sectors;
|
||||
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,
|
||||
.suppress_zero_warn = 1,
|
||||
};
|
||||
|
||||
if (lp->lv_name &&
|
||||
dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) {
|
||||
log_error("Failed to create metadata LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->lv_name &&
|
||||
!generate_lv_name(vg, "lvol%d_imeta", metaname, sizeof(metaname))) {
|
||||
log_error("Failed to generate LV name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lp_meta.lv_name = strdup(metaname)))
|
||||
return_0;
|
||||
|
||||
lp_meta.pvh = lp->pvh;
|
||||
|
||||
lv_size_bytes = lp->extents * vg->extent_size * 512;
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
|
||||
meta_sectors = meta_bytes / 512;
|
||||
lp_meta.extents = meta_sectors / vg->extent_size;
|
||||
|
||||
log_print("Creating integrity metadata LV %s with size %s.",
|
||||
metaname, display_size(cmd, meta_sectors));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*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;
|
||||
uint64_t data_sectors, extra_sectors;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
data_sectors = status.seg_status.integrity->provided_data_sectors;
|
||||
|
||||
if ((extra_sectors = (data_sectors % lv->vg->extent_size))) {
|
||||
data_sectors -= extra_sectors;
|
||||
log_debug("Reduce provided_data_sectors by %llu to %llu for extent alignment",
|
||||
(unsigned long long)extra_sectors, (unsigned long long)data_sectors);
|
||||
}
|
||||
|
||||
*provided_data_sectors = data_sectors;
|
||||
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lv_remove_integrity_from_raid(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg_top, *seg_image;
|
||||
struct logical_volume *lv_image;
|
||||
struct logical_volume *lv_iorig;
|
||||
struct logical_volume *lv_imeta;
|
||||
uint32_t area_count, s;
|
||||
|
||||
seg_top = first_seg(lv);
|
||||
|
||||
if (!seg_is_raid1(seg_top)) {
|
||||
log_error("LV %s segment is not raid1.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
area_count = seg_top->area_count;
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (!(lv_imeta = seg_image->integrity_meta_dev)) {
|
||||
log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv_iorig = seg_lv(seg_image, 0))) {
|
||||
log_error("LV %s integrity segment has no origin", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!remove_seg_from_segs_using_this_lv(seg_image->integrity_meta_dev, seg_image))
|
||||
return_0;
|
||||
|
||||
lv_set_visible(seg_image->integrity_meta_dev);
|
||||
|
||||
lv_image->status &= ~INTEGRITY;
|
||||
lv_imeta->status &= ~INTEGRITY_METADATA;
|
||||
|
||||
seg_image->integrity_meta_dev = NULL;
|
||||
seg_image->integrity_data_sectors = 0;
|
||||
memset(&seg_image->integrity_settings, 0, sizeof(seg_image->integrity_settings));
|
||||
|
||||
if (!remove_layer_from_lv(lv_image, lv_iorig))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(lv_iorig))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(lv_imeta))
|
||||
log_warn("WARNING: failed to remove integrity metadata LV.");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_remove_integrity(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *meta_lv;
|
||||
|
||||
if (!seg_is_integrity(seg)) {
|
||||
log_error("LV %s segment is not integrity.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!seg->integrity_meta_dev) {
|
||||
log_error("Internal integrity cannot be removed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(meta_lv = seg->integrity_meta_dev)) {
|
||||
log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(origin = seg_lv(seg, 0))) {
|
||||
log_error("LV %s integrity segment has no origin", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!remove_seg_from_segs_using_this_lv(seg->integrity_meta_dev, seg))
|
||||
return_0;
|
||||
|
||||
lv_set_visible(seg->integrity_meta_dev);
|
||||
|
||||
lv->status &= ~INTEGRITY;
|
||||
meta_lv->status &= ~INTEGRITY_METADATA;
|
||||
|
||||
seg->integrity_meta_dev = NULL;
|
||||
|
||||
if (!remove_layer_from_lv(lv, origin))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(origin))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(meta_lv))
|
||||
log_warn("WARNING: failed to remove integrity metadata LV.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add integrity to each raid image.
|
||||
*
|
||||
* for each rimage_N:
|
||||
* . create and allocate a new linear LV rimage_N_imeta
|
||||
* . move the segments from rimage_N to a new rimage_N_iorig
|
||||
* . add an integrity segment to rimage_N with
|
||||
* origin=rimage_N_iorig, meta_dev=rimage_N_imeta
|
||||
*
|
||||
* Before:
|
||||
* rimage_0
|
||||
* segment1: striped: pv0:A
|
||||
* rimage_1
|
||||
* segment1: striped: pv1:B
|
||||
*
|
||||
* After:
|
||||
* rimage_0
|
||||
* segment1: integrity: rimage_0_iorig, rimage_0_imeta
|
||||
* rimage_1
|
||||
* segment1: integrity: rimage_1_iorig, rimage_1_imeta
|
||||
* rimage_0_iorig
|
||||
* segment1: striped: pv0:A
|
||||
* rimage_1_iorig
|
||||
* segment1: striped: pv1:B
|
||||
* rimage_0_imeta
|
||||
* segment1: striped: pv2:A
|
||||
* rimage_1_imeta
|
||||
* segment1: striped: pv2:B
|
||||
*
|
||||
*/
|
||||
|
||||
int lv_add_integrity_to_raid(struct logical_volume *lv, const char *arg,
|
||||
struct integrity_settings *settings,
|
||||
struct dm_list *pvh)
|
||||
{
|
||||
struct lvcreate_params lp;
|
||||
struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *lv_image, *lv_imeta, *lv_iorig;
|
||||
struct lv_segment *seg_top, *seg_image;
|
||||
const struct segment_type *segtype;
|
||||
struct integrity_settings *set;
|
||||
uint64_t status_data_sectors = 0;
|
||||
uint32_t area_count, s;
|
||||
int external = 0, internal = 0;
|
||||
int ret = 1;
|
||||
|
||||
memset(imeta_lvs, 0, sizeof(imeta_lvs));
|
||||
|
||||
if (!arg || !strcmp(arg, "y") || !strcmp(arg, "external"))
|
||||
external = 1;
|
||||
else if (!strcmp(arg, "internal"))
|
||||
internal = 1;
|
||||
else {
|
||||
log_error("Invalid --integrity arg for lvcreate.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_list_size(&lv->segments) != 1)
|
||||
return_0;
|
||||
|
||||
seg_top = first_seg(lv);
|
||||
area_count = seg_top->area_count;
|
||||
|
||||
if (!seg_is_raid1(seg_top)) {
|
||||
log_error("Integrity can only be added to raid1.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (internal) {
|
||||
/*
|
||||
* FIXME: raid on internal integrity might not be used widely
|
||||
* enough to enable, given the additional complexity/support.
|
||||
* i.e. nearly everyone may just use external metadata.
|
||||
*
|
||||
* FIXME: _info_run() needs code to adjust the length, like
|
||||
* is done for if (lv_is_integrity()) length = ...
|
||||
*/
|
||||
/* goto skip_imeta; */
|
||||
log_error("Internal integrity metadata is not yet supported with raid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each rimage, create an _imeta LV for integrity metadata.
|
||||
* Each needs to be zeroed.
|
||||
*/
|
||||
for (s = 0; s < area_count; s++) {
|
||||
struct logical_volume *meta_lv;
|
||||
struct wipe_params wipe;
|
||||
|
||||
if (s >= DEFAULT_RAID_MAX_IMAGES)
|
||||
return_0;
|
||||
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
|
||||
if (!seg_is_striped(first_seg(lv_image))) {
|
||||
log_error("raid1 image must be linear to add integrity");
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a new linear LV NAME_rimage_N_imeta
|
||||
*/
|
||||
memset(&lp, 0, sizeof(lp));
|
||||
lp.lv_name = lv_image->name;
|
||||
lp.pvh = pvh;
|
||||
lp.extents = lv_image->size / vg->extent_size;
|
||||
|
||||
if (!_lv_create_integrity_metadata(cmd, vg, &lp, &meta_lv))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* dm-integrity requires the metadata LV header to be zeroed.
|
||||
*/
|
||||
|
||||
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 = 8;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Used below to set up the new integrity segment. */
|
||||
imeta_lvs[s] = meta_lv;
|
||||
}
|
||||
|
||||
/* skip_imeta: */
|
||||
|
||||
/*
|
||||
* For each rimage, move its segments to a new rimage_iorig and give
|
||||
* the rimage a new integrity segment.
|
||||
*/
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
|
||||
return_0;
|
||||
|
||||
log_debug("Adding integrity to raid image %s", lv_image->name);
|
||||
|
||||
/*
|
||||
* "lv_iorig" is a new LV with new id, but with the segments
|
||||
* from "lv_image". "lv_image" keeps the existing name and id,
|
||||
* but gets a new integrity segment, in place of the segments
|
||||
* that were moved to lv_iorig.
|
||||
*/
|
||||
if (!(lv_iorig = insert_layer_for_lv(cmd, lv_image, INTEGRITY, "_iorig")))
|
||||
return_0;
|
||||
|
||||
lv_image->status |= INTEGRITY;
|
||||
|
||||
/*
|
||||
* Set up the new first segment of lv_image as integrity.
|
||||
*/
|
||||
seg_image = first_seg(lv_image);
|
||||
seg_image->segtype = segtype;
|
||||
|
||||
if (external) {
|
||||
lv_imeta = imeta_lvs[s]; /* external metadata lv created above */
|
||||
lv_imeta->status |= INTEGRITY_METADATA;
|
||||
lv_set_hidden(lv_imeta);
|
||||
seg_image->integrity_data_sectors = lv_image->size;
|
||||
seg_image->integrity_meta_dev = lv_imeta;
|
||||
}
|
||||
|
||||
memcpy(&seg_image->integrity_settings, settings, sizeof(struct integrity_settings));
|
||||
set = &seg_image->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;
|
||||
}
|
||||
|
||||
/*
|
||||
* When using internal metadata, we have to temporarily activate the
|
||||
* integrity image with size 1 to get provided_data_sectors from the
|
||||
* dm-integrity module.
|
||||
*/
|
||||
if (internal) {
|
||||
/* Get size from the first image, others will be the same. */
|
||||
lv_image = seg_lv(seg_top, 0);
|
||||
|
||||
lv_image->status |= LV_TEMPORARY;
|
||||
lv_image->status |= LV_NOSCAN;
|
||||
seg_image = first_seg(lv_image);
|
||||
seg_image->integrity_data_sectors = 1;
|
||||
|
||||
/* write-commit allows activating the LV to get data_sectors */
|
||||
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||
log_error("Preliminary internal integrity write commit error");
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_debug("Activating temporary integrity LV to get data sectors.");
|
||||
|
||||
if (!activate_lv(cmd, lv_image)) {
|
||||
log_error("Failed to activate temporary integrity.");
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_get_provided_data_sectors(lv_image, &status_data_sectors)) {
|
||||
log_error("Failed to get data sectors from dm-integrity");
|
||||
ret = 0;
|
||||
} else {
|
||||
log_print("Found integrity provided_data_sectors %llu", (unsigned long long)status_data_sectors);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (!status_data_sectors) {
|
||||
log_error("LV size too small to include metadata.");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, lv_image)) {
|
||||
log_error("Failed to deactivate temporary integrity.");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
goto_out;
|
||||
|
||||
lv_image->status &= ~LV_NOSCAN;
|
||||
lv_image->status &= ~LV_TEMPORARY;
|
||||
|
||||
/* The main point, setting integrity_data_sectors. */
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
seg_image->integrity_data_sectors = status_data_sectors;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Write VG with integrity added to LV");
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lv_add_integrity(struct logical_volume *lv, const char *arg,
|
||||
const char *meta_name,
|
||||
struct integrity_settings *settings,
|
||||
struct dm_list *pvh)
|
||||
{
|
||||
char imeta_name[NAME_LEN];
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct integrity_settings *segset;
|
||||
struct logical_volume *lv_orig;
|
||||
struct logical_volume *meta_lv = NULL;
|
||||
const struct segment_type *segtype;
|
||||
struct lv_segment *seg;
|
||||
uint64_t lv_size_sectors;
|
||||
int external = 0, internal = 0;
|
||||
int ret = 1;
|
||||
|
||||
lv_size_sectors = lv->size;
|
||||
|
||||
/*
|
||||
* --integrity <arg> is y|external|internal
|
||||
*/
|
||||
|
||||
if (!arg || !strcmp(arg, "y") || !strcmp(arg, "external"))
|
||||
external = 1;
|
||||
else if (!strcmp(arg, "internal"))
|
||||
internal = 1;
|
||||
else {
|
||||
log_error("Invalid --integrity arg for lvcreate.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (internal && meta_name) {
|
||||
log_error("Internal integrity cannot be used with integritymetadata option.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (external && !meta_name) {
|
||||
struct lvcreate_params lp;
|
||||
memset(&lp, 0, sizeof(lp));
|
||||
lp.lv_name = lv->name;
|
||||
lp.pvh = pvh;
|
||||
lp.extents = lv->size / vg->extent_size;
|
||||
|
||||
if (!_lv_create_integrity_metadata(cmd, vg, &lp, &meta_lv))
|
||||
goto_out;
|
||||
|
||||
} else if (external && meta_name) {
|
||||
uint64_t meta_bytes, meta_sectors;
|
||||
|
||||
if (!(meta_lv = find_lv(vg, meta_name))) {
|
||||
log_error("LV %s not found.", meta_name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_sectors * 512);
|
||||
meta_sectors = meta_bytes / 512;
|
||||
|
||||
if (meta_lv->size < meta_sectors) {
|
||||
log_error("Integrity metadata needs %s, metadata LV is only %s.",
|
||||
display_size(cmd, meta_sectors), display_size(cmd, meta_lv->size));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
segset = &seg->integrity_settings;
|
||||
|
||||
if (!segset->mode[0])
|
||||
segset->mode[0] = DEFAULT_MODE;
|
||||
|
||||
if (!segset->tag_size)
|
||||
segset->tag_size = DEFAULT_TAG_SIZE;
|
||||
|
||||
if (!segset->internal_hash)
|
||||
segset->internal_hash = DEFAULT_INTERNAL_HASH;
|
||||
|
||||
/*
|
||||
* 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 = 8;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (meta_name) {
|
||||
/* LVM tradition to add a suffix to an existing LV when using it. */
|
||||
if (dm_snprintf(imeta_name, sizeof(imeta_name), "%s_imeta", meta_lv->name) < 0) {
|
||||
log_error("Can't prepare new imeta name for %s", display_lvname(meta_lv));
|
||||
return 0;
|
||||
}
|
||||
if (!lv_rename_update(cmd, meta_lv, imeta_name, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
meta_lv->status |= INTEGRITY_METADATA;
|
||||
seg->integrity_data_sectors = lv_size_sectors;
|
||||
seg->integrity_meta_dev = meta_lv;
|
||||
lv_set_hidden(meta_lv);
|
||||
} else {
|
||||
/* dm-integrity wants temp/fake size of 1 to report usable size */
|
||||
seg->integrity_data_sectors = 1;
|
||||
|
||||
/* write-commit allows activating the LV to get data_sectors */
|
||||
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||
log_error("Preliminary internal integrity write commit error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->status |= LV_TEMPORARY;
|
||||
lv->status |= LV_NOSCAN;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!seg->integrity_data_sectors) {
|
||||
log_error("LV size too small to include metadata.");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Failed to deactivate temporary integrity.");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -585,6 +585,8 @@ 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;
|
||||
}
|
||||
@@ -1200,10 +1202,13 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
|
||||
repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
|
||||
else if (lv_is_pool_metadata(lv) ||
|
||||
lv_is_pool_metadata_spare(lv) ||
|
||||
lv_is_raid_metadata(lv))
|
||||
lv_is_raid_metadata(lv) ||
|
||||
lv_is_integrity_metadata(lv))
|
||||
repstr[0] = 'e';
|
||||
else if (lv_is_cache_type(lv) || lv_is_writecache(lv))
|
||||
repstr[0] = 'C';
|
||||
else if (lv_is_integrity(lv))
|
||||
repstr[0] = 'g';
|
||||
else if (lv_is_raid(lv))
|
||||
repstr[0] = (lv_is_not_synced(lv)) ? 'R' : 'r';
|
||||
else if (lv_is_mirror(lv))
|
||||
|
||||
@@ -134,7 +134,9 @@ enum {
|
||||
LV_TYPE_SANLOCK,
|
||||
LV_TYPE_CACHEVOL,
|
||||
LV_TYPE_WRITECACHE,
|
||||
LV_TYPE_WRITECACHEORIGIN
|
||||
LV_TYPE_WRITECACHEORIGIN,
|
||||
LV_TYPE_INTEGRITY,
|
||||
LV_TYPE_INTEGRITYORIGIN
|
||||
};
|
||||
|
||||
static const char *_lv_type_names[] = {
|
||||
@@ -190,6 +192,8 @@ static const char *_lv_type_names[] = {
|
||||
[LV_TYPE_CACHEVOL] = "cachevol",
|
||||
[LV_TYPE_WRITECACHE] = "writecache",
|
||||
[LV_TYPE_WRITECACHEORIGIN] = "writecacheorigin",
|
||||
[LV_TYPE_INTEGRITY] = "integrity",
|
||||
[LV_TYPE_INTEGRITYORIGIN] = "integrityorigin",
|
||||
};
|
||||
|
||||
static int _lv_layout_and_role_mirror(struct dm_pool *mem,
|
||||
@@ -461,6 +465,43 @@ bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lv_layout_and_role_integrity(struct dm_pool *mem,
|
||||
const struct logical_volume *lv,
|
||||
struct dm_list *layout,
|
||||
struct dm_list *role,
|
||||
int *public_lv)
|
||||
{
|
||||
int top_level = 0;
|
||||
|
||||
/* non-top-level LVs */
|
||||
if (lv_is_integrity_metadata(lv)) {
|
||||
if (!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITY]) ||
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_METADATA]))
|
||||
goto_bad;
|
||||
} else if (lv_is_integrity_origin(lv)) {
|
||||
if (!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITY]) ||
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_ORIGIN]) ||
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITYORIGIN]))
|
||||
goto_bad;
|
||||
} else
|
||||
top_level = 1;
|
||||
|
||||
if (!top_level) {
|
||||
*public_lv = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* top-level LVs */
|
||||
if (lv_is_integrity(lv)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_INTEGRITY]))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lv_layout_and_role_thick_origin_snapshot(struct dm_pool *mem,
|
||||
const struct logical_volume *lv,
|
||||
struct dm_list *layout,
|
||||
@@ -577,6 +618,11 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
!_lv_layout_and_role_cache(mem, lv, *layout, *role, &public_lv))
|
||||
goto_bad;
|
||||
|
||||
/* Integrity related */
|
||||
if ((lv_is_integrity(lv) || lv_is_integrity_origin(lv) || lv_is_integrity_metadata(lv)) &&
|
||||
!_lv_layout_and_role_integrity(mem, lv, *layout, *role, &public_lv))
|
||||
goto_bad;
|
||||
|
||||
/* VDO and related */
|
||||
if (lv_is_vdo_type(lv) &&
|
||||
!_lv_layout_and_role_vdo(mem, lv, *layout, *role, &public_lv))
|
||||
@@ -1457,6 +1503,15 @@ 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;
|
||||
@@ -5654,6 +5709,11 @@ 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;
|
||||
|
||||
@@ -7679,6 +7739,15 @@ 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) || (seg_is_raid1(lp) && lp->integrity_arg))
|
||||
return 1;
|
||||
|
||||
/* Cannot zero read-only volume */
|
||||
if ((lv->status & LVM_WRITE) &&
|
||||
(lp->zero || lp->wipe_signatures))
|
||||
@@ -7934,6 +8003,11 @@ 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)) {
|
||||
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,
|
||||
@@ -8277,6 +8351,19 @@ 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) || (seg_is_raid1(lp) && lp->integrity_arg)) {
|
||||
/*
|
||||
* 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;
|
||||
@@ -8296,6 +8383,47 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_integrity(lp) || (seg_is_raid1(lp) && lp->integrity_arg)) {
|
||||
struct lv_activate_opts laopts = { 0 };
|
||||
|
||||
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 (seg_is_raid1(lp)) {
|
||||
if (!lv_add_integrity_to_raid(lv, lp->integrity_arg,
|
||||
&lp->integrity_settings, lp->pvh))
|
||||
goto revert_new_lv;
|
||||
} else {
|
||||
if (!lv_add_integrity(lv, lp->integrity_arg, lp->integrity_meta_name,
|
||||
&lp->integrity_settings, lp->pvh))
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
backup(vg);
|
||||
|
||||
/*
|
||||
* The integrity metadata (checksums) need to be initialized.
|
||||
* Activating the new integrity LVs with the recalculate
|
||||
* option will cause dm-integrity to initialize.
|
||||
*/
|
||||
laopts.integrity_recalculate = 1;
|
||||
|
||||
if (!activate_lv_opts(cmd, lv, &laopts)) {
|
||||
log_error("Failed to activate LV %s.", display_lvname(lv));
|
||||
log_error("The full LV should be zeroed to initialize integrity metadata.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_print("LV %s activated to initialize integrity.", display_lvname(lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (seg_is_vdo_pool(lp)) {
|
||||
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents)) {
|
||||
stack;
|
||||
|
||||
@@ -73,7 +73,7 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
|
||||
#define seg_error(msg) do { \
|
||||
log_error("LV %s, segment %u invalid: %s for %s segment.", \
|
||||
seg->lv->name, seg_count, (msg), lvseg_name(seg)); \
|
||||
display_lvname(seg->lv), seg_count, (msg), lvseg_name(seg)); \
|
||||
if ((*error_count)++ > ERROR_MAX) \
|
||||
return; \
|
||||
} while (0)
|
||||
@@ -86,14 +86,14 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
*/
|
||||
#define raid_seg_error(msg) do { \
|
||||
log_error("LV %s invalid: %s for %s segment", \
|
||||
seg->lv->name, (msg), lvseg_name(seg)); \
|
||||
display_lvname(seg->lv), (msg), lvseg_name(seg)); \
|
||||
if ((*error_count)++ > ERROR_MAX) \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define raid_seg_error_val(msg, val) do { \
|
||||
log_error("LV %s invalid: %s (is %u) for %s segment", \
|
||||
seg->lv->name, (msg), (val), lvseg_name(seg)); \
|
||||
display_lvname(seg->lv), (msg), (val), lvseg_name(seg)); \
|
||||
if ((*error_count)++ > ERROR_MAX) \
|
||||
return; \
|
||||
} while(0)
|
||||
@@ -742,6 +742,8 @@ 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++;
|
||||
|
||||
|
||||
@@ -84,12 +84,14 @@
|
||||
#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 INTEGRITY_METADATA UINT64_C(0x0000000004000000) /* LV - Internal use only */
|
||||
#define VIRTUAL_ORIGIN UINT64_C(0x0000000008000000) /* LV - internal use only */
|
||||
|
||||
#define MERGING UINT64_C(0x0000000010000000) /* LV SEG */
|
||||
@@ -261,6 +263,8 @@
|
||||
#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_integrity_metadata(lv) (((lv)->status & INTEGRITY_METADATA) ? 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)
|
||||
@@ -272,9 +276,11 @@
|
||||
/* Recognize component LV (matching lib/misc/lvm-string.c _lvname_has_reserved_component_string()) */
|
||||
#define lv_is_component(lv) (lv_is_cache_origin(lv) || \
|
||||
lv_is_writecache_origin(lv) || \
|
||||
lv_is_integrity_origin(lv) || \
|
||||
((lv)->status & (\
|
||||
CACHE_POOL_DATA |\
|
||||
CACHE_POOL_METADATA |\
|
||||
INTEGRITY_METADATA |\
|
||||
LV_CACHE_VOL |\
|
||||
LV_VDO_POOL_DATA |\
|
||||
MIRROR_IMAGE |\
|
||||
@@ -519,6 +525,10 @@ 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 */
|
||||
@@ -992,6 +1002,10 @@ 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 integrity_settings integrity_settings;
|
||||
|
||||
struct dm_list tags; /* all */
|
||||
|
||||
int yes;
|
||||
@@ -1086,6 +1100,8 @@ int lv_is_cache_origin(const struct logical_volume *lv);
|
||||
int lv_is_writecache_origin(const struct logical_volume *lv);
|
||||
int lv_is_writecache_cachevol(const struct logical_volume *lv);
|
||||
|
||||
int lv_is_integrity_origin(const struct logical_volume *lv);
|
||||
|
||||
int lv_is_merging_cow(const struct logical_volume *cow);
|
||||
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
|
||||
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
|
||||
@@ -1385,4 +1401,13 @@ 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,
|
||||
const char *meta_name, struct integrity_settings *settings,
|
||||
struct dm_list *pvh);
|
||||
int lv_add_integrity_to_raid(struct logical_volume *lv, const char *arg,
|
||||
struct integrity_settings *settings,
|
||||
struct dm_list *pvh);
|
||||
int lv_remove_integrity(struct logical_volume *lv);
|
||||
int lv_remove_integrity_from_raid(struct logical_volume *lv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -999,7 +999,7 @@ static int _vg_update_embedded_copy(struct volume_group *vg, struct volume_group
|
||||
if (!(cft = export_vg_to_config_tree(vg)))
|
||||
return_0;
|
||||
|
||||
if (!(*vg_embedded = import_vg_from_config_tree(cft, vg->fid))) {
|
||||
if (!(*vg_embedded = import_vg_from_config_tree(vg->cmd, vg->fid, cft))) {
|
||||
dm_config_destroy(cft);
|
||||
return_0;
|
||||
}
|
||||
@@ -3564,7 +3564,8 @@ static void _set_pv_device(struct format_instance *fid,
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (cmd && !cmd->pvscan_cache_single)
|
||||
if (cmd && !cmd->pvscan_cache_single &&
|
||||
(!vg_is_foreign(vg) && !cmd->include_foreign_vgs))
|
||||
log_warn("WARNING: Couldn't find device with uuid %s.", buffer);
|
||||
else
|
||||
log_debug_metadata("Couldn't find device with uuid %s.", buffer);
|
||||
@@ -4571,6 +4572,112 @@ void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reread an mda_header. If the text offset is the same as was seen and saved
|
||||
* by label scan, it means the metadata is unchanged and we do not need to
|
||||
* reread metadata.
|
||||
*/
|
||||
|
||||
static bool _scan_text_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid)
|
||||
{
|
||||
struct dm_list mda_list;
|
||||
struct mda_list *mdal, *safe;
|
||||
struct metadata_area *mda;
|
||||
struct mda_context *mdac;
|
||||
struct device_area *area;
|
||||
struct mda_header *mdah;
|
||||
struct raw_locn *rlocn;
|
||||
struct device *dev;
|
||||
uint32_t bad_fields;
|
||||
bool ret = true;
|
||||
|
||||
/*
|
||||
* if cmd->can_use_one_scan, check one mda_header is unchanged,
|
||||
* else check that all mda_headers are unchanged.
|
||||
*/
|
||||
|
||||
dm_list_init(&mda_list);
|
||||
|
||||
lvmcache_get_mdas(cmd, vgname, vgid, &mda_list);
|
||||
|
||||
dm_list_iterate_items(mdal, &mda_list) {
|
||||
mda = mdal->mda;
|
||||
|
||||
if (!mda->scan_text_offset)
|
||||
continue;
|
||||
|
||||
if (mda->mda_num != 1)
|
||||
continue;
|
||||
|
||||
if (!(dev = mda_get_device(mda))) {
|
||||
log_debug("rescan for text mismatch - no mda dev");
|
||||
goto out;
|
||||
}
|
||||
|
||||
bad_fields = 0;
|
||||
|
||||
mdac = mda->metadata_locn;
|
||||
area = &mdac->area;
|
||||
|
||||
/*
|
||||
* Invalidate mda_header in bcache so it will be reread from disk.
|
||||
*/
|
||||
if (!dev_invalidate_bytes(dev, 4096, 512)) {
|
||||
log_debug("rescan for text mismatch - cannot invalidate");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(mdah = raw_read_mda_header(cmd->fmt, area, 1, 0, &bad_fields))) {
|
||||
log_debug("rescan for text mismatch - no mda header");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
|
||||
if (bad_fields) {
|
||||
log_debug("rescan for text mismatch - bad_fields");
|
||||
} else if (rlocn->checksum != mda->scan_text_checksum) {
|
||||
log_debug("rescan for text checksum mismatch - now %x prev %x",
|
||||
rlocn->checksum, mda->scan_text_checksum);
|
||||
} else if (rlocn->offset != mda->scan_text_offset) {
|
||||
log_debug("rescan for text offset mismatch - now %llu prev %llu",
|
||||
(unsigned long long)rlocn->offset,
|
||||
(unsigned long long)mda->scan_text_offset);
|
||||
} else {
|
||||
/* the common case where fields match and no rescan needed */
|
||||
ret = false;
|
||||
}
|
||||
|
||||
dm_pool_free(cmd->mem, mdah);
|
||||
|
||||
/* For can_use_one_scan commands, return result from checking one mda. */
|
||||
if (cmd->can_use_one_scan)
|
||||
goto out;
|
||||
|
||||
/* For other commands, return mismatch immediately. */
|
||||
if (ret)
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
/* shouldn't happen */
|
||||
log_debug("rescan for text mismatch - no mdas");
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (!ret)
|
||||
log_debug("rescan skipped - unchanged offset %llu checksum %x",
|
||||
(unsigned long long)mda->scan_text_offset,
|
||||
mda->scan_text_checksum);
|
||||
|
||||
dm_list_iterate_items_safe(mdal, safe, &mda_list) {
|
||||
dm_list_del(&mdal->list);
|
||||
free(mdal);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
const char *vgid,
|
||||
@@ -4625,19 +4732,23 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
* find the same inconsistency. The VG repair (mistakenly done by
|
||||
* vg_read below) is supposed to fix that.
|
||||
*
|
||||
* 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.
|
||||
* If the VG was not modified between the time we scanned the PVs
|
||||
* and now, when we hold the lock, then we don't need to rescan.
|
||||
* We can read the mda_header, and look at the text offset/checksum,
|
||||
* and if the current text offset/checksum matches what was seen during
|
||||
* label scan, we know that metadata is unchanged and doesn't need
|
||||
* to be rescanned. For reporting/display commands (CAN_USE_ONE_SCAN/
|
||||
* can_use_one_scan), we check that the text offset/checksum are unchanged
|
||||
* in just one mda before deciding to skip rescanning. For other commands,
|
||||
* we check that they are unchanged in all mdas. This added checking is
|
||||
* probably unnecessary; all commands could likely just check a single mda.
|
||||
*/
|
||||
if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
|
||||
if (lvmcache_scan_mismatch(cmd, vgname, vgid) || _scan_text_mismatch(cmd, vgname, vgid)) {
|
||||
log_debug_metadata("Rescanning devices for %s %s", vgname, writing ? "rw" : "");
|
||||
if (writing)
|
||||
lvmcache_label_rescan_vg_rw(cmd, vgname, vgid);
|
||||
else
|
||||
lvmcache_label_rescan_vg(cmd, vgname, vgid);
|
||||
} else {
|
||||
log_debug_metadata("Skipped rescanning devices for %s", vgname);
|
||||
}
|
||||
|
||||
/* Now determine the correct vgname if none was supplied */
|
||||
@@ -4768,10 +4879,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
|
||||
if (vg->seqno == vg_ret->seqno) {
|
||||
release_vg(vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vg->seqno > vg_ret->seqno) {
|
||||
} else if (vg->seqno > vg_ret->seqno) {
|
||||
log_warn("WARNING: ignoring metadata seqno %u on %s for seqno %u on %s for VG %s.",
|
||||
vg_ret->seqno, dev_name(dev_ret),
|
||||
vg->seqno, dev_name(mda_dev), vg->name);
|
||||
@@ -4780,22 +4888,18 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
vg_ret = vg;
|
||||
dev_ret = mda_dev;
|
||||
vg_fmtdata = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vg_ret->seqno > vg->seqno) {
|
||||
} else { /* vg->seqno < vg_ret->seqno */
|
||||
log_warn("WARNING: ignoring metadata seqno %u on %s for seqno %u on %s for VG %s.",
|
||||
vg->seqno, dev_name(mda_dev),
|
||||
vg_ret->seqno, dev_name(dev_ret), vg->name);
|
||||
found_old_metadata = 1;
|
||||
release_vg(vg);
|
||||
vg_fmtdata = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_old_metadata)
|
||||
log_warn("WARNING: Inconsistent metadata found for VG %s", vgname);
|
||||
log_warn("WARNING: Inconsistent metadata found for VG %s.", vgname);
|
||||
|
||||
vg = NULL;
|
||||
|
||||
@@ -4826,16 +4930,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
if (!(dev->flags & DEV_IS_MD_COMPONENT))
|
||||
continue;
|
||||
|
||||
log_debug_metadata("Drop dev for MD component from cache %s", dev_name(dev));
|
||||
log_debug_metadata("Drop dev for MD component from cache %s.", dev_name(dev));
|
||||
lvmcache_del_dev(dev);
|
||||
|
||||
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
|
||||
if (mda_get_device(mda) != dev)
|
||||
continue;
|
||||
log_debug_metadata("Drop mda from MD component from mda list %s", dev_name(dev));
|
||||
dm_list_del(&mda->list);
|
||||
break;
|
||||
}
|
||||
dm_list_iterate_items(mda, &fid->metadata_areas_in_use)
|
||||
if (mda_get_device(mda) == dev) {
|
||||
log_debug_metadata("Drop mda from MD component from mda list %s.", dev_name(dev));
|
||||
dm_list_del(&mda->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4900,7 +5003,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
int activating = (vg_read_flags & READ_FOR_ACTIVATE);
|
||||
|
||||
if (is_orphan_vg(vg_name)) {
|
||||
log_very_verbose("Reading orphan VG %s", vg_name);
|
||||
log_very_verbose("Reading orphan VG %s.", vg_name);
|
||||
vg = vg_read_orphans(cmd, vg_name);
|
||||
*error_flags = 0;
|
||||
*error_vg = NULL;
|
||||
@@ -4910,7 +5013,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
if (!validate_name(vg_name)) {
|
||||
log_error("Volume group name \"%s\" has invalid characters.", vg_name);
|
||||
failure |= FAILED_NOTFOUND;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4925,15 +5028,15 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
|
||||
if (!(vg_read_flags & READ_WITHOUT_LOCK) &&
|
||||
!lock_vol(cmd, vg_name, (writing || activating) ? LCK_VG_WRITE : LCK_VG_READ, NULL)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
log_error("Can't get lock for %s.", vg_name);
|
||||
failure |= FAILED_LOCKING;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(vg = _vg_read(cmd, vg_name, vgid, 0, writing))) {
|
||||
/* Some callers don't care if the VG doesn't exist and don't want an error message. */
|
||||
if (!(vg_read_flags & READ_OK_NOTFOUND))
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
log_error("Volume group \"%s\" not found.", vg_name);
|
||||
failure |= FAILED_NOTFOUND;
|
||||
goto_bad;
|
||||
}
|
||||
@@ -4977,7 +5080,9 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
if (!pvl->pv->dev) {
|
||||
/* The obvious and common case of a missing device. */
|
||||
|
||||
if (pvl->pv->device_hint)
|
||||
if (vg_is_foreign(vg) && !cmd->include_foreign_vgs)
|
||||
log_debug("VG %s is missing PV %s (last written to %s)", vg_name, uuidstr, pvl->pv->device_hint ?: "na");
|
||||
else if (pvl->pv->device_hint)
|
||||
log_warn("WARNING: VG %s is missing PV %s (last written to %s).", vg_name, uuidstr, pvl->pv->device_hint);
|
||||
else
|
||||
log_warn("WARNING: VG %s is missing PV %s.", vg_name, uuidstr);
|
||||
@@ -5004,14 +5109,14 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
if (!check_pv_segments(vg)) {
|
||||
log_error(INTERNAL_ERROR "PV segments corrupted in %s.", vg->name);
|
||||
failure |= FAILED_INTERNAL_ERROR;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!check_lv_segments(lvl->lv, 0)) {
|
||||
log_error(INTERNAL_ERROR "LV segments corrupted in %s.", lvl->lv->name);
|
||||
failure |= FAILED_INTERNAL_ERROR;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5020,7 +5125,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
if (!check_lv_segments(lvl->lv, 1)) {
|
||||
log_error(INTERNAL_ERROR "LV segments corrupted in %s.", lvl->lv->name);
|
||||
failure |= FAILED_INTERNAL_ERROR;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5056,23 +5161,23 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
*/
|
||||
if (writing || activating) {
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group %s is read-only", vg->name);
|
||||
log_error("Volume group %s is read-only.", vg->name);
|
||||
failure |= FAILED_READ_ONLY;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!cmd->handles_missing_pvs && (missing_pv_dev || missing_pv_flag)) {
|
||||
log_error("Cannot change VG %s while PVs are missing.", vg->name);
|
||||
log_error("See vgreduce --removemissing and vgextend --restoremissing.");
|
||||
failure |= FAILED_NOT_ENABLED;
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (writing && !cmd->handles_unknown_segments && vg_has_unknown_segments(vg)) {
|
||||
log_error("Cannot change VG %s with unknown segments in it!", vg->name);
|
||||
failure |= FAILED_NOT_ENABLED; /* FIXME new failure code here? */
|
||||
goto_bad;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5087,31 +5192,31 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
|
||||
if (dm_pool_locked(vg->vgmem)) {
|
||||
/* FIXME: can this happen? */
|
||||
log_warn("WARNING: vg_read no vg copy: pool locked");
|
||||
log_warn("WARNING: vg_read no vg copy: pool locked.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vg->vg_committed) {
|
||||
/* FIXME: can this happen? */
|
||||
log_warn("WARNING: vg_read no vg copy: copy exists");
|
||||
log_warn("WARNING: vg_read no vg copy: copy exists.");
|
||||
release_vg(vg->vg_committed);
|
||||
vg->vg_committed = NULL;
|
||||
}
|
||||
|
||||
if (vg->vg_precommitted) {
|
||||
/* FIXME: can this happen? */
|
||||
log_warn("WARNING: vg_read no vg copy: pre copy exists");
|
||||
log_warn("WARNING: vg_read no vg copy: pre copy exists.");
|
||||
release_vg(vg->vg_precommitted);
|
||||
vg->vg_precommitted = NULL;
|
||||
}
|
||||
|
||||
if (!(cft = export_vg_to_config_tree(vg))) {
|
||||
log_warn("WARNING: vg_read no vg copy: copy export failed");
|
||||
log_warn("WARNING: vg_read no vg copy: copy export failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vg->vg_committed = import_vg_from_config_tree(cft, vg->fid)))
|
||||
log_warn("WARNING: vg_read no vg copy: copy import failed");
|
||||
if (!(vg->vg_committed = import_vg_from_config_tree(cmd, vg->fid, cft)))
|
||||
log_warn("WARNING: vg_read no vg copy: copy import failed.");
|
||||
|
||||
dm_config_destroy(cft);
|
||||
} else {
|
||||
|
||||
@@ -187,6 +187,8 @@ struct metadata_area {
|
||||
void *metadata_locn;
|
||||
uint32_t status;
|
||||
uint64_t header_start; /* mda_header.start */
|
||||
uint64_t scan_text_offset; /* rlocn->offset seen during scan */
|
||||
uint32_t scan_text_checksum; /* rlocn->checksum seen during scan */
|
||||
int mda_num;
|
||||
uint32_t bad_fields; /* BAD_MDA_ flags are set to indicate errors found when reading */
|
||||
uint32_t ignore_bad_fields; /* BAD_MDA_ flags are set to indicate errors to ignore */
|
||||
@@ -475,8 +477,10 @@ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahea
|
||||
* For internal metadata caching.
|
||||
*/
|
||||
struct dm_config_tree *export_vg_to_config_tree(struct volume_group *vg);
|
||||
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid);
|
||||
struct volume_group *import_vg_from_config_tree(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft);
|
||||
struct volume_group *vg_from_config_tree(struct cmd_context *cmd, const struct dm_config_tree *cft);
|
||||
|
||||
/*
|
||||
* Mirroring functions
|
||||
|
||||
@@ -266,7 +266,6 @@ static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
dev_set_last_byte(dev, sizeof(log_header));
|
||||
|
||||
if (!dev_write_bytes(dev, UINT64_C(0), sizeof(log_header), &log_header)) {
|
||||
dev_unset_last_byte(dev);
|
||||
log_error("Failed to write log header to %s.", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ 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)
|
||||
@@ -84,6 +85,7 @@ 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"
|
||||
@@ -117,6 +119,7 @@ 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)
|
||||
@@ -179,6 +182,7 @@ 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)
|
||||
@@ -347,6 +351,8 @@ 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)
|
||||
|
||||
@@ -503,11 +503,11 @@ int update_pool_lv(struct logical_volume *lv, int activate)
|
||||
* which Node has pool active.
|
||||
*/
|
||||
if (!activate_lv(lv->vg->cmd, lv)) {
|
||||
init_dmeventd_monitor(monitored);
|
||||
(void) init_dmeventd_monitor(monitored);
|
||||
return_0;
|
||||
}
|
||||
if (!lv_is_active(lv)) {
|
||||
init_dmeventd_monitor(monitored);
|
||||
(void) init_dmeventd_monitor(monitored);
|
||||
log_error("Cannot activate thin pool %s, perhaps skipped in lvm.conf volume_list?",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#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/activate/dev_manager.h"
|
||||
|
||||
int lv_is_writecache_origin(const struct logical_volume *lv)
|
||||
|
||||
@@ -164,7 +164,7 @@ static int _do_write_priority_flock(const char *file, int *fd, int operation, ui
|
||||
strcpy(file_aux, file);
|
||||
strcat(file_aux, AUX_LOCK_SUFFIX);
|
||||
|
||||
if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
|
||||
if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, nonblock))) {
|
||||
if (operation == LOCK_EX) {
|
||||
r = _do_flock(file, fd, operation, nonblock);
|
||||
_undo_flock(file_aux, fd_aux);
|
||||
|
||||
@@ -166,7 +166,9 @@ static const char *_lvname_has_reserved_component_string(const char *lvname)
|
||||
"_rmeta",
|
||||
"_tdata",
|
||||
"_tmeta",
|
||||
"_vdata"
|
||||
"_vdata",
|
||||
"_imeta",
|
||||
"_iorig"
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
@@ -252,10 +254,12 @@ char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
/* Suffixes used here MUST match lib/activate/dev_manager.c */
|
||||
layer = lv_is_cache_origin(lv) ? "real" :
|
||||
lv_is_writecache_origin(lv) ? "real" :
|
||||
lv_is_integrity_origin(lv) ? "real" :
|
||||
(lv_is_cache(lv) && lv_is_pending_delete(lv)) ? "real" :
|
||||
lv_is_cache_pool_data(lv) ? "cdata" :
|
||||
lv_is_cache_pool_metadata(lv) ? "cmeta" :
|
||||
lv_is_cache_vol(lv) ? "cvol" :
|
||||
lv_is_integrity_metadata(lv) ? "imeta" :
|
||||
// FIXME: dm-tree needs fixes for mirrors/raids
|
||||
//lv_is_mirror_image(lv) ? "mimage" :
|
||||
//lv_is_mirror_log(lv) ? "mlog" :
|
||||
|
||||
@@ -240,6 +240,26 @@ static int _raid_text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
return _raid_text_export_raid(seg, f);
|
||||
}
|
||||
|
||||
static int _image_integrity_data_sectors(struct lv_segment *seg, uint64_t *data_sectors)
|
||||
{
|
||||
struct logical_volume *lv_image;
|
||||
struct lv_segment *seg_image;
|
||||
int s;
|
||||
|
||||
*data_sectors = 0;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
|
||||
if (lv_is_integrity(lv_image)) {
|
||||
seg_image = first_seg(lv_image);
|
||||
*data_sectors = seg_image->integrity_data_sectors;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)),
|
||||
struct dm_pool *mem __attribute__((unused)),
|
||||
struct cmd_context *cmd __attribute__((unused)),
|
||||
@@ -256,6 +276,7 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)),
|
||||
uint64_t writemostly[RAID_BITMAP_SIZE] = { 0 };
|
||||
struct dm_tree_node_raid_params_v2 params = { 0 };
|
||||
unsigned attrs;
|
||||
uint64_t integrity_data_sectors = 0;
|
||||
|
||||
if (seg_is_raid4(seg)) {
|
||||
if (!_raid_target_present(cmd, NULL, &attrs) ||
|
||||
@@ -351,6 +372,21 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)),
|
||||
params.stripe_size = seg->stripe_size;
|
||||
params.flags = flags;
|
||||
|
||||
/*
|
||||
* The len needs to be reduced only when the raid images are using
|
||||
* integrity with internal metadata, which reduces the usable
|
||||
* size of the image, and needs to be reflected in the dm table
|
||||
* that's loaded. (internal metadata is not currently allowed
|
||||
* with raid, so this is unused.)
|
||||
*/
|
||||
if (!_image_integrity_data_sectors(seg, &integrity_data_sectors))
|
||||
return_0;
|
||||
if (integrity_data_sectors) {
|
||||
log_debug("Reducing raid size from %llu to integrity_data_sectors %llu",
|
||||
(unsigned long long)len, (unsigned long long)integrity_data_sectors);
|
||||
len = integrity_data_sectors;
|
||||
}
|
||||
|
||||
if (!dm_tree_node_add_raid_target_with_params_v2(node, len, ¶ms))
|
||||
return_0;
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ static int _target_present(struct cmd_context *cmd,
|
||||
|
||||
if (!_writecache_checked) {
|
||||
_writecache_checked = 1;
|
||||
_writecache_present = target_present(cmd, TARGET_NAME_WRITECACHE, 0);
|
||||
_writecache_present = target_present(cmd, TARGET_NAME_WRITECACHE, 1);
|
||||
}
|
||||
|
||||
return _writecache_present;
|
||||
|
||||
@@ -656,7 +656,8 @@ void daemon_start(daemon_state s)
|
||||
failed = 1; /* FD out of available selectable set */
|
||||
|
||||
sigfillset(&new_set);
|
||||
sigprocmask(SIG_SETMASK, NULL, &old_set);
|
||||
if (sigprocmask(SIG_SETMASK, NULL, &old_set))
|
||||
perror("sigprocmask error");
|
||||
|
||||
while (!failed) {
|
||||
_reset_timeout(s);
|
||||
|
||||
@@ -1238,8 +1238,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
}
|
||||
|
||||
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
|
||||
if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
|
||||
dmt->major < 0))
|
||||
if (DEV_NAME(dmt) &&
|
||||
(((dmt->type != DM_DEVICE_RESUME) &&
|
||||
(dmt->type != DM_DEVICE_RELOAD)) ||
|
||||
(dmt->minor < 0) || (dmt->major < 0)))
|
||||
/* When RESUME or RELOAD sets maj:min and dev_name, use just maj:min,
|
||||
* passed dev_name is useful for better error/debug messages */
|
||||
strncpy(dmi->name, DEV_NAME(dmt), sizeof(dmi->name));
|
||||
|
||||
if (DEV_UUID(dmt))
|
||||
@@ -1425,6 +1429,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
|
||||
|
||||
static int _create_and_load_v4(struct dm_task *dmt)
|
||||
{
|
||||
struct dm_info info;
|
||||
struct dm_task *task;
|
||||
int r;
|
||||
uint32_t cookie;
|
||||
@@ -1455,6 +1460,9 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
if (!dm_task_run(task))
|
||||
goto_bad;
|
||||
|
||||
if (!dm_task_get_info(task, &info) || !info.exists)
|
||||
goto_bad;
|
||||
|
||||
dm_task_destroy(task);
|
||||
|
||||
/* Next load the table */
|
||||
@@ -1472,6 +1480,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
goto revert;
|
||||
}
|
||||
|
||||
task->major = info.major;
|
||||
task->minor = info.minor;
|
||||
task->read_only = dmt->read_only;
|
||||
task->head = dmt->head;
|
||||
task->tail = dmt->tail;
|
||||
@@ -1904,7 +1914,8 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
log_verbose("device-mapper: %s ioctl on %s %s%s%.0d%s%.0d%s%s "
|
||||
"failed: %s",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid,
|
||||
dmi->name[0] ? dmi->name : DEV_NAME(dmt) ? : "",
|
||||
dmi->uuid[0] ? dmi->uuid : DEV_UUID(dmt) ? : "",
|
||||
dmt->major > 0 ? "(" : "",
|
||||
dmt->major > 0 ? dmt->major : 0,
|
||||
dmt->major > 0 ? ":" : "",
|
||||
@@ -1916,7 +1927,8 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
log_error("device-mapper: %s ioctl on %s %s%s%.0d%s%.0d%s%s "
|
||||
"failed: %s",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid,
|
||||
dmi->name[0] ? dmi->name : DEV_NAME(dmt) ? : "",
|
||||
dmi->uuid[0] ? dmi->uuid : DEV_UUID(dmt) ? : "",
|
||||
dmt->major > 0 ? "(" : "",
|
||||
dmt->major > 0 ? dmt->major : 0,
|
||||
dmt->major > 0 ? ":" : "",
|
||||
|
||||
133
man/pvck.8_des
133
man/pvck.8_des
@@ -1,8 +1,129 @@
|
||||
pvck checks LVM metadata on PVs.
|
||||
pvck checks and repairs LVM metadata on PVs.
|
||||
|
||||
Use the --dump option to extract metadata from PVs for debugging.
|
||||
With dump, set --pvmetadatacopies 2 to extract metadata from a
|
||||
second metadata area at the end of the device. Use the --file
|
||||
option to save the raw metadata to a specified file. (The raw
|
||||
metadata is not usable with vgcfgbackup and vgcfgrestore.)
|
||||
.SS Dump
|
||||
|
||||
.B headers
|
||||
.br
|
||||
Print header values and warn if any values are incorrect. Checks the
|
||||
label_header, pv_header, mda_header(s), and metadata text.
|
||||
|
||||
.B metadata
|
||||
.br
|
||||
Print or save the current metadata text, using headers to locate the
|
||||
metadata. If headers are damaged, the metadata may not be found. Use
|
||||
--settings "mda_num=2" to look in mda2 (the second mda at the end of the
|
||||
device (if used). The metadata text is printed to stdout. With --file,
|
||||
the metadata text is saved to a file.
|
||||
|
||||
.B metadata_all
|
||||
.br
|
||||
List or save all versions of metadata found in the metadata area, using
|
||||
headers to locate the metadata. If headers are damaged, the metadata may
|
||||
not be found. Use --settings "mda_num=2" as above. All metadata versions
|
||||
are listed (add -v to include descriptions and dates in the listing.)
|
||||
With -file, all versions are written to a file.
|
||||
|
||||
.B metadata_search
|
||||
.br
|
||||
Search for all versions of metadata in the common locations. This does
|
||||
not use headers, so it can find metadata even when headers are damaged.
|
||||
Use --settings "mda_num=2" as above. All metadata versions are listed
|
||||
(add -v to include descriptions and dates in the listing.) With --file,
|
||||
all versions are written to a file. To save one copy of metadata, use
|
||||
--settings "metadata_offset=<offset>", where the offset is taken from the
|
||||
dump listing.
|
||||
|
||||
.B metadata_area
|
||||
.br
|
||||
Save the entire text metadata area to a file without processing.
|
||||
|
||||
.SS Repair
|
||||
|
||||
.B --repair
|
||||
.br
|
||||
Repair headers and metadata on a PV. This uses a metadata input file that
|
||||
was extracted by --dump, or a backup file (from /etc/lvm/backup). When
|
||||
possible, use metadata saved by --dump from another PV in the same VG (or
|
||||
from a second metadata area on the PV).
|
||||
|
||||
There are cases where the PV UUID needs to be specified for the PV being
|
||||
repaired. It is specified using --settings "pv_uuid=<UUID>". In
|
||||
particular, if the device name for the PV being repaired does not match
|
||||
the previous device name of the PV, then LVM may not be able to determine
|
||||
the correct PV UUID. When headers are damaged on more than one PV in a
|
||||
VG, it is important for the user to determine the correct PV UUID and
|
||||
specify it in --settings. Otherwise, the wrong PV UUID could be used if
|
||||
device names have been swapped since the metadata was last written.
|
||||
|
||||
If a PV had no metadata areas and the pv_header is damaged, then the
|
||||
repair will not know to create no metadata areas during repair. It will
|
||||
by default repair metadata in mda1. To repair with no metadata areas, use
|
||||
--settings "mda_offset=0 mda_size=0".
|
||||
|
||||
There are cases where repair should be run on all PVs in the VG (using the
|
||||
same metadata file): if all PVs in the VG are damaged, if using an old
|
||||
metadata version, or if a backup file is used instead of raw metadata.
|
||||
|
||||
Using --repair is equivalent to running --repairtype pv_header followed by
|
||||
--repairtype metadata.
|
||||
|
||||
.B --repairtype pv_header
|
||||
.br
|
||||
Repairs the header sector, containing the pv_header and label_header.
|
||||
|
||||
.B --repairtype metadata
|
||||
.br
|
||||
Repairs the mda_header and metadata text. It requires the headers to be
|
||||
correct (having been undamaged or already repaired).
|
||||
|
||||
.B --repairtype label_header
|
||||
.br
|
||||
Repairs label_header fields, leaving the pv_header (in the same sector)
|
||||
unchanged. (repairtype pv_header should usually be used instead.)
|
||||
|
||||
.SS Settings
|
||||
|
||||
The --settings option controls or overrides certain dump or repair
|
||||
behaviors. All offset and size values in settings are in bytes (units are
|
||||
not recognized.) These settings are subject to change.
|
||||
|
||||
.B mda_num=1|2
|
||||
.br
|
||||
Select which metadata area should be used. By default the first metadata
|
||||
area (1) is used. mda1 is always located at offset 4096. mda2, at the
|
||||
end of the device, often does not exist (it's not created by default.) If
|
||||
mda1 is erased, mda2, if it exists, will often still have metadata.
|
||||
|
||||
\fBmetadata_offset=\fP\fIbytes\fP
|
||||
.br
|
||||
Select metadata text at this offset. Use with metadata_search to
|
||||
print/save one instance of metadata text.
|
||||
|
||||
\fBmda_offset=\fP\fIbytes\fP \fBmda_size=\fP\fIbytes\fP
|
||||
.br
|
||||
Refers to a metadata area (mda) location and size. An mda includes an
|
||||
mda_header and circular text buffer. Setting this forces metadata_search
|
||||
look for metadata in the given area instead of the normal locations. When
|
||||
set to zero with repair, it indicates no metadata areas should exist.
|
||||
|
||||
\fBmda2_offset=\fP\fIbytes\fP \fBmda2_size=\fP\fIbytes\fP
|
||||
.br
|
||||
When repairing a pv_header, this forces a specific offset and size for
|
||||
mda2 that should be recorded in the pv_header.
|
||||
|
||||
\fBpv_uuid=\fP\fIuuid\fP
|
||||
.br
|
||||
Specify the PV UUID of the device being repaired. When not specified,
|
||||
repair will attempt to determine the correct PV UUID by matching a device
|
||||
name in the metadata.
|
||||
|
||||
\fBdevice_size=\fP\fIbytes\fP
|
||||
.br
|
||||
\fBdata_offset=\fP\fIbytes\fP
|
||||
.br
|
||||
When repairing a pv_header, the device_size, data_offset, and pvid can all
|
||||
be specified directly, in which case these values are not taken from a
|
||||
metadata file (where they usually come from), and the metadata file can be
|
||||
omitted. data_offset is the starting location of the first physical
|
||||
extent (data), which follows the first metadata area.
|
||||
|
||||
|
||||
@@ -7,14 +7,173 @@ pvck - Check metadata on physical volumes
|
||||
.br
|
||||
[ \fIoption_args\fP ]
|
||||
.br
|
||||
.P
|
||||
.ad l
|
||||
\fB--commandprofile\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--config\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-d\fP|\fB--debug\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--driverloaded\fP \fBy\fP|\fBn\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--dump\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-f\fP|\fB--file\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-h\fP|\fB--help\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--labelsector\fP \fINumber\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--lockopt\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--longhelp\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--nolocking\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--profile\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--[pv]metadatacopies\fP \fB0\fP|\fB1\fP|\fB2\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-q\fP|\fB--quiet\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--repair\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--repairtype\fP \fBpv_header\fP|\fBmetadata\fP|\fBlabel_header\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--settings\fP \fIString\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-t\fP|\fB--test\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-v\fP|\fB--verbose\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB--version\fP
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
\fB-y\fP|\fB--yes\fP
|
||||
.ad b
|
||||
.SH DESCRIPTION
|
||||
pvck checks LVM metadata on PVs.
|
||||
pvck checks and repairs LVM metadata on PVs.
|
||||
|
||||
Use the --dump option to extract metadata from PVs for debugging.
|
||||
With dump, set --pvmetadatacopies 2 to extract metadata from a
|
||||
second metadata area at the end of the device. Use the --file
|
||||
option to save the raw metadata to a specified file. (The raw
|
||||
metadata is not usable with vgcfgbackup and vgcfgrestore.)
|
||||
.SS Dump
|
||||
|
||||
.B headers
|
||||
.br
|
||||
Print header values and warn if any values are incorrect. Checks the
|
||||
label_header, pv_header, mda_header(s), and metadata text.
|
||||
|
||||
.B metadata
|
||||
.br
|
||||
Print or save the current metadata text, using headers to locate the
|
||||
metadata. If headers are damaged, the metadata may not be found. Use
|
||||
--settings "mda_num=2" to look in mda2 (the second mda at the end of the
|
||||
device (if used). The metadata text is printed to stdout. With --file,
|
||||
the metadata text is saved to a file.
|
||||
|
||||
.B metadata_all
|
||||
.br
|
||||
List or save all versions of metadata found in the metadata area, using
|
||||
headers to locate the metadata. If headers are damaged, the metadata may
|
||||
not be found. Use --settings "mda_num=2" as above. All metadata versions
|
||||
are listed (add -v to include descriptions and dates in the listing.)
|
||||
With -file, all versions are written to a file.
|
||||
|
||||
.B metadata_search
|
||||
.br
|
||||
Search for all versions of metadata in the common locations. This does
|
||||
not use headers, so it can find metadata even when headers are damaged.
|
||||
Use --settings "mda_num=2" as above. All metadata versions are listed
|
||||
(add -v to include descriptions and dates in the listing.) With --file,
|
||||
all versions are written to a file. To save one copy of metadata, use
|
||||
--settings "metadata_offset=<offset>", where the offset is taken from the
|
||||
dump listing.
|
||||
|
||||
.B metadata_area
|
||||
.br
|
||||
Save the entire text metadata area to a file without processing.
|
||||
|
||||
.SS Repair
|
||||
|
||||
.B --repair
|
||||
.br
|
||||
Repair headers and metadata on a PV. This uses a metadata input file that
|
||||
was extracted by --dump, or a backup file (from /etc/lvm/backup). When
|
||||
possible, use metadata saved by --dump from another PV in the same VG (or
|
||||
from a second metadata area on the PV).
|
||||
|
||||
There are cases where the PV UUID needs to be specified for the PV being
|
||||
repaired. It is specified using --settings "pv_uuid=<UUID>". In
|
||||
particular, if the device name for the PV being repaired does not match
|
||||
the previous device name of the PV, then LVM may not be able to determine
|
||||
the correct PV UUID. When headers are damaged on more than one PV in a
|
||||
VG, it is important for the user to determine the correct PV UUID and
|
||||
specify it in --settings. Otherwise, the wrong PV UUID could be used if
|
||||
device names have been swapped since the metadata was last written.
|
||||
|
||||
If a PV had no metadata areas and the pv_header is damaged, then the
|
||||
repair will not know to create no metadata areas during repair. It will
|
||||
by default repair metadata in mda1. To repair with no metadata areas, use
|
||||
--settings "mda_offset=0 mda_size=0".
|
||||
|
||||
There are cases where repair should be run on all PVs in the VG (using the
|
||||
same metadata file): if all PVs in the VG are damaged, if using an old
|
||||
metadata version, or if a backup file is used instead of raw metadata.
|
||||
|
||||
Using --repair is equivalent to running --repairtype pv_header followed by
|
||||
--repairtype metadata.
|
||||
|
||||
.B --repairtype pv_header
|
||||
.br
|
||||
Repairs the header sector, containing the pv_header and label_header.
|
||||
|
||||
.B --repairtype metadata
|
||||
.br
|
||||
Repairs the mda_header and metadata text. It requires the headers to be
|
||||
correct (having been undamaged or already repaired).
|
||||
|
||||
.B --repairtype label_header
|
||||
.br
|
||||
Repairs label_header fields, leaving the pv_header (in the same sector)
|
||||
unchanged. (repairtype pv_header should usually be used instead.)
|
||||
|
||||
.SH USAGE
|
||||
Check for metadata on a device
|
||||
@@ -26,8 +185,9 @@ Check for metadata on a device
|
||||
[ COMMON_OPTIONS ]
|
||||
.RE
|
||||
.br
|
||||
-
|
||||
|
||||
Print metadata from a device
|
||||
Check and print LVM headers and metadata on a device
|
||||
.br
|
||||
.P
|
||||
\fBpvck\fP \fB--dump\fP \fIString\fP \fIPV\fP
|
||||
@@ -38,12 +198,51 @@ Print metadata from a device
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
[ \fB--settings\fP \fIString\fP ]
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
[ \fB--[pv]metadatacopies\fP \fB0\fP|\fB1\fP|\fB2\fP ]
|
||||
.ad b
|
||||
.br
|
||||
[ COMMON_OPTIONS ]
|
||||
.RE
|
||||
.br
|
||||
-
|
||||
|
||||
Repair LVM headers or metadata on a device
|
||||
.br
|
||||
.P
|
||||
\fBpvck\fP \fB--repairtype\fP \fBpv_header\fP|\fBmetadata\fP|\fBlabel_header\fP \fIPV\fP
|
||||
.br
|
||||
.RS 4
|
||||
.ad l
|
||||
[ \fB-f\fP|\fB--file\fP \fIString\fP ]
|
||||
.ad b
|
||||
.br
|
||||
.ad l
|
||||
[ \fB--settings\fP \fIString\fP ]
|
||||
.ad b
|
||||
.br
|
||||
[ COMMON_OPTIONS ]
|
||||
.RE
|
||||
.br
|
||||
-
|
||||
|
||||
Repair LVM headers and metadata on a device
|
||||
.br
|
||||
.P
|
||||
\fBpvck\fP \fB--repair\fP \fB-f\fP|\fB--file\fP \fIString\fP \fIPV\fP
|
||||
.br
|
||||
.RS 4
|
||||
.ad l
|
||||
[ \fB--settings\fP \fIString\fP ]
|
||||
.ad b
|
||||
.br
|
||||
[ COMMON_OPTIONS ]
|
||||
.RE
|
||||
.br
|
||||
-
|
||||
|
||||
Common options for command:
|
||||
.
|
||||
@@ -147,16 +346,19 @@ For testing and debugging.
|
||||
.ad l
|
||||
\fB--dump\fP \fIString\fP
|
||||
.br
|
||||
Dump metadata from a PV. Option values include \fBmetadata\fP
|
||||
to print or save the current text metadata, \fBmetadata_area\fP
|
||||
to save the entire text metadata area to a file, \fBmetadata_all\fP
|
||||
to save the current and any previous complete versions of metadata
|
||||
to a file, and \fBheaders\fP to print and check LVM headers.
|
||||
Dump headers and metadata from a PV for debugging and repair.
|
||||
Option values include: \fBheaders\fP to print and check LVM headers,
|
||||
\fBmetadata\fP to print or save the current text metadata,
|
||||
\fBmetadata_all\fP to list or save all versions of metadata,
|
||||
\fBmetadata_search\fP to list or save all versions of metadata,
|
||||
searching standard locations in case of damaged headers,
|
||||
\fBmetadata_area\fP to save an entire text metadata area to a file.
|
||||
.ad b
|
||||
.HP
|
||||
.ad l
|
||||
\fB-f\fP|\fB--file\fP \fIString\fP
|
||||
.br
|
||||
Metadata file to read or write.
|
||||
.ad b
|
||||
.HP
|
||||
.ad l
|
||||
@@ -220,6 +422,25 @@ Repeat once to also suppress any prompts with answer 'no'.
|
||||
.ad b
|
||||
.HP
|
||||
.ad l
|
||||
\fB--repair\fP
|
||||
.br
|
||||
Repair headers and metadata on a PV.
|
||||
.ad b
|
||||
.HP
|
||||
.ad l
|
||||
\fB--repairtype\fP \fBpv_header\fP|\fBmetadata\fP|\fBlabel_header\fP
|
||||
.br
|
||||
Repair headers and metadata on a PV. See command description.
|
||||
.ad b
|
||||
.HP
|
||||
.ad l
|
||||
\fB--settings\fP \fIString\fP
|
||||
.br
|
||||
Specifies command specific settings in "Key = Value" form.
|
||||
Repeat this option to specify multiple values.
|
||||
.ad b
|
||||
.HP
|
||||
.ad l
|
||||
\fB-t\fP|\fB--test\fP
|
||||
.br
|
||||
Run in test mode. Commands will not update metadata.
|
||||
|
||||
@@ -315,7 +315,7 @@ lib/dm-version-expected: $(top_srcdir)/VERSION_DM .lib-dir-stamp
|
||||
CMDS = lvm $(shell cat $(top_builddir)/tools/.commands 2>/dev/null)
|
||||
LIB = $(addprefix lib/, $(LIB_SECURETEST) $(LIB_DMSECURETEST) $(LIB_SHARED) $(LIB_LOCAL) $(LIB_NOT) $(LIB_LINK_NOT) $(LIB_FLAVOURS))
|
||||
|
||||
.tests-stamp: $(ALL) $(LIB) $(SUBDIRS) lib/version-expected lib/dm-version-expected unit-test
|
||||
.tests-stamp: .lib-dir-stamp $(ALL) $(LIB) $(SUBDIRS) lib/version-expected lib/dm-version-expected unit-test
|
||||
@echo " [TEST-STAMP]"
|
||||
@if test "$(srcdir)" != . ; then \
|
||||
echo "Linking tests to builddir."; \
|
||||
|
||||
@@ -382,7 +382,7 @@ teardown_devs_prefixed() {
|
||||
|
||||
while :; do
|
||||
local sortby="name"
|
||||
local num_devs=0
|
||||
local progress=0
|
||||
|
||||
# HACK: sort also by minors - so we try to close 'possibly later' created device first
|
||||
test "$i" = 0 || sortby="-minor"
|
||||
@@ -392,23 +392,23 @@ teardown_devs_prefixed() {
|
||||
DM_NAME=${dm##DM_NAME=}
|
||||
DM_NAME=${DM_NAME%%;DM_OPEN*}
|
||||
DM_OPEN=${dm##*;DM_OPEN=}
|
||||
local force="-f"
|
||||
if test "$i" = 0; then
|
||||
if test "$once" = 1 ; then
|
||||
once=0
|
||||
echo "## removing stray mapped devices with names beginning with $prefix: "
|
||||
fi
|
||||
test "$DM_OPEN" = 0 || break # stop loop with 1st. opened device
|
||||
dmsetup remove "$DM_NAME" --mangle none || true # &>/dev/null || touch REMOVE_FAILED &
|
||||
else
|
||||
dmsetup remove -f "$DM_NAME" --mangle none || true
|
||||
force=""
|
||||
fi
|
||||
|
||||
num_devs=$(( num_devs + 1 ))
|
||||
# Succesfull 'remove' signals progress
|
||||
dmsetup remove $force "$DM_NAME" --mangle none && progress=1
|
||||
done
|
||||
|
||||
test "$i" = 0 || break
|
||||
|
||||
test "$num_devs" -gt 0 || break
|
||||
test "$progress" = 1 || break
|
||||
|
||||
udev_wait
|
||||
wait
|
||||
@@ -520,7 +520,7 @@ teardown() {
|
||||
|
||||
if test ! -f SKIP_THIS_TEST ; then
|
||||
# Evaluate left devices only for non-skipped tests
|
||||
TEST_LEAKED_DEVICES=$(dmsetup table | grep "$PREFIX" | grep -v "${PREFIX}pv") || true
|
||||
TEST_LEAKED_DEVICES=$(dmsetup table | grep "$PREFIX" | grep -Ev "${PREFIX}(pv|[0-9])") || true
|
||||
fi
|
||||
|
||||
kill_tagged_processes
|
||||
@@ -874,7 +874,11 @@ prepare_devs() {
|
||||
wait
|
||||
finish_udev_transaction
|
||||
|
||||
if test -f CREATE_FAILED -a -n "$LVM_TEST_BACKING_DEVICE"; then
|
||||
if test -f CREATE_FAILED ; then
|
||||
if test -z "$LVM_TEST_BACKING_DEVICE"; then
|
||||
echo "failed"
|
||||
return 1
|
||||
fi
|
||||
LVM_TEST_BACKING_DEVICE=
|
||||
rm -f BACKING_DEV CREATE_FAILED
|
||||
prepare_devs "$@"
|
||||
|
||||
@@ -48,6 +48,7 @@ int main (int argc, char *argv[])
|
||||
char aes[] = "434r0pono02pn68sson9268222p3789q703sr62427o78o308518o3228s6n2122";
|
||||
const char *device = (argc > 1) ? argv[1] : "/dev/loop0"; /* device for use */
|
||||
const char *devname = (argc > 2) ? argv[2] : "test-secure"; /* name of dm device */
|
||||
const char *cipher = (argc > 3) ? argv[3] : "aes-xts-plain64"; /* name of dm device */
|
||||
uint32_t cookie = 0;
|
||||
char table[300];
|
||||
struct dm_task *dmt;
|
||||
@@ -63,7 +64,7 @@ int main (int argc, char *argv[])
|
||||
(void) dm_task_set_name(dmt, devname);
|
||||
(void) dm_task_secure_data(dmt);
|
||||
rot13(aes);
|
||||
snprintf(table, sizeof(table), "aes-xts-plain64 %s 0 %s %u", aes, device, sz);
|
||||
snprintf(table, sizeof(table), "%s %s 0 %s %u", cipher, aes, device, sz);
|
||||
memset(aes, 0, sizeof(aes));
|
||||
(void) dm_task_add_target(dmt, 0, sz, "crypt", table);
|
||||
memset(table, 0, sizeof(table));
|
||||
@@ -71,10 +72,9 @@ int main (int argc, char *argv[])
|
||||
(void) dm_task_set_cookie(dmt, &cookie, DM_UDEV_DISABLE_LIBRARY_FALLBACK);
|
||||
(void) dm_task_run(dmt);
|
||||
(void) dm_task_destroy(dmt);
|
||||
(void) dm_udev_wait(cookie); /* Finish udev processing */
|
||||
}
|
||||
|
||||
dm_task_update_nodes();
|
||||
|
||||
/* At this point there should be no memory trace from a secure table line */
|
||||
|
||||
#ifdef SLEEP
|
||||
|
||||
@@ -45,7 +45,9 @@ sleep .5
|
||||
dmsetup status "$DMTEST"
|
||||
|
||||
# generate core file for running&sleeping binary
|
||||
gcore "$PID"
|
||||
gcore "$PID" | tee out
|
||||
# check we capture core while dmsecuretest was already sleeping
|
||||
grep "nanosleep" out
|
||||
kill "$PID" || true
|
||||
wait
|
||||
|
||||
@@ -55,7 +57,7 @@ cat cmdout
|
||||
not grep "$SECURE" "core.$PID" || {
|
||||
## cp "core.$PID" /dev/shm/core
|
||||
rm -f "core.$PID"
|
||||
dmsetup remove "$DMTEST"
|
||||
should dmsetup remove "$DMTEST" # go around weird bugs
|
||||
die "!!! Secure string $SECURE found present in core.$PID !!!"
|
||||
}
|
||||
rm -f "core.$PID"
|
||||
|
||||
@@ -368,7 +368,7 @@ aux enable_dev "$dev2"
|
||||
aux aux udev_wait
|
||||
cat /proc/mdstat
|
||||
# for some reason enabling dev2 starts an odd md dev
|
||||
mdadm --stop "$mddev" || true
|
||||
mdadm --stop $(lsblk -al -o NAME --noheadings "$dev2" | grep '^md') || true
|
||||
cat /proc/mdstat
|
||||
aux wipefs_a "$dev1" || true
|
||||
aux wipefs_a "$dev2" || true
|
||||
@@ -433,7 +433,7 @@ aux enable_dev "$dev2"
|
||||
aux aux udev_wait
|
||||
cat /proc/mdstat
|
||||
# for some reason enabling dev2 starts an odd md dev
|
||||
mdadm --stop "$mddev" || true
|
||||
mdadm --stop $(lsblk -al -o NAME --noheadings "$dev2" | grep '^md') || true
|
||||
cat /proc/mdstat
|
||||
aux wipefs_a "$dev1" || true
|
||||
aux wipefs_a "$dev2" || true
|
||||
|
||||
@@ -415,7 +415,7 @@ aux enable_dev "$dev2"
|
||||
aux udev_wait
|
||||
cat /proc/mdstat
|
||||
# for some reason enabling dev2 starts an odd md dev
|
||||
mdadm --stop "$mddev" || true
|
||||
mdadm --stop $(lsblk -al -o NAME --noheadings "$dev2" | grep '^md') || true
|
||||
cat /proc/mdstat
|
||||
aux wipefs_a "$dev1" || true
|
||||
aux wipefs_a "$dev2" || true
|
||||
@@ -479,7 +479,7 @@ aux enable_dev "$dev2"
|
||||
aux udev_wait
|
||||
cat /proc/mdstat
|
||||
# for some reason enabling dev2 starts an odd md dev
|
||||
mdadm --stop "$mddev" || true
|
||||
mdadm --stop $(lsblk -al -o NAME --noheadings "$dev2" | grep '^md') || true
|
||||
cat /proc/mdstat
|
||||
aux wipefs_a "$dev1" || true
|
||||
aux wipefs_a "$dev2" || true
|
||||
@@ -617,7 +617,7 @@ aux enable_dev "$dev4"
|
||||
aux udev_wait
|
||||
cat /proc/mdstat
|
||||
# for some reason enabling dev2 starts an odd md dev
|
||||
mdadm --stop "$mddev" || true
|
||||
mdadm --stop $(lsblk -al -o NAME --noheadings "$dev2" | grep '^md') || true
|
||||
cat /proc/mdstat
|
||||
aux wipefs_a "$dev1" || true
|
||||
aux wipefs_a "$dev2" || true
|
||||
|
||||
@@ -52,15 +52,17 @@ pvs
|
||||
grep -v -E "$dev1|$dev2" $HINTS > tmptest
|
||||
not grep scan: tmptest
|
||||
|
||||
# test that 'pvs' submits only two reads, one for each PV in hints
|
||||
# test that 'pvs' submits only three reads, one for each PV in hints
|
||||
# for initial scan, and one more in vg_read rescan check
|
||||
|
||||
if [ -e "/usr/bin/strace" ]; then
|
||||
strace -e io_submit pvs 2>&1|tee tmptest
|
||||
test "$(grep io_submit tmptest | wc -l)" -eq 2
|
||||
test "$(grep io_submit tmptest | wc -l)" -eq 3
|
||||
|
||||
# test that 'pvs -a' submits six reads, one for each device
|
||||
# test that 'pvs -a' submits seven reads, one for each device,
|
||||
# and one more in vg_read rescan check
|
||||
strace -e io_submit pvs -a 2>&1|tee tmptest
|
||||
test "$(grep io_submit tmptest | wc -l)" -eq 6
|
||||
test "$(grep io_submit tmptest | wc -l)" -eq 7
|
||||
fi
|
||||
|
||||
#
|
||||
|
||||
167
test/shell/integrity.sh
Normal file
167
test/shell/integrity.sh
Normal file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# Test writecache usage
|
||||
|
||||
SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
# aux have_integrity 1 0 0 || skip
|
||||
which mkfs.xfs || skip
|
||||
|
||||
mnt="mnt"
|
||||
mkdir -p $mnt
|
||||
aux prepare_devs 4 64
|
||||
|
||||
for i in `seq 1 16384`; do echo -n "A" >> fileA; done
|
||||
for i in `seq 1 16384`; do echo -n "B" >> fileB; done
|
||||
for i in `seq 1 16384`; do echo -n "C" >> fileC; done
|
||||
|
||||
_prepare_vg() {
|
||||
# zero devs so we are sure to find the correct file data
|
||||
# on the underlying devs when corrupting it
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
dd if=/dev/zero of="$dev3" || true
|
||||
dd if=/dev/zero of="$dev4" || true
|
||||
vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
}
|
||||
|
||||
_test_fs_with_error() {
|
||||
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
|
||||
|
||||
mount "$DM_DEV_DIR/$vg/$lv1" $mnt
|
||||
|
||||
# add original data
|
||||
cp fileA $mnt
|
||||
cp fileB $mnt
|
||||
cp fileC $mnt
|
||||
|
||||
umount $mnt
|
||||
lvchange -an $vg/$lv1
|
||||
|
||||
# corrupt the original data on the underying dev
|
||||
# flip one bit in fileB, changing a 0x42 to 0x43
|
||||
# the bit is changed in the last 4096 byte block
|
||||
# of the file, so when reading back the file we
|
||||
# will get the first three 4096 byte blocks, for
|
||||
# a total of 12288 bytes before getting an error
|
||||
# on the last 4096 byte block.
|
||||
xxd "$dev1" > dev1.txt
|
||||
tac dev1.txt > dev1.rev
|
||||
sed -e '0,/4242 4242 4242 4242 4242 4242 4242 4242/ s/4242 4242 4242 4242 4242 4242 4242 4242/4242 4242 4242 4242 4242 4242 4242 4243/' dev1.rev > dev1.rev.bad
|
||||
tac dev1.rev.bad > dev1.bad
|
||||
xxd -r dev1.bad > "$dev1"
|
||||
rm dev1.txt dev1.rev dev1.rev.bad dev1.bad
|
||||
|
||||
lvchange -ay $vg/$lv1
|
||||
mount "$DM_DEV_DIR/$vg/$lv1" $mnt
|
||||
|
||||
# read complete fileA which was not corrupted
|
||||
dd if=$mnt/fileA of=tmp bs=1k
|
||||
ls -l tmp
|
||||
stat -c %s tmp
|
||||
diff fileA tmp
|
||||
rm tmp
|
||||
|
||||
# read partial fileB which was corrupted
|
||||
not dd if=$mnt/fileB of=tmp bs=1k
|
||||
ls -l tmp
|
||||
stat -c %s tmp | grep 12288
|
||||
not diff fileB tmp
|
||||
rm tmp
|
||||
|
||||
umount $mnt
|
||||
}
|
||||
|
||||
_test_fs_with_raid1() {
|
||||
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
|
||||
|
||||
mount "$DM_DEV_DIR/$vg/$lv1" $mnt
|
||||
|
||||
# add original data
|
||||
cp fileA $mnt
|
||||
cp fileB $mnt
|
||||
cp fileC $mnt
|
||||
|
||||
umount $mnt
|
||||
lvchange -an $vg/$lv1
|
||||
|
||||
xxd "$dev1" > dev1.txt
|
||||
tac dev1.txt > dev1.rev
|
||||
sed -e '0,/4242 4242 4242 4242 4242 4242 4242 4242/ s/4242 4242 4242 4242 4242 4242 4242 4242/4242 4242 4242 4242 4242 4242 4242 4243/' dev1.rev > dev1.rev.bad
|
||||
tac dev1.rev.bad > dev1.bad
|
||||
xxd -r dev1.bad > "$dev1"
|
||||
rm dev1.txt dev1.rev dev1.rev.bad dev1.bad
|
||||
|
||||
lvchange -ay $vg/$lv1
|
||||
mount "$DM_DEV_DIR/$vg/$lv1" $mnt
|
||||
|
||||
# read complete fileA which was not corrupted
|
||||
dd if=$mnt/fileA of=tmp bs=1k
|
||||
ls -l tmp
|
||||
stat -c %s tmp | grep 16384
|
||||
diff fileA tmp
|
||||
rm tmp
|
||||
|
||||
# read complete fileB, corruption is corrected by raid1
|
||||
dd if=$mnt/fileB of=tmp bs=1k
|
||||
ls -l tmp
|
||||
stat -c %s tmp | grep 16384
|
||||
diff fileB tmp
|
||||
rm tmp
|
||||
|
||||
umount $mnt
|
||||
}
|
||||
|
||||
_prepare_vg
|
||||
lvcreate --integrity y -n $lv1 -l 8 $vg "$dev1"
|
||||
_test_fs_with_error
|
||||
lvchange -an $vg/$lv1
|
||||
lvconvert --integrity n $vg/$lv1
|
||||
lvremove $vg/$lv1
|
||||
vgremove -ff $vg
|
||||
|
||||
_prepare_vg
|
||||
lvcreate -y --integrity internal -n $lv1 -l 8 $vg "$dev1"
|
||||
_test_fs_with_error
|
||||
lvchange -an $vg/$lv1
|
||||
not lvconvert --integrity n $vg/$lv1
|
||||
lvremove $vg/$lv1
|
||||
vgremove -ff $vg
|
||||
|
||||
_prepare_vg
|
||||
lvcreate -an -n meta -L4M $vg "$dev2"
|
||||
lvcreate --integrity y --integritymetadata meta -n $lv1 -l 8 $vg "$dev1"
|
||||
_test_fs_with_error
|
||||
lvchange -an $vg/$lv1
|
||||
lvconvert --integrity n $vg/$lv1
|
||||
lvremove $vg/$lv1
|
||||
vgremove -ff $vg
|
||||
|
||||
_prepare_vg
|
||||
lvcreate --type raid1 -m1 --integrity y -n $lv1 -l 8 $vg
|
||||
_test_fs_with_raid1
|
||||
lvchange -an $vg/$lv1
|
||||
lvconvert --integrity n $vg/$lv1
|
||||
lvremove $vg/$lv1
|
||||
vgremove -ff $vg
|
||||
|
||||
_prepare_vg
|
||||
lvcreate --type raid1 -m2 --integrity y -n $lv1 -l 8 $vg
|
||||
_test_fs_with_raid1
|
||||
lvchange -an $vg/$lv1
|
||||
lvconvert --integrity n $vg/$lv1
|
||||
lvremove $vg/$lv1
|
||||
vgremove -ff $vg
|
||||
|
||||
@@ -56,7 +56,7 @@ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
|
||||
|
||||
echo 3 >/proc/sys/vm/drop_caches
|
||||
# FIXME: This is filling up ram disk. Use sane amount of data please! Rate limit the data written!
|
||||
dd if=/dev/urandom of="$mount_dir/random" bs=1M count=50 conv=fdatasync
|
||||
dd if=/dev/urandom of="$mount_dir/random" bs=1M count=4 conv=fdatasync
|
||||
checksum_ "$mount_dir/random" >MD5
|
||||
|
||||
# FIXME: wait_for_sync - is this really testing anything under load?
|
||||
|
||||
@@ -74,6 +74,8 @@ check active $vg mirror12
|
||||
vgchange -a n $vg
|
||||
aux enable_dev "$dev3"
|
||||
aux disable_dev "$dev4"
|
||||
dmsetup table
|
||||
dmsetup info -c
|
||||
vgchange -aey $vg
|
||||
not vgck $vg
|
||||
|
||||
|
||||
452
test/shell/pvck-repair.sh
Normal file
452
test/shell/pvck-repair.sh
Normal file
@@ -0,0 +1,452 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (C) 2008-2013,2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
. lib/inittest
|
||||
|
||||
aux prepare_devs 2
|
||||
get_devs
|
||||
|
||||
# One PV, one mda, pv_header zeroed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate $vg "$dev1"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, one mda, mda_header zeroed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate $vg "$dev1"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, one mda, pv_header and mda_header zeroed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate $vg "$dev1"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, one mda, metadata zeroed, use backup
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate $vg "$dev1"
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, one mda, mda_header and metadata zeroed, use backup
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate $vg "$dev1"
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, one mda, pv_header, mda_header and metadata zeroed, use backup
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate $vg "$dev1"
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, pv_header zeroed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, mda_header1 zeroed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata_search --settings mda_num=1 "$dev1" || true
|
||||
pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=1 "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, pv_header and mda_header1 zeroed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, metadata1 zeroed, use mda2
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, mda_header1 and metadata1 zeroed, use mda2
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, pv_header, mda_header1 and metadata1 zeroed, use mda2
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata_search --settings "mda_num=2 seqno=1" -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, pv_header, both mda_header, and both metadata zeroed, use backup
|
||||
# only writes mda1 since there's no evidence that mda2 existed
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=67584
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, two mdas, pv_header, both mda_header, and both metadata zeroed, use backup
|
||||
# writes mda1 and also mda2 because of the mda2 settings passed to repair
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
vgcreate --pvmetadatacopies 2 $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=67584
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata "$dev1" || true
|
||||
pvck --dump metadata --settings mda_num=2 "$dev1" || true
|
||||
pvck --dump metadata_search "$dev1" || true
|
||||
pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
|
||||
pvck --repair --settings "mda2_offset=34603008 mda2_size=1048576" -y -f etc/backup/$vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, pv_header and mda_header zeroed on each
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --repair -y -f meta "$dev2"
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, metadata zeroed on each, use backup
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=2 seek=9
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --repair -y -f etc/backup/$vg "$dev2"
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, pv_header, mda_header and metadata zeroed on each, use backup
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --repair -y -f etc/backup/$vg "$dev2"
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, pv_header and mda_header zeroed on first
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --dump metadata -f meta "$dev2"
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, metadata zeroed on first
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --dump metadata -f meta "$dev2"
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, pv_header, mda_header and metadata zeroed on first
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --dump metadata -f meta "$dev2"
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda on first, no mda on second, zero header on first
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
pvcreate "$dev1"
|
||||
pvcreate --pvmetadatacopies 0 "$dev2"
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --dump headers "$dev1"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda on first, no mda on second, zero headers on both
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
pvcreate "$dev1"
|
||||
pvcreate --pvmetadatacopies 0 "$dev2"
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=2
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
pvck --repair -y --settings "mda_offset=0 mda_size=0" -f meta "$dev2"
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda on first, no mda on second, zero all on first
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
pvcreate "$dev1"
|
||||
pvcreate --pvmetadatacopies 0 "$dev2"
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
vgcfgbackup
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --repair -y -f etc/backup/$vg "$dev1"
|
||||
pvck --repair -y --settings "mda_offset=0 mda_size=0" -f etc/backup/$vg "$dev2"
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, two mda on each, pv_header and mda_header1 zeroed on both
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
pvcreate --pvmetadatacopies 2 "$dev1"
|
||||
pvcreate --pvmetadatacopies 2 "$dev2"
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
pvck --dump metadata_search --settings "mda_num=2 seqno=1" -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
rm meta
|
||||
pvck --dump metadata_search --settings "mda_num=2 seqno=1" -f meta "$dev2" || true
|
||||
pvck --repair -y -f meta "$dev2"
|
||||
rm meta
|
||||
pvck --dump headers "$dev1"
|
||||
pvck --dump headers "$dev2"
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# Two PV, one mda each, pv_header and mda_header zeroed on each,
|
||||
# non-standard data_offset/mda_size on first
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
pvcreate --metadatasize 2048k --dataalignment 128k "$dev1"
|
||||
pvcreate "$dev2"
|
||||
vgcreate $vg "$dev1" "$dev2"
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=2
|
||||
dd if=/dev/zero of="$dev2" bs=512 count=1 seek=8
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
pvck --repair -y -f meta "$dev1"
|
||||
rm meta
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev2" || true
|
||||
pvck --repair -y -f meta "$dev2"
|
||||
rm meta
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump headers "$dev2" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
# One PV, one mda, pv_header zeroed, unmatching dev name requires specified uuid
|
||||
rm meta || true
|
||||
dd if=/dev/zero of="$dev1" || true
|
||||
dd if=/dev/zero of="$dev2" || true
|
||||
vgcreate $vg "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
UUID1=`pvck --dump headers "$dev1" | grep pv_header.pv_uuid | awk '{print $2}'`
|
||||
echo $UUID1
|
||||
dd if=/dev/zero of="$dev1" bs=512 count=2
|
||||
pvck --dump headers "$dev1" || true
|
||||
pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
|
||||
sed 's/\/dev\/mapper\/LVMTEST/\/dev\/mapper\/BADTEST/' meta > meta.bad
|
||||
grep device meta
|
||||
grep device meta.bad
|
||||
not pvck --repair -y -f meta.bad "$dev1"
|
||||
pvck --repair -y -f meta.bad --settings pv_uuid=$UUID1 "$dev1"
|
||||
pvck --dump headers "$dev1" || true
|
||||
vgs $vg
|
||||
lvcreate -l1 -an $vg
|
||||
|
||||
44
tools/args.h
44
tools/args.h
@@ -213,12 +213,14 @@ arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0,
|
||||
"If set to no, the command will not attempt to use device-mapper.\n"
|
||||
"For testing and debugging.\n")
|
||||
|
||||
arg(dump_ARG, '\0', "dump", string_VAL, 0, 0,
|
||||
"Dump metadata from a PV. Option values include \\fBmetadata\\fP\n"
|
||||
"to print or save the current text metadata, \\fBmetadata_area\\fP\n"
|
||||
"to save the entire text metadata area to a file, \\fBmetadata_all\\fP\n"
|
||||
"to save the current and any previous complete versions of metadata\n"
|
||||
"to a file, and \\fBheaders\\fP to print and check LVM headers.\n")
|
||||
arg(dump_ARG, '\0', "dump", dumptype_VAL, 0, 0,
|
||||
"Dump headers and metadata from a PV for debugging and repair.\n"
|
||||
"Option values include: \\fBheaders\\fP to print and check LVM headers,\n"
|
||||
"\\fBmetadata\\fP to print or save the current text metadata,\n"
|
||||
"\\fBmetadata_all\\fP to list or save all versions of metadata,\n"
|
||||
"\\fBmetadata_search\\fP to list or save all versions of metadata,\n"
|
||||
"searching standard locations in case of damaged headers,\n"
|
||||
"\\fBmetadata_area\\fP to save an entire text metadata area to a file.\n")
|
||||
|
||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0,
|
||||
"Specifies thin pool behavior when data space is exhausted.\n"
|
||||
@@ -230,9 +232,6 @@ arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0,
|
||||
"(Also see dm-thin-pool kernel module option no_space_timeout.)\n"
|
||||
"See \\fBlvmthin\\fP(7) for more information.\n")
|
||||
|
||||
arg(file_long_ARG, '\0', "file", string_VAL, 0, 0,
|
||||
"File name.\n")
|
||||
|
||||
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0,
|
||||
"Force metadata restore even with thin pool LVs.\n"
|
||||
"Use with extreme caution. Most changes to thin metadata\n"
|
||||
@@ -275,6 +274,18 @@ 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", integrity_VAL, 0, 0,
|
||||
"Enable or disable integrity metadata for an LV.\n"
|
||||
"\\fBy|external\\fP adds integrity with metadata stored on a separate, external LV.\n"
|
||||
"\\fBinternal\\fP adds integrity with metadata interleaved with data\n"
|
||||
"(cannot be removed.) Use \\fBn\\fP to remove integrity.\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"
|
||||
@@ -462,6 +473,11 @@ arg(setphysicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0,
|
||||
"Overrides the automatically detected size of the PV.\n"
|
||||
"Use with care, or prior to reducing the physical size of the device.\n")
|
||||
|
||||
arg(settings_ARG, '\0', "settings", string_VAL, ARG_GROUPABLE, 0,
|
||||
"Specifies command specific settings in \"Key = Value\" form.\n"
|
||||
"Combine multiple settings in quotes, or repeat the settings\n"
|
||||
"option for each.\n")
|
||||
|
||||
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0,
|
||||
"When yes, start the background transformation of an LV.\n"
|
||||
"An incomplete transformation, e.g. pvmove or lvconvert interrupted\n"
|
||||
@@ -543,9 +559,15 @@ arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0,
|
||||
"See \\fBlvmraid\\fP(7) for more information.\n")
|
||||
|
||||
arg(repair_ARG, '\0', "repair", 0, 0, 0,
|
||||
"#lvconvert\n"
|
||||
"Replace failed PVs in a raid or mirror LV, or run a repair\n"
|
||||
"utility on a thin pool. See \\fBlvmraid\\fP(7) and \\fBlvmthin\\fP(7)\n"
|
||||
"for more information.\n")
|
||||
"for more information.\n"
|
||||
"#pvck\n"
|
||||
"Repair headers and metadata on a PV.\n")
|
||||
|
||||
arg(repairtype_ARG, '\0', "repairtype", repairtype_VAL, 0, 0,
|
||||
"Repair headers and metadata on a PV. See command description.\n")
|
||||
|
||||
arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0,
|
||||
"Replace a specific PV in a raid LV with another PV.\n"
|
||||
@@ -1000,6 +1022,8 @@ arg(exported_ARG, 'e', "exported", 0, 0, 0,
|
||||
arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0, NULL)
|
||||
|
||||
arg(file_ARG, 'f', "file", string_VAL, 0, 0,
|
||||
"#pvck\n"
|
||||
"Metadata file to read or write.\n"
|
||||
"#lvmconfig\n"
|
||||
"#dumpconfig\n"
|
||||
"#config\n"
|
||||
|
||||
@@ -719,12 +719,12 @@ FLAGS: SECONDARY_SYNTAX
|
||||
# and the LV type is known.
|
||||
|
||||
lvconvert --repair LV_cache_cachepool_mirror_raid_thinpool
|
||||
OO: --usepolicies, --interval Number, --poolmetadataspare Bool, --file_long String, OO_LVCONVERT
|
||||
OO: --usepolicies, --interval Number, --poolmetadataspare Bool, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_repair
|
||||
DESC: Replace failed PVs in a raid or mirror LV.
|
||||
DESC: Repair a thin pool.
|
||||
DESC: Repair a cache pool or cache.
|
||||
DESC: Repair a cache pool.
|
||||
RULE: all not lv_is_locked lv_is_pvmove
|
||||
RULE: --poolmetadataspare and LV_cache LV_cachepool LV_thinpool
|
||||
|
||||
@@ -757,6 +757,20 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
lvconvert --type integrity LV_linear_striped
|
||||
OO: OO_LVCONVERT, --integrity IntegrityType, --integritymetadata LV, --integritysettings String
|
||||
OP: PV ...
|
||||
ID: lvconvert_integrity
|
||||
DESC: Convert LV to type integrity.
|
||||
|
||||
lvconvert --integrity IntegrityType LV_linear_striped_raid_integrity
|
||||
OO: OO_LVCONVERT, --integritymetadata LV, --integritysettings String
|
||||
OP: PV ...
|
||||
ID: lvconvert_integrity
|
||||
DESC: Add or remove integrity to LV, or to an LV's raid images.
|
||||
|
||||
---
|
||||
|
||||
# --extents is not specified; it's an automatic alternative for --size
|
||||
|
||||
OO_LVCREATE: --addtag Tag, --alloc Alloc, --autobackup Bool, --activate Active,
|
||||
@@ -870,7 +884,8 @@ DESC: Create a raid1 or mirror LV (infers --type raid1|mirror).
|
||||
# R9,R10,R11,R12 (--type raid with any use of --stripes/--mirrors)
|
||||
lvcreate --type raid --size SizeMB VG
|
||||
OO: --mirrors PNumber, --stripes Number, --stripesize SizeKB,
|
||||
--regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB, OO_LVCREATE
|
||||
--regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
||||
--integrity IntegrityType, --integritysettings String, OO_LVCREATE
|
||||
OP: PV ...
|
||||
ID: lvcreate_raid_any
|
||||
DESC: Create a raid LV (a specific raid level must be used, e.g. raid1).
|
||||
@@ -1269,6 +1284,20 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
lvcreate --type integrity --size SizeMB VG
|
||||
OO: --integrity IntegrityType, --integritymetadata LV, --integritysettings String, OO_LVCREATE
|
||||
OP: PV ...
|
||||
ID: lvcreate_integrity
|
||||
DESC: Create a LV with integrity.
|
||||
|
||||
lvcreate --integrity IntegrityType --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,
|
||||
@@ -1436,10 +1465,21 @@ OO: --labelsector Number
|
||||
ID: pvck_general
|
||||
DESC: Check for metadata on a device
|
||||
|
||||
pvck --dump String PV
|
||||
OO: --file String, --pvmetadatacopies MetadataCopiesPV, --labelsector Number
|
||||
pvck --dump DumpType PV
|
||||
OO: --settings String, --file String,
|
||||
--pvmetadatacopies MetadataCopiesPV, --labelsector Number
|
||||
ID: pvck_dump
|
||||
DESC: Print metadata from a device
|
||||
DESC: Check and print LVM headers and metadata on a device
|
||||
|
||||
pvck --repairtype RepairType PV
|
||||
OO: --settings String, --file String, --labelsector Number
|
||||
ID: pvck_repair_type
|
||||
DESC: Repair LVM headers or metadata on a device
|
||||
|
||||
pvck --repair --file String PV
|
||||
OO: --settings String, --labelsector Number
|
||||
ID: pvck_repair
|
||||
DESC: Repair LVM headers and metadata on a device
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -122,6 +122,9 @@ static inline int syncaction_arg(struct cmd_context *cmd __attribute__((unused))
|
||||
static inline int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
||||
static inline int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
||||
static inline int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
||||
static inline int repairtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
||||
static inline int dumptype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
||||
static inline int integritytype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
|
||||
|
||||
/* needed to include commands.h when building man page generator */
|
||||
#define CACHE_VGMETADATA 0x00000001
|
||||
|
||||
@@ -34,5 +34,6 @@ 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)
|
||||
|
||||
|
||||
@@ -2480,339 +2480,10 @@ deactivate_pmslv:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use cache_repair to read metadata from cachevol_lv and
|
||||
* write repaired metadata to new file.
|
||||
/* TODO: lots of similar code with thinpool repair
|
||||
* investigate possible better code sharing...
|
||||
*/
|
||||
|
||||
static int _run_cache_repair_from_cachevol(struct cmd_context *cmd,
|
||||
struct logical_volume *cachevol_lv,
|
||||
const char *meta_file)
|
||||
{
|
||||
char cachevol_lv_path[PATH_MAX];
|
||||
char *cachevol_lv_name;
|
||||
const char *dmdir = dm_dir();
|
||||
const char *cache_repair = find_config_tree_str_allow_empty(cmd, global_cache_repair_executable_CFG, NULL);
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *argv[MAX_PDATA_ARGS + 7]; /* Max supported args */
|
||||
int args = 0;
|
||||
int status;
|
||||
|
||||
if (!cache_repair || !cache_repair[0]) {
|
||||
log_error("No cache_repair command set in lvm.conf. Repair is disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cachevol_lv_name = dm_build_dm_name(cmd->mem, cachevol_lv->vg->name, cachevol_lv->name, NULL))) {
|
||||
log_error("Failed to create dm name for %s.", display_lvname(cachevol_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(cachevol_lv_path, sizeof(cachevol_lv_path), "%s/%s", dmdir, cachevol_lv_name) < 0) {
|
||||
log_error("Failed to create path for %s.", display_lvname(cachevol_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_tree_array(cmd, global_cache_repair_options_CFG, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for global/cache_repair_options");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv && args < MAX_PDATA_ARGS; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"global/cache_repair_options");
|
||||
return 0;
|
||||
}
|
||||
argv[++args] = cv->v.str;
|
||||
}
|
||||
|
||||
if (args >= MAX_PDATA_ARGS) {
|
||||
log_error("Too many cache_repair_options set in lvm.conf.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
argv[0] = cache_repair;
|
||||
argv[++args] = "-i";
|
||||
argv[++args] = cachevol_lv_path;
|
||||
argv[++args] = "-o";
|
||||
argv[++args] = meta_file;
|
||||
argv[++args] = NULL;
|
||||
|
||||
if (!exec_cmd(cmd, (const char * const *)argv, &status, 1)) {
|
||||
log_error("The cache_repair command failed (status %d).", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("cache_repair of metadata completed from %s to %s", display_lvname(cachevol_lv), meta_file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _run_cache_writeback_from_cachevol(struct cmd_context *cmd,
|
||||
struct logical_volume *cache_lv,
|
||||
struct logical_volume *cachevol_lv,
|
||||
const char *meta_file,
|
||||
uint64_t data_offset_bytes)
|
||||
{
|
||||
char orig_path[PATH_MAX];
|
||||
char data_path[PATH_MAX];
|
||||
char *orig_name;
|
||||
char *data_name;
|
||||
const char *dmdir = dm_dir();
|
||||
const char *cache_writeback = "cache_writeback";
|
||||
const char *argv[MAX_PDATA_ARGS + 7]; /* Max supported args */
|
||||
char offset_str[16];
|
||||
int args = 0;
|
||||
int status;
|
||||
|
||||
if (!(orig_name = dm_build_dm_name(cmd->mem, cache_lv->vg->name, cache_lv->name, NULL))) {
|
||||
log_error("Failed to create dm name for %s.", display_lvname(cache_lv));
|
||||
}
|
||||
|
||||
if (!(data_name = dm_build_dm_name(cmd->mem, cachevol_lv->vg->name, cachevol_lv->name, NULL))) {
|
||||
log_error("Failed to create dm name for %s.", display_lvname(cachevol_lv));
|
||||
}
|
||||
|
||||
if (dm_snprintf(orig_path, sizeof(orig_path), "%s/%s", dmdir, orig_name) < 0) {
|
||||
log_error("Failed to create path for %s.", display_lvname(cache_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* _off suffix is temp hack to allow manual offset */
|
||||
if (dm_snprintf(data_path, sizeof(data_path), "%s/%s_off", dmdir, data_name) < 0) {
|
||||
log_error("Failed to create path for %s.", display_lvname(cachevol_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(offset_str, sizeof(offset_str), "%llu",
|
||||
(unsigned long long)data_offset_bytes) < 0)
|
||||
return_0;
|
||||
|
||||
/* let the user set up an _off dm wrapper */
|
||||
if (yes_no_prompt("Done creating wrapper %s with offset %u sectors? [y/n]: ",
|
||||
data_path, (uint32_t)data_offset_bytes/512) == 'n')
|
||||
return_0;
|
||||
|
||||
argv[0] = cache_writeback;
|
||||
argv[++args] = "--metadata-device";
|
||||
argv[++args] = meta_file;
|
||||
argv[++args] = "--origin-device";
|
||||
argv[++args] = orig_path;
|
||||
argv[++args] = "--fast-device";
|
||||
argv[++args] = data_path;
|
||||
/*
|
||||
argv[++args] = "--fast-device-offset";
|
||||
argv[++args] = offset_str;
|
||||
*/
|
||||
argv[++args] = "--no-metadata-update";
|
||||
argv[++args] = NULL;
|
||||
|
||||
if (!exec_cmd(cmd, (const char * const *)argv, &status, 1)) {
|
||||
log_error("The cache_writeback command failed (status %d).", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("cache_writeback of data completed from %s to %s",
|
||||
display_lvname(cachevol_lv), display_lvname(cache_lv));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvconvert_cache_repair_cachevol(struct cmd_context *cmd,
|
||||
struct logical_volume *cache_lv,
|
||||
struct dm_list *pvh)
|
||||
{
|
||||
char filepath[PATH_MAX];
|
||||
char zero_sector_buf[512];
|
||||
struct volume_group *vg = cache_lv->vg;
|
||||
struct logical_volume *cachevol_lv;
|
||||
struct lv_segment *cache_seg, *cachevol_seg;
|
||||
uint64_t metadata_len_sectors, data_offset_bytes;
|
||||
uint64_t orig_cachevol_seglen;
|
||||
const char *meta_file = NULL;
|
||||
FILE *fp;
|
||||
uint32_t prealloc_sectors_written = 0;
|
||||
int cache_mode;
|
||||
int ret = 0;
|
||||
|
||||
memset(zero_sector_buf, 0, 512);
|
||||
|
||||
if (!(cache_seg = first_seg(cache_lv)))
|
||||
return_0;
|
||||
|
||||
if (!(cachevol_lv = cache_seg->pool_lv))
|
||||
return_0;
|
||||
|
||||
if (!lv_is_cache_vol(cachevol_lv))
|
||||
return_0;
|
||||
|
||||
if (cache_seg->metadata_start) {
|
||||
/* metadata is always at 0, but check in case it changes in future */
|
||||
log_error("Cannot handle non-zero metadata start locations.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_active(cache_lv)) {
|
||||
log_error("LV %s must not be active.", display_lvname(cache_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_active(cachevol_lv)) {
|
||||
log_error("LV %s must not be active.", display_lvname(cachevol_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg_is_shared(vg)) {
|
||||
/* cache LV using the cachevol cannot be active elsewhere */
|
||||
if (!lockd_lv(cmd, cache_lv, "ex", 0))
|
||||
return_0;
|
||||
|
||||
/* cachevol cannot be active elsewhere. */
|
||||
if (!lockd_lv(cmd, cachevol_lv, "ex", 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
metadata_len_sectors = cache_seg->metadata_len;
|
||||
cache_mode = cache_seg->cache_mode;
|
||||
|
||||
/* Disable syncing the cache during split */
|
||||
if (cache_mode != CACHE_MODE_WRITETHROUGH)
|
||||
cache_seg->cache_mode = CACHE_MODE_WRITETHROUGH;
|
||||
|
||||
if (!_lvconvert_split_and_keep_cachevol(cmd, cache_lv, cachevol_lv)) {
|
||||
log_error("Failed to detach cachevol, not repairing.");
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: following the spilt, cache_lv is no longer technically a cache
|
||||
* and cachevol_lv is no longer technically a cachevol. The variable
|
||||
* names represent their previous types.
|
||||
*/
|
||||
|
||||
if (cache_mode == CACHE_MODE_WRITETHROUGH) {
|
||||
log_print("No repair or writeback required for writethrough cache mode.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent the active LVs from being exposed and used outside of lvm.
|
||||
*/
|
||||
cachevol_lv->status |= LV_TEMPORARY;
|
||||
cache_lv->status |= LV_TEMPORARY;
|
||||
|
||||
/*
|
||||
* Temporarily change the cachevol LV size to be only the
|
||||
* metadata size, so cache_repair will only look at the
|
||||
* metadata portion.
|
||||
* seg->len and seg->metadata_len units are sectors
|
||||
*/
|
||||
cachevol_seg = first_seg(cachevol_lv);
|
||||
orig_cachevol_seglen = cachevol_seg->len;
|
||||
cachevol_seg->len = metadata_len_sectors / vg->extent_size;
|
||||
|
||||
if (!activate_lv(cmd, cachevol_lv)) {
|
||||
log_error("Failed to activate LV %s for cache repair and writeback.", display_lvname(cachevol_lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Failed to sync local devices before cache_repair.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* cache_repair wants the destination file to be preallocated.
|
||||
* FIXME: what's the relationship between the metadata size and
|
||||
* the file size?
|
||||
*/
|
||||
|
||||
if (arg_is_set(cmd, file_long_ARG))
|
||||
meta_file = arg_str_value(cmd, file_long_ARG, NULL);
|
||||
else {
|
||||
snprintf(filepath, PATH_MAX, "/tmp/lvconvert-cache-repair-metadata-%d", getpid());
|
||||
meta_file = filepath;
|
||||
}
|
||||
|
||||
log_print("Allocating %u MB for metadata in %s",
|
||||
(uint32_t)(metadata_len_sectors * 512 / 1048576), meta_file);
|
||||
|
||||
if (!(fp = fopen(meta_file, "w+"))) {
|
||||
log_error("Failed to open file for metadata %s", meta_file);
|
||||
meta_file = NULL;
|
||||
goto out;
|
||||
}
|
||||
while (prealloc_sectors_written < metadata_len_sectors) {
|
||||
if (!fwrite(zero_sector_buf, 512, 1, fp)) {
|
||||
fclose(fp);
|
||||
log_error("Failed to allocate space for metadata in %s", meta_file);
|
||||
goto out;
|
||||
}
|
||||
prealloc_sectors_written++;
|
||||
}
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
|
||||
if (!_run_cache_repair_from_cachevol(cmd, cachevol_lv, meta_file)) {
|
||||
log_error("cache_repair failed, cache data not written back to original volume.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deactivate cachevol LV, and reactivate with correct size.
|
||||
* Activate cache LV.
|
||||
*/
|
||||
|
||||
if (!deactivate_lv(cmd, cachevol_lv)) {
|
||||
log_error("Failed to deactivate LV %s", cachevol_lv->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cachevol_seg->len = orig_cachevol_seglen;
|
||||
|
||||
if (!activate_lv(cmd, cachevol_lv)) {
|
||||
log_error("Failed to activate LV %s for cache repair and writeback.", display_lvname(cachevol_lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, cache_lv)) {
|
||||
log_error("Failed to activate LV %s for cache repair and writeback.", display_lvname(cache_lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Failed to sync local devices before cache_writeback.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
data_offset_bytes = metadata_len_sectors * 512;
|
||||
|
||||
if (!_run_cache_writeback_from_cachevol(cmd, cache_lv, cachevol_lv, meta_file, data_offset_bytes)) {
|
||||
log_error("cache_writeback failed");
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_print("cachevol writeback complete, %s now unused.", cachevol_lv->name);
|
||||
ret = 1;
|
||||
out:
|
||||
if (!deactivate_lv(cmd, cache_lv))
|
||||
log_error("Failed to deactivate LV %s", cache_lv->name);
|
||||
|
||||
if (!deactivate_lv(cmd, cachevol_lv))
|
||||
log_error("Failed to deactivate LV %s", cachevol_lv->name);
|
||||
|
||||
if (meta_file)
|
||||
unlink(meta_file);
|
||||
|
||||
if (!ret)
|
||||
log_error("Cache data on %s not written back to original LV %s.",
|
||||
display_lvname(cachevol_lv), display_lvname(cache_lv));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lvconvert_cache_repair_cachepool(struct cmd_context *cmd,
|
||||
static int _lvconvert_cache_repair(struct cmd_context *cmd,
|
||||
struct logical_volume *cache_lv,
|
||||
struct dm_list *pvh, int poolmetadataspare)
|
||||
{
|
||||
@@ -2831,6 +2502,11 @@ static int _lvconvert_cache_repair_cachepool(struct cmd_context *cmd,
|
||||
struct logical_volume *pmslv;
|
||||
struct logical_volume *mlv;
|
||||
|
||||
if (lv_is_cache(cache_lv) && lv_is_cache_vol(first_seg(cache_lv)->pool_lv)) {
|
||||
log_error("Manual repair required.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pool_lv = lv_is_cache_pool(cache_lv) ? cache_lv : first_seg(cache_lv)->pool_lv;
|
||||
mlv = first_seg(pool_lv)->metadata_lv;
|
||||
|
||||
@@ -4093,7 +3769,7 @@ static int _lvconvert_repair_pvs(struct cmd_context *cmd, struct logical_volume
|
||||
return ret ? ECMD_PROCESSED : ECMD_FAILED;
|
||||
}
|
||||
|
||||
static int _lvconvert_repair_cache_or_thin(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
static int _lvconvert_repair_cachepool_thinpool(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
int poolmetadataspare = arg_int_value(cmd, poolmetadataspare_ARG, DEFAULT_POOL_METADATA_SPARE);
|
||||
@@ -4114,13 +3790,8 @@ static int _lvconvert_repair_cache_or_thin(struct cmd_context *cmd, struct logic
|
||||
if (!_lvconvert_thin_pool_repair(cmd, lv, use_pvh, poolmetadataspare))
|
||||
return_ECMD_FAILED;
|
||||
} else /* cache */ {
|
||||
if (lv_is_cache(lv) && lv_is_cache_vol(first_seg(lv)->pool_lv)) {
|
||||
if (!_lvconvert_cache_repair_cachevol(cmd, lv, use_pvh))
|
||||
return_ECMD_FAILED;
|
||||
} else {
|
||||
if (!_lvconvert_cache_repair_cachepool(cmd, lv, use_pvh, poolmetadataspare))
|
||||
return_ECMD_FAILED;
|
||||
}
|
||||
if (!_lvconvert_cache_repair(cmd, lv, use_pvh, poolmetadataspare))
|
||||
return_ECMD_FAILED;
|
||||
}
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
@@ -4132,7 +3803,7 @@ static int _lvconvert_repair_single(struct cmd_context *cmd, struct logical_volu
|
||||
if (lv_is_thin_pool(lv) ||
|
||||
lv_is_cache(lv) ||
|
||||
lv_is_cache_pool(lv))
|
||||
return _lvconvert_repair_cache_or_thin(cmd, lv, handle);
|
||||
return _lvconvert_repair_cachepool_thinpool(cmd, lv, handle);
|
||||
|
||||
if (lv_is_raid(lv) || lv_is_mirror(lv))
|
||||
return _lvconvert_repair_pvs(cmd, lv, handle);
|
||||
@@ -4143,6 +3814,12 @@ static int _lvconvert_repair_single(struct cmd_context *cmd, struct logical_volu
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: add option --repair-pvs to call _lvconvert_repair_pvs() directly,
|
||||
* and option --repair-thinpool to call _lvconvert_repair_thinpool().
|
||||
* and option --repair-cache to call _lvconvert_repair_cache().
|
||||
* and option --repair-cachepool to call _lvconvert_repair_cachepool().
|
||||
*/
|
||||
int lvconvert_repair_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle;
|
||||
@@ -6053,6 +5730,150 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lvconvert_integrity_remove(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct volume_group *vg = lv->vg;
|
||||
|
||||
if (!lv_is_integrity(lv) && !lv_is_raid(lv)) {
|
||||
log_error("LV does not have integrity.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: lift this restriction */
|
||||
if (lv_info(cmd, lv, 1, NULL, 0, 0)) {
|
||||
log_error("LV must be inactive to remove integrity.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
return_0;
|
||||
|
||||
if (lv_is_integrity(lv)) {
|
||||
if (!lv_remove_integrity(lv))
|
||||
return_0;
|
||||
} else if (lv_is_raid(lv)) {
|
||||
if (!lv_remove_integrity_from_raid(lv))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
return_0;
|
||||
|
||||
backup(vg);
|
||||
|
||||
log_print_unless_silent("Logical volume %s has removed integrity.", display_lvname(lv));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvconvert_integrity_add(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
const char *meta_name,
|
||||
struct integrity_settings *set)
|
||||
{
|
||||
struct lv_activate_opts laopts = { 0 };
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct lv_segment *seg;
|
||||
struct dm_list *use_pvh;
|
||||
int ret;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
/* TODO: lift this restriction, if we can reload table to set recalculate */
|
||||
if (lv_info(cmd, lv, 1, NULL, 0, 0)) {
|
||||
log_error("LV must be inactive to add integrity.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ensure it's not active elsewhere. */
|
||||
if (!lockd_lv(cmd, lv, "ex", 0))
|
||||
return_0;
|
||||
|
||||
if (cmd->position_argc > 1) {
|
||||
/* First pos arg is required LV, remaining are optional PVs. */
|
||||
if (!(use_pvh = create_pv_list(cmd->mem, vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
|
||||
return_0;
|
||||
} else
|
||||
use_pvh = &vg->pvs;
|
||||
|
||||
if (!archive(vg))
|
||||
return_0;
|
||||
|
||||
if (seg_is_raid(seg))
|
||||
ret = lv_add_integrity_to_raid(lv, "external", set, use_pvh);
|
||||
else
|
||||
ret = lv_add_integrity(lv, "external", meta_name, set, use_pvh);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
backup(vg);
|
||||
|
||||
/*
|
||||
* The LV needs to be activated to start the integrity metadata
|
||||
* initialization.
|
||||
*/
|
||||
|
||||
laopts.integrity_recalculate = 1;
|
||||
|
||||
if (!activate_lv_opts(cmd, lv, &laopts)) {
|
||||
log_error("Failed to activate LV %s.", display_lvname(lv));
|
||||
log_error("The full LV should be zeroed to initialize integrity metadata.");
|
||||
} else {
|
||||
log_print("LV %s activated to initialize integrity.", display_lvname(lv));
|
||||
}
|
||||
|
||||
log_print_unless_silent("Logical volume %s has added integrity.", display_lvname(lv));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvconvert_integrity_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct integrity_settings settings;
|
||||
const char *meta_name = NULL;
|
||||
const char *arg = NULL;
|
||||
int ret = 0;
|
||||
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
|
||||
if (!get_integrity_options(cmd, &arg, &meta_name, &settings))
|
||||
return 0;
|
||||
|
||||
if (!arg || !strcmp(arg, "external") || !strcmp(arg, "y"))
|
||||
ret = _lvconvert_integrity_add(cmd, lv, meta_name, &settings);
|
||||
|
||||
else if (!strcmp(arg, "none") || !strcmp(arg, "n"))
|
||||
ret = _lvconvert_integrity_remove(cmd, lv);
|
||||
|
||||
else
|
||||
log_error("Invalid integrity option value.");
|
||||
|
||||
if (!ret)
|
||||
return ECMD_FAILED;
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle;
|
||||
int ret;
|
||||
|
||||
if (!(handle = init_processing_handle(cmd, NULL))) {
|
||||
log_error("Failed to initialize processing handle.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
|
||||
|
||||
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
|
||||
&_lvconvert_integrity_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* All lvconvert command defs have their own function,
|
||||
* so the generic function name is unused.
|
||||
|
||||
@@ -575,6 +575,13 @@ static int _read_raid_params(struct cmd_context *cmd,
|
||||
log_error("Minimum recovery rate cannot be higher than maximum.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->region_size < lp->stripe_size) {
|
||||
log_print_unless_silent("Adjusting %s %s region size to required minimum of stripe size %s.",
|
||||
lp->segtype->name, display_size(cmd, (uint64_t)lp->region_size),
|
||||
display_size(cmd, (uint64_t)lp->stripe_size));
|
||||
lp->region_size = lp->stripe_size;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -785,6 +792,8 @@ 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;
|
||||
|
||||
@@ -819,6 +828,8 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
readahead_ARG,\
|
||||
setactivationskip_ARG,\
|
||||
test_ARG,\
|
||||
integrity_ARG,\
|
||||
integritysettings_ARG,\
|
||||
type_ARG
|
||||
|
||||
#define CACHE_POOL_ARGS \
|
||||
@@ -1218,6 +1229,11 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_integrity(lp) || seg_is_raid(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;
|
||||
|
||||
@@ -1575,6 +1591,13 @@ static int _check_zero_parameters(struct cmd_context *cmd, struct lvcreate_param
|
||||
if (seg_is_thin(lp))
|
||||
return 1;
|
||||
|
||||
if (seg_is_integrity(lp)) {
|
||||
if (lp->zero && !is_change_activating(lp->activate)) {
|
||||
log_error("Zeroing integrity is not compatible with inactive creation (-an).");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is some problem, buffer will not be empty */
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
|
||||
lp->origin_name ? "origin " : "",
|
||||
@@ -1702,6 +1725,16 @@ static int _lvcreate_single(struct cmd_context *cmd, const char *vg_name,
|
||||
lp->pool_name ? : "with generated name", lp->vg_name, lp->segtype->name);
|
||||
}
|
||||
|
||||
if (seg_is_integrity(lp) && lp->integrity_arg &&
|
||||
!strcmp(lp->integrity_arg, "internal")) {
|
||||
log_warn("WARNING: integrity cannot be removed from LV with internal metadata.");
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
(yes_no_prompt("Create LV with internal integrity metadata?") == 'n')) {
|
||||
log_error("LV not created.");
|
||||
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.");
|
||||
@@ -1775,5 +1808,6 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
_destroy_lvcreate_params(&lp);
|
||||
destroy_processing_handle(cmd, handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -149,6 +149,9 @@ static const struct command_function _command_functions[CMD_COUNT] = {
|
||||
{ lvconvert_to_vdopool_CMD, lvconvert_to_vdopool_cmd },
|
||||
{ lvconvert_to_vdopool_param_CMD, lvconvert_to_vdopool_param_cmd },
|
||||
|
||||
/* lvconvert for integrity */
|
||||
{ lvconvert_integrity_CMD, lvconvert_integrity_cmd },
|
||||
|
||||
{ pvscan_display_CMD, pvscan_display_cmd },
|
||||
{ pvscan_cache_CMD, pvscan_cache_cmd },
|
||||
};
|
||||
@@ -1077,6 +1080,37 @@ int configtype_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int repairtype_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "pv_header") ||
|
||||
!strcmp(av->value, "metadata") ||
|
||||
!strcmp(av->value, "label_header"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dumptype_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "headers") ||
|
||||
!strcmp(av->value, "metadata") ||
|
||||
!strcmp(av->value, "metadata_all") ||
|
||||
!strcmp(av->value, "metadata_search") ||
|
||||
!strcmp(av->value, "metadata_area") ||
|
||||
!strcmp(av->value, "backup_to_raw"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int integritytype_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "y") ||
|
||||
!strcmp(av->value, "n") ||
|
||||
!strcmp(av->value, "external") ||
|
||||
!strcmp(av->value, "internal"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: there's been a confusing mixup among:
|
||||
* resizeable, resizable, allocatable, allocation.
|
||||
|
||||
1776
tools/pvck.c
1776
tools/pvck.c
File diff suppressed because it is too large
Load Diff
@@ -420,7 +420,7 @@ check_duplicate:
|
||||
log_error("pvscan[%d] PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
|
||||
getpid(), dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
|
||||
|
||||
if (file_vgname[0] && strcmp(file_vgname, vgname))
|
||||
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
|
||||
log_error("pvscan[%d] PV %s has unexpected VG %s vs %s.",
|
||||
getpid(), dev_name(dev), vgname, file_vgname);
|
||||
|
||||
|
||||
180
tools/toollib.c
180
tools/toollib.c
@@ -1414,6 +1414,174 @@ 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)
|
||||
{
|
||||
@@ -2579,6 +2747,8 @@ 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:
|
||||
@@ -2637,6 +2807,8 @@ 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;
|
||||
@@ -4284,7 +4456,8 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
|
||||
/*
|
||||
* When processing only specific PVs, we can quit once they've all been found.
|
||||
*/
|
||||
if (!process_all_pvs && dm_list_empty(arg_tags) && dm_list_empty(arg_devices))
|
||||
if (!process_all_pvs && dm_list_empty(arg_tags) &&
|
||||
(!arg_devices || dm_list_empty(arg_devices)))
|
||||
break;
|
||||
log_set_report_object_name_and_id(NULL, NULL);
|
||||
}
|
||||
@@ -5576,10 +5749,11 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
* Reacquire the lock that was released above before waiting, then
|
||||
* check again that the devices can still be used. If the second loop
|
||||
* finds them changed, or can't find them any more, then they aren't
|
||||
* used.
|
||||
* used. Use a non-blocking request when reacquiring to avoid
|
||||
* potential deadlock since this is not the normal locking sequence.
|
||||
*/
|
||||
|
||||
if (!lockf_global(cmd, "ex")) {
|
||||
if (!lockf_global_nonblock(cmd, "ex")) {
|
||||
log_error("Failed to reacquire global lock after prompt.");
|
||||
goto_out;
|
||||
}
|
||||
|
||||
@@ -184,6 +184,9 @@ int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_v
|
||||
int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int repairtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int dumptype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int integritytype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
|
||||
/* we use the enums to access the switches */
|
||||
unsigned arg_count(const struct cmd_context *cmd, int a);
|
||||
@@ -233,6 +236,9 @@ 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);
|
||||
@@ -272,6 +278,8 @@ int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
int lvconvert_to_vdopool_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
int lvconvert_to_vdopool_param_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
int pvscan_display_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
|
||||
@@ -141,6 +141,9 @@ val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair")
|
||||
val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json")
|
||||
val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg")
|
||||
val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata")
|
||||
val(repairtype_VAL, repairtype_arg, "RepairType", "pv_header|metadata|label_header")
|
||||
val(dumptype_VAL, dumptype_arg, "DumpType", "headers|metadata|metadata_all|metadata_search")
|
||||
val(integrity_VAL, integritytype_arg, "IntegrityType", "y|n|external|internal")
|
||||
|
||||
/* this should always be last */
|
||||
val(VAL_COUNT, NULL, NULL, NULL)
|
||||
|
||||
Reference in New Issue
Block a user