mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
integrity: add --integritysettings for tuning
The option can be used in multiple ways (like --cachesettings): --integritysettings key=val --integritysettings 'key1=val1 key2=val2' --integritysettings key1=val1 --integritysettings key2=val2 Use with lvcreate or lvconvert when integrity is first enabled to configure: journal_sectors journal_watermark commit_time bitmap_flush_interval allow_discards Use with lvchange to configure (only while inactive): journal_watermark commit_time bitmap_flush_interval allow_discards lvchange --integritysettings "" clears any previously configured settings, so dm-integrity will use its own defaults. lvs -a -o integritysettings displays configured settings.
This commit is contained in:
parent
07576f7e51
commit
78d14a805c
@ -1023,6 +1023,7 @@ struct integrity_settings {
|
||||
uint32_t commit_time;
|
||||
uint32_t bitmap_flush_interval;
|
||||
uint64_t sectors_per_bit;
|
||||
uint32_t allow_discards;
|
||||
|
||||
unsigned journal_sectors_set:1;
|
||||
unsigned interleave_sectors_set:1;
|
||||
@ -1031,6 +1032,7 @@ struct integrity_settings {
|
||||
unsigned commit_time_set:1;
|
||||
unsigned bitmap_flush_interval_set:1;
|
||||
unsigned sectors_per_bit_set:1;
|
||||
unsigned allow_discards_set:1;
|
||||
};
|
||||
|
||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
||||
|
@ -2868,6 +2868,8 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
|
||||
count++;
|
||||
if (set->sectors_per_bit_set)
|
||||
count++;
|
||||
if (set->allow_discards_set && set->allow_discards)
|
||||
count++;
|
||||
|
||||
EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s",
|
||||
origin_dev,
|
||||
@ -2904,6 +2906,9 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
|
||||
if (set->sectors_per_bit_set)
|
||||
EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
if (set->allow_discards_set && set->allow_discards)
|
||||
EMIT_PARAMS(pos, " allow_discards");
|
||||
|
||||
if (!dm_task_secure_data(dmt))
|
||||
stack;
|
||||
|
||||
|
@ -156,6 +156,12 @@ static int _integrity_text_import(struct lv_segment *seg,
|
||||
set->sectors_per_bit_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "allow_discards")) {
|
||||
if (!dm_config_get_uint32(sn, "allow_discards", &set->allow_discards))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->allow_discards_set = 1;
|
||||
}
|
||||
|
||||
seg->origin = origin_lv;
|
||||
seg->integrity_meta_dev = meta_lv;
|
||||
seg->lv->status |= INTEGRITY;
|
||||
@ -217,6 +223,9 @@ static int _integrity_text_export(const struct lv_segment *seg,
|
||||
if (set->sectors_per_bit)
|
||||
outf(f, "sectors_per_bit = %llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
if (set->allow_discards_set)
|
||||
outf(f, "allow_discards = %u", set->allow_discards);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,8 @@ int lv_is_integrity_origin(const struct logical_volume *lv)
|
||||
* plus some initial space for journals.
|
||||
* (again from trial and error testing.)
|
||||
*/
|
||||
static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
|
||||
static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes, uint32_t journal_sectors,
|
||||
uint32_t extent_size)
|
||||
{
|
||||
uint64_t meta_bytes;
|
||||
uint64_t initial_bytes;
|
||||
@ -58,8 +59,16 @@ static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
|
||||
/* Every 500M of data needs 4M of metadata. */
|
||||
meta_bytes = ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES);
|
||||
|
||||
if (journal_sectors) {
|
||||
/* for calculating the metadata LV size for the specified
|
||||
journal size, round the specified journal size up to the
|
||||
nearest extent. extent_size is in sectors. */
|
||||
initial_bytes = dm_round_up(journal_sectors, extent_size) * 512;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* initial space used for journals
|
||||
* initial space used for journals (when journal size is not specified):
|
||||
* lv_size <= 512M -> 4M
|
||||
* lv_size <= 1G -> 8M
|
||||
* lv_size <= 4G -> 32M
|
||||
@ -73,7 +82,10 @@ static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
|
||||
initial_bytes = 32 * ONE_MB_IN_BYTES;
|
||||
else if (lv_size_bytes > (4ULL * ONE_GB_IN_BYTES))
|
||||
initial_bytes = 64 * ONE_MB_IN_BYTES;
|
||||
|
||||
out:
|
||||
log_debug("integrity_meta_bytes %llu from lv_size_bytes %llu meta_bytes %llu initial_bytes %llu journal_sectors %u",
|
||||
(unsigned long long)(meta_bytes+initial_bytes), (unsigned long long)lv_size_bytes,
|
||||
(unsigned long long)meta_bytes, (unsigned long long)initial_bytes, journal_sectors);
|
||||
return meta_bytes + initial_bytes;
|
||||
}
|
||||
|
||||
@ -84,6 +96,7 @@ static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
|
||||
static int _lv_create_integrity_metadata(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct lvcreate_params *lp,
|
||||
struct integrity_settings *settings,
|
||||
struct logical_volume **meta_lv)
|
||||
{
|
||||
char metaname[NAME_LEN] = { 0 };
|
||||
@ -115,7 +128,7 @@ static int _lv_create_integrity_metadata(struct cmd_context *cmd,
|
||||
lp_meta.pvh = lp->pvh;
|
||||
|
||||
lv_size_bytes = (uint64_t)lp->extents * (uint64_t)vg->extent_size * 512;
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes, settings->journal_sectors, vg->extent_size);
|
||||
meta_sectors = meta_bytes / 512;
|
||||
lp_meta.extents = meta_sectors / vg->extent_size;
|
||||
|
||||
@ -181,7 +194,7 @@ int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh)
|
||||
}
|
||||
|
||||
lv_size_bytes = lv_iorig->size * 512;
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes, 0, 0);
|
||||
meta_sectors = meta_bytes / 512;
|
||||
meta_extents = meta_sectors / vg->extent_size;
|
||||
|
||||
@ -597,7 +610,7 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
lp.pvh = use_pvh;
|
||||
lp.extents = lv_image->size / vg->extent_size;
|
||||
|
||||
if (!_lv_create_integrity_metadata(cmd, vg, &lp, &meta_lv))
|
||||
if (!_lv_create_integrity_metadata(cmd, vg, &lp, settings, &meta_lv))
|
||||
goto_bad;
|
||||
|
||||
revert_meta_lvs++;
|
||||
@ -975,3 +988,29 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int integrity_settings_to_str_list(struct integrity_settings *settings, struct dm_list *result, struct dm_pool *mem)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
if (settings->journal_watermark_set)
|
||||
if (!setting_str_list_add("journal_watermark", settings->journal_watermark, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->commit_time_set)
|
||||
if (!setting_str_list_add("commit_time", settings->commit_time, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->bitmap_flush_interval_set)
|
||||
if (!setting_str_list_add("bitmap_flush_interval", settings->bitmap_flush_interval, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->allow_discards_set)
|
||||
if (!setting_str_list_add("allow_discards", settings->allow_discards, NULL, result, mem))
|
||||
errors++;
|
||||
if (errors)
|
||||
log_warn("Failed to create list of integrity settings.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1169,6 +1169,7 @@ bool lv_writecache_is_clean(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
bool writecache_cleaner_supported(struct cmd_context *cmd);
|
||||
|
||||
int lv_is_integrity_origin(const struct logical_volume *lv);
|
||||
int integrity_settings_to_str_list(struct integrity_settings *settings, struct dm_list *result, struct dm_pool *mem);
|
||||
|
||||
int lv_is_merging_cow(const struct logical_volume *cow);
|
||||
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
|
||||
@ -1511,4 +1512,6 @@ int integrity_mode_set(const char *mode, struct integrity_settings *settings);
|
||||
int lv_integrity_mismatches(struct cmd_context *cmd, const struct logical_volume *lv, uint64_t *mismatches);
|
||||
int lv_raid_integrity_total_mismatches(struct cmd_context *cmd, const struct logical_volume *lv, uint64_t *mismatches);
|
||||
|
||||
int setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem);
|
||||
|
||||
#endif
|
||||
|
@ -5279,3 +5279,24 @@ int lv_is_striped(struct logical_volume *lv)
|
||||
return segtype_is_striped(seg->segtype);
|
||||
}
|
||||
|
||||
int setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem)
|
||||
{
|
||||
char buf[128];
|
||||
char *list_item;
|
||||
|
||||
if (val_str) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s=%s", field, val_str) < 0)
|
||||
return_0;
|
||||
} else {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s=%llu", field, (unsigned long long)val) < 0)
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(list_item = dm_pool_strdup(mem, buf)))
|
||||
return_0;
|
||||
|
||||
if (!str_list_add_no_dup_check(mem, result, list_item))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -449,78 +449,56 @@ int lv_writecache_set_cleaner(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _writecache_setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem)
|
||||
{
|
||||
char buf[128];
|
||||
char *list_item;
|
||||
|
||||
if (val_str) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s=%s", field, val_str) < 0)
|
||||
return_0;
|
||||
} else {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s=%llu", field, (unsigned long long)val) < 0)
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(list_item = dm_pool_strdup(mem, buf)))
|
||||
return_0;
|
||||
|
||||
if (!str_list_add_no_dup_check(mem, result, list_item))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
if (settings->high_watermark_set)
|
||||
if (!_writecache_setting_str_list_add("high_watermark", settings->high_watermark, NULL, result, mem))
|
||||
if (!setting_str_list_add("high_watermark", settings->high_watermark, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->low_watermark_set)
|
||||
if (!_writecache_setting_str_list_add("low_watermark", settings->low_watermark, NULL, result, mem))
|
||||
if (!setting_str_list_add("low_watermark", settings->low_watermark, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->writeback_jobs_set)
|
||||
if (!_writecache_setting_str_list_add("writeback_jobs", settings->writeback_jobs, NULL, result, mem))
|
||||
if (!setting_str_list_add("writeback_jobs", settings->writeback_jobs, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->autocommit_blocks_set)
|
||||
if (!_writecache_setting_str_list_add("autocommit_blocks", settings->autocommit_blocks, NULL, result, mem))
|
||||
if (!setting_str_list_add("autocommit_blocks", settings->autocommit_blocks, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->autocommit_time_set)
|
||||
if (!_writecache_setting_str_list_add("autocommit_time", settings->autocommit_time, NULL, result, mem))
|
||||
if (!setting_str_list_add("autocommit_time", settings->autocommit_time, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->fua_set)
|
||||
if (!_writecache_setting_str_list_add("fua", (uint64_t)settings->fua, NULL, result, mem))
|
||||
if (!setting_str_list_add("fua", (uint64_t)settings->fua, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->nofua_set)
|
||||
if (!_writecache_setting_str_list_add("nofua", (uint64_t)settings->nofua, NULL, result, mem))
|
||||
if (!setting_str_list_add("nofua", (uint64_t)settings->nofua, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->cleaner_set && settings->cleaner)
|
||||
if (!_writecache_setting_str_list_add("cleaner", (uint64_t)settings->cleaner, NULL, result, mem))
|
||||
if (!setting_str_list_add("cleaner", (uint64_t)settings->cleaner, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->max_age_set)
|
||||
if (!_writecache_setting_str_list_add("max_age", (uint64_t)settings->max_age, NULL, result, mem))
|
||||
if (!setting_str_list_add("max_age", (uint64_t)settings->max_age, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->metadata_only_set)
|
||||
if (!_writecache_setting_str_list_add("metadata_only", (uint64_t)settings->metadata_only, NULL, result, mem))
|
||||
if (!setting_str_list_add("metadata_only", (uint64_t)settings->metadata_only, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->pause_writeback_set)
|
||||
if (!_writecache_setting_str_list_add("pause_writeback", (uint64_t)settings->pause_writeback, NULL, result, mem))
|
||||
if (!setting_str_list_add("pause_writeback", (uint64_t)settings->pause_writeback, NULL, result, mem))
|
||||
errors++;
|
||||
|
||||
if (settings->new_key && settings->new_val)
|
||||
if (!_writecache_setting_str_list_add(settings->new_key, 0, settings->new_val, result, mem))
|
||||
if (!setting_str_list_add(settings->new_key, 0, settings->new_val, result, mem))
|
||||
errors++;
|
||||
|
||||
if (errors)
|
||||
|
@ -291,6 +291,7 @@ FIELD(SEGS, seg, STR_LIST, "Metadata Devs", list, 0, metadatadevices, metadata_d
|
||||
FIELD(SEGS, seg, STR, "Monitor", list, 0, segmonitor, seg_monitor, "Dmeventd monitoring status of the segment.", 0)
|
||||
FIELD(SEGS, seg, STR, "CachePolicy", list, 0, cache_policy, cache_policy, "The cache policy (cached segments only).", 0)
|
||||
FIELD(SEGS, seg, STR_LIST, "CacheSettings", list, 0, cache_settings, cache_settings, "Cache settings/parameters (cached segments only).", 0)
|
||||
FIELD(SEGS, seg, STR_LIST, "IntegSettings", list, 0, integrity_settings, integrity_settings, "Integrity settings.", 0)
|
||||
|
||||
FIELD(SEGS, seg, BIN, "VDOCompression", list, 0, vdo_compression, vdo_compression, "Set for compressed LV (vdopool).", 0)
|
||||
FIELD(SEGS, seg, BIN, "VDODeduplication", list, 0, vdo_deduplication, vdo_deduplication, "Set for deduplicated LV (vdopool).", 0)
|
||||
|
@ -651,6 +651,8 @@ GET_LVSEG_STR_PROPERTY_FN(seg_monitor, lvseg_monitor_dup(lvseg->lv->vg->vgmem, l
|
||||
#define _kernel_cache_policy_set prop_not_implemented_set
|
||||
#define _kernel_metadata_format_get prop_not_implemented_get
|
||||
#define _kernel_metadata_format_set prop_not_implemented_set
|
||||
#define _integrity_settings_get prop_not_implemented_get
|
||||
#define _integrity_settings_set prop_not_implemented_set
|
||||
|
||||
/* PVSEG */
|
||||
GET_PVSEG_NUM_PROPERTY_FN(pvseg_start, pvseg->pe)
|
||||
|
@ -3376,6 +3376,31 @@ static int _integritymismatches_disp(struct dm_report *rh __attribute__((unused)
|
||||
return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64));
|
||||
}
|
||||
|
||||
static int _integrity_settings_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
{
|
||||
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||
struct dm_list *result;
|
||||
struct dm_list dummy_list; /* dummy list to display "nothing" */
|
||||
|
||||
if (seg_is_integrity(seg)) {
|
||||
if (!(result = str_list_create(mem)))
|
||||
return_0;
|
||||
|
||||
if (!integrity_settings_to_str_list((struct integrity_settings *)&seg->integrity_settings, result, mem))
|
||||
return_0;
|
||||
|
||||
return _field_set_string_list(rh, field, result, private, 0, NULL);
|
||||
} else {
|
||||
dm_list_init(&dummy_list);
|
||||
return _field_set_string_list(rh, field, &dummy_list, private, 0, NULL);
|
||||
/* TODO: once we have support for STR_LIST reserved values, replace with:
|
||||
* return _field_set_value(field, GET_FIRST_RESERVED_NAME(integrity_settings_undef), GET_FIELD_RESERVED_VALUE(integrity_settings_undef));
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static int _writecache_block_size_disp(struct dm_report *rh __attribute__((unused)),
|
||||
struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
|
@ -809,6 +809,18 @@ system sector/block sizes. It may be less than the file system
|
||||
sector/block size, but not less than the device logical block size.
|
||||
Possible values: 512, 1024, 2048, 4096.
|
||||
.
|
||||
.TP
|
||||
.BR --integritysettings " " key=val
|
||||
dm-integrity kernel tunable options can be specified here.
|
||||
Settings can be included with lvcreate or lvconvert when integrity is first
|
||||
enabled, or changed with lvchange on an existing, inactive LV.
|
||||
See kernel documentation for descriptions of tunable options.
|
||||
Repeat the option to set multiple values.
|
||||
Use lvs -a -o integritysettings VG/LV_rimage_N to display configured values.
|
||||
Use lvchange --integritysettings "" to clear
|
||||
all configured values (dm-integrity will use its defaults.)
|
||||
.P
|
||||
.
|
||||
.SS Integrity initialization
|
||||
.
|
||||
When integrity is added to an LV, the kernel needs to initialize the
|
||||
|
@ -769,4 +769,19 @@ not lvconvert --raidintegrity y $vg/${lv2}_cpool_cdata
|
||||
not lvconvert --raidintegrity y $vg/${lv2}_cpool_cmeta
|
||||
lvremove -y $vg/$lv1
|
||||
|
||||
lvcreate --type raid1 -m1 -n $lv1 -l 8 --raidintegrity y --integritysettings journal_watermark=10 $vg
|
||||
lvs -a -o integritysettings $vg/${lv1}_rimage_0 | grep journal_watermark=10
|
||||
not lvchange --integritysettings journal_watermark=20 $vg/$lv1
|
||||
lvchange -an $vg/$lv1
|
||||
lvchange --integritysettings journal_watermark=80 $vg/$lv1
|
||||
lvchange -ay $vg/$lv1
|
||||
lvs -a -o integritysettings $vg/${lv1}_rimage_0 | grep journal_watermark=80
|
||||
# The journal_watermark value reported in the table may be
|
||||
# slightly different from the value set due to the kernel
|
||||
# reporting it as a computed value that may include rounding.
|
||||
dmsetup table $vg-${lv1}_rimage_0 | tee out
|
||||
grep journal_watermark out
|
||||
lvchange -an $vg/$lv1
|
||||
lvremove -y $vg/$lv1
|
||||
|
||||
vgremove -ff $vg
|
||||
|
@ -1392,6 +1392,10 @@ arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0,
|
||||
"Ignore the \"activation skip\" LV flag during activation\n"
|
||||
"to allow LVs with the flag set to be activated.\n")
|
||||
|
||||
arg(integritysettings_ARG, '\0', "integritysettings", string_VAL, ARG_GROUPABLE, 0,
|
||||
"Specifies tunable kernel options for dm-integrity.\n"
|
||||
"See \\fBlvmraid\\fP(7) for more information.\n")
|
||||
|
||||
arg(maps_ARG, 'm', "maps", 0, 0, 0,
|
||||
"#lvdisplay\n"
|
||||
"Display the mapping of logical extents to PVs and physical extents.\n"
|
||||
|
@ -244,7 +244,7 @@ OO_LVCHANGE_META: --addtag Tag, --deltag Tag,
|
||||
--setautoactivation Bool, --errorwhenfull Bool, --discards Discards, --zero Bool,
|
||||
--cachemode CacheMode, --cachepolicy String, --cachesettings String,
|
||||
--minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
||||
--vdosettings String,
|
||||
--vdosettings String, --integritysettings String,
|
||||
--writebehind Number, --writemostly WriteMostlyPV, --persistent n
|
||||
|
||||
# It's unfortunate that activate needs to be optionally allowed here;
|
||||
@ -843,7 +843,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
---
|
||||
|
||||
lvconvert --raidintegrity Bool LV_raid
|
||||
OO: --raidintegritymode String, --raidintegrityblocksize Number, OO_LVCONVERT
|
||||
OO: --raidintegritymode String, --raidintegrityblocksize Number, --integritysettings String, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_integrity
|
||||
DESC: Add or remove data integrity checksums to raid images.
|
||||
@ -869,7 +869,7 @@ OO_LVCREATE_VDO: --compression Bool, --deduplication Bool, --vdosettings String
|
||||
OO_LVCREATE_THINPOOL: --discards Discards, --errorwhenfull Bool, --pooldatavdo Bool, OO_LVCREATE_VDO, OO_LVCREATE_POOL
|
||||
|
||||
OO_LVCREATE_RAID: --regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
||||
--raidintegrity Bool, --raidintegritymode String, --raidintegrityblocksize Number
|
||||
--raidintegrity Bool, --raidintegritymode String, --raidintegrityblocksize Number, --integritysettings String
|
||||
|
||||
---
|
||||
|
||||
|
108
tools/lvchange.c
108
tools/lvchange.c
@ -810,6 +810,109 @@ static int _lvchange_vdo(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_integrity(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
uint32_t *mr)
|
||||
{
|
||||
struct integrity_settings settings = { 0 };
|
||||
struct logical_volume *lv_image;
|
||||
struct lv_segment *seg, *seg_image;
|
||||
uint32_t s;
|
||||
int set_count = 0;
|
||||
|
||||
if (!lv_is_raid(lv)) {
|
||||
log_error("A raid LV with integrity is required.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_raid_has_integrity(lv)) {
|
||||
log_error("No integrity found in specified raid LV.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the case of dm-integrity, a new dm table line does not trigger a
|
||||
* table reload (see skip_reload_params_compare), so new settings are
|
||||
* not applied to an active integrity device. We could add a flag to
|
||||
* override skip_reload_params_compare through all the layers to lift
|
||||
* this restriction.
|
||||
*/
|
||||
if (lv_is_active(lv)) {
|
||||
log_error("LV must be inactive to change integrity settings.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!get_integrity_settings(cmd, &settings))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* The new specified settings modify the current settings.
|
||||
* A current setting is not changed if a new value is not
|
||||
* specified. Only certain settings can be changed.
|
||||
*/
|
||||
seg = first_seg(lv);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (seg_is_integrity(seg_image)) {
|
||||
if (settings.journal_watermark_set) {
|
||||
seg_image->integrity_settings.journal_watermark_set = 1;
|
||||
seg_image->integrity_settings.journal_watermark = settings.journal_watermark;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.commit_time_set) {
|
||||
seg_image->integrity_settings.commit_time_set = 1;
|
||||
seg_image->integrity_settings.commit_time = settings.commit_time;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.bitmap_flush_interval_set) {
|
||||
seg_image->integrity_settings.bitmap_flush_interval_set = 1;
|
||||
seg_image->integrity_settings.bitmap_flush_interval = settings.bitmap_flush_interval;
|
||||
set_count++;
|
||||
}
|
||||
if (settings.allow_discards_set) {
|
||||
seg_image->integrity_settings.allow_discards_set = 1;
|
||||
seg_image->integrity_settings.allow_discards = settings.allow_discards;
|
||||
set_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* --integritysettings "" clears all previously configured settings,
|
||||
* so dm-integrity kernel code will revert to using its defaults.
|
||||
*/
|
||||
|
||||
if (set_count)
|
||||
goto out;
|
||||
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt("Clear all integrity settings? ") == 'n') {
|
||||
log_print("No settings changed.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (seg_is_integrity(seg_image)) {
|
||||
seg_image->integrity_settings.journal_watermark_set = 0;
|
||||
seg_image->integrity_settings.commit_time_set = 0;
|
||||
seg_image->integrity_settings.bitmap_flush_interval_set = 0;
|
||||
seg_image->integrity_settings.allow_discards_set = 0;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/* Request caller to commit and reload metadata */
|
||||
*mr |= MR_RELOAD;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int arg, uint32_t *mr)
|
||||
{
|
||||
@ -1210,6 +1313,7 @@ static int _option_requires_direct_commit(int opt_enum)
|
||||
cachepolicy_ARG,
|
||||
cachesettings_ARG,
|
||||
vdosettings_ARG,
|
||||
integritysettings_ARG,
|
||||
-1
|
||||
};
|
||||
|
||||
@ -1414,6 +1518,10 @@ static int _lvchange_properties_single(struct cmd_context *cmd,
|
||||
docmds++;
|
||||
doit += _lvchange_vdo(cmd, lv, &mr);
|
||||
break;
|
||||
case integritysettings_ARG:
|
||||
docmds++;
|
||||
doit += _lvchange_integrity(cmd, lv, &mr);
|
||||
break;
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "Failed to check for option %s",
|
||||
arg_long_option_name(i));
|
||||
|
@ -6519,6 +6519,11 @@ static int _lvconvert_integrity_single(struct cmd_context *cmd,
|
||||
struct integrity_settings settings = { .tag_size = 0 };
|
||||
int ret;
|
||||
|
||||
if (arg_is_set(cmd, integritysettings_ARG)) {
|
||||
if (!get_integrity_settings(cmd, &settings))
|
||||
return_ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!integrity_mode_set(arg_str_value(cmd, raidintegritymode_ARG, NULL), &settings))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
|
@ -615,6 +615,10 @@ static int _read_raid_params(struct cmd_context *cmd,
|
||||
if (!integrity_mode_set(arg_str_value(cmd, raidintegritymode_ARG, NULL), &lp->integrity_settings))
|
||||
return_0;
|
||||
}
|
||||
if (arg_is_set(cmd, integritysettings_ARG)) {
|
||||
if (!get_integrity_settings(cmd, &lp->integrity_settings))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -936,7 +940,8 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
raidminrecoveryrate_ARG, \
|
||||
raidintegrity_ARG, \
|
||||
raidintegritymode_ARG, \
|
||||
raidintegrityblocksize_ARG
|
||||
raidintegrityblocksize_ARG, \
|
||||
integritysettings_ARG
|
||||
|
||||
#define SIZE_ARGS \
|
||||
extents_ARG,\
|
||||
|
112
tools/toollib.c
112
tools/toollib.c
@ -1627,6 +1627,118 @@ int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_one_integrity_setting(struct cmd_context *cmd, struct integrity_settings *settings,
|
||||
char *key, char *val)
|
||||
{
|
||||
/*
|
||||
* Some settings handled by other options:
|
||||
* settings->mode from --raidintegritymode
|
||||
* settings->block_size from --raidintegrityblocksize
|
||||
*/
|
||||
|
||||
/* always set in metadata and on table line */
|
||||
|
||||
if (!strncmp(key, "journal_sectors", sizeof("journal_sectors") - 1)) {
|
||||
uint32_t size_mb;
|
||||
|
||||
if (sscanf(val, "%u", &settings->journal_sectors) != 1)
|
||||
goto_bad;
|
||||
|
||||
size_mb = settings->journal_sectors / 2048;
|
||||
if (size_mb < 4 || size_mb > 1024) {
|
||||
log_error("Invalid raid integrity journal size %d MiB (use 4-1024 MiB).", size_mb);
|
||||
goto_bad;
|
||||
}
|
||||
settings->journal_sectors_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* optional, not included in metadata or table line unless set */
|
||||
|
||||
if (!strncmp(key, "journal_watermark", sizeof("journal_watermark") - 1)) {
|
||||
if (sscanf(val, "%u", &settings->journal_watermark) != 1)
|
||||
goto_bad;
|
||||
if (settings->journal_watermark > 100)
|
||||
goto_bad;
|
||||
settings->journal_watermark_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "commit_time", sizeof("commit_time") - 1)) {
|
||||
if (sscanf(val, "%u", &settings->commit_time) != 1)
|
||||
goto_bad;
|
||||
settings->commit_time_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "bitmap_flush_interval", sizeof("bitmap_flush_interval") - 1)) {
|
||||
if (sscanf(val, "%u", &settings->bitmap_flush_interval) != 1)
|
||||
goto_bad;
|
||||
settings->bitmap_flush_interval_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "allow_discards", sizeof("allow_discards") - 1)) {
|
||||
if (sscanf(val, "%u", &settings->allow_discards) != 1)
|
||||
goto_bad;
|
||||
if (settings->allow_discards != 0 && settings->allow_discards != 1)
|
||||
goto_bad;
|
||||
settings->allow_discards_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Invalid setting: %s", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned 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;
|
||||
}
|
||||
|
||||
/* FIXME move to lib */
|
||||
static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
|
||||
{
|
||||
|
@ -227,6 +227,8 @@ int get_vdo_settings(struct cmd_context *cmd,
|
||||
int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
|
||||
uint32_t *block_size_sectors);
|
||||
|
||||
int get_integrity_settings(struct cmd_context *cmd, struct integrity_settings *settings);
|
||||
|
||||
int change_tag(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct physical_volume *pv, int arg);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user