From: Jonathan Earl Brassow Date: Fri, 8 Jan 2010 22:32:35 +0000 (+0000) Subject: Add the new mirror log type "redundant". The options are now: X-Git-Tag: v2_02_91~2417 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=77dd1c0e5f9ba2dfd516c3d9df8092303f2df381;p=lvm2.git Add the new mirror log type "redundant". The options are now: --mirrorlog core: in-memory log --mirrorlog disk: persistent log --mirrorlog redundant: redundant persistent log Signed-off-by: Jonathan Brassow --- diff --git a/WHATS_NEW b/WHATS_NEW index 2ab9ba35a..243d0f015 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.57 - ==================================== + Add redundant mirror log option. Add capability to split off and keep mirror legs to lvconvert. Change background polldaemon's process name to "(lvm2)". Allow vgremove of a VG with PVs missing. diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index b49a2113b..3d39da973 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -515,7 +515,7 @@ struct alloc_handle { struct dm_list *parallel_areas; /* PVs to avoid */ - struct alloced_area log_area; /* Extent used for log */ + struct dm_list log_areas; /* Extents used for logs */ struct dm_list alloced_areas[0]; /* Lists of areas in each stripe */ }; @@ -582,6 +582,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, ah->alloc = alloc; ah->area_multiple = calc_area_multiple(segtype, area_count); + dm_list_init(&ah->log_areas); for (s = 0; s < ah->area_count; s++) dm_list_init(&ah->alloced_areas[s]); @@ -644,8 +645,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status, uint32_t stripe_size, const struct segment_type *segtype, struct alloced_area *aa, - uint32_t region_size, - struct logical_volume *log_lv __attribute((unused))) + uint32_t region_size) { uint32_t s, extents, area_multiple; struct lv_segment *seg; @@ -685,15 +685,14 @@ static int _setup_alloced_segments(struct logical_volume *lv, uint64_t status, uint32_t stripe_size, const struct segment_type *segtype, - uint32_t region_size, - struct logical_volume *log_lv) + uint32_t region_size) { struct alloced_area *aa; dm_list_iterate_items(aa, &alloced_areas[0]) { if (!_setup_alloced_segment(lv, status, area_count, stripe_size, segtype, aa, - region_size, log_lv)) + region_size)) return_0; } @@ -729,11 +728,11 @@ static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint3 */ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed, struct pv_area **areas, - uint32_t *ix, struct pv_area *log_area, + uint32_t *ix, struct pv_area **log_areas, uint32_t log_len) { uint32_t area_len, remaining; - uint32_t s; + uint32_t i,s; struct alloced_area *aa; remaining = needed - *ix; @@ -744,8 +743,8 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed, if (area_len > areas[s]->count) area_len = areas[s]->count; - if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) * - (ah->area_count + (log_area ? 1 : 0))))) { + s = sizeof(*aa) * (ah->area_count + ah->log_count); + if (!(aa = dm_pool_alloc(ah->mem, s))) { log_error("alloced_area allocation failed"); return 0; } @@ -762,11 +761,14 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed, for (s = 0; s < ah->area_count; s++) consume_pv_area(areas[s], area_len); - if (log_area) { - ah->log_area.pv = log_area->map->pv; - ah->log_area.pe = log_area->start; - ah->log_area.len = log_len; - consume_pv_area(log_area, ah->log_area.len); + for (i = 0, s = ah->area_count; + (s < ah->area_count + ah->log_count); + s++, i++) { + aa[s].pv = log_areas[i]->map->pv; + aa[s].pe = log_areas[i]->start; + aa[s].len = log_len; + dm_list_add(&ah->log_areas, &aa[s].list); + consume_pv_area(log_areas[i], log_len); } *ix += area_len * ah->area_multiple; @@ -983,6 +985,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, struct lv_segment *prev_lvseg, uint32_t *allocated, uint32_t needed) { + int i, j, skip = 0; struct pv_map *pvm; struct pv_area *pva; struct pv_list *pvl; @@ -997,8 +1000,9 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, struct dm_list *parallel_pvs; uint32_t free_pes; uint32_t log_len; - struct pv_area *log_area; + struct pv_area **log_areas; unsigned log_needs_allocating; + struct alloced_area *aa; /* Is there enough total space? */ free_pes = pv_maps_size(pvms); @@ -1061,10 +1065,16 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, continue; /* Next PV */ if (alloc != ALLOC_ANYWHERE) { - /* Don't allocate onto the log pv */ - if (ah->log_count && - pvm->pv == ah->log_area.pv) - continue; /* Next PV */ + /* Don't allocate onto the log pvs */ + dm_list_iterate_items(aa, &ah->log_areas) + if (pvm->pv == aa->pv) { + skip = 1; + break; + } + if (skip) { + skip = 0; + continue; + } /* Avoid PVs used by existing parallel areas */ if (parallel_pvs) @@ -1125,11 +1135,17 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, if ((contiguous || cling) && (preferred_count < ix_offset)) break; - log_needs_allocating = (ah->log_count && !ah->log_area.len) ? - 1 : 0; + log_needs_allocating = 0; + if (ah->log_count && dm_list_empty(&ah->log_areas)) + log_needs_allocating = 1; + /* + * Note: If we allow logs on the same devices as mirror + * images, then that shouldn't factor into the equation. + */ if (ix + ix_offset < ah->area_count + - (log_needs_allocating ? ah->log_count : 0)) + ((log_needs_allocating && (alloc != ALLOC_ANYWHERE)) ? + ah->log_count : 0)) break; /* sort the areas so we allocate from the biggest */ @@ -1148,8 +1164,12 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, if (!log_needs_allocating) { log_len = 0; - log_area = NULL; + log_areas = NULL; } else { + log_areas = dm_pool_alloc(ah->mem, + sizeof(struct pv_area) * + ah->log_count); + log_len = mirror_log_extents(ah->log_region_size, pv_pe_size((*areas)->map->pv), (max_parallel - *allocated) / ah->area_multiple); @@ -1160,18 +1180,25 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, too_small_for_log_count))->count < log_len) too_small_for_log_count++; - log_area = *(areas + ix_offset + ix - 1 - - too_small_for_log_count); + i = ah->log_count - 1; + j = ix_offset + ix - 1 - too_small_for_log_count; + for (; (i >= 0) && (j >= 0); i--) { + log_areas[i] = *(areas + j); + + /* Advance to next PV */ + for (; ((j >= 0) && + (log_areas[i]->map->pv == (*(areas + j))->map->pv)); j--); + } } if (ix + ix_offset < ah->area_count + - (log_needs_allocating ? ah->log_count + - too_small_for_log_count : 0)) + ((log_needs_allocating && (alloc != ALLOC_ANYWHERE)) ? + ah->log_count + too_small_for_log_count : 0)) /* FIXME With ALLOC_ANYWHERE, need to split areas */ break; if (!_alloc_parallel_area(ah, max_parallel, areas, allocated, - log_area, log_len)) + log_areas, log_len)) return_0; } while (!contiguous && *allocated != needed && can_split); @@ -1199,6 +1226,7 @@ static int _allocate(struct alloc_handle *ah, struct dm_list *pvms; uint32_t areas_size; alloc_policy_t alloc; + struct alloced_area *aa; if (allocated >= new_extents && !ah->log_count) { log_error("_allocate called with no work to do!"); @@ -1264,11 +1292,14 @@ static int _allocate(struct alloc_handle *ah, goto out; } - if (ah->log_count && !ah->log_area.len) { - log_error("Insufficient extents for log allocation " - "for logical volume %s.", - lv ? lv->name : ""); - goto out; + if (ah->log_count) { + dm_list_iterate_items(aa, &ah->log_areas) + if (!aa->len) { + log_error("Insufficient extents for log " + "allocation for logical volume %s.", + lv ? lv->name : ""); + goto out; + } } r = 1; @@ -1359,6 +1390,18 @@ int lv_add_segment(struct alloc_handle *ah, uint32_t region_size, struct logical_volume *log_lv) { + int i; + struct dm_list *aa_list; + + /* + * We don't actually use the 'log_lv' parameter for anything more + * than just figuring out that this allocation is for a log device + * It'd be nice to change the arguments type, but the function is + * exported. + */ + aa_list = (log_lv) ? &ah->log_areas : + &ah->alloced_areas[first_area]; + if (!segtype) { log_error("Missing segtype in lv_add_segment()."); return 0; @@ -1369,10 +1412,8 @@ int lv_add_segment(struct alloc_handle *ah, return 0; } - if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area], - num_areas, status, - stripe_size, segtype, - region_size, log_lv)) + if (!_setup_alloced_segments(lv, aa_list, num_areas, status, + stripe_size, segtype, region_size)) return_0; if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) { @@ -1545,10 +1586,21 @@ int lv_add_mirror_lvs(struct logical_volume *lv, /* * Turn an empty LV into a mirror log. + * + * Only for the addition of the first, linear log. */ int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv) { struct lv_segment *seg; + struct alloced_area *log_area; + + dm_list_iterate_items(log_area, &ah->log_areas) + break; + + if (!log_area) + return 0; + + dm_list_del(&log_area->list); if (dm_list_size(&log_lv->segments)) { log_error("Log segments can only be added to an empty LV"); @@ -1558,19 +1610,21 @@ int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv) if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem, get_segtype_from_string(log_lv->vg->cmd, "striped"), - log_lv, 0, ah->log_area.len, MIRROR_LOG, - 0, NULL, 1, ah->log_area.len, 0, 0, 0))) { + log_lv, 0, log_area->len, MIRROR_LOG, + 0, NULL, 1, log_area->len, 0, 0, 0))) { log_error("Couldn't allocate new mirror log segment."); return 0; } - if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe)) + if (!set_lv_segment_area_pv(seg, 0, log_area->pv, log_area->pe)) return_0; dm_list_add(&log_lv->segments, &seg->list); - log_lv->le_count += ah->log_area.len; + log_lv->le_count += log_area->len; log_lv->size += (uint64_t) log_lv->le_count * log_lv->vg->extent_size; + dm_pool_free(ah->mem, log_area); + if (log_lv->vg->fid->fmt->ops->lv_setup && !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv)) return_0; @@ -3055,7 +3109,7 @@ int lv_create_single(struct volume_group *vg, vg->extent_size, lv->le_count, lp->region_size), - lp->corelog ? 0U : 1U, lp->pvh, lp->alloc, + lp->log_count, lp->pvh, lp->alloc, MIRROR_BY_LV | (lp->nosync ? MIRROR_SKIP_INIT_SYNC : 0))) { stack; diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index e4bab7f3e..911fb8e6e 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -527,7 +527,7 @@ struct lvcreate_params { int zero; /* all */ int major; /* all */ int minor; /* all */ - int corelog; /* mirror */ + int log_count; /* mirror */ int nosync; /* mirror */ char *origin; /* snap */ @@ -652,6 +652,8 @@ int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t region_size, uint32_t log_count, struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags); +int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name, + uint32_t split_count, struct dm_list *removable_pvs); int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t log_count, struct dm_list *pvs, uint64_t status_mask); diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index bbd41b19a..05c91e6f6 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -1171,7 +1171,8 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr static int _create_mimage_lvs(struct alloc_handle *ah, uint32_t num_mirrors, struct logical_volume *lv, - struct logical_volume **img_lvs) + struct logical_volume **img_lvs, + int for_log) { uint32_t m; char *img_name; @@ -1202,7 +1203,7 @@ static int _create_mimage_lvs(struct alloc_handle *ah, if (!lv_add_segment(ah, m, 1, img_lvs[m], get_segtype_from_string(lv->vg->cmd, "striped"), - 0, 0, 0, NULL)) { + 0, 0, 0, for_log ? lv : NULL)) { log_error("Aborting. Failed to add mirror image segment " "to %s. Remove new LV and retry.", img_lvs[m]->name); @@ -1547,11 +1548,51 @@ static struct logical_volume *_create_mirror_log(struct logical_volume *lv, return log_lv; } +/* + * Returns: 1 on success, 0 on error + */ +static int _form_mirror(struct cmd_context *cmd, struct alloc_handle *ah, + struct logical_volume *lv, + uint32_t mirrors, uint32_t region_size, int for_log) +{ + struct logical_volume **img_lvs; + + /* + * insert a mirror layer + */ + if (dm_list_size(&lv->segments) != 1 || + seg_type(first_seg(lv), 0) != AREA_LV) + if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d")) + return 0; + + /* + * create mirror image LVs + */ + if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) { + log_error("img_lvs allocation failed. " + "Remove new LV and retry."); + return 0; + } + + if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs, for_log)) + return 0; + + if (!lv_add_mirror_lvs(lv, img_lvs, mirrors, + MIRROR_IMAGE | (lv->status & LOCKED), + region_size)) { + log_error("Aborting. Failed to add mirror segment. " + "Remove new LV and retry."); + return 0; + } + + return 1; +} + static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd, struct alloc_handle *ah, struct logical_volume *lv, uint32_t log_count, - uint32_t region_size __attribute((unused)), + uint32_t region_size, alloc_policy_t alloc, int in_sync) { @@ -1563,11 +1604,6 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd, init_mirror_in_sync(in_sync); - if (log_count != 1) { - log_error("log_count != 1 is not supported."); - return NULL; - } - /* Mirror log name is lv_name + suffix, determined as the following: * 1. suffix is: * o "_mlog" for the original mirror LV. @@ -1600,6 +1636,12 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd, return NULL; } + if ((log_count > 1) && + !_form_mirror(cmd, ah, log_lv, log_count-1, region_size, 1)) { + log_error("Failed to form mirrored log."); + return NULL; + } + if (!_init_mirror_log(cmd, log_lv, in_sync, &lv->tags, 1)) { log_error("Failed to initialise mirror log."); return NULL; @@ -1630,12 +1672,6 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, struct lvinfo info; int r = 0; - /* Unimplemented features */ - if (log_count > 1) { - log_error("log_count > 1 is not supported"); - return 0; - } - if (dm_list_size(&lv->segments) != 1) { log_error("Multiple-segment mirror is not supported"); return 0; @@ -1707,7 +1743,6 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv, struct alloc_handle *ah; const struct segment_type *segtype; struct dm_list *parallel_areas; - struct logical_volume **img_lvs; struct logical_volume *log_lv = NULL; if (stripes > 1) { @@ -1747,34 +1782,9 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv, So from here on, if failure occurs, the log must be explicitly removed and the updated vg metadata should be committed. */ - /* - * insert a mirror layer - */ - if (dm_list_size(&lv->segments) != 1 || - seg_type(first_seg(lv), 0) != AREA_LV) - if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d")) - goto out_remove_log; - - /* - * create mirror image LVs - */ - if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) { - log_error("img_lvs allocation failed. " - "Remove new LV and retry."); - goto out_remove_log; - } - - if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs)) + if (!_form_mirror(cmd, ah, lv, mirrors, region_size, 0)) goto out_remove_log; - if (!lv_add_mirror_lvs(lv, img_lvs, mirrors, - MIRROR_IMAGE | (lv->status & LOCKED), - region_size)) { - log_error("Aborting. Failed to add mirror segment. " - "Remove new LV and retry."); - goto out_remove_images; - } - if (log_count && !attach_mirror_log(first_seg(lv), log_lv)) stack; diff --git a/man/lvconvert.8.in b/man/lvconvert.8.in index 3dcc8289c..e269c3155 100644 --- a/man/lvconvert.8.in +++ b/man/lvconvert.8.in @@ -3,7 +3,7 @@ lvconvert \- convert a logical volume from linear to mirror or snapshot .SH SYNOPSIS .B lvconvert -\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize] +\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core|redundant}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize] [\-A|\-\-alloc AllocationPolicy] [\-b|\-\-background] [\-f|\-\-force] [\-i|\-\-interval Seconds] [\-h|\-?|\-\-help] @@ -71,6 +71,7 @@ from the data being mirrored. Core may be useful for short-lived mirrors: It means the mirror is regenerated by copying the data from the first device again every time the device is activated - perhaps, for example, after every reboot. +Using "redundant" will create a persistent log that is itself mirrored. .TP .I \-\-corelog The optional argument "--corelog" is the same as specifying "--mirrorlog core". diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in index 5041eab8b..575f5a9b8 100644 --- a/man/lvcreate.8.in +++ b/man/lvcreate.8.in @@ -11,7 +11,7 @@ lvcreate \- create a logical volume in an existing volume group {\-l|\-\-extents LogicalExtentsNumber[%{VG|PVS|FREE}] | \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]} [\-M|\-\-persistent y|n] [\-\-minor minor] -[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core}] [\-\-corelog] +[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core|redundant}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize]] [\-n|\-\-name LogicalVolumeName] [\-p|\-\-permission r|rw] [\-r|\-\-readahead ReadAheadSectors|auto|none] @@ -107,9 +107,10 @@ intensive initial sync of an empty device. The optional argument --mirrorlog specifies the type of log to be used. The default is disk, which is persistent and requires a small amount of storage space, usually on a separate device from the -data being mirrored. Using core means the mirror is regenerated +data being mirrored. Using core means the mirror is regenerated by copying the data from the first device again each time the -device is activated, for example, after every reboot. +device is activated, for example, after every reboot. Using "redundant" +will create a persistent log that is itself mirrored. The optional argument --corelog is equivalent to --mirrorlog core. diff --git a/tools/commands.h b/tools/commands.h index 20db37397..325906472 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -96,7 +96,7 @@ xx(lvconvert, "Change logical volume layout", 0, "lvconvert " - "[-m|--mirrors Mirrors [{--mirrorlog {disk|core}|--corelog}]]\n" + "[-m|--mirrors Mirrors [{--mirrorlog {disk|core|redundant}|--corelog}]]\n" "\t[--repair [--use-policies]]\n" "\t[-R|--regionsize MirrorLogRegionSize]\n" "\t[--alloc AllocationPolicy]\n" @@ -145,7 +145,7 @@ xx(lvcreate, "\t{-l|--extents LogicalExtentsNumber |\n" "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n" "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n" - "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n" + "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core|redundant}|--corelog}]]\n" "\t[-n|--name LogicalVolumeName]\n" "\t[--noudevsync]\n" "\t[-p|--permission {r|rw}]\n" diff --git a/tools/lvconvert.c b/tools/lvconvert.c index fd5b35302..1b73bad28 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -550,18 +550,18 @@ static int _using_corelog(struct logical_volume *lv) static int _lv_update_log_type(struct cmd_context *cmd, struct lvconvert_params *lp, struct logical_volume *lv, - int corelog) + int log_count) { struct logical_volume *original_lv = _original_lv(lv); - if (_using_corelog(lv) && !corelog) { - if (!add_mirror_log(cmd, original_lv, 1, + if (_using_corelog(lv) && log_count) { + if (!add_mirror_log(cmd, original_lv, log_count, adjusted_mirror_region_size( lv->vg->extent_size, lv->le_count, lp->region_size), lp->pvh, lp->alloc)) return_0; - } else if (!_using_corelog(lv) && corelog) { + } else if (!_using_corelog(lv) && !log_count) { if (!remove_mirror_log(cmd, original_lv, lp->pv_count ? lp->pvh : NULL)) return_0; @@ -613,7 +613,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv struct lv_segment *seg; uint32_t existing_mirrors; const char *mirrorlog; - unsigned corelog = 0; + unsigned log_count = 0; int r = 0; struct logical_volume *log_lv, *layer_lv; int failed_mirrors = 0, failed_log = 0; @@ -671,7 +671,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv if (existing_mirrors && lp->mirrors && (lp->mirrors != existing_mirrors) && !arg_count(cmd, mirrorlog_ARG) && !arg_count(cmd, corelog_ARG)) { - corelog = first_seg(lv)->log_lv ? 0 : 1; + log_count = lv_mirror_count(first_seg(lv)->log_lv); } if (repair) { @@ -692,8 +692,10 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv return_0; lp->pvh = lp->failed_pvs = failed_pvs; log_lv=first_seg(lv)->log_lv; - if (!log_lv || log_lv->status & PARTIAL_LV) - failed_log = corelog = 1; + if (!log_lv || log_lv->status & PARTIAL_LV) { + failed_log = 1; + log_count = 0; + } } else { /* * Did the user try to subtract more legs than available? @@ -707,20 +709,29 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv /* * Adjust log type */ + /* + * This param used to be 'corelog' and was initialized to '0'. + * We initially set to '1' here so as not to screw the logic. + */ + log_count = 1; if (arg_count(cmd, corelog_ARG)) - corelog = 1; + log_count = 0; mirrorlog = arg_str_value(cmd, mirrorlog_ARG, - corelog ? "core" : DEFAULT_MIRRORLOG); - if (!strcmp("disk", mirrorlog)) { - if (corelog) { - log_error("--mirrorlog disk and --corelog " - "are incompatible"); - return 0; - } - corelog = 0; - } else if (!strcmp("core", mirrorlog)) - corelog = 1; + !log_count ? "core" : DEFAULT_MIRRORLOG); + + if (strcmp("core", mirrorlog) && !log_count) { + log_error("--mirrorlog disk and --corelog " + "are incompatible"); + return 0; + } + + if (!strcmp("redundant", mirrorlog)) + log_count = 2; + else if (!strcmp("disk", mirrorlog)) + log_count = 1; + else if (!strcmp("core", mirrorlog)) + log_count = 0; else { log_error("Unknown mirrorlog type: %s", mirrorlog); return 0; @@ -779,12 +790,12 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv remove_pvs)) return 0; } else if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors, - (corelog || lp->mirrors == 1) ? 1U : 0U, + (!log_count || lp->mirrors == 1) ? 1U : 0U, remove_pvs, 0)) return_0; if (lp->mirrors > 1 && - !_lv_update_log_type(cmd, lp, lv, corelog)) + !_lv_update_log_type(cmd, lp, lv, log_count)) return_0; } else if (!(lv->status & MIRRORED)) { /* @@ -811,7 +822,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv lv->vg->extent_size, lv->le_count, lp->region_size), - corelog ? 0U : 1U, lp->pvh, lp->alloc, + log_count, lp->pvh, lp->alloc, MIRROR_BY_LV)) { stack; return failure_code; @@ -843,7 +854,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv * insertion to make the end result consistent with * linear-to-mirror conversion. */ - if (!_lv_update_log_type(cmd, lp, lv, corelog)) { + if (!_lv_update_log_type(cmd, lp, lv, log_count)) { stack; return failure_code; } @@ -881,8 +892,8 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv } if (lp->mirrors == existing_mirrors) { - if (_using_corelog(lv) != corelog) { - if (!_lv_update_log_type(cmd, lp, lv, corelog)) { + if (_using_corelog(lv) != !log_count) { + if (!_lv_update_log_type(cmd, lp, lv, log_count)) { stack; return failure_code; } @@ -922,8 +933,10 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv if (failed_log || failed_mirrors) { lp->pvh = old_pvh; - if (failed_log && replace_log) - failed_log = corelog = 0; + if (failed_log && replace_log) { + failed_log = 0; + log_count = 1; + } if (replace_mirrors) lp->mirrors += failed_mirrors; failed_mirrors = 0; diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 06f347897..fa5243035 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -323,21 +323,29 @@ static int _read_mirror_params(struct lvcreate_params *lp, int region_size; const char *mirrorlog; + /* + * This param used to be 'corelog' and was initialized to '0'. + * We initially set to '1' here so as not to screw the logic. + */ + lp->log_count = 1; if (arg_count(cmd, corelog_ARG)) - lp->corelog = 1; + lp->log_count = 0; mirrorlog = arg_str_value(cmd, mirrorlog_ARG, - lp->corelog ? "core" : DEFAULT_MIRRORLOG); + !lp->log_count ? "core" : DEFAULT_MIRRORLOG); - if (!strcmp("disk", mirrorlog)) { - if (lp->corelog) { - log_error("--mirrorlog disk and --corelog " - "are incompatible"); - return 0; - } - lp->corelog = 0; - } else if (!strcmp("core", mirrorlog)) - lp->corelog = 1; + if (strcmp("core", mirrorlog) && !lp->log_count) { + log_error("--mirrorlog disk and --corelog " + "are incompatible"); + return 0; + } + + if (!strcmp("redundant", mirrorlog)) + lp->log_count = 2; + else if (!strcmp("disk", mirrorlog)) + lp->log_count = 1; + else if (!strcmp("core", mirrorlog)) + lp->log_count = 0; else { log_error("Unknown mirrorlog type: %s", mirrorlog); return 0;