1
0
mirror of git://sourceware.org/git/lvm2.git synced 2026-01-25 00:32:58 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
a0bbc94900 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:

- for internal, zero start of origin LV

- 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 13:51:06 -06:00
13 changed files with 98 additions and 646 deletions

View File

@@ -105,7 +105,6 @@ static const struct flag _lv_flags[] = {
{LV_VDO_POOL_DATA, NULL, 0},
{WRITECACHE, NULL, 0},
{INTEGRITY, NULL, 0},
{INTEGRITY_METADATA, NULL, 0},
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
{LV_REMOVED, NULL, 0},
{LV_UNCOMMITTED, NULL, 0},

View File

@@ -156,9 +156,6 @@ static int _integrity_text_import(struct lv_segment *seg,
seg->integrity_meta_dev = meta_lv;
seg->lv->status |= INTEGRITY;
if (meta_lv)
meta_lv->status |= INTEGRITY_METADATA;
if (meta_lv && !add_seg_to_segs_using_this_lv(meta_lv, seg))
return_0;

View File

@@ -252,6 +252,8 @@ struct label *label_create(struct labeller *labeller)
/* global variable for accessing the bcache populated by label scan */
struct bcache *scan_bcache;
#define BCACHE_BLOCK_SIZE_IN_SECTORS 256 /* 256*512 = 128K */
static bool _in_bcache(struct device *dev)
{
if (!dev)

View File

@@ -118,14 +118,6 @@ int label_scan_open(struct device *dev);
int label_scan_open_excl(struct device *dev);
int label_scan_open_rw(struct device *dev);
/*
* These are the sizes the label.c uses to set up
* and use bcache (they are not bcache restrictions
* or defs.)
*/
#define BCACHE_BLOCK_SIZE_IN_SECTORS 256 /* 256*512 = 128K */
#define BCACHE_BLOCK_SIZE_IN_BYTES 131072
/*
* Wrappers around bcache equivalents.
* (these make it easier to disable bcache and revert to direct rw if needed)

View File

@@ -29,28 +29,6 @@
#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. Save it in
@@ -61,7 +39,7 @@ int lv_create_integrity_metadata(struct cmd_context *cmd,
struct lvcreate_params *lp)
{
char metaname[NAME_LEN];
uint64_t lv_size_bytes, meta_bytes, meta_sectors;
uint32_t extent_bytes;
struct logical_volume *lv;
struct lvcreate_params lp_meta = {
.activate = CHANGE_AN,
@@ -75,7 +53,6 @@ int lv_create_integrity_metadata(struct cmd_context *cmd,
.vg_name = vg->name,
.zero = 0,
.wipe_signatures = 0,
.suppress_zero_warn = 1,
};
if (dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) {
@@ -86,15 +63,12 @@ int lv_create_integrity_metadata(struct cmd_context *cmd,
if (!(lp_meta.lv_name = strdup(metaname)))
return_0;
lp_meta.pvh = lp->pvh;
/* TODO: set pvh per command line */
/* TODO: scale size according to LV size. */
extent_bytes = vg->extent_size * SECTOR_SIZE;
lp_meta.extents = (4 * ONE_MB_IN_BYTES) / extent_bytes;
lv_size_bytes = lp->extents * 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("Creating integrity metadata LV %s with size %s.",
metaname, display_size(cmd, meta_sectors));
log_debug("Creating integrity metadata LV with %u extents", lp_meta.extents);
dm_list_init(&lp_meta.tags);
@@ -113,7 +87,6 @@ int lv_create_integrity_metadata(struct cmd_context *cmd,
static int _get_provided_data_sectors(struct logical_volume *lv, uint64_t *provided_data_sectors)
{
struct lv_with_info_and_seg_status status;
uint64_t data_sectors, extra_sectors;
memset(&status, 0, sizeof(status));
status.seg_status.type = SEG_STATUS_NONE;
@@ -142,15 +115,7 @@ static int _get_provided_data_sectors(struct logical_volume *lv, uint64_t *provi
goto fail;
}
data_sectors = status.seg_status.integrity->provided_data_sectors;
if ((extra_sectors = (data_sectors % lv->vg->extent_size))) {
data_sectors -= extra_sectors;
log_debug("Reduce provided_data_sectors by %llu to %llu for extent alignment",
(unsigned long long)extra_sectors, (unsigned long long)data_sectors);
}
*provided_data_sectors = data_sectors;
*provided_data_sectors = status.seg_status.integrity->provided_data_sectors;
dm_pool_destroy(status.seg_status.mem);
return 1;
@@ -160,243 +125,18 @@ fail:
return 0;
}
int lv_remove_integrity(struct logical_volume *lv)
{
struct lv_segment *seg = first_seg(lv);
struct logical_volume *origin;
struct logical_volume *meta_lv;
if (!seg_is_integrity(seg)) {
log_error("LV %s segment is not integrity.", display_lvname(lv));
return 0;
}
if (!(meta_lv = seg->integrity_meta_dev)) {
log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
return 0;
}
if (!(origin = seg_lv(seg, 0))) {
log_error("LV %s integrity segment has no origin", display_lvname(lv));
return 0;
}
if (!remove_seg_from_segs_using_this_lv(seg->integrity_meta_dev, seg))
return_0;
lv_set_visible(seg->integrity_meta_dev);
lv->status &= ~INTEGRITY;
meta_lv->status &= ~INTEGRITY_METADATA;
seg->integrity_meta_dev = NULL;
if (!remove_layer_from_lv(lv, origin))
return_0;
if (!lv_remove(origin))
return_0;
if (!lv_remove(meta_lv))
log_warn("WARNING: failed to remove integrity metadata LV.");
return 1;
}
/*
* Add integrity to each raid image.
*
* for each rimage_N:
* . create and allocate a new linear LV rimage_N_imeta
* . create a new empty linear LV rimage_N_iorig
* . move the segments from rimage_N to 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
*
*/
static int _lv_add_integrity_to_raid(struct logical_volume *lv, const char *arg,
struct integrity_settings *settings,
struct dm_list *pvh)
{
struct lvcreate_params lp;
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;
const struct segment_type *segtype;
struct integrity_settings *set;
uint64_t lv_size_sectors;
uint32_t area_count, s;
int ret = 1;
memset(imeta_lvs, 0, sizeof(imeta_lvs));
if (dm_list_size(&lv->segments) != 1)
return_0;
seg_top = first_seg(lv);
area_count = seg_top->area_count;
/*
* 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;
if (s >= DEFAULT_RAID_MAX_IMAGES)
return_0;
lv_image = seg_lv(seg_top, s);
if (!seg_is_striped(first_seg(lv_image))) {
log_error("raid1 image must be linear to add integrity");
return_0;
}
/*
* allocate a new linear LV NAME_rimage_N_imeta
* lv_create_integrity_metadata() returns its result in lp
*/
memset(&lp, 0, sizeof(lp));
lp.lv_name = lv_image->name;
lp.pvh = pvh;
lp.extents = lv_image->size / vg->extent_size;
if (!lv_create_integrity_metadata(cmd, vg, &lp)) {
return_0;
}
meta_lv = lp.integrity_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));
return 0;
}
memset(&wipe, 0, sizeof(wipe));
wipe.do_zero = 1;
wipe.zero_sectors = 8;
if (!wipe_lv(meta_lv, wipe)) {
log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv));
return 0;
}
if (!deactivate_lv(cmd, meta_lv)) {
log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
return 0;
}
/* Used below to set up the new integrity segment. */
imeta_lvs[s] = meta_lv;
}
/*
* 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);
lv_size_sectors = lv_image->size;
lv_imeta = imeta_lvs[s]; /* integrity metadata lv created above */
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
return_0;
log_print("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")))
return_0;
lv_image->status |= INTEGRITY;
lv_imeta->status |= INTEGRITY_METADATA;
lv_set_hidden(lv_imeta);
/*
* Set up the new first segment of lv_image as integrity.
*/
seg_image = first_seg(lv_image);
seg_image->segtype = segtype;
seg_image->integrity_data_sectors = lv_size_sectors;
seg_image->integrity_meta_dev = lv_imeta;
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->internal_hash)
set->internal_hash = DEFAULT_INTERNAL_HASH;
}
log_debug("Write VG with integrity added to LV");
if (!vg_write(vg) || !vg_commit(vg))
ret = 0;
return ret;
}
int lv_add_integrity(struct logical_volume *lv, const char *arg,
struct logical_volume *meta_lv_created,
const char *meta_name,
struct integrity_settings *settings,
struct dm_list *pvh)
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;
uint64_t meta_bytes, meta_sectors;
uint64_t lv_size_sectors;
int ret = 1;
if (lv_is_raid(lv))
return _lv_add_integrity_to_raid(lv, arg, settings, pvh);
lv_size_sectors = lv->size;
int ret;
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
return_0;
@@ -447,19 +187,10 @@ 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(vg, meta_name))) {
if (!(meta_lv = find_lv(lv->vg, meta_name))) {
log_error("LV %s not found.", meta_name);
return_0;
}
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv->size * 512);
meta_sectors = meta_bytes / 512;
if (meta_lv->size < meta_sectors) {
log_error("Integrity metadata needs %s, metadata LV is only %s.",
display_size(cmd, meta_sectors), display_size(cmd, meta_lv->size));
return 0;
}
}
/*
@@ -477,41 +208,20 @@ 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;
}
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 = 8;
if (!wipe_lv(meta_lv, wipe)) {
log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv));
if (!activate_and_wipe_lv(meta_lv, 0)) {
log_error("LV %s could not be zeroed.", display_lvname(meta_lv));
return 0;
}
if (!deactivate_lv(cmd, meta_lv)) {
log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
return 0;
}
meta_lv->status |= INTEGRITY_METADATA;
seg->integrity_data_sectors = lv_size_sectors;
seg->integrity_data_sectors = seg->len;
seg->integrity_meta_dev = meta_lv;
lv_set_hidden(meta_lv);
/* TODO: give meta_lv a suffix? e.g. _imeta */
ret = 1;
} else {
/* dm-integrity wants temp/fake size of 1 to report usable size */
seg->integrity_data_sectors = 1;
@@ -536,11 +246,6 @@ int lv_add_integrity(struct logical_volume *lv, const char *arg,
ret = 1;
}
if (!seg->integrity_data_sectors) {
log_error("LV size too small to include metadata.");
ret = 0;
}
lv->status |= LV_UNCOMMITTED;
if (!deactivate_lv(cmd, lv)) {
@@ -552,11 +257,6 @@ 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

@@ -1202,13 +1202,10 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
else if (lv_is_pool_metadata(lv) ||
lv_is_pool_metadata_spare(lv) ||
lv_is_raid_metadata(lv) ||
lv_is_integrity_metadata(lv))
lv_is_raid_metadata(lv))
repstr[0] = 'e';
else if (lv_is_cache_type(lv) || lv_is_writecache(lv))
repstr[0] = 'C';
else if (lv_is_integrity(lv))
repstr[0] = 'g';
else if (lv_is_raid(lv))
repstr[0] = (lv_is_not_synced(lv)) ? 'R' : 'r';
else if (lv_is_mirror(lv))

View File

@@ -28,7 +28,6 @@
#include "lib/datastruct/str_list.h"
#include "lib/config/defaults.h"
#include "lib/misc/lvm-exec.h"
#include "lib/misc/lvm-signal.h"
#include "lib/mm/memlock.h"
#include "lib/locking/lvmlockd.h"
#include "lib/label/label.h"
@@ -56,8 +55,6 @@ typedef enum {
#define A_POSITIONAL_FILL 0x40 /* Slots are positional and filled using PREFERRED */
#define A_PARTITION_BY_TAGS 0x80 /* No allocated area may share any tag with any other */
#define ONE_MB_IN_BYTES 1048576
/*
* Constant parameters during a single allocation attempt.
*/
@@ -137,9 +134,7 @@ enum {
LV_TYPE_SANLOCK,
LV_TYPE_CACHEVOL,
LV_TYPE_WRITECACHE,
LV_TYPE_WRITECACHEORIGIN,
LV_TYPE_INTEGRITY,
LV_TYPE_INTEGRITYORIGIN
LV_TYPE_WRITECACHEORIGIN
};
static const char *_lv_type_names[] = {
@@ -195,8 +190,6 @@ static const char *_lv_type_names[] = {
[LV_TYPE_CACHEVOL] = "cachevol",
[LV_TYPE_WRITECACHE] = "writecache",
[LV_TYPE_WRITECACHEORIGIN] = "writecacheorigin",
[LV_TYPE_INTEGRITY] = "integrity",
[LV_TYPE_INTEGRITYORIGIN] = "integrityorigin",
};
static int _lv_layout_and_role_mirror(struct dm_pool *mem,
@@ -468,43 +461,6 @@ bad:
return 0;
}
static int _lv_layout_and_role_integrity(struct dm_pool *mem,
const struct logical_volume *lv,
struct dm_list *layout,
struct dm_list *role,
int *public_lv)
{
int top_level = 0;
/* non-top-level LVs */
if (lv_is_integrity_metadata(lv)) {
if (!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITY]) ||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_METADATA]))
goto_bad;
} else if (lv_is_integrity_origin(lv)) {
if (!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITY]) ||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_ORIGIN]) ||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITYORIGIN]))
goto_bad;
} else
top_level = 1;
if (!top_level) {
*public_lv = 0;
return 1;
}
/* top-level LVs */
if (lv_is_integrity(lv)) {
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_INTEGRITY]))
goto_bad;
}
return 1;
bad:
return 0;
}
static int _lv_layout_and_role_thick_origin_snapshot(struct dm_pool *mem,
const struct logical_volume *lv,
struct dm_list *layout,
@@ -621,11 +577,6 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
!_lv_layout_and_role_cache(mem, lv, *layout, *role, &public_lv))
goto_bad;
/* Integrity related */
if ((lv_is_integrity(lv) || lv_is_integrity_origin(lv) || lv_is_integrity_metadata(lv)) &&
!_lv_layout_and_role_integrity(mem, lv, *layout, *role, &public_lv))
goto_bad;
/* VDO and related */
if (lv_is_vdo_type(lv) &&
!_lv_layout_and_role_vdo(mem, lv, *layout, *role, &public_lv))
@@ -7473,88 +7424,11 @@ int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
return 1;
}
int zero_lv_name(struct cmd_context *cmd, const char *vg_name, const char *lv_name, uint64_t lv_size_bytes)
{
char name[PATH_MAX];
struct device *dev;
uint64_t off = 0, i = 0, j = 0;
uint64_t zero_bytes;
uint32_t extra_bytes;
if (dm_snprintf(name, sizeof(name), "%s%s/%s", cmd->dev_dir, vg_name, lv_name) < 0) {
log_error("Device path name too long, device not zeroed (%s).", lv_name);
return 0;
}
if (!(dev = dev_cache_get(cmd, name, NULL))) {
log_error("Failed to find device %s: device not zeroed.", name);
return 0;
}
if (!label_scan_open_rw(dev)) {
log_error("Failed to open %s: device not zeroed.", name);
return 0;
}
zero_bytes = lv_size_bytes;
log_print("Zeroing %s %s... (cancel command to zero manually)",
name, display_size(cmd, zero_bytes/512));
if ((extra_bytes = (zero_bytes % ONE_MB_IN_BYTES)))
zero_bytes -= extra_bytes;
/*
* Write 1MiB at a time to avoid going over bcache size.
* Then write 128KiB (bcache block sizes) at a time to
* cover remaining dev size.
*/
sigint_allow();
for (i = 0; i < (zero_bytes / ONE_MB_IN_BYTES); i++) {
off = i * ONE_MB_IN_BYTES;
if (!dev_write_zeros(dev, off, (size_t)ONE_MB_IN_BYTES))
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
if (off && !(off % (1024 * ONE_MB_IN_BYTES)))
log_print("Zeroed %s...", display_size(cmd, off/512));
if (sigint_caught()) {
log_print("Zeroing canceled.");
goto out;
}
}
if (extra_bytes) {
log_debug("Zeroing final %u bytes at %llu.", extra_bytes, (unsigned long long)off);
for (j = 0; j < (extra_bytes / BCACHE_BLOCK_SIZE_IN_BYTES); j++) {
off = i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES;
if (!dev_write_zeros(dev, off, (size_t)BCACHE_BLOCK_SIZE_IN_BYTES))
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
if (sigint_caught()) {
log_print("Zeroing canceled.");
goto out;
}
}
}
/*
* FIXME: bcache can't write partial blocks yet.
* This shouldn't actually happen given current
* usage where LV size is a multiple of extents.
*/
if ((extra_bytes = lv_size_bytes - (i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES)))
log_warn("WARNING: last %llu bytes not zeroed.", (unsigned long long)extra_bytes);
out:
sigint_restore();
label_scan_invalidate(dev);
return 1;
}
/* FIXME: copied from label.c */
#define BCACHE_BLOCK_SIZE_IN_SECTORS 256 /* 256*512 = 128K */
#define BCACHE_BLOCK_SIZE_IN_BYTES 131072
#define ONE_MB_IN_BYTES 1048576
#define ONE_MB_IN_SECTORS 2048 /* 2048 * 512 = 1048576 */
/*
* Initialize the LV with 'value'.
@@ -7614,7 +7488,44 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
stack;
}
if (wp.do_zero) {
if (wp.do_zero && !wp.zero_value && (wp.zero_sectors >= ONE_MB_IN_SECTORS)) {
uint64_t off = 0, i = 0, j = 0;
uint64_t zero_bytes;
uint32_t extra_bytes;
zero_bytes = wp.zero_sectors * 512;
if ((extra_bytes = (zero_bytes % ONE_MB_IN_BYTES)))
zero_bytes -= extra_bytes;
log_print("Zeroing %llu MiB...", (unsigned long long)(zero_bytes / ONE_MB_IN_BYTES));
/*
* Write 1MiB at a time to avoid going over bcache size.
* Then write 128KiB at a time to cover remaining dev size.
*/
for (i = 0; i < (zero_bytes / ONE_MB_IN_BYTES); i++) {
off = i * ONE_MB_IN_BYTES;
if (!dev_write_zeros(dev, off, (size_t)ONE_MB_IN_BYTES))
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
}
if (extra_bytes) {
log_warn("Zeroing %u bytes at %llu...", extra_bytes, (unsigned long long)off);
for (j = 0; j < (extra_bytes / BCACHE_BLOCK_SIZE_IN_BYTES); j++) {
off = i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES;
if (!dev_write_zeros(dev, off, (size_t)BCACHE_BLOCK_SIZE_IN_BYTES))
log_error("Failed to zero LV at offset %llu.", (unsigned long long)off);
}
}
/* FIXME: bcache can't write partial block yet */
if ((extra_bytes = (wp.zero_sectors * 512) - (i * ONE_MB_IN_BYTES + j * BCACHE_BLOCK_SIZE_IN_BYTES)))
log_warn("WARNING: last %llu bytes not zeroed.", (unsigned long long)extra_bytes);
} else if (wp.do_zero) {
zero_sectors = wp.zero_sectors ? : UINT64_C(4096) >> SECTOR_SHIFT;
if (zero_sectors > lv->size)
@@ -7825,14 +7736,10 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
first_seg(first_seg(lv)->pool_lv)->zero_new_blocks))
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) || (seg_is_raid1(lp) && lp->integrity_arg))
return 1;
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;
}
/* Cannot zero read-only volume */
if ((lv->status & LVM_WRITE) &&
@@ -8091,6 +7998,13 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return_0;
} else if (seg_is_integrity(lp)) {
/*
* TODO: if using internal metadata, estimate the amount of metadata
* that will be needed, and add this to the amount of PV space being
* allocated so that the usable LV size is what the user requested.
* Or, just request an extra extent_size bytes, then round the
* provided_data_sectors down to be an extent_size multiple.
*/
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
@@ -8318,6 +8232,12 @@ 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);
/*
@@ -8437,25 +8357,27 @@ 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) || (seg_is_raid1(lp) && lp->integrity_arg)) {
/*
* 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 (_should_wipe_lv(lp, lv, !lp->suppress_zero_warn)) {
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 (!wipe_lv(lv, (struct wipe_params)
{
.do_zero = lp->zero,
@@ -8469,53 +8391,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
if (seg_is_integrity(lp) || (seg_is_raid1(lp) && lp->integrity_arg)) {
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, lp->pvh))
goto revert_new_lv;
backup(vg);
/*
* The standard option combination should be -Zy -ay, in which
* case we activate here, and zero at the end of the command.
* The invalid combination -Zy -an has been prevented earlier.
* The combination -Zn -an involves no zeroing or activation.
* For combination -Zn -ay we activate here.
*/
if (lp->zero) {
/* Activate for zeroing at the end of lvcreate. */
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate LV %s.", display_lvname(lv));
goto out;
}
} else if (!lp->zero && is_change_activating(lp->activate)) {
if (!activate_lv(cmd, lv)) {
log_error("Failed to activate LV %s.", display_lvname(lv));
goto out;
}
}
/*
* The entire LV is zeroed, which can take a long time,
* so defer this to the end of the command when no locks
* are held, and the command can be canceled without
* problems (if the user doesn't want to wait, or wants
* to do the zeroing themselves.)
*/
lp->integrity_bytes_to_zero = first_seg(lv)->integrity_data_sectors * 512;
goto out;
}
if (seg_is_vdo_pool(lp)) {
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents)) {
stack;

View File

@@ -91,7 +91,6 @@
//#define POSTORDER_FLAG UINT64_C(0x0000000002000000) /* Not real flags, reserved for
//#define POSTORDER_OPEN_FLAG UINT64_C(0x0000000004000000) temporary use inside vg_read_internal. */
#define INTEGRITY_METADATA UINT64_C(0x0000000004000000) /* LV - Internal use only */
#define LV_UNCOMMITTED UINT64_C(0x0000000002000000)
#define VIRTUAL_ORIGIN UINT64_C(0x0000000008000000) /* LV - internal use only */
@@ -264,8 +263,7 @@
#define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
#define lv_is_lockd_sanlock_lv(lv) (((lv)->status & LOCKD_SANLOCK_LV) ? 1 : 0)
#define lv_is_writecache(lv) (((lv)->status & WRITECACHE) ? 1 : 0)
#define lv_is_integrity(lv) (((lv)->status & INTEGRITY) ? 1 : 0)
#define lv_is_integrity_metadata(lv) (((lv)->status & INTEGRITY_METADATA) ? 1 : 0)
#define lv_is_integrity(lv) (((lv)->status & INTEGRITY) ? 1 : 0)
#define lv_is_vdo(lv) (((lv)->status & LV_VDO) ? 1 : 0)
#define lv_is_vdo_pool(lv) (((lv)->status & LV_VDO_POOL) ? 1 : 0)
@@ -277,11 +275,9 @@
/* Recognize component LV (matching lib/misc/lvm-string.c _lvname_has_reserved_component_string()) */
#define lv_is_component(lv) (lv_is_cache_origin(lv) || \
lv_is_writecache_origin(lv) || \
lv_is_integrity_origin(lv) || \
((lv)->status & (\
CACHE_POOL_DATA |\
CACHE_POOL_METADATA |\
INTEGRITY_METADATA |\
LV_CACHE_VOL |\
LV_VDO_POOL_DATA |\
MIRROR_IMAGE |\
@@ -1007,7 +1003,6 @@ struct lvcreate_params {
const char *integrity_meta_name; /* external LV is user-specified */
struct logical_volume *integrity_meta_lv; /* external LV we create */
struct integrity_settings integrity_settings;
uint64_t integrity_bytes_to_zero; /* zeros the final LV after it's created */
struct dm_list tags; /* all */
@@ -1103,8 +1098,6 @@ int lv_is_cache_origin(const struct logical_volume *lv);
int lv_is_writecache_origin(const struct logical_volume *lv);
int lv_is_writecache_cachevol(const struct logical_volume *lv);
int lv_is_integrity_origin(const struct logical_volume *lv);
int lv_is_merging_cow(const struct logical_volume *cow);
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
@@ -1406,13 +1399,10 @@ void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
int lv_add_integrity(struct logical_volume *lv, const char *arg,
struct logical_volume *meta_lv_created,
const char *meta_name, struct integrity_settings *settings,
struct dm_list *pvh);
const char *meta_name, struct integrity_settings *settings);
int lv_create_integrity_metadata(struct cmd_context *cmd,
struct volume_group *vg,
struct lvcreate_params *lp);
int lv_remove_integrity(struct logical_volume *lv);
int zero_lv_name(struct cmd_context *cmd, const char *vg_name, const char *lv_name, uint64_t zero_bytes);
#endif

View File

@@ -757,14 +757,6 @@ FLAGS: SECONDARY_SYNTAX
---
lvconvert --integrity String LV
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_integrity
DESC: Remove integrity from an LV.
---
# --extents is not specified; it's an automatic alternative for --size
OO_LVCREATE: --addtag Tag, --alloc Alloc, --autobackup Bool, --activate Active,
@@ -878,8 +870,7 @@ DESC: Create a raid1 or mirror LV (infers --type raid1|mirror).
# R9,R10,R11,R12 (--type raid with any use of --stripes/--mirrors)
lvcreate --type raid --size SizeMB VG
OO: --mirrors PNumber, --stripes Number, --stripesize SizeKB,
--regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
--integrity String, --integritysettings String, OO_LVCREATE
--regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_raid_any
DESC: Create a raid LV (a specific raid level must be used, e.g. raid1).

View File

@@ -5730,75 +5730,6 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
return ret;
}
static int _lvconvert_integrity_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
struct volume_group *vg = lv->vg;
struct lv_segment *seg;
const char *arg = arg_str_value(cmd, integrity_ARG, NULL);
if (strcmp(arg, "none") && strcmp(arg, "n")) {
log_error("Integrity can only be removed from an existing LV (see --integrity none).");
return ECMD_FAILED;
}
if (!lv_is_integrity(lv)) {
log_error("LV does not have integrity.");
return ECMD_FAILED;
}
seg = first_seg(lv);
if (!seg->integrity_meta_dev) {
log_error("Internal integrity cannot be removed.");
return ECMD_FAILED;
}
/* TODO: lift this restriction */
if (lv_info(cmd, lv, 1, NULL, 0, 0)) {
log_error("LV must be inactive to remove integrity.");
return ECMD_FAILED;
}
if (!archive(vg))
return ECMD_FAILED;
if (!lv_remove_integrity(lv))
return ECMD_FAILED;
if (!vg_write(vg) || !vg_commit(vg))
return ECMD_FAILED;
backup(vg);
log_print_unless_silent("Logical volume %s has removed integrity.", display_lvname(lv));
return ECMD_PROCESSED;
}
int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv)
{
struct processing_handle *handle;
struct lvconvert_result lr = { 0 };
int ret;
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
return ECMD_FAILED;
}
handle->custom_handle = &lr;
cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
&_lvconvert_integrity_single);
destroy_processing_handle(cmd, handle);
return ret;
}
/*
* All lvconvert command defs have their own function,
* so the generic function name is unused.

View File

@@ -848,8 +848,6 @@ static int _lvcreate_params(struct cmd_context *cmd,
poolmetadataspare_ARG
#define RAID_ARGS \
integrity_ARG,\
integritysettings_ARG,\
maxrecoveryrate_ARG,\
minrecoveryrate_ARG,\
raidmaxrecoveryrate_ARG,\
@@ -1222,7 +1220,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
}
}
if (seg_is_integrity(lp) || seg_is_raid(lp)) {
if (seg_is_integrity(lp)) {
if (!get_integrity_options(cmd, &lp->integrity_arg, &lp->integrity_meta_name, &lp->integrity_settings))
return 0;
}
@@ -1584,13 +1582,6 @@ static int _check_zero_parameters(struct cmd_context *cmd, struct lvcreate_param
if (seg_is_thin(lp))
return 1;
if (seg_is_integrity(lp)) {
if (lp->zero && !is_change_activating(lp->activate)) {
log_error("Zeroing integrity is not compatible with inactive creation (-an).");
return 0;
}
}
/* If there is some problem, buffer will not be empty */
if (dm_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
lp->origin_name ? "origin " : "",
@@ -1809,13 +1800,5 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
_destroy_lvcreate_params(&lp);
destroy_processing_handle(cmd, handle);
if (lp.integrity_bytes_to_zero) {
if (!lp.zero)
log_warn("WARNING: not zeroing integrity LV, read errors are possible.");
else
zero_lv_name(cmd, lp.vg_name, lp.lv_name, lp.integrity_bytes_to_zero);
}
return ret;
}

View File

@@ -149,9 +149,6 @@ static const struct command_function _command_functions[CMD_COUNT] = {
{ lvconvert_to_vdopool_CMD, lvconvert_to_vdopool_cmd },
{ lvconvert_to_vdopool_param_CMD, lvconvert_to_vdopool_param_cmd },
/* lvconvert for integrity */
{ lvconvert_integrity_CMD, lvconvert_integrity_cmd },
{ pvscan_display_CMD, pvscan_display_cmd },
{ pvscan_cache_CMD, pvscan_cache_cmd },
};

View File

@@ -275,8 +275,6 @@ int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_to_vdopool_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_to_vdopool_param_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv);
int pvscan_display_cmd(struct cmd_context *cmd, int argc, char **argv);
int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv);