diff options
Diffstat (limited to 'lib/metadata/integrity_manip.c')
-rw-r--r-- | lib/metadata/integrity_manip.c | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c new file mode 100644 index 000000000..b78b76188 --- /dev/null +++ b/lib/metadata/integrity_manip.c @@ -0,0 +1,790 @@ +/* + * 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 'J' +#define DEFAULT_INTERNAL_HASH "crc32c" +#define DEFAULT_BLOCK_SIZE 512 + +#define ONE_MB_IN_BYTES 1048576 + +int lv_is_integrity_origin(const struct logical_volume *lv) +{ + struct seg_list *sl; + + dm_list_iterate_items(sl, &lv->segs_using_this_lv) { + if (!sl->seg || !sl->seg->lv || !sl->seg->origin) + continue; + if (lv_is_integrity(sl->seg->lv) && (sl->seg->origin == lv)) + return 1; + } + return 0; +} + +/* + * Every 500M of data needs 4M of metadata. + * (From trial and error testing.) + */ +static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes) +{ + return ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES); +} + +/* + * The user wants external metadata, but did not specify an existing + * LV to hold metadata, so create an LV for metadata. + */ +static int _lv_create_integrity_metadata(struct cmd_context *cmd, + struct volume_group *vg, + struct lvcreate_params *lp, + struct logical_volume **meta_lv) +{ + char metaname[NAME_LEN]; + uint64_t lv_size_bytes, meta_bytes, meta_sectors; + 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, + .suppress_zero_warn = 1, + }; + + if (lp->lv_name && + dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) { + log_error("Failed to create metadata LV name."); + return 0; + } + + lp_meta.lv_name = metaname; + 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_sectors = meta_bytes / 512; + lp_meta.extents = meta_sectors / vg->extent_size; + + log_print_unless_silent("Creating integrity metadata LV %s with size %s.", + metaname, display_size(cmd, meta_sectors)); + + 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; + } + + if (dm_list_size(&lv->segments) > 1) { + log_error("Integrity metadata uses more than one segment."); + return 0; + } + + *meta_lv = lv; + return 1; +} + +int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh) +{ + struct cmd_context *cmd = lv->vg->cmd; + struct volume_group *vg = lv->vg; + const struct segment_type *segtype; + struct lv_segment *seg_top, *seg_image; + struct logical_volume *lv_image; + struct logical_volume *lv_iorig; + struct logical_volume *lv_imeta; + struct dm_list allocatable_pvs; + struct dm_list *use_pvh; + uint64_t lv_size_bytes, meta_bytes, meta_sectors, prev_meta_sectors; + uint32_t meta_extents, prev_meta_extents; + uint32_t area_count, s; + + seg_top = first_seg(lv); + + if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED))) + return_0; + + area_count = seg_top->area_count; + + for (s = 0; s < area_count; s++) { + lv_image = seg_lv(seg_top, s); + seg_image = first_seg(lv_image); + + if (!(lv_imeta = seg_image->integrity_meta_dev)) { + log_error("LV %s segment has no integrity metadata device.", display_lvname(lv)); + return 0; + } + + if (!(lv_iorig = seg_lv(seg_image, 0))) { + log_error("LV %s integrity segment has no origin", display_lvname(lv)); + return 0; + } + + lv_size_bytes = lv_iorig->size * 512; + meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes); + 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; + + if (meta_extents <= prev_meta_extents) { + log_debug("extend not needed for imeta LV %s", lv_imeta->name); + continue; + } + + /* + * We only allow lv_imeta to exist on a single PV (for now), + * so the allocatable_pvs is the one PV currently used by + * lv_imeta. + */ + dm_list_init(&allocatable_pvs); + + if (!get_pv_list_for_lv(cmd->mem, lv_imeta, &allocatable_pvs)) { + log_error("Failed to build list of PVs for extending %s.", display_lvname(lv_imeta)); + return 0; + } + + use_pvh = &allocatable_pvs; + + if (!lv_extend(lv_imeta, segtype, 1, 0, 0, 0, + meta_extents - prev_meta_extents, + use_pvh, lv_imeta->alloc, 0)) { + log_error("Failed to extend integrity metadata LV %s", lv_imeta->name); + return 0; + } + } + + return 1; +} + +int lv_remove_integrity_from_raid(struct logical_volume *lv) +{ + struct logical_volume *iorig_lvs[DEFAULT_RAID_MAX_IMAGES]; + struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES]; + struct cmd_context *cmd = lv->vg->cmd; + struct volume_group *vg = lv->vg; + struct lv_segment *seg_top, *seg_image; + struct logical_volume *lv_image; + struct logical_volume *lv_iorig; + struct logical_volume *lv_imeta; + uint32_t area_count, s; + int is_active = lv_is_active(lv); + + seg_top = first_seg(lv); + + if (!seg_is_raid1(seg_top) && !seg_is_raid4(seg_top) && + !seg_is_any_raid5(seg_top) && !seg_is_any_raid6(seg_top) && + !seg_is_any_raid10(seg_top)) { + log_error("LV %s segment is unsupported raid for integrity.", display_lvname(lv)); + return 0; + } + + area_count = seg_top->area_count; + + for (s = 0; s < area_count; s++) { + lv_image = seg_lv(seg_top, s); + seg_image = first_seg(lv_image); + + if (!(lv_imeta = seg_image->integrity_meta_dev)) { + log_error("LV %s segment has no integrity metadata device.", display_lvname(lv)); + return 0; + } + + if (!(lv_iorig = seg_lv(seg_image, 0))) { + log_error("LV %s integrity segment has no origin", display_lvname(lv)); + return 0; + } + + if (!remove_seg_from_segs_using_this_lv(seg_image->integrity_meta_dev, seg_image)) + return_0; + + iorig_lvs[s] = lv_iorig; + imeta_lvs[s] = lv_imeta; + + lv_image->status &= ~INTEGRITY; + seg_image->integrity_meta_dev = NULL; + seg_image->integrity_data_sectors = 0; + memset(&seg_image->integrity_settings, 0, sizeof(seg_image->integrity_settings)); + + if (!remove_layer_from_lv(lv_image, lv_iorig)) + return_0; + } + + if (is_active) { + /* vg_write(), suspend_lv(), vg_commit(), resume_lv() */ + if (!lv_update_and_reload(lv)) { + log_error("Failed to update and reload LV after integrity remove."); + return 0; + } + } + + for (s = 0; s < area_count; s++) { + lv_iorig = iorig_lvs[s]; + lv_imeta = imeta_lvs[s]; + + if (is_active) { + if (!deactivate_lv(cmd, lv_iorig)) + log_error("Failed to deactivate unused iorig LV %s.", lv_iorig->name); + + if (!deactivate_lv(cmd, lv_imeta)) + log_error("Failed to deactivate unused imeta LV %s.", lv_imeta->name); + } + + lv_imeta->status &= ~INTEGRITY_METADATA; + lv_set_visible(lv_imeta); + + if (!lv_remove(lv_iorig)) + log_error("Failed to remove unused iorig LV %s.", lv_iorig->name); + + if (!lv_remove(lv_imeta)) + log_error("Failed to remove unused imeta LV %s.", lv_imeta->name); + } + + if (!vg_write(vg) || !vg_commit(vg)) + return_0; + + return 1; +} + +static int _set_integrity_block_size(struct cmd_context *cmd, struct logical_volume *lv, + struct integrity_settings *settings, int lbs_4k, int lbs_512) +{ + char pathname[PATH_MAX]; + struct device *fs_dev; + uint32_t fs_block_size = 0; + int rv; + + if (lbs_4k && lbs_512) { + log_error("Integrity requires consistent logical block size for LV devices."); + goto_bad; + } + + if (settings->block_size && + (settings->block_size != 512 && settings->block_size != 1024 && + settings->block_size != 2048 && settings->block_size != 4096)) { + log_error("Invalid integrity block size, possible values are 512, 1024, 2048, 4096"); + goto_bad; + } + + if (lbs_4k && settings->block_size && (settings->block_size < 4096)) { + log_error("Integrity block size %u not allowed with device logical block size 4096.", + settings->block_size); + goto_bad; + } + + if (!strcmp(cmd->name, "lvcreate")) { + if (lbs_4k) { + settings->block_size = 4096; + } else if (lbs_512) { + if (!settings->block_size) + settings->block_size = 512; + } else if (!lbs_4k && !lbs_512) { + if (!settings->block_size) + settings->block_size = 512; + log_print("Using integrity block size %u with unknown device logical block size.", + settings->block_size); + } else { + goto_bad; + } + + } else if (!strcmp(cmd->name, "lvconvert")) { + if (dm_snprintf(pathname, sizeof(pathname), "%s%s/%s", cmd->dev_dir, + lv->vg->name, lv->name) < 0) { + log_error("Path name too long to get LV block size %s", display_lvname(lv)); + goto_bad; + } + if (!(fs_dev = dev_cache_get(cmd, pathname, NULL))) { + log_error("Device for LV not found to check block size %s", display_lvname(lv)); + goto_bad; + } + + rv = get_fs_block_size(fs_dev, &fs_block_size); + if (!rv || !fs_block_size) { + if (lbs_4k) { + /* require the user to specify --raidintegrityblocksize 4096 as confirmation */ + if (settings->block_size == 4096) { + settings->block_size = 4096; + } else { + log_error("Set --raidintegrityblocksize 4096 if the file system block size is not less than 4096."); + goto_bad; + } + } else { + /* --raidintegrityblocksize must be 512 or unspecified */ + if (settings->block_size && (settings->block_size != 512)) { + log_error("Set --raidintegrityblocksize 512 for unknown file system block size and logical block size 512."); + goto_bad; + } + settings->block_size = 512; + } + log_print("Using integrity block size %u for unknown file system block size and logical block size %u.", + settings->block_size, lbs_4k ? 4096 : 512); + goto out; + } + + if (!settings->block_size) { + if (fs_block_size <= 4096) + settings->block_size = fs_block_size; + else + settings->block_size = 4096; /* dm-integrity max is 4096 */ + log_print("Using integrity block size %u for file system block size %u.", + settings->block_size, fs_block_size); + } else { + /* let user specify integrity block size that is less than fs block size */ + if (settings->block_size > fs_block_size) { + log_error("Integrity block size %u cannot be larger than file system block size %u.", + settings->block_size, fs_block_size); + goto_bad; + } + log_print("Using integrity block size %u for file system block size %u.", + settings->block_size, fs_block_size); + } + } +out: + return 1; +bad: + return 0; +} + +/* + * Add integrity to each raid image. + * + * for each rimage_N: + * . create and allocate a new linear LV rimage_N_imeta + * . move the segments from rimage_N to a new rimage_N_iorig + * . add an integrity segment to rimage_N with + * origin=rimage_N_iorig, meta_dev=rimage_N_imeta + * + * Before: + * rimage_0 + * segment1: striped: pv0:A + * rimage_1 + * segment1: striped: pv1:B + * + * After: + * rimage_0 + * segment1: integrity: rimage_0_iorig, rimage_0_imeta + * rimage_1 + * segment1: integrity: rimage_1_iorig, rimage_1_imeta + * rimage_0_iorig + * segment1: striped: pv0:A + * rimage_1_iorig + * segment1: striped: pv1:B + * rimage_0_imeta + * segment1: striped: pv2:A + * rimage_1_imeta + * segment1: striped: pv2:B + * + */ + +int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_settings *settings, + struct dm_list *pvh, struct logical_volume *lv_imeta_0) +{ + char imeta_name[NAME_LEN]; + char *imeta_name_dup; + struct lvcreate_params lp; + struct dm_list allocatable_pvs; + struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES]; + struct cmd_context *cmd = lv->vg->cmd; + struct volume_group *vg = lv->vg; + struct logical_volume *lv_image, *lv_imeta, *lv_iorig; + struct lv_segment *seg_top, *seg_image; + struct pv_list *pvl; + const struct segment_type *segtype; + struct integrity_settings *set = NULL; + struct dm_list *use_pvh = NULL; + uint32_t area_count, s; + uint32_t revert_meta_lvs = 0; + int lbs_4k = 0, lbs_512 = 0, lbs_unknown = 0; + int is_active; + + memset(imeta_lvs, 0, sizeof(imeta_lvs)); + + is_active = lv_is_active(lv); + + if (dm_list_size(&lv->segments) != 1) + return_0; + + if (!dm_list_empty(&lv->segs_using_this_lv)) { + log_error("Integrity can only be added to top level raid LV."); + return 0; + } + + if (lv_is_origin(lv)) { + log_error("Integrity cannot be added to snapshot origins."); + return 0; + } + + seg_top = first_seg(lv); + area_count = seg_top->area_count; + + if (!seg_is_raid1(seg_top) && !seg_is_raid4(seg_top) && + !seg_is_any_raid5(seg_top) && !seg_is_any_raid6(seg_top) && + !seg_is_any_raid10(seg_top)) { + log_error("Integrity can only be added to raid1,4,5,6,10."); + return 0; + } + + /* + * For each rimage, create an _imeta LV for integrity metadata. + * Each needs to be zeroed. + */ + for (s = 0; s < area_count; s++) { + struct logical_volume *meta_lv; + struct wipe_params wipe = { .do_zero = 1, .zero_sectors = 8 }; + + if (s >= DEFAULT_RAID_MAX_IMAGES) + goto_bad; + + lv_image = seg_lv(seg_top, s); + + /* + * This function is used to add integrity to new images added + * to the raid, in which case old images will already be + * integrity. + */ + if (seg_is_integrity(first_seg(lv_image))) + continue; + + if (!seg_is_striped(first_seg(lv_image))) { + log_error("raid image must be linear to add integrity"); + goto_bad; + } + + /* + * Use an existing lv_imeta from previous linear+integrity LV. + * FIXME: is it guaranteed that lv_image_0 is the existing? + */ + if (!s && lv_imeta_0) { + if (dm_snprintf(imeta_name, sizeof(imeta_name), "%s_imeta", lv_image->name) > 0) { + if ((imeta_name_dup = dm_pool_strdup(vg->vgmem, imeta_name))) + lv_imeta_0->name = imeta_name_dup; + } + imeta_lvs[0] = lv_imeta_0; + continue; + } + + dm_list_init(&allocatable_pvs); + + if (!get_pv_list_for_lv(cmd->mem, lv_image, &allocatable_pvs)) { + log_error("Failed to build list of PVs for %s.", display_lvname(lv_image)); + goto_bad; + } + + dm_list_iterate_items(pvl, &allocatable_pvs) { + unsigned int pbs = 0; + unsigned int lbs = 0; + + if (!dev_get_direct_block_sizes(pvl->pv->dev, &pbs, &lbs)) + lbs_unknown++; + else if (lbs == 4096) + lbs_4k++; + else if (lbs == 512) + lbs_512++; + else + lbs_unknown++; + } + + use_pvh = &allocatable_pvs; + + /* + * allocate a new linear LV NAME_rimage_N_imeta + */ + memset(&lp, 0, sizeof(lp)); + lp.lv_name = lv_image->name; + lp.pvh = use_pvh; + lp.extents = lv_image->size / vg->extent_size; + + if (!_lv_create_integrity_metadata(cmd, vg, &lp, &meta_lv)) + goto_bad; + + revert_meta_lvs++; + + /* Used below to set up the new integrity segment. */ + imeta_lvs[s] = meta_lv; + + /* + * dm-integrity requires the metadata LV header to be zeroed. + */ + + if (!activate_lv(cmd, meta_lv)) { + log_error("Failed to activate LV %s to zero", display_lvname(meta_lv)); + goto_bad; + } + + if (!wipe_lv(meta_lv, wipe)) { + log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv)); + if (deactivate_lv(cmd, meta_lv)) + log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv)); + goto_bad; + } + + if (!deactivate_lv(cmd, meta_lv)) { + log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv)); + goto_bad; + } + } + + /* + * Set settings->block_size which will be copied to segment settings below. + * integrity block size chosen based on device logical block size and + * file system block size. + */ + if (!_set_integrity_block_size(cmd, lv, settings, lbs_4k, lbs_512)) + goto_bad; + + /* + * For each rimage, move its segments to a new rimage_iorig and give + * the rimage a new integrity segment. + */ + for (s = 0; s < area_count; s++) { + lv_image = seg_lv(seg_top, s); + + /* Not adding integrity to this image. */ + if (!imeta_lvs[s]) + continue; + + if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY))) + goto_bad; + + log_debug("Adding integrity to raid image %s", lv_image->name); + + /* + * "lv_iorig" is a new LV with new id, but with the segments + * from "lv_image". "lv_image" keeps the existing name and id, + * but gets a new integrity segment, in place of the segments + * that were moved to lv_iorig. + */ + if (!(lv_iorig = insert_layer_for_lv(cmd, lv_image, INTEGRITY, "_iorig"))) + goto_bad; + + lv_image->status |= INTEGRITY; + + /* + * Set up the new first segment of lv_image as integrity. + */ + seg_image = first_seg(lv_image); + seg_image->segtype = segtype; + + lv_imeta = imeta_lvs[s]; + lv_imeta->status |= INTEGRITY_METADATA; + lv_set_hidden(lv_imeta); + seg_image->integrity_data_sectors = lv_image->size; + seg_image->integrity_meta_dev = lv_imeta; + seg_image->integrity_recalculate = 1; + + memcpy(&seg_image->integrity_settings, settings, sizeof(struct integrity_settings)); + set = &seg_image->integrity_settings; + + if (!set->mode[0]) + set->mode[0] = DEFAULT_MODE; + + if (!set->tag_size) + set->tag_size = DEFAULT_TAG_SIZE; + + if (!set->block_size) + set->block_size = DEFAULT_BLOCK_SIZE; + + if (!set->internal_hash) + set->internal_hash = DEFAULT_INTERNAL_HASH; + } + + if (is_active) { + log_debug("Writing VG and updating LV with new integrity LV %s", lv->name); + + /* vg_write(), suspend_lv(), vg_commit(), resume_lv() */ + if (!lv_update_and_reload(lv)) { + log_error("LV update and reload failed"); + goto_bad; + } + revert_meta_lvs = 0; + + } else { + log_debug("Writing VG with new integrity LV %s", lv->name); + + if (!vg_write(vg) || !vg_commit(vg)) + goto_bad; + + revert_meta_lvs = 0; + + /* + * This first activation includes "recalculate" which starts the + * kernel's recalculating (initialization) process. + */ + + log_debug("Activating to start integrity initialization for LV %s", lv->name); + + if (!activate_lv(cmd, lv)) { + log_error("Failed to activate integrity LV to initialize."); + goto_bad; + } + } + + /* + * Now that the device is being initialized, update the VG to clear + * integrity_recalculate so that subsequent activations will not + * include "recalculate" and restart initialization. + */ + + log_debug("Writing VG with initialized integrity LV %s", lv->name); + + for (s = 0; s < area_count; s++) { + lv_image = seg_lv(seg_top, s); + seg_image = first_seg(lv_image); + seg_image->integrity_recalculate = 0; + } + + if (!vg_write(vg) || !vg_commit(vg)) + goto_bad; + + return 1; + +bad: + log_error("Failed to add integrity."); + + for (s = 0; s < revert_meta_lvs; s++) { + if (!lv_remove(imeta_lvs[s])) + log_error("New integrity metadata LV may require manual removal."); + } + + if (!vg_write(vg) || !vg_commit(vg)) + log_error("New integrity metadata LV may require manual removal."); + + return 0; +} + +/* + * This should rarely if ever be used. A command that adds integrity + * to an LV will activate and then clear the flag. If it fails before + * clearing the flag, then this function will be used by a subsequent + * activation to clear the flag. + */ +void lv_clear_integrity_recalculate_metadata(struct logical_volume *lv) +{ + struct volume_group *vg = lv->vg; + struct logical_volume *lv_image; + struct lv_segment *seg, *seg_image; + uint32_t s; + + seg = first_seg(lv); + + if (seg_is_raid(seg)) { + for (s = 0; s < seg->area_count; s++) { + lv_image = seg_lv(seg, s); + seg_image = first_seg(lv_image); + seg_image->integrity_recalculate = 0; + } + } else if (seg_is_integrity(seg)) { + seg->integrity_recalculate = 0; + } else { + log_error("Invalid LV type for clearing integrity"); + return; + } + + if (!vg_write(vg) || !vg_commit(vg)) { + log_warn("WARNING: failed to clear integrity recalculate flag for %s", + display_lvname(lv)); + } +} + +int lv_has_integrity_recalculate_metadata(struct logical_volume *lv) +{ + struct logical_volume *lv_image; + struct lv_segment *seg, *seg_image; + uint32_t s; + int ret = 0; + + seg = first_seg(lv); + + if (seg_is_raid(seg)) { + 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)) + continue; + if (seg_image->integrity_recalculate) + ret = 1; + } + } else if (seg_is_integrity(seg)) { + ret = seg->integrity_recalculate; + } + + return ret; +} + +int lv_raid_has_integrity(struct logical_volume *lv) +{ + struct logical_volume *lv_image; + struct lv_segment *seg, *seg_image; + uint32_t s; + + seg = first_seg(lv); + + if (seg_is_raid(seg)) { + 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)) + return 1; + } + } + + return 0; +} + +int lv_get_raid_integrity_settings(struct logical_volume *lv, struct integrity_settings **isettings) +{ + struct logical_volume *lv_image; + struct lv_segment *seg, *seg_image; + uint32_t s; + + seg = first_seg(lv); + + if (seg_is_raid(seg)) { + 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)) { + *isettings = &seg_image->integrity_settings; + return 1; + } + } + } + + return 0; +} + |