diff options
Diffstat (limited to 'device_mapper')
-rw-r--r-- | device_mapper/all.h | 39 | ||||
-rw-r--r-- | device_mapper/ioctl/libdm-iface.c | 31 | ||||
-rw-r--r-- | device_mapper/ioctl/libdm-targets.h | 1 | ||||
-rw-r--r-- | device_mapper/libdm-deptree.c | 154 | ||||
-rw-r--r-- | device_mapper/libdm-targets.c | 27 |
5 files changed, 245 insertions, 7 deletions
diff --git a/device_mapper/all.h b/device_mapper/all.h index b23485f00..f00b6a5dc 100644 --- a/device_mapper/all.h +++ b/device_mapper/all.h @@ -234,6 +234,7 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt); int dm_task_secure_data(struct dm_task *dmt); int dm_task_retry_remove(struct dm_task *dmt); int dm_task_deferred_remove(struct dm_task *dmt); +void dm_task_skip_reload_params_compare(struct dm_task *dmt); /* * Record timestamp immediately after the ioctl returns. @@ -392,6 +393,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 +980,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; + uint32_t block_size; /* optional table param always set by lvm */ + const char *internal_hash; /* optional table param always set by lvm */ + + uint32_t journal_sectors; + uint32_t interleave_sectors; + uint32_t buffer_sectors; + uint32_t journal_watermark; + uint32_t commit_time; + 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 bitmap_flush_interval_set:1; + unsigned sectors_per_bit_set:1; +}; + +int dm_tree_node_add_integrity_target(struct dm_tree_node *node, + uint64_t size, + const char *origin_uuid, + const char *meta_uuid, + struct integrity_settings *settings, + int recalculate); /* * VDO target diff --git a/device_mapper/ioctl/libdm-iface.c b/device_mapper/ioctl/libdm-iface.c index fe04af8bf..25e7d1a75 100644 --- a/device_mapper/ioctl/libdm-iface.c +++ b/device_mapper/ioctl/libdm-iface.c @@ -805,6 +805,11 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt) return 1; } +void dm_task_skip_reload_params_compare(struct dm_task *dmt) +{ + dmt->skip_reload_params_compare = 1; +} + int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node) { switch (add_node) { @@ -1575,11 +1580,29 @@ static int _reload_with_suppression_v4(struct dm_task *dmt) len = strlen(t2->params); while (len-- > 0 && t2->params[len] == ' ') t2->params[len] = '\0'; - if ((t1->start != t2->start) || - (t1->length != t2->length) || - (strcmp(t1->type, t2->type)) || - (strcmp(t1->params, t2->params))) + + if (t1->start != t2->start) { + log_debug("reload %u:%u start diff", task->major, task->minor); + goto no_match; + } + if (t1->length != t2->length) { + log_debug("reload %u:%u length diff", task->major, task->minor); goto no_match; + } + if (strcmp(t1->type, t2->type)) { + log_debug("reload %u:%u type diff %s %s", task->major, task->minor, t1->type, t2->type); + goto no_match; + } + if (strcmp(t1->params, t2->params)) { + if (dmt->skip_reload_params_compare) + log_debug("reload %u:%u skip params ignore %s %s", + task->major, task->minor, t1->params, t2->params); + else { + log_debug("reload %u:%u params diff", task->major, task->minor); + goto no_match; + } + } + t1 = t1->next; t2 = t2->next; } diff --git a/device_mapper/ioctl/libdm-targets.h b/device_mapper/ioctl/libdm-targets.h index b5b20d5e9..9786a7eda 100644 --- a/device_mapper/ioctl/libdm-targets.h +++ b/device_mapper/ioctl/libdm-targets.h @@ -59,6 +59,7 @@ struct dm_task { int skip_lockfs; int query_inactive_table; int suppress_identical_reload; + int skip_reload_params_compare; dm_add_node_t add_node; uint64_t existing_table_size; int cookie_set; diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c index 7fac6ab20..9ba24cbbf 100644 --- a/device_mapper/libdm-deptree.c +++ b/device_mapper/libdm-deptree.c @@ -38,6 +38,7 @@ enum { SEG_STRIPED, SEG_ZERO, SEG_WRITECACHE, + SEG_INTEGRITY, SEG_THIN_POOL, SEG_THIN, SEG_VDO, @@ -78,6 +79,7 @@ static const struct { { SEG_STRIPED, "striped" }, { SEG_ZERO, "zero"}, { SEG_WRITECACHE, "writecache"}, + { SEG_INTEGRITY, "integrity"}, { SEG_THIN_POOL, "thin-pool"}, { SEG_THIN, "thin"}, { SEG_VDO, "vdo" }, @@ -221,6 +223,11 @@ struct load_segment { int writecache_pmem; /* writecache, 1 if pmem, 0 if ssd */ uint32_t writecache_block_size; /* writecache, in bytes */ struct writecache_settings writecache_settings; /* writecache */ + + uint64_t integrity_data_sectors; /* integrity (provided_data_sectors) */ + struct dm_tree_node *integrity_meta_node; /* integrity */ + struct integrity_settings integrity_settings; /* integrity */ + int integrity_recalculate; /* integrity */ }; /* Per-device properties */ @@ -268,6 +275,16 @@ struct load_properties { unsigned delay_resume_if_extended; /* + * When comparing table lines to decide if a reload is + * needed, ignore any differences betwen the lvm device + * params and the kernel-reported device params. + * dm-integrity reports many internal parameters on the + * table line when lvm does not explicitly set them, + * causing lvm and the kernel to have differing params. + */ + unsigned skip_reload_params_compare; + + /* * Call node_send_messages(), set to 2 if there are messages * When != 0, it validates matching transaction id, thus thin-pools * where transation_id is passed as 0 are never validated, this @@ -2705,6 +2722,84 @@ 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 = 3; /* block_size, internal_hash, fix_padding options are always passed */ + + if (seg->integrity_meta_node) + count++; + + if (seg->integrity_recalculate) + count++; + + if (set->journal_sectors_set) + count++; + if (set->interleave_sectors_set) + count++; + if (set->buffer_sectors_set) + count++; + if (set->journal_watermark_set) + count++; + if (set->commit_time_set) + count++; + if (set->bitmap_flush_interval_set) + count++; + if (set->sectors_per_bit_set) + count++; + + EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s", + origin_dev, + set->tag_size, + set->mode, + count, + set->block_size, + set->internal_hash); + + if (seg->integrity_meta_node) + EMIT_PARAMS(pos, " meta_device:%s", meta_dev); + + if (seg->integrity_recalculate) + EMIT_PARAMS(pos, " recalculate"); + + if (set->journal_sectors_set) + EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors); + + if (set->interleave_sectors_set) + EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors); + + if (set->buffer_sectors_set) + EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors); + + if (set->journal_watermark_set) + EMIT_PARAMS(pos, " journal_watermark:%u", set->journal_watermark); + + if (set->commit_time_set) + EMIT_PARAMS(pos, " commit_time:%u", set->commit_time); + + if (set->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 +2984,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 +3000,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: @@ -3005,6 +3105,9 @@ static int _load_node(struct dm_tree_node *dnode) if (!dm_task_suppress_identical_reload(dmt)) log_warn("WARNING: Failed to suppress reload of identical tables."); + if (dnode->props.skip_reload_params_compare) + dm_task_skip_reload_params_compare(dmt); + if ((r = dm_task_run(dmt))) { r = dm_task_get_info(dmt, &dnode->info); if (r && !dnode->info.inactive_table) @@ -3023,8 +3126,8 @@ static int _load_node(struct dm_tree_node *dnode) if (!existing_table_size && dnode->props.delay_resume_if_new) dnode->props.size_changed = 0; - log_debug_activation("Table size changed from %" PRIu64 " to %" - PRIu64 " for %s.%s", existing_table_size, + log_debug_activation("Table size changed from %" PRIu64 " to %" PRIu64 " for %s.%s", + existing_table_size, seg_start, _node_name(dnode), dnode->props.size_changed ? "" : " (Ignoring.)"); @@ -3136,7 +3239,10 @@ int dm_tree_preload_children(struct dm_tree_node *dnode, } /* No resume for a device without parents or with unchanged or smaller size */ - if (!dm_tree_node_num_children(child, 1) || (child->props.size_changed <= 0)) + if (!dm_tree_node_num_children(child, 1)) + continue; + + if (child->props.size_changed <= 0) continue; if (!child->info.inactive_table && !child->info.suspended) @@ -3738,6 +3844,48 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node, return 1; } +int dm_tree_node_add_integrity_target(struct dm_tree_node *node, + uint64_t size, + const char *origin_uuid, + const char *meta_uuid, + struct integrity_settings *settings, + int recalculate) +{ + struct load_segment *seg; + + if (!(seg = _add_segment(node, SEG_INTEGRITY, size))) + return_0; + + if (!meta_uuid) { + log_error("No integrity meta uuid."); + return 0; + } + + if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) { + log_error("Missing integrity's meta uuid %s.", meta_uuid); + return 0; + } + + if (!_link_tree_nodes(node, seg->integrity_meta_node)) + return_0; + + if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) { + log_error("Missing integrity's origin uuid %s.", origin_uuid); + return 0; + } + + if (!_link_tree_nodes(node, seg->origin)) + return_0; + + memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings)); + + seg->integrity_recalculate = recalculate; + + node->props.skip_reload_params_compare = 1; + + return 1; +} + int dm_tree_node_add_replicator_target(struct dm_tree_node *node, uint64_t size, const char *rlog_uuid, diff --git a/device_mapper/libdm-targets.c b/device_mapper/libdm-targets.c index 86cb84713..bfe76c5ff 100644 --- a/device_mapper/libdm-targets.c +++ b/device_mapper/libdm-targets.c @@ -380,6 +380,33 @@ 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[16] = "\0"; + + if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) + return_0; + + 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; |