diff options
author | Alasdair G Kergon <agk@redhat.com> | 2016-05-23 16:46:38 +0100 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2016-05-23 16:46:38 +0100 |
commit | bf8d00985ada723778701530c7ea863c617dda8a (patch) | |
tree | c79d81b7616c3c15352001a24f9622d24bad408e | |
parent | ad4ca55543428f909fde8ba03e88d355560fe320 (diff) | |
download | lvm2-bf8d00985ada723778701530c7ea863c617dda8a.tar.gz |
raid0: Add raid0 segment type.
This remains experimental and quite restrictive so should only be used
for testing at this stage. (E.g. lvreduce is not supported.)
-rw-r--r-- | WHATS_NEW | 1 | ||||
-rw-r--r-- | lib/activate/dev_manager.c | 14 | ||||
-rw-r--r-- | lib/format_text/export.c | 13 | ||||
-rw-r--r-- | lib/metadata/lv_manip.c | 31 | ||||
-rw-r--r-- | lib/metadata/segtype.h | 5 | ||||
-rw-r--r-- | lib/raid/raid.c | 128 | ||||
-rw-r--r-- | lib/report/report.c | 2 | ||||
-rw-r--r-- | libdm/libdm-deptree.c | 5 | ||||
-rw-r--r-- | man/lvcreate.8.in | 12 | ||||
-rw-r--r-- | tools/lvcreate.c | 27 |
10 files changed, 168 insertions, 70 deletions
@@ -1,5 +1,6 @@ Version 2.02.155 - ================================ + Add basic support for --type raid0 using md. Add support for lvchange --cachemode for cached LV. Fix liblvm2app error handling when setting up context. Delay liblvm2app init in python code until it is needed. diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index f6cc0be53..711074d64 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -2207,7 +2207,7 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, (!dm->track_pending_delete || !lv_is_cache(lv)) && !_add_lv_to_dtree(dm, dtree, seg_lv(seg, s), 0)) return_0; - if (seg_is_raid(seg) && + if (seg_is_raid(seg) && seg->meta_areas && seg_metalv(seg, s) && !_add_lv_to_dtree(dm, dtree, seg_metalv(seg, s), 0)) return_0; } @@ -2379,9 +2379,13 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, return_0; continue; } - if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s), NULL))) - return_0; - if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s))) + + if (seg->meta_areas && seg_metalv(seg, s)) { + if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s), NULL))) + return_0; + if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s))) + return_0; + } else if (!dm_tree_node_add_null_area(node, 0)) return_0; if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s), NULL))) @@ -2709,7 +2713,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm, !_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s), laopts, NULL)) return_0; - if (seg_is_raid(seg) && + if (seg_is_raid(seg) && seg->meta_areas && seg_metalv(seg, s) && !_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s), laopts, NULL)) return_0; diff --git a/lib/format_text/export.c b/lib/format_text/export.c index c0af3fafb..a762c742d 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -621,6 +621,7 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, (s == seg->area_count - 1) ? "" : ","); break; case AREA_LV: + /* FIXME This helper code should be target-independent! Check for metadata LV property. */ if (!(seg->status & RAID)) { outf(f, "\"%s\", %u%s", seg_lv(seg, s)->name, @@ -630,15 +631,19 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, } /* RAID devices are laid-out in metadata/data pairs */ + /* FIXME Validation should be elsewhere, not here! */ if (!lv_is_raid_image(seg_lv(seg, s)) || - !lv_is_raid_metadata(seg_metalv(seg, s))) { + (seg->meta_areas && seg_metalv(seg, s) && !lv_is_raid_metadata(seg_metalv(seg, s)))) { log_error("RAID segment has non-RAID areas"); return 0; } - outf(f, "\"%s\", \"%s\"%s", - seg_metalv(seg, s)->name, seg_lv(seg, s)->name, - (s == seg->area_count - 1) ? "" : ","); + if (seg->meta_areas && seg_metalv(seg,s)) + outf(f, "\"%s\", \"%s\"%s", + (seg->meta_areas && seg_metalv(seg, s)) ? seg_metalv(seg, s)->name : "", + seg_lv(seg, s)->name, (s == seg->area_count - 1) ? "" : ","); + else + outf(f, "\"%s\"%s", seg_lv(seg, s)->name, (s == seg->area_count - 1) ? "" : ","); break; case AREA_UNASSIGNED: diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 9bfef4544..82faf4296 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -114,6 +114,7 @@ enum { LV_TYPE_DATA, LV_TYPE_SPARE, LV_TYPE_VIRTUAL, + LV_TYPE_RAID0, LV_TYPE_RAID1, LV_TYPE_RAID10, LV_TYPE_RAID4, @@ -162,6 +163,7 @@ static const char *_lv_type_names[] = { [LV_TYPE_DATA] = "data", [LV_TYPE_SPARE] = "spare", [LV_TYPE_VIRTUAL] = "virtual", + [LV_TYPE_RAID0] = SEG_TYPE_NAME_RAID0, [LV_TYPE_RAID1] = SEG_TYPE_NAME_RAID1, [LV_TYPE_RAID10] = SEG_TYPE_NAME_RAID10, [LV_TYPE_RAID4] = SEG_TYPE_NAME_RAID4, @@ -256,7 +258,10 @@ static int _lv_layout_and_role_raid(struct dm_pool *mem, segtype = first_seg(lv)->segtype; - if (segtype_is_raid1(segtype)) { + if (segtype_is_raid0(segtype)) { + if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID0])) + goto_bad; + } else if (segtype_is_raid1(segtype)) { if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID1])) goto_bad; } else if (segtype_is_raid10(segtype)) { @@ -860,7 +865,7 @@ dm_percent_t copy_percent(const struct logical_volume *lv) denominator += seg->area_len; /* FIXME Generalise name of 'extents_copied' field */ - if ((seg_is_raid(seg) || seg_is_mirrored(seg)) && + if (((seg_is_raid(seg) && !seg_is_any_raid0(seg)) || seg_is_mirrored(seg)) && (seg->area_count > 1)) numerator += seg->extents_copied; else @@ -3751,7 +3756,7 @@ static int _lv_insert_empty_sublvs(struct logical_volume *lv, return_0; /* Metadata LVs for raid */ - if (segtype_is_raid(segtype)) { + if (segtype_is_raid(segtype) && !segtype_is_raid0(segtype)) { if (dm_snprintf(img_name, sizeof(img_name), "%s_rmeta_%u", lv->name, i) < 0) goto_bad; @@ -3787,6 +3792,7 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, struct lv_segment *seg = first_seg(lv); uint32_t fa, s; int clear_metadata = 0; + uint32_t area_multiple = 1; if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED))) return_0; @@ -3797,13 +3803,14 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, * 'stripes' and 'stripe_size' parameters meaningless. */ if (seg_is_raid(seg)) { + area_multiple = _calc_area_multiple(seg->segtype, seg->area_count, 0); stripes = 1; stripe_size = 0; } for (fa = first_area, s = 0; s < seg->area_count; s++) { if (is_temporary_mirror_layer(seg_lv(seg, s))) { - if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents, + if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents / area_multiple, fa, stripes, stripe_size)) return_0; fa += lv_mirror_count(seg_lv(seg, s)); @@ -3819,7 +3826,7 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, } /* Extend metadata LVs only on initial creation */ - if (seg_is_raid(seg) && !lv->le_count) { + if (seg_is_raid(seg) && !seg_is_raid0(seg) && !lv->le_count) { if (!seg->meta_areas) { log_error("No meta_areas for RAID type"); return 0; @@ -3854,6 +3861,7 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, /* * We must clear the metadata areas upon creation. */ + /* FIXME VG is not in a fully-consistent state here and should not be committed! */ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; @@ -3898,7 +3906,7 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, } } - seg->area_len += extents; + seg->area_len += extents / area_multiple; seg->len += extents; if (!_setup_lv_size(lv, lv->le_count + extents)) @@ -3953,7 +3961,7 @@ int lv_extend(struct logical_volume *lv, */ /* FIXME Support striped metadata pool */ log_count = 1; - } else if (segtype_is_raid(segtype) && !lv->le_count) + } else if (segtype_is_raid(segtype) && !segtype_is_raid0(segtype) && !lv->le_count) log_count = mirrors * stripes; /* FIXME log_count should be 1 for mirrors */ @@ -3963,7 +3971,7 @@ int lv_extend(struct logical_volume *lv, return_0; new_extents = ah->new_extents; - if (segtype_is_raid(segtype)) + if (segtype_is_raid(segtype) && !segtype_is_raid0(segtype)) new_extents -= ah->log_len * ah->area_multiple; if (segtype_is_pool(segtype)) { @@ -7078,7 +7086,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, if (!activation()) { if (seg_is_cache(lp) || seg_is_mirror(lp) || - seg_is_raid(lp) || + (seg_is_raid(lp) && !seg_is_raid0(lp)) || seg_is_thin(lp) || lp->snapshot) { /* @@ -7256,7 +7264,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, /* FIXME Eventually support raid/mirrors with -m */ if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED))) return_0; - } else if (seg_is_mirrored(lp) || seg_is_raid(lp)) { + } else if (seg_is_mirrored(lp) || (seg_is_raid(lp) && !seg_is_any_raid0(lp))) { if (is_change_activating(lp->activate) && (lp->activate != CHANGE_AEY) && vg_is_clustered(vg) && seg_is_mirrored(lp) && !seg_is_raid(lp) && !cluster_mirror_is_available(vg->cmd)) { @@ -7389,7 +7397,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, if (!archive(vg)) return_NULL; - if (pool_lv && segtype_is_thin_volume(create_segtype)) { /* Ensure all stacked messages are submitted */ if ((pool_is_active(pool_lv) || is_change_activating(lp->activate)) && @@ -7444,7 +7451,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, stack; goto revert_new_lv; } - } else if (lv_is_raid(lv)) { + } else if (lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv))) { first_seg(lv)->min_recovery_rate = lp->min_recovery_rate; first_seg(lv)->max_recovery_rate = lp->max_recovery_rate; } else if (lv_is_thin_pool(lv)) { diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h index 67fb11c01..3fc42666c 100644 --- a/lib/metadata/segtype.h +++ b/lib/metadata/segtype.h @@ -47,6 +47,7 @@ struct dev_manager; #define SEG_ONLY_EXCLUSIVE 0x0000000000010000ULL /* In cluster only exlusive activation */ #define SEG_CAN_ERROR_WHEN_FULL 0x0000000000020000ULL +#define SEG_RAID0 0x0000000000040000ULL #define SEG_RAID1 0x0000000000100000ULL #define SEG_RAID10 0x0000000000200000ULL #define SEG_RAID4 0x0000000000400000ULL @@ -100,6 +101,8 @@ struct dev_manager; #define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0) #define segtype_is_mirror(segtype) ((segtype)->flags & SEG_MIRROR ? 1 : 0) #define segtype_is_pool(segtype) ((segtype)->flags & (SEG_CACHE_POOL | SEG_THIN_POOL) ? 1 : 0) +#define segtype_is_raid0(segtype) ((segtype)->flags & SEG_RAID0 ? 1 : 0) +#define segtype_is_any_raid0(segtype) ((segtype)->flags & SEG_RAID0 ? 1 : 0) #define segtype_is_raid(segtype) ((segtype)->flags & SEG_RAID ? 1 : 0) #define segtype_is_raid1(segtype) ((segtype)->flags & SEG_RAID1 ? 1 : 0) #define segtype_is_raid4(segtype) ((segtype)->flags & SEG_RAID4 ? 1 : 0) @@ -130,6 +133,8 @@ struct dev_manager; #define seg_is_mirror(seg) segtype_is_mirror((seg)->segtype) #define seg_is_mirrored(seg) segtype_is_mirrored((seg)->segtype) #define seg_is_pool(seg) segtype_is_pool((seg)->segtype) +#define seg_is_raid0(seg) segtype_is_raid0((seg)->segtype) +#define seg_is_any_raid0(seg) segtype_is_any_raid0((seg)->segtype) #define seg_is_raid(seg) segtype_is_raid((seg)->segtype) #define seg_is_raid1(seg) segtype_is_raid1((seg)->segtype) #define seg_is_raid4(seg) segtype_is_raid4((seg)->segtype) diff --git a/lib/raid/raid.c b/lib/raid/raid.c index 28fd45bcb..4987f9175 100644 --- a/lib/raid/raid.c +++ b/lib/raid/raid.c @@ -33,8 +33,10 @@ static void _raid_display(const struct lv_segment *seg) display_stripe(seg, s, " "); } - for (s = 0; s < seg->area_count; ++s) - log_print(" Raid Metadata LV%2d\t%s", s, seg_metalv(seg, s)->name); + if (seg->meta_areas) { + for (s = 0; s < seg->area_count; ++s) + log_print(" Raid Metadata LV%2d\t%s", s, seg_metalv(seg, s)->name); + } log_print(" "); } @@ -42,11 +44,26 @@ static void _raid_display(const struct lv_segment *seg) static int _raid_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count) { - if (!dm_config_get_uint32(sn, "device_count", area_count)) { - log_error("Couldn't read 'device_count' for " + uint32_t stripe_count = 0, device_count = 0; + int stripe_count_found, device_count_found; + + device_count_found = dm_config_get_uint32(sn, "device_count", &device_count); + stripe_count_found = dm_config_get_uint32(sn, "stripe_count", &stripe_count); + + if (!device_count_found && !stripe_count_found) { + log_error("Couldn't read 'device_count' or 'stripe_count' for " + "segment '%s'.", dm_config_parent_name(sn)); + return 0; + } + + if (device_count_found && stripe_count_found) { + log_error("Only one of 'device_count' and 'stripe_count' allowed for " "segment '%s'.", dm_config_parent_name(sn)); return 0; } + + *area_count = stripe_count + device_count; + return 1; } @@ -69,22 +86,25 @@ static int _raid_text_import_areas(struct lv_segment *seg, return 0; } - if (!cv->next) { - log_error("Missing data device in areas array for segment %s.", seg_name); - return 0; + /* Metadata device comes first. */ + if (!seg_is_raid0(seg)) { + if (!(lv = find_lv(seg->lv->vg, cv->v.str))) { + log_error("Couldn't find volume '%s' for segment '%s'.", + cv->v.str ? : "NULL", seg_name); + return 0; + } + + if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_META)) + return_0; + cv = cv->next; } - /* Metadata device comes first */ - if (!(lv = find_lv(seg->lv->vg, cv->v.str))) { - log_error("Couldn't find volume '%s' for segment '%s'.", - cv->v.str ? : "NULL", seg_name); + if (!cv) { + log_error("Missing data device in areas array for segment %s.", seg_name); return 0; } - if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_META)) - return_0; /* Data device comes second */ - cv = cv->next; if (!(lv = find_lv(seg->lv->vg, cv->v.str))) { log_error("Couldn't find volume '%s' for segment '%s'.", cv->v.str ? : "NULL", seg_name); @@ -133,7 +153,7 @@ static int _raid_text_import(struct lv_segment *seg, } } - if (!dm_config_get_list(sn, "raids", &cv)) { + if (!dm_config_get_list(sn, seg_is_any_raid0(seg) ? "raid0_lvs" : "raids", &cv)) { log_error("Couldn't find RAID array for " "segment %s of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); @@ -145,18 +165,31 @@ static int _raid_text_import(struct lv_segment *seg, return 0; } + if (seg_is_any_raid0(seg)) + seg->area_len /= seg->area_count; seg->status |= RAID; return 1; } -static int _raid_text_export(const struct lv_segment *seg, struct formatter *f) +static int _raid_text_export_raid0(const struct lv_segment *seg, struct formatter *f) +{ + outf(f, "stripe_count = %u", seg->area_count); + + if (seg->stripe_size) + outf(f, "stripe_size = %" PRIu32, seg->stripe_size); + + return out_areas(f, seg, "raid0_lv"); +} + +static int _raid_text_export_raid(const struct lv_segment *seg, struct formatter *f) { outf(f, "device_count = %u", seg->area_count); - if (seg->region_size) - outf(f, "region_size = %" PRIu32, seg->region_size); + if (seg->stripe_size) outf(f, "stripe_size = %" PRIu32, seg->stripe_size); + if (seg->region_size) + outf(f, "region_size = %" PRIu32, seg->region_size); if (seg->writebehind) outf(f, "writebehind = %" PRIu32, seg->writebehind); if (seg->min_recovery_rate) @@ -167,6 +200,14 @@ static int _raid_text_export(const struct lv_segment *seg, struct formatter *f) return out_areas(f, seg, "raid"); } +static int _raid_text_export(const struct lv_segment *seg, struct formatter *f) +{ + if (seg_is_any_raid0(seg)) + return _raid_text_export_raid0(seg, f); + + return _raid_text_export_raid(seg, f); +} + static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)), struct dm_pool *mem __attribute__((unused)), struct cmd_context *cmd __attribute__((unused)), @@ -181,6 +222,7 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)), uint64_t rebuilds = 0; uint64_t writemostly = 0; struct dm_tree_node_raid_params params; + int raid0 = seg_is_any_raid0(seg); memset(¶ms, 0, sizeof(params)); @@ -200,24 +242,32 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)), return 0; } - if (!seg->region_size) { - log_error("Missing region size for mirror segment."); - return 0; - } + if (!raid0) { + if (!seg->region_size) { + log_error("Missing region size for mirror segment."); + return 0; + } - for (s = 0; s < seg->area_count; s++) - if (seg_lv(seg, s)->status & LV_REBUILD) - rebuilds |= 1ULL << s; + for (s = 0; s < seg->area_count; s++) + if (seg_lv(seg, s)->status & LV_REBUILD) + rebuilds |= 1ULL << s; - for (s = 0; s < seg->area_count; s++) - if (seg_lv(seg, s)->status & LV_WRITEMOSTLY) - writemostly |= 1ULL << s; + for (s = 0; s < seg->area_count; s++) + if (seg_lv(seg, s)->status & LV_WRITEMOSTLY) + writemostly |= 1ULL << s; - if (mirror_in_sync()) - flags = DM_NOSYNC; + if (mirror_in_sync()) + flags = DM_NOSYNC; + } params.raid_type = lvseg_name(seg); - if (seg->segtype->parity_devs) { + params.stripe_size = seg->stripe_size; + params.flags = flags; + + if (raid0) { + params.mirrors = 1; + params.stripes = seg->area_count; + } else if (seg->segtype->parity_devs) { /* RAID 4/5/6 */ params.mirrors = 1; params.stripes = seg->area_count - seg->segtype->parity_devs; @@ -231,13 +281,14 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)), params.stripes = 1; params.writebehind = seg->writebehind; } - params.region_size = seg->region_size; - params.stripe_size = seg->stripe_size; - params.rebuilds = rebuilds; - params.writemostly = writemostly; - params.min_recovery_rate = seg->min_recovery_rate; - params.max_recovery_rate = seg->max_recovery_rate; - params.flags = flags; + + if (!raid0) { + params.region_size = seg->region_size; + params.rebuilds = rebuilds; + params.writemostly = writemostly; + params.min_recovery_rate = seg->min_recovery_rate; + params.max_recovery_rate = seg->max_recovery_rate; + } if (!dm_tree_node_add_raid_target_with_params(node, len, ¶ms)) return_0; @@ -418,6 +469,7 @@ static const struct raid_type { unsigned parity; uint64_t extra_flags; } _raid_types[] = { + { SEG_TYPE_NAME_RAID0, 0, SEG_RAID0 | SEG_AREAS_STRIPED }, { SEG_TYPE_NAME_RAID1, 0, SEG_RAID1 | SEG_AREAS_MIRRORED }, { SEG_TYPE_NAME_RAID10, 0, SEG_RAID10 | SEG_AREAS_MIRRORED }, { SEG_TYPE_NAME_RAID4, 1, SEG_RAID4 }, diff --git a/lib/report/report.c b/lib/report/report.c index 92eb64c18..8fa9daf75 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -2845,7 +2845,7 @@ static int _copypercent_disp(struct dm_report *rh, struct lv_status_cache *status; dm_percent_t percent = DM_PERCENT_INVALID; - if (((lv_is_raid(lv) && lv_raid_percent(lv, &percent)) || + if (((lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv)) && lv_raid_percent(lv, &percent)) || (lv_is_mirror(lv) && lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL))) && (percent != DM_PERCENT_INVALID)) { percent = copy_percent(lv); diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c index 6f18ae2a8..dd5ee9e46 100644 --- a/libdm/libdm-deptree.c +++ b/libdm/libdm-deptree.c @@ -42,6 +42,7 @@ enum { SEG_ZERO, SEG_THIN_POOL, SEG_THIN, + SEG_RAID0, SEG_RAID1, SEG_RAID10, SEG_RAID4, @@ -74,6 +75,7 @@ static const struct { { SEG_ZERO, "zero"}, { SEG_THIN_POOL, "thin-pool"}, { SEG_THIN, "thin"}, + { SEG_RAID0, "raid0"}, { SEG_RAID1, "raid1"}, { SEG_RAID10, "raid10"}, { SEG_RAID4, "raid4"}, @@ -2131,6 +2133,7 @@ static int _emit_areas_line(struct dm_task *dmt __attribute__((unused)), EMIT_PARAMS(*pos, "%s", synctype); } break; + case SEG_RAID0: case SEG_RAID1: case SEG_RAID10: case SEG_RAID4: @@ -2572,6 +2575,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major, seg->iv_offset != DM_CRYPT_IV_DEFAULT ? seg->iv_offset : *seg_start); break; + case SEG_RAID0: case SEG_RAID1: case SEG_RAID10: case SEG_RAID4: @@ -3848,6 +3852,7 @@ int dm_tree_node_add_null_area(struct dm_tree_node *node, uint64_t offset) seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment); switch (seg->type) { + case SEG_RAID0: case SEG_RAID1: case SEG_RAID4: case SEG_RAID5_LA: diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in index e008b5822..8614cb195 100644 --- a/man/lvcreate.8.in +++ b/man/lvcreate.8.in @@ -606,7 +606,14 @@ would use 3 devices for striped logical volumes, RAID 4/5/6 will stripe across all PVs in the volume group or all of the PVs specified if the \fB\-i\fP argument is omitted. -. +Two implementations of basic striping are available in the kernel. +The original device-mapper implementation is the default and should +normally be used. The alternative implementation using MD, available +since version 1.7 of the RAID device-mapper kernel target (kernel +version 4.2) is provided to facilitate the development of new RAID +features. It may be accessed with \fB--type raid0\fP, but is best +avoided at present because of assorted restrictions on resizing and converting +such devices. .HP .BR \-I | \-\-stripesize .IR StripeSize @@ -649,6 +656,7 @@ Supported types are: .BR error , .BR linear , .BR mirror, +.BR raid0 , .BR raid1 , .BR raid4 , .BR raid5_la , @@ -683,7 +691,7 @@ is selected from combination of options: (snapshot or thin), .BR \-i | \-\-stripes (striped). -Default segment type is \fBlinear\fP. +The default segment type is \fBlinear\fP. . .HP .BR \-V | \-\-virtualsize diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 97147899a..8ddecae68 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -987,6 +987,12 @@ static int _lvcreate_params(struct cmd_context *cmd, return 0; } + if (segtype_is_any_raid0(lp->segtype) && + !(lp->target_attr & RAID_FEATURE_RAID0)) { + log_error("RAID module does not support RAID0."); + return 0; + } + if (segtype_is_raid10(lp->segtype) && !(lp->target_attr & RAID_FEATURE_RAID10)) { log_error("RAID module does not support RAID10."); return 0; @@ -1209,18 +1215,23 @@ static int _check_raid_parameters(struct volume_group *vg, unsigned devs = lcp->pv_count ? : dm_list_size(&vg->pvs); struct cmd_context *cmd = vg->cmd; - /* - * If number of devices was not supplied, we can infer from - * the PVs given. - */ - if (!seg_is_mirrored(lp)) { + if (!seg_is_mirrored(lp) && !lp->stripe_size) + lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2; + + if (seg_is_any_raid0(lp)) { + if (lp->stripes < 2) { + log_error("Segment type 'raid0' requires 2 or more stripes."); + return 0; + } + } else if (!seg_is_mirrored(lp)) { + /* + * If number of devices was not supplied, we can infer from + * the PVs given. + */ if (!arg_count(cmd, stripes_ARG) && (devs > 2 * lp->segtype->parity_devs)) lp->stripes = devs - lp->segtype->parity_devs; - if (!lp->stripe_size) - lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2; - if (lp->stripes <= lp->segtype->parity_devs) { log_error("Number of stripes must be at least %d for %s", lp->segtype->parity_devs + 1, |