1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

integrity: add --integritysettings for kernel 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

Can be used to tune kernel settings:
journal_sectors
journal_watermark
commit_time
bitmap_flush_interval
allow_discards

Described in the kernel documentation
Documentation/admin-guide/device-mapper/dm-integrity.rst

Not yet supported:
lvs -o integritysettings
lvchange --integritysettings
lvextend --integritysettings journal_sectors
This commit is contained in:
David Teigland 2024-08-05 13:20:58 -05:00
parent 07576f7e51
commit 3b9f78332b
10 changed files with 173 additions and 9 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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,13 +194,20 @@ 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;
prev_meta_sectors = lv_imeta->size;
prev_meta_extents = prev_meta_sectors / vg->extent_size;
/*
* FIXME: allow --integritysettings journal_sectors to be used
* with lvextend to override the default journal_sectors
* calculation, but only if the LV is inactive (the journal
* sectors cannot be updated in reload.)
*/
if (meta_extents <= prev_meta_extents) {
log_debug("extend not needed for imeta LV %s", lv_imeta->name);
continue;
@ -597,7 +617,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++;

View File

@ -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"

View File

@ -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
---

View File

@ -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;

View File

@ -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,\

View File

@ -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)
{

View File

@ -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);