mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-30 08:32:45 +03:00
Compare commits
31 Commits
dev-dct-ca
...
dev-dct-in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0bbc94900 | ||
|
|
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 |
@@ -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,35 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||
uint32_t writecache_block_size,
|
||||
struct writecache_settings *settings);
|
||||
|
||||
struct integrity_settings {
|
||||
char mode[8];
|
||||
uint32_t tag_size;
|
||||
const char *internal_hash;
|
||||
|
||||
uint32_t journal_sectors;
|
||||
uint32_t interleave_sectors;
|
||||
uint32_t buffer_sectors;
|
||||
uint32_t journal_watermark;
|
||||
uint32_t commit_time;
|
||||
uint32_t block_size;
|
||||
uint32_t bitmap_flush_interval;
|
||||
uint64_t sectors_per_bit;
|
||||
|
||||
unsigned journal_sectors_set:1;
|
||||
unsigned interleave_sectors_set:1;
|
||||
unsigned buffer_sectors_set:1;
|
||||
unsigned journal_watermark_set:1;
|
||||
unsigned commit_time_set:1;
|
||||
unsigned block_size_set:1;
|
||||
unsigned bitmap_flush_interval_set:1;
|
||||
unsigned sectors_per_bit_set:1;
|
||||
};
|
||||
|
||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *origin_uuid,
|
||||
const char *meta_uuid,
|
||||
struct integrity_settings *settings);
|
||||
|
||||
/*
|
||||
* VDO target
|
||||
|
||||
@@ -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,10 @@ struct load_segment {
|
||||
int writecache_pmem; /* writecache, 1 if pmem, 0 if ssd */
|
||||
uint32_t writecache_block_size; /* writecache, in bytes */
|
||||
struct writecache_settings writecache_settings; /* writecache */
|
||||
|
||||
uint64_t integrity_data_sectors; /* integrity (provided_data_sectors) */
|
||||
struct dm_tree_node *integrity_meta_node; /* integrity */
|
||||
struct integrity_settings integrity_settings; /* integrity */
|
||||
};
|
||||
|
||||
/* Per-device properties */
|
||||
@@ -2705,6 +2711,82 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _integrity_emit_segment_line(struct dm_task *dmt,
|
||||
struct load_segment *seg,
|
||||
char *params, size_t paramsize)
|
||||
{
|
||||
struct integrity_settings *set = &seg->integrity_settings;
|
||||
int pos = 0;
|
||||
int count;
|
||||
char origin_dev[DM_FORMAT_DEV_BUFSIZE];
|
||||
char meta_dev[DM_FORMAT_DEV_BUFSIZE];
|
||||
|
||||
if (!_build_dev_string(origin_dev, sizeof(origin_dev), seg->origin))
|
||||
return_0;
|
||||
|
||||
if (seg->integrity_meta_node &&
|
||||
!_build_dev_string(meta_dev, sizeof(meta_dev), seg->integrity_meta_node))
|
||||
return_0;
|
||||
|
||||
count = 1; /* for internal_hash which we always pass in */
|
||||
|
||||
if (seg->integrity_meta_node)
|
||||
count++;
|
||||
|
||||
if (set->journal_sectors_set)
|
||||
count++;
|
||||
if (set->interleave_sectors_set)
|
||||
count++;
|
||||
if (set->buffer_sectors_set)
|
||||
count++;
|
||||
if (set->journal_watermark_set)
|
||||
count++;
|
||||
if (set->commit_time_set)
|
||||
count++;
|
||||
if (set->block_size_set)
|
||||
count++;
|
||||
if (set->bitmap_flush_interval_set)
|
||||
count++;
|
||||
if (set->sectors_per_bit_set)
|
||||
count++;
|
||||
|
||||
EMIT_PARAMS(pos, "%s 0 %u %s %d internal_hash:%s",
|
||||
origin_dev,
|
||||
set->tag_size,
|
||||
set->mode,
|
||||
count,
|
||||
set->internal_hash);
|
||||
|
||||
if (seg->integrity_meta_node)
|
||||
EMIT_PARAMS(pos, " meta_device:%s", meta_dev);
|
||||
|
||||
if (set->journal_sectors_set)
|
||||
EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
|
||||
|
||||
if (set->interleave_sectors_set)
|
||||
EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors);
|
||||
|
||||
if (set->buffer_sectors_set)
|
||||
EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors);
|
||||
|
||||
if (set->journal_watermark_set)
|
||||
EMIT_PARAMS(pos, " journal_watermark:%u", set->journal_watermark);
|
||||
|
||||
if (set->commit_time_set)
|
||||
EMIT_PARAMS(pos, " commit_time:%u", set->commit_time);
|
||||
|
||||
if (set->block_size_set)
|
||||
EMIT_PARAMS(pos, " block_size:%u", set->block_size);
|
||||
|
||||
if (set->bitmap_flush_interval_set)
|
||||
EMIT_PARAMS(pos, " bitmap_flush_interval:%u", set->bitmap_flush_interval);
|
||||
|
||||
if (set->sectors_per_bit_set)
|
||||
EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _thin_pool_emit_segment_line(struct dm_task *dmt,
|
||||
struct load_segment *seg,
|
||||
char *params, size_t paramsize)
|
||||
@@ -2889,6 +2971,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 +2987,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 +3825,39 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *origin_uuid,
|
||||
const char *meta_uuid,
|
||||
struct integrity_settings *settings)
|
||||
{
|
||||
struct load_segment *seg;
|
||||
|
||||
if (!(seg = _add_segment(node, SEG_INTEGRITY, size)))
|
||||
return_0;
|
||||
|
||||
if (meta_uuid) {
|
||||
if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) {
|
||||
log_error("Missing integrity's meta uuid %s.", meta_uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_link_tree_nodes(node, seg->integrity_meta_node))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
|
||||
log_error("Missing integrity's origin uuid %s.", origin_uuid);
|
||||
return 0;
|
||||
}
|
||||
if (!_link_tree_nodes(node, seg->origin))
|
||||
return_0;
|
||||
|
||||
memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *rlog_uuid,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -2870,6 +2870,7 @@ int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
|
||||
int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *active_lv;
|
||||
const struct logical_volume *lv_use;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -2888,19 +2889,30 @@ int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lv->status & LV_UNCOMMITTED)
|
||||
lv_use = lv;
|
||||
else
|
||||
lv_use = lv_committed(lv);
|
||||
|
||||
ret = lv_activate_with_filter(cmd, NULL, 0,
|
||||
(lv->status & LV_NOSCAN) ? 1 : 0,
|
||||
(lv->status & LV_TEMPORARY) ? 1 : 0,
|
||||
lv_committed(lv));
|
||||
lv_use);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int deactivate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_use;
|
||||
int ret;
|
||||
|
||||
ret = lv_deactivate(cmd, NULL, lv_committed(lv));
|
||||
if (lv->status & LV_UNCOMMITTED)
|
||||
lv_use = lv;
|
||||
else
|
||||
lv_use = lv_committed(lv);
|
||||
|
||||
ret = lv_deactivate(cmd, NULL, lv_use);
|
||||
|
||||
return 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;
|
||||
};
|
||||
};
|
||||
@@ -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"
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
30
lib/cache/lvmcache.c
vendored
30
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"
|
||||
|
||||
@@ -1952,24 +1951,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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,8 +104,10 @@ static const struct flag _lv_flags[] = {
|
||||
{LV_VDO_POOL, NULL, 0},
|
||||
{LV_VDO_POOL_DATA, NULL, 0},
|
||||
{WRITECACHE, NULL, 0},
|
||||
{INTEGRITY, NULL, 0},
|
||||
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
|
||||
{LV_REMOVED, NULL, 0},
|
||||
{LV_UNCOMMITTED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
325
lib/integrity/integrity.c
Normal file
325
lib/integrity/integrity.c
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/metadata/segtype.h"
|
||||
#include "lib/display/display.h"
|
||||
#include "lib/format_text/text_export.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/datastruct/str_list.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/metadata/lv_alloc.h"
|
||||
#include "lib/config/defaults.h"
|
||||
|
||||
#define SEG_LOG_ERROR(t, p...) \
|
||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||
|
||||
static void _integrity_display(const struct lv_segment *seg)
|
||||
{
|
||||
/* TODO: lvdisplay segments */
|
||||
}
|
||||
|
||||
static int _integrity_text_import(struct lv_segment *seg,
|
||||
const struct dm_config_node *sn,
|
||||
struct dm_hash_table *pv_hash __attribute__((unused)))
|
||||
{
|
||||
struct integrity_settings *set;
|
||||
struct logical_volume *origin_lv = NULL;
|
||||
struct logical_volume *meta_lv = NULL;
|
||||
const char *origin_name = NULL;
|
||||
const char *meta_dev = NULL;
|
||||
const char *mode = NULL;
|
||||
const char *hash = NULL;
|
||||
|
||||
memset(&seg->integrity_settings, 0, sizeof(struct integrity_settings));
|
||||
set = &seg->integrity_settings;
|
||||
|
||||
/* origin always set */
|
||||
|
||||
if (!dm_config_has_node(sn, "origin"))
|
||||
return SEG_LOG_ERROR("origin not specified in");
|
||||
|
||||
if (!dm_config_get_str(sn, "origin", &origin_name))
|
||||
return SEG_LOG_ERROR("origin must be a string in");
|
||||
|
||||
if (!(origin_lv = find_lv(seg->lv->vg, origin_name)))
|
||||
return SEG_LOG_ERROR("Unknown LV specified for integrity origin %s in", origin_name);
|
||||
|
||||
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
|
||||
return_0;
|
||||
|
||||
/* data_sectors always set */
|
||||
|
||||
if (!dm_config_get_uint64(sn, "data_sectors", &seg->integrity_data_sectors))
|
||||
return SEG_LOG_ERROR("integrity data_sectors must be set in");
|
||||
|
||||
/* mode always set */
|
||||
|
||||
if (!dm_config_get_str(sn, "mode", &mode))
|
||||
return SEG_LOG_ERROR("integrity mode must be set in");
|
||||
|
||||
if (strlen(mode) > 7)
|
||||
return SEG_LOG_ERROR("integrity mode invalid in");
|
||||
|
||||
strncpy(set->mode, mode, 7);
|
||||
|
||||
/* tag_size always set */
|
||||
|
||||
if (!dm_config_get_uint32(sn, "tag_size", &set->tag_size))
|
||||
return SEG_LOG_ERROR("integrity tag_size must be set in");
|
||||
|
||||
/* internal_hash always set */
|
||||
|
||||
if (!dm_config_get_str(sn, "internal_hash", &hash))
|
||||
return SEG_LOG_ERROR("integrity internal_hash must be set in");
|
||||
|
||||
if (!(set->internal_hash = strdup(hash)))
|
||||
return SEG_LOG_ERROR("integrity internal_hash failed to be set in");
|
||||
|
||||
/* meta_dev optional */
|
||||
|
||||
if (dm_config_has_node(sn, "meta_dev")) {
|
||||
if (!dm_config_get_str(sn, "meta_dev", &meta_dev))
|
||||
return SEG_LOG_ERROR("meta_dev must be a string in");
|
||||
|
||||
if (!(meta_lv = find_lv(seg->lv->vg, meta_dev)))
|
||||
return SEG_LOG_ERROR("Unknown logical volume %s specified for integrity in", meta_dev);
|
||||
}
|
||||
|
||||
/* the rest are optional */
|
||||
|
||||
if (dm_config_has_node(sn, "journal_sectors")) {
|
||||
if (!dm_config_get_uint32(sn, "journal_sectors", &set->journal_sectors))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->journal_sectors_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "interleave_sectors")) {
|
||||
if (!dm_config_get_uint32(sn, "interleave_sectors", &set->interleave_sectors))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->interleave_sectors_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "buffer_sectors")) {
|
||||
if (!dm_config_get_uint32(sn, "buffer_sectors", &set->buffer_sectors))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->buffer_sectors_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "journal_watermark")) {
|
||||
if (!dm_config_get_uint32(sn, "journal_watermark", &set->journal_watermark))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->journal_watermark_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "commit_time")) {
|
||||
if (!dm_config_get_uint32(sn, "commit_time", &set->commit_time))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->commit_time_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "block_size")) {
|
||||
if (!dm_config_get_uint32(sn, "block_size", &set->block_size))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->block_size_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "bitmap_flush_interval")) {
|
||||
if (!dm_config_get_uint32(sn, "bitmap_flush_interval", &set->bitmap_flush_interval))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->bitmap_flush_interval_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "sectors_per_bit")) {
|
||||
if (!dm_config_get_uint64(sn, "sectors_per_bit", &set->sectors_per_bit))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->sectors_per_bit_set = 1;
|
||||
}
|
||||
|
||||
seg->origin = origin_lv;
|
||||
seg->integrity_meta_dev = meta_lv;
|
||||
seg->lv->status |= INTEGRITY;
|
||||
|
||||
if (meta_lv && !add_seg_to_segs_using_this_lv(meta_lv, seg))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _integrity_text_import_area_count(const struct dm_config_node *sn,
|
||||
uint32_t *area_count)
|
||||
{
|
||||
*area_count = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _integrity_text_export(const struct lv_segment *seg,
|
||||
struct formatter *f)
|
||||
{
|
||||
const struct integrity_settings *set = &seg->integrity_settings;
|
||||
|
||||
outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name);
|
||||
outf(f, "data_sectors = %llu", (unsigned long long)seg->integrity_data_sectors);
|
||||
|
||||
outf(f, "mode = \"%s\"", set->mode);
|
||||
outf(f, "tag_size = %u", set->tag_size);
|
||||
outf(f, "internal_hash = \"%s\"", set->internal_hash);
|
||||
|
||||
if (seg->integrity_meta_dev)
|
||||
outf(f, "meta_dev = \"%s\"", seg->integrity_meta_dev->name);
|
||||
|
||||
if (set->journal_sectors_set)
|
||||
outf(f, "journal_sectors = %u", set->journal_sectors);
|
||||
|
||||
if (set->interleave_sectors_set)
|
||||
outf(f, "interleave_sectors = %u", set->interleave_sectors);
|
||||
|
||||
if (set->buffer_sectors_set)
|
||||
outf(f, "buffer_sectors = %u", set->buffer_sectors);
|
||||
|
||||
if (set->journal_watermark_set)
|
||||
outf(f, "journal_watermark = %u", set->journal_watermark);
|
||||
|
||||
if (set->commit_time_set)
|
||||
outf(f, "commit_time = %u", set->commit_time);
|
||||
|
||||
if (set->block_size_set)
|
||||
outf(f, "block_size = %u", set->block_size);
|
||||
|
||||
if (set->bitmap_flush_interval)
|
||||
outf(f, "bitmap_flush_interval = %u", set->bitmap_flush_interval);
|
||||
|
||||
if (set->sectors_per_bit)
|
||||
outf(f, "sectors_per_bit = %llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct segment_type *segtype)
|
||||
{
|
||||
free((void *) segtype);
|
||||
}
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
|
||||
static int _target_present(struct cmd_context *cmd,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
{
|
||||
static int _integrity_checked = 0;
|
||||
static int _integrity_present = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!_integrity_checked) {
|
||||
_integrity_checked = 1;
|
||||
_integrity_present = target_present(cmd, TARGET_NAME_INTEGRITY, 0);
|
||||
}
|
||||
|
||||
return _integrity_present;
|
||||
}
|
||||
|
||||
static int _modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
struct dm_list *modules)
|
||||
{
|
||||
if (!str_list_add(mem, modules, MODULE_NAME_INTEGRITY)) {
|
||||
log_error("String list allocation failed for integrity module.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _integrity_add_target_line(struct dev_manager *dm,
|
||||
struct dm_pool *mem,
|
||||
struct cmd_context *cmd __attribute__((unused)),
|
||||
void **target_state __attribute__((unused)),
|
||||
struct lv_segment *seg,
|
||||
const struct lv_activate_opts *laopts __attribute__((unused)),
|
||||
struct dm_tree_node *node, uint64_t len,
|
||||
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
||||
{
|
||||
char *origin_uuid;
|
||||
char *meta_uuid = NULL;
|
||||
|
||||
if (!seg_is_integrity(seg)) {
|
||||
log_error(INTERNAL_ERROR "Passed segment is not integrity.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0), NULL)))
|
||||
return_0;
|
||||
|
||||
if (seg->integrity_meta_dev) {
|
||||
if (!(meta_uuid = build_dm_uuid(mem, seg->integrity_meta_dev, NULL)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!seg->integrity_data_sectors) {
|
||||
log_error("_integrity_add_target_line zero size");
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!dm_tree_node_add_integrity_target(node, seg->integrity_data_sectors,
|
||||
origin_uuid, meta_uuid,
|
||||
&seg->integrity_settings))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
static struct segtype_handler _integrity_ops = {
|
||||
.display = _integrity_display,
|
||||
.text_import = _integrity_text_import,
|
||||
.text_import_area_count = _integrity_text_import_area_count,
|
||||
.text_export = _integrity_text_export,
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
.add_target_line = _integrity_add_target_line,
|
||||
.target_present = _target_present,
|
||||
.modules_needed = _modules_needed,
|
||||
#endif
|
||||
.destroy = _destroy,
|
||||
};
|
||||
|
||||
int init_integrity_segtypes(struct cmd_context *cmd,
|
||||
struct segtype_library *seglib)
|
||||
{
|
||||
struct segment_type *segtype = zalloc(sizeof(*segtype));
|
||||
|
||||
if (!segtype) {
|
||||
log_error("Failed to allocate memory for integrity segtype");
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = SEG_TYPE_NAME_INTEGRITY;
|
||||
segtype->flags = SEG_INTEGRITY;
|
||||
segtype->ops = &_integrity_ops;
|
||||
|
||||
if (!lvm_register_segtype(seglib, segtype))
|
||||
return_0;
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -218,7 +218,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 +655,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 +701,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++;
|
||||
@@ -1451,6 +1449,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,6 +1457,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
264
lib/metadata/integrity_manip.c
Normal file
264
lib/metadata/integrity_manip.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/locking/locking.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/display/display.h"
|
||||
#include "lib/metadata/segtype.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/config/defaults.h"
|
||||
#include "lib/activate/dev_manager.h"
|
||||
|
||||
#define DEFAULT_TAG_SIZE 4 /* bytes */
|
||||
#define DEFAULT_MODE 'B'
|
||||
#define DEFAULT_INTERNAL_HASH "crc32c"
|
||||
|
||||
#define ONE_MB_IN_BYTES 1048576
|
||||
|
||||
/*
|
||||
* The user wants external metadata, but did not specify an existing
|
||||
* LV to hold metadata, so create an LV for metadata. Save it in
|
||||
* lp->integrity_meta_lv and it will be passed to lv_add_integrity().
|
||||
*/
|
||||
int lv_create_integrity_metadata(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct lvcreate_params *lp)
|
||||
{
|
||||
char metaname[NAME_LEN];
|
||||
uint32_t extent_bytes;
|
||||
struct logical_volume *lv;
|
||||
struct lvcreate_params lp_meta = {
|
||||
.activate = CHANGE_AN,
|
||||
.alloc = ALLOC_INHERIT,
|
||||
.major = -1,
|
||||
.minor = -1,
|
||||
.permission = LVM_READ | LVM_WRITE,
|
||||
.pvh = &vg->pvs,
|
||||
.read_ahead = DM_READ_AHEAD_NONE,
|
||||
.stripes = 1,
|
||||
.vg_name = vg->name,
|
||||
.zero = 0,
|
||||
.wipe_signatures = 0,
|
||||
};
|
||||
|
||||
if (dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) {
|
||||
log_error("Failed to create metadata LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lp_meta.lv_name = strdup(metaname)))
|
||||
return_0;
|
||||
|
||||
/* TODO: set pvh per command line */
|
||||
/* TODO: scale size according to LV size. */
|
||||
extent_bytes = vg->extent_size * SECTOR_SIZE;
|
||||
lp_meta.extents = (4 * ONE_MB_IN_BYTES) / extent_bytes;
|
||||
|
||||
log_debug("Creating integrity metadata LV with %u extents", lp_meta.extents);
|
||||
|
||||
dm_list_init(&lp_meta.tags);
|
||||
|
||||
if (!(lp_meta.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!(lv = lv_create_single(vg, &lp_meta))) {
|
||||
log_error("Failed to create integrity metadata LV");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->integrity_meta_lv = lv;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_provided_data_sectors(struct logical_volume *lv, uint64_t *provided_data_sectors)
|
||||
{
|
||||
struct lv_with_info_and_seg_status status;
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
status.seg_status.type = SEG_STATUS_NONE;
|
||||
|
||||
status.seg_status.seg = first_seg(lv);
|
||||
|
||||
/* FIXME: why reporter_pool? */
|
||||
if (!(status.seg_status.mem = dm_pool_create("reporter_pool", 1024))) {
|
||||
log_error("Failed to get mem for LV status.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info_with_seg_status(lv->vg->cmd, first_seg(lv), &status, 1, 1)) {
|
||||
log_error("Failed to get device mapper status for %s", display_lvname(lv));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!status.info.exists) {
|
||||
log_error("No device mapper info exists for %s", display_lvname(lv));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (status.seg_status.type != SEG_STATUS_INTEGRITY) {
|
||||
log_error("Invalid device mapper status type (%d) for %s",
|
||||
(uint32_t)status.seg_status.type, display_lvname(lv));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*provided_data_sectors = status.seg_status.integrity->provided_data_sectors;
|
||||
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lv_add_integrity(struct logical_volume *lv, const char *arg,
|
||||
struct logical_volume *meta_lv_created,
|
||||
const char *meta_name,
|
||||
struct integrity_settings *settings)
|
||||
{
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct integrity_settings *set;
|
||||
struct logical_volume *lv_orig;
|
||||
struct logical_volume *meta_lv = NULL;
|
||||
const struct segment_type *segtype;
|
||||
struct lv_segment *seg;
|
||||
int ret;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* "lv_orig" is a new LV with new id, but with the segments from "lv".
|
||||
* "lv" keeps the existing name and id, but gets a new integrity segment,
|
||||
* in place of the segments that were moved to lv_orig.
|
||||
*/
|
||||
|
||||
if (!(lv_orig = insert_layer_for_lv(cmd, lv, INTEGRITY, "_iorig")))
|
||||
return_0;
|
||||
|
||||
seg = first_seg(lv);
|
||||
seg->segtype = segtype;
|
||||
|
||||
lv->status |= INTEGRITY;
|
||||
|
||||
memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
|
||||
set = &seg->integrity_settings;
|
||||
|
||||
if (!set->mode[0])
|
||||
set->mode[0] = DEFAULT_MODE;
|
||||
|
||||
if (!set->tag_size)
|
||||
set->tag_size = DEFAULT_TAG_SIZE;
|
||||
|
||||
if (!set->internal_hash)
|
||||
set->internal_hash = DEFAULT_INTERNAL_HASH;
|
||||
|
||||
/*
|
||||
* --integrity <arg> is y|external|internal
|
||||
*/
|
||||
|
||||
if (!arg)
|
||||
arg = "external";
|
||||
|
||||
if (!strcmp(arg, "none")) {
|
||||
log_error("Invalid --integrity arg for lvcreate.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "internal") && meta_name) {
|
||||
log_error("Internal integrity cannot be used with integritymetadata option.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (meta_lv_created)
|
||||
meta_lv = meta_lv_created;
|
||||
else if (meta_name) {
|
||||
if (!(meta_lv = find_lv(lv->vg, meta_name))) {
|
||||
log_error("LV %s not found.", meta_name);
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When not using a meta_dev, dm-integrity needs to tell us what the
|
||||
* usable size of the LV is, which is the dev size minus the integrity
|
||||
* overhead. To find that, we need to do a special, temporary activation
|
||||
* of the new LV, specifying a dm dev size of 1, then check the dm dev
|
||||
* status field provided_data_sectors, which is the actual size of the
|
||||
* LV. We need to include provided_data_sectors in the metadata for the
|
||||
* new LV, and use this as the dm dev size for normal LV activation.
|
||||
*
|
||||
* When using a meta_dev, the dm dev size is the size of the data
|
||||
* device. The necessary size of the meta_dev for the given data
|
||||
* device needs to be estimated.
|
||||
*/
|
||||
|
||||
if (meta_lv) {
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Failed to sync local devices.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!activate_and_wipe_lv(meta_lv, 0)) {
|
||||
log_error("LV %s could not be zeroed.", display_lvname(meta_lv));
|
||||
return 0;
|
||||
}
|
||||
seg->integrity_data_sectors = seg->len;
|
||||
seg->integrity_meta_dev = meta_lv;
|
||||
lv_set_hidden(meta_lv);
|
||||
/* TODO: give meta_lv a suffix? e.g. _imeta */
|
||||
ret = 1;
|
||||
} else {
|
||||
/* dm-integrity wants temp/fake size of 1 to report usable size */
|
||||
seg->integrity_data_sectors = 1;
|
||||
|
||||
lv->status |= LV_TEMPORARY;
|
||||
lv->status |= LV_NOSCAN;
|
||||
lv->status |= LV_UNCOMMITTED;
|
||||
|
||||
log_debug("Activating temporary integrity LV to get data sectors.");
|
||||
|
||||
if (!activate_lv(cmd, lv)) {
|
||||
log_error("Failed to activate temporary integrity.");
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_get_provided_data_sectors(lv, &seg->integrity_data_sectors)) {
|
||||
log_error("Failed to get data sectors from dm-integrity");
|
||||
ret = 0;
|
||||
} else {
|
||||
log_debug("Found integrity provided_data_sectors %llu", (unsigned long long)seg->integrity_data_sectors);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
lv->status |= LV_UNCOMMITTED;
|
||||
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Failed to deactivate temporary integrity.");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
lv->status &= ~LV_UNCOMMITTED;
|
||||
lv->status &= ~LV_NOSCAN;
|
||||
lv->status &= ~LV_TEMPORARY;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1457,6 +1457,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 +5663,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;
|
||||
|
||||
@@ -7410,6 +7424,12 @@ int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: copied from label.c */
|
||||
#define BCACHE_BLOCK_SIZE_IN_SECTORS 256 /* 256*512 = 128K */
|
||||
#define BCACHE_BLOCK_SIZE_IN_BYTES 131072
|
||||
#define ONE_MB_IN_BYTES 1048576
|
||||
#define ONE_MB_IN_SECTORS 2048 /* 2048 * 512 = 1048576 */
|
||||
|
||||
/*
|
||||
* Initialize the LV with 'value'.
|
||||
*/
|
||||
@@ -7468,7 +7488,44 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
|
||||
stack;
|
||||
}
|
||||
|
||||
if (wp.do_zero) {
|
||||
if (wp.do_zero && !wp.zero_value && (wp.zero_sectors >= ONE_MB_IN_SECTORS)) {
|
||||
uint64_t off = 0, i = 0, j = 0;
|
||||
uint64_t zero_bytes;
|
||||
uint32_t extra_bytes;
|
||||
|
||||
zero_bytes = wp.zero_sectors * 512;
|
||||
|
||||
if ((extra_bytes = (zero_bytes % ONE_MB_IN_BYTES)))
|
||||
zero_bytes -= extra_bytes;
|
||||
|
||||
log_print("Zeroing %llu MiB...", (unsigned long long)(zero_bytes / ONE_MB_IN_BYTES));
|
||||
|
||||
/*
|
||||
* Write 1MiB at a time to avoid going over bcache size.
|
||||
* Then write 128KiB at a time to cover remaining dev size.
|
||||
*/
|
||||
|
||||
for (i = 0; i < (zero_bytes / ONE_MB_IN_BYTES); i++) {
|
||||
off = i * ONE_MB_IN_BYTES;
|
||||
if (!dev_write_zeros(dev, off, (size_t)ONE_MB_IN_BYTES))
|
||||
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
|
||||
}
|
||||
|
||||
if (extra_bytes) {
|
||||
log_warn("Zeroing %u bytes at %llu...", extra_bytes, (unsigned long long)off);
|
||||
|
||||
for (j = 0; j < (extra_bytes / BCACHE_BLOCK_SIZE_IN_BYTES); j++) {
|
||||
off = i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES;
|
||||
if (!dev_write_zeros(dev, off, (size_t)BCACHE_BLOCK_SIZE_IN_BYTES))
|
||||
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: bcache can't write partial block yet */
|
||||
if ((extra_bytes = (wp.zero_sectors * 512) - (i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES)))
|
||||
log_warn("WARNING: last %llu bytes not zeroed.", (unsigned long long)extra_bytes);
|
||||
|
||||
} else if (wp.do_zero) {
|
||||
zero_sectors = wp.zero_sectors ? : UINT64_C(4096) >> SECTOR_SHIFT;
|
||||
|
||||
if (zero_sectors > lv->size)
|
||||
@@ -7679,6 +7736,11 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
|
||||
first_seg(first_seg(lv)->pool_lv)->zero_new_blocks))
|
||||
return 0;
|
||||
|
||||
if (seg_is_integrity(lp) && (!lp->zero || !(lv->status & LVM_WRITE))) {
|
||||
log_warn("WARNING: --zero not enabled, integrity will not be initialized and may cause read errors.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cannot zero read-only volume */
|
||||
if ((lv->status & LVM_WRITE) &&
|
||||
(lp->zero || lp->wipe_signatures))
|
||||
@@ -7934,6 +7996,18 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
/* FIXME Eventually support raid/mirrors with -m */
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
} else if (seg_is_integrity(lp)) {
|
||||
/*
|
||||
* TODO: if using internal metadata, estimate the amount of metadata
|
||||
* that will be needed, and add this to the amount of PV space being
|
||||
* allocated so that the usable LV size is what the user requested.
|
||||
* Or, just request an extra extent_size bytes, then round the
|
||||
* provided_data_sectors down to be an extent_size multiple.
|
||||
*/
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
} else if (seg_is_mirrored(lp) || (seg_is_raid(lp) && !seg_is_any_raid0(lp))) {
|
||||
if (!(lp->region_size = adjusted_mirror_region_size(vg->cmd,
|
||||
vg->extent_size,
|
||||
@@ -8158,6 +8232,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_integrity(lp)) {
|
||||
if (!lv_add_integrity(lv, lp->integrity_arg, lp->integrity_meta_lv,
|
||||
lp->integrity_meta_name, &lp->integrity_settings))
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
lv_set_activation_skip(lv, lp->activation_skip & ACTIVATION_SKIP_SET,
|
||||
lp->activation_skip & ACTIVATION_SKIP_SET_ENABLED);
|
||||
/*
|
||||
@@ -8282,7 +8362,22 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
if (_should_wipe_lv(lp, lv, !lp->suppress_zero_warn)) {
|
||||
if (seg_is_integrity(lp)) {
|
||||
struct wipe_params wipe;
|
||||
|
||||
memset(&wipe, 0, sizeof(wipe));
|
||||
wipe.do_zero = 1;
|
||||
wipe.zero_sectors = first_seg(lv)->integrity_data_sectors;
|
||||
|
||||
if (!_should_wipe_lv(lp, lv, 1))
|
||||
goto_out;
|
||||
|
||||
if (!wipe_lv(lv, wipe))
|
||||
log_error("Failed to zero LV.");
|
||||
|
||||
goto out;
|
||||
|
||||
} else if (_should_wipe_lv(lp, lv, !lp->suppress_zero_warn)) {
|
||||
if (!wipe_lv(lv, (struct wipe_params)
|
||||
{
|
||||
.do_zero = lp->zero,
|
||||
|
||||
@@ -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 LV_UNCOMMITTED UINT64_C(0x0000000002000000)
|
||||
#define VIRTUAL_ORIGIN UINT64_C(0x0000000008000000) /* LV - internal use only */
|
||||
|
||||
#define MERGING UINT64_C(0x0000000010000000) /* LV SEG */
|
||||
@@ -261,6 +263,7 @@
|
||||
#define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
|
||||
#define lv_is_lockd_sanlock_lv(lv) (((lv)->status & LOCKD_SANLOCK_LV) ? 1 : 0)
|
||||
#define lv_is_writecache(lv) (((lv)->status & WRITECACHE) ? 1 : 0)
|
||||
#define lv_is_integrity(lv) (((lv)->status & INTEGRITY) ? 1 : 0)
|
||||
|
||||
#define lv_is_vdo(lv) (((lv)->status & LV_VDO) ? 1 : 0)
|
||||
#define lv_is_vdo_pool(lv) (((lv)->status & LV_VDO_POOL) ? 1 : 0)
|
||||
@@ -519,6 +522,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 +999,11 @@ struct lvcreate_params {
|
||||
alloc_policy_t alloc; /* all */
|
||||
struct dm_vdo_target_params vdo_params; /* vdo */
|
||||
|
||||
const char *integrity_arg;
|
||||
const char *integrity_meta_name; /* external LV is user-specified */
|
||||
struct logical_volume *integrity_meta_lv; /* external LV we create */
|
||||
struct integrity_settings integrity_settings;
|
||||
|
||||
struct dm_list tags; /* all */
|
||||
|
||||
int yes;
|
||||
@@ -1385,4 +1397,12 @@ int vg_is_foreign(struct volume_group *vg);
|
||||
|
||||
void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
int lv_add_integrity(struct logical_volume *lv, const char *arg,
|
||||
struct logical_volume *meta_lv_created,
|
||||
const char *meta_name, struct integrity_settings *settings);
|
||||
int lv_create_integrity_metadata(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct lvcreate_params *lp);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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."; \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
12
tools/args.h
12
tools/args.h
@@ -230,9 +230,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 +272,15 @@ arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0,
|
||||
"and \\fBdiff\\fP types include unsupported settings in their output by default,\n"
|
||||
"all the other types ignore unsupported settings.\n")
|
||||
|
||||
arg(integrity_ARG, '\0', "integrity", string_VAL, 0, 0,
|
||||
"Controls if integrity metadata should be stored and checked for an LV.\n")
|
||||
|
||||
arg(integritymetadata_ARG, '\0', "integritymetadata", lv_VAL, 0, 0,
|
||||
"The name of an LV to hold integrity metadata.\n")
|
||||
|
||||
arg(integritysettings_ARG, '\0', "integritysettings", string_VAL, ARG_GROUPABLE, 0,
|
||||
"Set dm-integrity parameters.\n")
|
||||
|
||||
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
|
||||
"By default the PV is labelled with an LVM2 identifier in its second\n"
|
||||
"sector (sector 1). This lets you use a different sector near the\n"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1269,6 +1269,20 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
lvcreate --type integrity --size SizeMB VG
|
||||
OO: --integrity String, --integritymetadata LV, --integritysettings String, OO_LVCREATE
|
||||
OP: PV ...
|
||||
ID: lvcreate_integrity
|
||||
DESC: Create a LV with integrity.
|
||||
|
||||
lvcreate --integrity String --size SizeMB VG
|
||||
OO: --type integrity, --integritymetadata LV, --integritysettings String, OO_LVCREATE
|
||||
OP: PV ...
|
||||
ID: lvcreate_integrity
|
||||
DESC: Create a LV with integrity (infers --type integrity).
|
||||
|
||||
---
|
||||
|
||||
lvdisplay
|
||||
OO: --aligned, --all, --binary, --colon, --columns,
|
||||
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -785,6 +785,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;
|
||||
|
||||
@@ -1218,6 +1220,11 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_integrity(lp)) {
|
||||
if (!get_integrity_options(cmd, &lp->integrity_arg, &lp->integrity_meta_name, &lp->integrity_settings))
|
||||
return 0;
|
||||
}
|
||||
|
||||
lcp->pv_count = argc;
|
||||
lcp->pvs = argv;
|
||||
|
||||
@@ -1702,6 +1709,24 @@ static int _lvcreate_single(struct cmd_context *cmd, const char *vg_name,
|
||||
lp->pool_name ? : "with generated name", lp->vg_name, lp->segtype->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an LV to hold integrity metadata when:
|
||||
*
|
||||
* . The user wants external (not internal) metadata. External
|
||||
* is indicated by: no option set (external is default), or
|
||||
* --integrity y|external.
|
||||
*
|
||||
* . The user did not specify an existing metadata LV with
|
||||
* --integritymetadata, saved as lp->integrity_meta_name.
|
||||
*/
|
||||
if (seg_is_integrity(lp) && !lp->integrity_meta_name &&
|
||||
(!lp->integrity_arg ||
|
||||
!strcmp(lp->integrity_arg, "external") ||
|
||||
!strcmp(lp->integrity_arg, "y"))) {
|
||||
if (!lv_create_integrity_metadata(cmd, vg, lp))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (vg->lock_type && !strcmp(vg->lock_type, "sanlock")) {
|
||||
if (!handle_sanlock_lv(cmd, vg)) {
|
||||
log_error("No space for sanlock lock, extend the internal lvmlock LV.");
|
||||
|
||||
63
tools/pvck.c
63
tools/pvck.c
@@ -359,7 +359,10 @@ static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct de
|
||||
continue;
|
||||
}
|
||||
|
||||
sscanf(line, "seqno = %u", &seqno);
|
||||
if (sscanf(line, "seqno = %u", &seqno) != 1) {
|
||||
log_warn("WARNING: Failed to parse seqno.");
|
||||
seqno = 0; /* Skip? */
|
||||
}
|
||||
|
||||
/*
|
||||
* The first three lines look like metadata with
|
||||
@@ -417,11 +420,11 @@ static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct de
|
||||
memset(line, 0, sizeof(line));
|
||||
_copy_line(str1, line, &len);
|
||||
log_print("%s", line);
|
||||
}
|
||||
if ((str2 = strstr(str1, "creation_time = "))) {
|
||||
memset(line, 0, sizeof(line));
|
||||
_copy_line(str2, line, &len);
|
||||
log_print("%s\n", line);
|
||||
if ((str2 = strstr(str1, "creation_time = "))) {
|
||||
memset(line, 0, sizeof(line));
|
||||
_copy_line(str2, line, &len);
|
||||
log_print("%s\n", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,27 +655,31 @@ static int _dump_meta_area(struct device *dev, const char *tofile,
|
||||
if (!tofile)
|
||||
return_0;
|
||||
|
||||
if (!(meta_buf = malloc(mda_size)))
|
||||
if (!(meta_buf = zalloc(mda_size)))
|
||||
return_0;
|
||||
memset(meta_buf, 0, mda_size);
|
||||
|
||||
if (!dev_read_bytes(dev, mda_offset, mda_size, meta_buf)) {
|
||||
log_print("CHECK: failed to read metadata area at offset %llu size %llu",
|
||||
(unsigned long long)mda_offset, (unsigned long long)mda_size);
|
||||
free(meta_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fp = fopen(tofile, "wx"))) {
|
||||
log_error("Failed to create file %s", tofile);
|
||||
log_error("Failed to create file %s.", tofile);
|
||||
free(meta_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fwrite(meta_buf, mda_size - 512, 1, fp);
|
||||
if (fwrite(meta_buf, mda_size - 512, 1, fp) < (mda_size - 512))
|
||||
log_warn("WARNING: Failed to write " FMTu64 " bytes to file %s.", mda_size - 512, tofile);
|
||||
|
||||
free(meta_buf);
|
||||
if (fflush(fp))
|
||||
stack;
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -705,12 +712,11 @@ static int _dump_current_text(struct device *dev,
|
||||
int ri = rlocn_index; /* 0 or 1 */
|
||||
int bad = 0;
|
||||
|
||||
if (!(meta_buf = malloc(meta_size))) {
|
||||
if (!(meta_buf = zalloc(meta_size))) {
|
||||
log_print("CHECK: mda_header_%d.raw_locn[%d] no mem for metadata text size %llu", mn, ri,
|
||||
(unsigned long long)meta_size);
|
||||
return 0;
|
||||
}
|
||||
memset(meta_buf, 0, meta_size);
|
||||
|
||||
/*
|
||||
* Read the metadata text specified by the raw_locn so we can
|
||||
@@ -721,7 +727,7 @@ static int _dump_current_text(struct device *dev,
|
||||
* mda_offset + meta_offset.
|
||||
*/
|
||||
if (meta_offset + meta_size > mda_size) {
|
||||
/* text metadata wraps to start of text metadata area */
|
||||
/* text metadata wraps to start of text metadata area */
|
||||
uint32_t wrap = (uint32_t) ((meta_offset + meta_size) - mda_size);
|
||||
off_t offset_a = mda_offset + meta_offset;
|
||||
uint32_t size_a = meta_size - wrap;
|
||||
@@ -732,6 +738,7 @@ static int _dump_current_text(struct device *dev,
|
||||
log_print("CHECK: failed to read metadata text at mda_header_%d.raw_locn[%d].offset %llu size %llu part_a %llu %llu", mn, ri,
|
||||
(unsigned long long)meta_offset, (unsigned long long)meta_size,
|
||||
(unsigned long long)offset_a, (unsigned long long)size_a);
|
||||
free(meta_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -739,12 +746,14 @@ static int _dump_current_text(struct device *dev,
|
||||
log_print("CHECK: failed to read metadata text at mda_header_%d.raw_locn[%d].offset %llu size %llu part_b %llu %llu", mn, ri,
|
||||
(unsigned long long)meta_offset, (unsigned long long)meta_size,
|
||||
(unsigned long long)offset_b, (unsigned long long)size_b);
|
||||
free(meta_buf);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!dev_read_bytes(dev, mda_offset + meta_offset, meta_size, meta_buf)) {
|
||||
log_print("CHECK: failed to read metadata text at mda_header_%d.raw_locn[%d].offset %llu size %llu", mn, ri,
|
||||
(unsigned long long)meta_offset, (unsigned long long)meta_size);
|
||||
free(meta_buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -802,9 +811,9 @@ static int _dump_current_text(struct device *dev,
|
||||
}
|
||||
|
||||
out:
|
||||
if (bad)
|
||||
return 0;
|
||||
return 1;
|
||||
free(meta_buf);
|
||||
|
||||
return (!bad) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields,
|
||||
@@ -848,6 +857,7 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields,
|
||||
if (!dev_read_bytes(dev, lh_offset, 512, buf)) {
|
||||
log_print("CHECK: failed to read label_header at %llu",
|
||||
(unsigned long long)lh_offset);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1042,9 +1052,9 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields,
|
||||
(unsigned long long)xlate64(dlocn->size));
|
||||
}
|
||||
|
||||
if (bad)
|
||||
return 0;
|
||||
return 1;
|
||||
free(buf);
|
||||
|
||||
return (!bad) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1097,6 +1107,7 @@ static int _dump_mda_header(struct cmd_context *cmd,
|
||||
|
||||
if (!dev_read_bytes(dev, mda_offset, 512, buf)) {
|
||||
log_print("CHECK: failed to read mda_header at %llu", (unsigned long long)mda_offset);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1187,11 +1198,9 @@ static int _dump_mda_header(struct cmd_context *cmd,
|
||||
|
||||
/* Should we also check text metadata if it exists in rlocn1? */
|
||||
out:
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (bad)
|
||||
return 0;
|
||||
return 1;
|
||||
free(buf);
|
||||
|
||||
return (!bad) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int _dump_headers(struct cmd_context *cmd,
|
||||
@@ -1457,7 +1466,8 @@ static int _dump_search(struct cmd_context *cmd,
|
||||
uint64_t dev_bytes;
|
||||
uint64_t extra_bytes;
|
||||
|
||||
dev_get_size(dev, &dev_sectors);
|
||||
if (!dev_get_size(dev, &dev_sectors))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
dev_bytes = dev_sectors * 512;
|
||||
extra_bytes = dev_bytes % ONE_MB_IN_BYTES;
|
||||
@@ -1484,9 +1494,8 @@ static int _dump_search(struct cmd_context *cmd,
|
||||
log_print("Searching for metadata in mda%d at offset %llu size %llu", mda_num,
|
||||
(unsigned long long)mda_offset, (unsigned long long)mda_size);
|
||||
|
||||
if (!(buf = malloc(mda_size)))
|
||||
if (!(buf = zalloc(mda_size)))
|
||||
return ECMD_FAILED;
|
||||
memset(buf, 0, mda_size);
|
||||
|
||||
if (!dev_read_bytes(dev, mda_offset, mda_size, buf)) {
|
||||
log_print("CHECK: failed to read metadata area at offset %llu size %llu",
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
175
tools/toollib.c
175
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);
|
||||
}
|
||||
|
||||
@@ -233,6 +233,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);
|
||||
|
||||
Reference in New Issue
Block a user