1
0
mirror of git://sourceware.org/git/lvm2.git synced 2026-02-04 12:32:46 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
262ffa5251 Add dm-integrity support
Create a linear LV with integrity added to it:

lvcreate --type integrity -n Name -L Size VG

or

lvcreate --integrity y -n Name -L Size VG

When creating, --zero y will zero the entire LV.
This is suggested to initialize integrity checksums
and avoid causing read errors in unwritten portions
of the new LV.

Options:

  --integrity internal
  integrity checksum metadata is interleaved with data.

  --integrity external
  integrity checksum metadata on separate LV, allows
  adding integrity to existing LV, or removing integrity.

  --integritymetadata LV
  use the specified LV for external metadata.

  --integritysettings String
  set dm-integrity parameters.

TODO:

- increase allocated LV size by an extra extent, and then
  round provided_data_sectors down to be a multiple of extent size

- add command to remove intregrity from an LV (only for external),
  i.e. lvconvert --integrity none LV

- let integrity be used by raid images
2019-12-02 15:39:36 -06:00
2 changed files with 107 additions and 30 deletions

View File

@@ -131,13 +131,18 @@ int lv_add_integrity(struct logical_volume *lv, const char *arg,
struct integrity_settings *settings)
{
struct cmd_context *cmd = lv->vg->cmd;
struct volume_group *vg = lv->vg;
struct integrity_settings *set;
struct logical_volume *lv_orig;
struct logical_volume *meta_lv = NULL;
const struct segment_type *segtype;
struct lv_segment *seg;
uint32_t orig_seg_len; /* extents */
int ret;
seg = first_seg(lv);
orig_seg_len = seg->len;
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
return_0;
@@ -187,7 +192,7 @@ int lv_add_integrity(struct logical_volume *lv, const char *arg,
if (meta_lv_created)
meta_lv = meta_lv_created;
else if (meta_name) {
if (!(meta_lv = find_lv(lv->vg, meta_name))) {
if (!(meta_lv = find_lv(vg, meta_name))) {
log_error("LV %s not found.", meta_name);
return_0;
}
@@ -208,16 +213,38 @@ int lv_add_integrity(struct logical_volume *lv, const char *arg,
*/
if (meta_lv) {
struct wipe_params wipe;
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local devices.");
return 0;
}
if (!activate_and_wipe_lv(meta_lv, 0)) {
log_error("LV %s could not be zeroed.", display_lvname(meta_lv));
log_verbose("Zeroing LV for integrity metadata");
if (!lv_is_active(meta_lv)) {
if (!activate_lv(cmd, meta_lv)) {
log_error("Failed to activate LV %s to zero", display_lvname(meta_lv));
return 0;
}
}
memset(&wipe, 0, sizeof(wipe));
wipe.do_zero = 1;
wipe.zero_sectors = 1;
if (!wipe_lv(meta_lv, wipe)) {
log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv));
return 0;
}
seg->integrity_data_sectors = seg->len;
if (!deactivate_lv(cmd, meta_lv)) {
log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
return 0;
}
/* orig_seg_len and extent_size are both in sectors */
seg->integrity_data_sectors = (orig_seg_len * vg->extent_size);
seg->integrity_meta_dev = meta_lv;
lv_set_hidden(meta_lv);
/* TODO: give meta_lv a suffix? e.g. _imeta */
@@ -257,6 +284,11 @@ int lv_add_integrity(struct logical_volume *lv, const char *arg,
lv->status &= ~LV_NOSCAN;
lv->status &= ~LV_TEMPORARY;
}
log_debug("Write VG with integrity added to LV");
if (!vg_write(vg) || !vg_commit(vg))
ret = 0;
out:
return ret;
}

View File

@@ -7736,10 +7736,14 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
first_seg(first_seg(lv)->pool_lv)->zero_new_blocks))
return 0;
if (seg_is_integrity(lp) && (!lp->zero || !(lv->status & LVM_WRITE))) {
log_warn("WARNING: --zero not enabled, integrity will not be initialized and may cause read errors.");
return 0;
}
/*
* dm-integrity requires the first sector (integrity superblock) to be
* zero when creating a new integrity device.
* TODO: print a warning or error if the user specifically
* asks for no wiping or zeroing?
*/
if (seg_is_integrity(lp))
return 1;
/* Cannot zero read-only volume */
if ((lv->status & LVM_WRITE) &&
@@ -8232,12 +8236,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
if (seg_is_integrity(lp)) {
if (!lv_add_integrity(lv, lp->integrity_arg, lp->integrity_meta_lv,
lp->integrity_meta_name, &lp->integrity_settings))
return_NULL;
}
lv_set_activation_skip(lv, lp->activation_skip & ACTIVATION_SKIP_SET,
lp->activation_skip & ACTIVATION_SKIP_SET_ENABLED);
/*
@@ -8357,27 +8355,25 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
goto revert_new_lv;
}
lv->status &= ~LV_TEMPORARY;
} else if (seg_is_integrity(lp)) {
/*
* Activate the new origin LV so it can be zeroed/wiped
* below before adding integrity.
*/
lv->status |= LV_TEMPORARY;
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate new LV for wiping.");
goto revert_new_lv;
}
lv->status &= ~LV_TEMPORARY;
} else if (!lv_active_change(cmd, lv, lp->activate)) {
log_error("Failed to activate new LV %s.", display_lvname(lv));
goto deactivate_and_revert_new_lv;
}
if (seg_is_integrity(lp)) {
struct wipe_params wipe;
memset(&wipe, 0, sizeof(wipe));
wipe.do_zero = 1;
wipe.zero_sectors = first_seg(lv)->integrity_data_sectors;
if (!_should_wipe_lv(lp, lv, 1))
goto_out;
if (!wipe_lv(lv, wipe))
log_error("Failed to zero LV.");
goto out;
} else if (_should_wipe_lv(lp, lv, !lp->suppress_zero_warn)) {
if (_should_wipe_lv(lp, lv, !lp->suppress_zero_warn)) {
if (!wipe_lv(lv, (struct wipe_params)
{
.do_zero = lp->zero,
@@ -8391,6 +8387,55 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
if (seg_is_integrity(lp)) {
struct wipe_params wipe;
log_verbose("Adding integrity to new LV");
/* Origin is active from zeroing, deactivate to add integrity. */
if (!deactivate_lv(cmd, lv)) {
log_error("Failed to deactivate LV to add integrity");
goto revert_new_lv;
}
if (!lv_add_integrity(lv, lp->integrity_arg, lp->integrity_meta_lv,
lp->integrity_meta_name, &lp->integrity_settings))
goto revert_new_lv;
backup(vg);
/*
* This zeroing is for the final integrity LV, which
* initializes the integrity metadata (checksums). It's
* different from zeroing the first sector of the integrity
* origin or integrity metadata.
*/
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate LV to zero integrity.");
goto out;
}
memset(&wipe, 0, sizeof(wipe));
wipe.do_zero = 1;
wipe.zero_sectors = first_seg(lv)->integrity_data_sectors;
log_print("Zeroing integrity checksums (%llu sectors) on LV %s",
(unsigned long long)wipe.zero_sectors, display_lvname(lv));
if (!wipe_lv(lv, wipe))
log_error("Failed to zero integrity metadata.");
/* If the final requested state is inactive, then deactivate LV. */
if (!lv_active_change(cmd, lv, lp->activate)) {
log_error("Failed to activate new LV %s.", display_lvname(lv));
goto deactivate_and_revert_new_lv;
}
goto out;
}
if (seg_is_vdo_pool(lp)) {
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents)) {
stack;