]> sourceware.org Git - lvm2.git/commitdiff
integrity: add --integritysettings for tuning 1404928847
authorDavid Teigland <teigland@redhat.com>
Mon, 5 Aug 2024 18:20:58 +0000 (13:20 -0500)
committerDavid Teigland <teigland@redhat.com>
Wed, 7 Aug 2024 22:40:34 +0000 (17:40 -0500)
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.

19 files changed:
device_mapper/all.h
device_mapper/libdm-deptree.c
lib/integrity/integrity.c
lib/metadata/integrity_manip.c
lib/metadata/metadata-exported.h
lib/metadata/metadata.c
lib/metadata/writecache_manip.c
lib/report/columns.h
lib/report/properties.c
lib/report/report.c
man/lvmraid.7_main
test/shell/integrity.sh
tools/args.h
tools/command-lines.in
tools/lvchange.c
tools/lvconvert.c
tools/lvcreate.c
tools/toollib.c
tools/toollib.h

index 2bea150aff619f332d5f85edc2810d589f9aa00c..fb6030419638c7ec20233576f0ea01ad4f99fa27 100644 (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,
index 3140bbbf26cd6eef2e24b0f0262d48e8c955d39b..a99ac55435a947cb4b91e6cbb481db8d4ce4d4b1 100644 (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;
 
index 1576c856f1503fd638302230676381788a5660ce..b630f8e09d2989685a7e8de1e8674f647291e91d 100644 (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;
 }
 
index 4ac517d63ebc6d084b8f2d8f0a965ab29d745e58..3a186bec18202f28ff694dedc21abd3ad9202245 100644 (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,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;
+}
+
+
index e7cf8cc0d22a6dce7979067bd9b9e67c9c73167c..b8ebca62aa5e73f81c75a86fa1541763142162c4 100644 (file)
@@ -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
index d21df54c582148ae56e9af1c2140be4fad8bb859..785350f5e59d9874d563c581d89e0acaf52ebf59 100644 (file)
@@ -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;
+}
index aa43ae082ebb5d5e62815090d73831090d1733ca..fd26c9b58459f9c807f5253f34b66abe8629549e 100644 (file)
@@ -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)
index 1bb36b9a3bf25437caa3e44d584db0bec2be67e6..f200a304106a5103bad3826bc4ef584b8ed80b15 100644 (file)
@@ -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)
index 6f302360f5d051fb185834c79929c6a66ea3d393..111dbb1c725590fa290a63b1f98cefc019fa658d 100644 (file)
@@ -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)
index 1f2de23f05fa7e136dd4e0778182d73b3d384a63..b1139e5b174af76c6e623f240f8ea0d81f089bfe 100644 (file)
@@ -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,
index 086f534913a1c9c6da500bb2e6486399073a1a1f..c73403e7163fa58b70aea98a86eb4e5ac2bfe93b 100644 (file)
@@ -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
index 940b5fde85d639bde4ca68abe3fe424855fab956..16d8930e88a235f439e569dc80f2515c88dbb177 100644 (file)
@@ -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
index ae4fd05a21086d099c71bce5ddf443fe10693379..7fc2251717b129edebdfce62e6f80f1c94471762 100644 (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"
index 3ad5d3c46b7e90ba74b903662ae38353cf96f372..e9b12f30ea5a2287ab81f4bf66c41b8712dcd716 100644 (file)
@@ -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
 
 ---
 
index 662be01096178d4a30392d7a351f53d47a2e81d3..783bb0b1e4229865e62198b3c8853892fe535c64 100644 (file)
@@ -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));
index 65e0d51cd11f049dac9501b2cc0d1a5771925726..c575f823bf579e1c2ba7ab1b344aa105325e1d2c 100644 (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;
 
index bfe4035a41c082dedfb1a42a0ea42c0424541442..3c24c050dd11276252e3d39ca4a00578b1be7c8c 100644 (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,\
index 62cc5cf650a8a5507cf9c285eff0c62a04aa749f..5031b2cc242bfad6547a3e66adcd12349d78aaeb 100644 (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)
 {
index abf3726a3ff46b0539cb31b55b81fe8a23ec5626..5671229edf5df7c847022be8607b7aa33e45b085 100644 (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);
 
This page took 0.072446 seconds and 5 git commands to generate.