From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18508 invoked by alias); 6 Sep 2011 00:26:46 -0000 Received: (qmail 18491 invoked by uid 9447); 6 Sep 2011 00:26:45 -0000 Date: Tue, 06 Sep 2011 00:26:00 -0000 Message-ID: <20110906002645.18489.qmail@sourceware.org> From: agk@sourceware.org To: lvm-devel@redhat.com, lvm2-cvs@sourceware.org Subject: LVM2 lib/format1/import-extents.c lib/format_p ... Mailing-List: contact lvm2-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: lvm2-cvs-owner@sourceware.org X-SW-Source: 2011-09/txt/msg00017.txt.bz2 CVSROOT: /cvs/lvm2 Module name: LVM2 Changes by: agk@sourceware.org 2011-09-06 00:26:44 Modified files: lib/format1 : import-extents.c lib/format_pool: import_export.c lib/format_text: import_vsn1.c lib/metadata : lv_alloc.h lv_manip.c merge.c metadata-exported.h lib/misc : lvm-string.c lib/thin : thin.c man : lvcreate.8.in tools : args.h commands.h lvcreate.c lvresize.c Log message: lvcreate parsing for thin provisioning. The rest is incomplete so this isn't usable yet. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format1/import-extents.c.diff?cvsroot=lvm2&r1=1.40&r2=1.41 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_pool/import_export.c.diff?cvsroot=lvm2&r1=1.33&r2=1.34 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_text/import_vsn1.c.diff?cvsroot=lvm2&r1=1.92&r2=1.93 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_alloc.h.diff?cvsroot=lvm2&r1=1.29&r2=1.30 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.277&r2=1.278 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/merge.c.diff?cvsroot=lvm2&r1=1.45&r2=1.46 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.203&r2=1.204 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/misc/lvm-string.c.diff?cvsroot=lvm2&r1=1.29&r2=1.30 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/thin/thin.c.diff?cvsroot=lvm2&r1=1.7&r2=1.8 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/lvcreate.8.in.diff?cvsroot=lvm2&r1=1.21&r2=1.22 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/args.h.diff?cvsroot=lvm2&r1=1.83&r2=1.84 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/commands.h.diff?cvsroot=lvm2&r1=1.161&r2=1.162 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.234&r2=1.235 http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvresize.c.diff?cvsroot=lvm2&r1=1.134&r2=1.135 --- LVM2/lib/format1/import-extents.c 2011/03/30 12:30:39 1.40 +++ LVM2/lib/format1/import-extents.c 2011/09/06 00:26:42 1.41 @@ -223,7 +223,7 @@ len = _area_length(lvm, le); if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le, - len, 0, 0, NULL, 1, len, 0, 0, 0, NULL))) { + len, 0, 0, NULL, NULL, 1, len, 0, 0, 0, NULL))) { log_error("Failed to allocate linear segment."); return 0; } @@ -295,7 +295,7 @@ if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, lvm->stripes * first_area_le, lvm->stripes * area_len, - 0, lvm->stripe_size, NULL, + 0, lvm->stripe_size, NULL, NULL, lvm->stripes, area_len, 0, 0, 0, NULL))) { log_error("Failed to allocate striped segment."); --- LVM2/lib/format_pool/import_export.c 2010/12/01 13:05:07 1.33 +++ LVM2/lib/format_pool/import_export.c 2011/09/06 00:26:42 1.34 @@ -195,7 +195,7 @@ if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur, area_len * usp->num_devs, 0, - usp->striping, NULL, usp->num_devs, + usp->striping, NULL, NULL, usp->num_devs, area_len, 0, 0, 0, NULL))) { log_error("Unable to allocate striped lv_segment structure"); return 0; @@ -235,7 +235,7 @@ if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur, area_len, 0, usp->striping, - NULL, 1, area_len, + NULL, NULL, 1, area_len, POOL_PE_SIZE, 0, 0, NULL))) { log_error("Unable to allocate linear lv_segment " "structure"); --- LVM2/lib/format_text/import_vsn1.c 2011/08/31 15:19:19 1.92 +++ LVM2/lib/format_text/import_vsn1.c 2011/09/06 00:26:43 1.93 @@ -329,7 +329,7 @@ return_0; if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent, - extent_count, 0, 0, NULL, area_count, + extent_count, 0, 0, NULL, NULL, area_count, extent_count, 0, 0, 0, NULL))) { log_error("Segment allocation failed"); return 0; --- LVM2/lib/metadata/lv_alloc.h 2011/07/19 16:37:42 1.29 +++ LVM2/lib/metadata/lv_alloc.h 2011/09/06 00:26:43 1.30 @@ -22,6 +22,7 @@ uint64_t status, uint32_t stripe_size, struct logical_volume *log_lv, + struct logical_volume *thin_pool_lv, uint32_t area_count, uint32_t area_len, uint32_t chunk_size, @@ -72,7 +73,9 @@ int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area, struct logical_volume *log_lv, uint64_t status); int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status, - uint32_t extents, const struct segment_type *segtype); + uint32_t extents, + const struct segment_type *segtype, + const char *thin_pool_name); void alloc_destroy(struct alloc_handle *ah); --- LVM2/lib/metadata/lv_manip.c 2011/08/30 14:55:17 1.277 +++ LVM2/lib/metadata/lv_manip.c 2011/09/06 00:26:43 1.278 @@ -198,6 +198,22 @@ return i; } +static int _attach_pool_metadata(struct lv_segment *seg, struct logical_volume *thin_pool_metadata) +{ + // FIXME Housekeeping needed here (cf attach_mirror_log) + seg->metadata_lv = thin_pool_metadata; + + return 1; +} + +static int _attach_pool_lv(struct lv_segment *seg, struct logical_volume *thin_pool_lv) +{ + // FIXME Housekeeping needed here (cf attach_mirror_log) + seg->thin_pool_lv = thin_pool_lv; + + return 1; +} + /* * All lv_segments get created here. */ @@ -208,6 +224,7 @@ uint64_t status, uint32_t stripe_size, struct logical_volume *log_lv, + struct logical_volume *thin_pool_lv, uint32_t area_count, uint32_t area_len, uint32_t chunk_size, @@ -248,13 +265,20 @@ seg->chunk_size = chunk_size; seg->region_size = region_size; seg->extents_copied = extents_copied; - seg->log_lv = log_lv; seg->pvmove_source_seg = pvmove_source_seg; dm_list_init(&seg->tags); - if (log_lv && !attach_mirror_log(seg, log_lv)) + if (thin_pool_lv && !_attach_pool_lv(seg, thin_pool_lv)) return_NULL; + if (log_lv) { + if (thin_pool_lv) { + if (!_attach_pool_metadata(seg, log_lv)) + return_NULL; + } else if (!attach_mirror_log(seg, log_lv)) + return_NULL; + } + return seg; } @@ -272,7 +296,7 @@ if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, old_le_count, lv->le_count - old_le_count, status, 0, - NULL, 0, lv->le_count - old_le_count, + NULL, NULL, 0, lv->le_count - old_le_count, 0, 0, 0, NULL))) { log_error("Couldn't allocate new snapshot segment."); return NULL; @@ -559,9 +583,7 @@ /* FIXME: Should we bug if we find a log_lv attached? */ - if (!lv_add_virtual_segment(lv, 0, len, - get_segtype_from_string(lv->vg->cmd, - "error"))) + if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, "error"), NULL)) return_0; return 1; @@ -917,7 +939,7 @@ if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, lv->le_count, aa[0].len * area_multiple, - status, stripe_size, NULL, + status, stripe_size, NULL, NULL, area_count, aa[0].len, 0u, region_size, 0u, NULL))) { log_error("Couldn't allocate new LV segment."); @@ -1987,13 +2009,25 @@ } int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status, - uint32_t extents, const struct segment_type *segtype) + uint32_t extents, const struct segment_type *segtype, + const char *thin_pool_name) { struct lv_segment *seg; + struct logical_volume *thin_pool_lv = NULL; + struct lv_list *lvl; + + if (thin_pool_name) { + if (!(lvl = find_lv_in_vg(lv->vg, thin_pool_name))) { + log_error("Unable to find existing pool LV %s in VG %s.", + thin_pool_name, lv->vg->name); + return 0; + } + thin_pool_lv = lvl->lv; + } if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, lv->le_count, extents, status, 0, - NULL, 0, extents, 0, 0, 0, NULL))) { + NULL, thin_pool_lv, 0, extents, 0, 0, 0, NULL))) { log_error("Couldn't allocate new zero segment."); return 0; } @@ -2129,7 +2163,7 @@ get_segtype_from_string(seg->lv->vg->cmd, "mirror"), seg->lv, seg->le, seg->len, seg->status, seg->stripe_size, - log_lv, + log_lv, NULL, seg->area_count, seg->area_len, seg->chunk_size, region_size, seg->extents_copied, NULL))) { @@ -2316,14 +2350,18 @@ lv->status |= MIRRORED; status = MIRROR_IMAGE; layer_name = "mimage"; - } else + } else if (segtype_is_thin_pool(segtype)) { + // lv->status |= THIN_POOL; + // status = THIN_IMAGE; + layer_name = "tdata"; + } return_0; /* * First, create our top-level segment for our top-level LV */ if (!(mapseg = alloc_lv_segment(lv->vg->cmd->mem, segtype, - lv, 0, 0, lv->status, stripe_size, NULL, + lv, 0, 0, lv->status, stripe_size, NULL, NULL, devices, 0, 0, region_size, 0, NULL))) { log_error("Failed to create mapping segment for %s", lv->name); return 0; @@ -2363,6 +2401,8 @@ } dm_list_add(&lv->segments, &mapseg->list); +// FIXME If thin pool, create one "log_lv" as tmeta here lv->metadata_lv + return 1; } @@ -2481,7 +2521,7 @@ const struct segment_type *segtype, uint32_t stripes, uint32_t stripe_size, uint32_t mirrors, uint32_t region_size, - uint32_t extents, + uint32_t extents, const char *thin_pool_name, struct dm_list *allocatable_pvs, alloc_policy_t alloc) { int r = 1; @@ -2492,17 +2532,19 @@ log_very_verbose("Extending segment type, %s", segtype->name); if (segtype_is_virtual(segtype)) - return lv_add_virtual_segment(lv, 0u, extents, segtype); + return lv_add_virtual_segment(lv, 0u, extents, segtype, thin_pool_name); if (segtype_is_raid(segtype) && !lv->le_count) raid_logs = mirrors * stripes; +// For thin pool, ensure space for "log_lv" ->metadata_lv is allocated simultaneously here + if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, raid_logs, region_size, extents, allocatable_pvs, alloc, NULL))) return_0; - if (!segtype_is_mirrored(segtype) && !segtype_is_raid(segtype)) + if (!segtype_is_mirrored(segtype) && !segtype_is_raid(segtype) && !segtype_is_thin_pool(segtype)) r = lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size, 0u, 0); else { @@ -2524,6 +2566,7 @@ return 0; } +// For thin_pool, populate tmeta here too r = _lv_extend_layered_lv(ah, lv, extents, 0, stripes, stripe_size); } @@ -3372,7 +3415,7 @@ /* Replace the empty layer with error segment */ segtype = get_segtype_from_string(lv->vg->cmd, "error"); - if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype)) + if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype, NULL)) return_0; return 1; @@ -3425,7 +3468,7 @@ segtype = get_segtype_from_string(cmd, "error"); - if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype)) { + if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype, NULL)) { log_error("Creation of transient LV %s for mirror conversion in VG %s failed.", name, lv_where->vg->name); return NULL; } @@ -3466,7 +3509,7 @@ /* allocate a new linear segment */ if (!(mapseg = alloc_lv_segment(cmd->mem, segtype, lv_where, 0, layer_lv->le_count, - status, 0, NULL, 1, layer_lv->le_count, + status, 0, NULL, NULL, 1, layer_lv->le_count, 0, 0, 0, NULL))) return_NULL; @@ -3510,7 +3553,7 @@ if (!(mapseg = alloc_lv_segment(layer_lv->vg->cmd->mem, segtype, layer_lv, layer_lv->le_count, seg->area_len, status, 0, - NULL, 1, seg->area_len, 0, 0, 0, seg))) + NULL, NULL, 1, seg->area_len, 0, 0, 0, seg))) return_0; /* map the new segment to the original underlying are */ @@ -3737,7 +3780,6 @@ return 1; } - static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd, struct volume_group *vg, const char *lv_name, @@ -3766,7 +3808,7 @@ return_NULL; if (!lv_extend(lv, segtype, 1, 0, 1, 0, voriginextents, - NULL, ALLOC_INHERIT)) + NULL, NULL, ALLOC_INHERIT)) return_NULL; /* store vg on disk(s) */ @@ -3778,8 +3820,14 @@ return lv; } -int lv_create_single(struct volume_group *vg, - struct lvcreate_params *lp) +/* Thin notes: + * If lp->thin OR lp->activate is AY*, activate the pool if not already active. + * If lp->thin, create thin LV within the pool - as a snapshot if lp->snapshot. + * If lp->activate is AY*, activate it. + * If lp->activate was AN* and the pool was originally inactive, deactivate it. + */ +static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct lvcreate_params *lp, + const char *new_lv_name) { struct cmd_context *cmd = vg->cmd; uint32_t size_rest; @@ -3788,24 +3836,24 @@ int origin_active = 0; struct lvinfo info; - if (lp->lv_name && find_lv_in_vg(vg, lp->lv_name)) { + if (new_lv_name && find_lv_in_vg(vg, new_lv_name)) { log_error("Logical volume \"%s\" already exists in " - "volume group \"%s\"", lp->lv_name, lp->vg_name); - return 0; + "volume group \"%s\"", new_lv_name, lp->vg_name); + return NULL; } if (vg_max_lv_reached(vg)) { log_error("Maximum number of logical volumes (%u) reached " "in volume group %s", vg->max_lv, vg->name); - return 0; + return NULL; } if ((segtype_is_mirrored(lp->segtype) || - segtype_is_raid(lp->segtype)) && + segtype_is_raid(lp->segtype) || segtype_is_thin(lp->segtype)) && !(vg->fid->fmt->features & FMT_SEGMENTS)) { - log_error("Metadata does not support %s.", - segtype_is_raid(lp->segtype) ? "RAID" : "mirroring"); - return 0; + log_error("Metadata does not support %s segments.", + lp->segtype->name); + return NULL; } if (lp->read_ahead != DM_READ_AHEAD_AUTO && @@ -3813,7 +3861,7 @@ (vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) && (lp->read_ahead < 2 || lp->read_ahead > 120)) { log_error("Metadata only supports readahead values between 2 and 120."); - return 0; + return NULL; } if (lp->stripe_size > vg->extent_size) { @@ -3830,7 +3878,7 @@ (lp->stripe_size > STRIPE_SIZE_MAX)) { log_error("Stripe size may not exceed %s", display_size(cmd, (uint64_t) STRIPE_SIZE_MAX)); - return 0; + return NULL; } if ((size_rest = lp->extents % lp->stripes)) { @@ -3840,19 +3888,20 @@ lp->extents = lp->extents - size_rest + lp->stripes; } - if (lp->zero && !activation()) { + if (lp->zero && !segtype_is_thin(lp->segtype) && !activation()) { log_error("Can't wipe start of new LV without using " "device-mapper kernel driver"); - return 0; + return NULL; } status |= lp->permission | VISIBLE_LV; + /* FIXME Thin snapshots are different */ if (lp->snapshot) { if (!activation()) { log_error("Can't create snapshot without using " "device-mapper kernel driver"); - return 0; + return NULL; } /* Must zero cow */ @@ -3865,27 +3914,27 @@ if (!(org = find_lv(vg, lp->origin))) { log_error("Couldn't find origin volume '%s'.", lp->origin); - return 0; + return NULL; } if (lv_is_virtual_origin(org)) { log_error("Can't share virtual origins. " "Use --virtualsize."); - return 0; + return NULL; } if (lv_is_cow(org)) { log_error("Snapshots of snapshots are not " "supported yet."); - return 0; + return NULL; } if (org->status & LOCKED) { log_error("Snapshots of locked devices are not " "supported yet"); - return 0; + return NULL; } if (lv_is_merging_origin(org)) { log_error("Snapshots of an origin that has a " "merging snapshot is not supported"); - return 0; + return NULL; } if ((org->status & MIRROR_IMAGE) || (org->status & MIRROR_LOG)) { @@ -3893,13 +3942,13 @@ "are not supported", (org->status & MIRROR_LOG) ? "log" : "image"); - return 0; + return NULL; } if (!lv_info(cmd, org, 0, &info, 0, 0)) { log_error("Check for existence of snapshot " "origin '%s' failed.", org->name); - return 0; + return NULL; } origin_active = info.exists; @@ -3907,19 +3956,19 @@ !lv_is_active_exclusive_locally(org)) { log_error("%s must be active exclusively to" " create snapshot", org->name); - return 0; + return NULL; } } } - if (!lp->extents) { + if (!lp->thin && !lp->extents) { log_error("Unable to create new logical volume with no extents"); - return 0; + return NULL; } if (lp->snapshot && (lp->extents * vg->extent_size < 2 * lp->chunk_size)) { log_error("Unable to create a snapshot smaller than 2 chunks."); - return 0; + return NULL; } if (!seg_is_virtual(lp) && @@ -3927,38 +3976,38 @@ log_error("Volume group \"%s\" has insufficient free space " "(%u extents): %u required.", vg->name, vg->free_count, lp->extents); - return 0; + return NULL; } if (lp->stripes > dm_list_size(lp->pvh) && lp->alloc != ALLOC_ANYWHERE) { log_error("Number of stripes (%u) must not exceed " "number of physical volumes (%d)", lp->stripes, dm_list_size(lp->pvh)); - return 0; + return NULL; } if ((segtype_is_mirrored(lp->segtype) || - segtype_is_raid(lp->segtype)) && !activation()) { + segtype_is_raid(lp->segtype) || seg_is_thin_volume(lp)) && !activation()) { log_error("Can't create %s without using " "device-mapper kernel driver.", segtype_is_raid(lp->segtype) ? lp->segtype->name : "mirror"); - return 0; + return NULL; } /* The snapshot segment gets created later */ if (lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "striped"))) - return_0; + return_NULL; if (!archive(vg)) - return 0; + return_NULL; if (!dm_list_empty(&lp->tags)) { if (!(vg->fid->fmt->features & FMT_TAGS)) { log_error("Volume group %s does not support tags", vg->name); - return 0; + return NULL; } } @@ -3973,16 +4022,16 @@ } } - if (!(lv = lv_create_empty(lp->lv_name ? lp->lv_name : "lvol%d", NULL, + if (!(lv = lv_create_empty(new_lv_name ? : "lvol%d", NULL, status, lp->alloc, vg))) - return_0; + return_NULL; if (lp->read_ahead != lv->read_ahead) { log_verbose("Setting read ahead sectors"); lv->read_ahead = lp->read_ahead; } - if (lp->minor >= 0) { + if (!seg_is_thin_pool(lp) && lp->minor >= 0) { lv->major = lp->major; lv->minor = lp->minor; lv->status |= FIXED_MINOR; @@ -4000,8 +4049,12 @@ if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size, lp->mirrors, lp->region_size, - lp->extents, lp->pvh, lp->alloc)) - return_0; + seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents, + seg_is_thin_volume(lp) ? lp->pool : NULL, lp->pvh, lp->alloc)) + return_NULL; + + if (seg_is_thin_pool(lp) && lp->zero) + first_seg(lv)->zero_new_blocks = 1; if (lp->log_count && !seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) { @@ -4015,7 +4068,7 @@ /* store vg on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) - return_0; + return_NULL; backup(vg); @@ -4038,12 +4091,12 @@ log_error("Failed to activate new LV."); if (lp->zero) goto deactivate_and_revert_new_lv; - return 0; + return NULL; } - if (!lp->zero && !lp->snapshot) + if (!seg_is_thin(lp) && !lp->zero && !lp->snapshot) log_warn("WARNING: \"%s\" not zeroed", lv->name); - else if (!set_lv(cmd, lv, UINT64_C(0), 0)) { + else if (!seg_is_thin(lp) && !set_lv(cmd, lv, UINT64_C(0), 0)) { log_error("Aborting. Failed to wipe %s.", lp->snapshot ? "snapshot exception store" : "start of new LV"); @@ -4059,7 +4112,7 @@ if (!origin_active && !deactivate_lv(cmd, lv)) { log_error("Aborting. Couldn't deactivate snapshot " "COW area. Manual intervention required."); - return 0; + return NULL; } /* A virtual origin must be activated explicitly. */ @@ -4085,40 +4138,33 @@ /* store vg on disk(s) */ if (!vg_write(vg)) - return_0; + return_NULL; if (!suspend_lv(cmd, org)) { log_error("Failed to suspend origin %s", org->name); vg_revert(vg); - return 0; + return NULL; } if (!vg_commit(vg)) - return_0; + return_NULL; if (!resume_lv(cmd, org)) { log_error("Problem reactivating origin %s", org->name); - return 0; + return NULL; } } /* FIXME out of sequence */ backup(vg); out: - log_print("Logical volume \"%s\" created", lv->name); - - /* - * FIXME: as a sanity check we could try reading the - * last block of the device ? - */ - - return 1; + return lv; deactivate_and_revert_new_lv: if (!deactivate_lv(cmd, lv)) { log_error("Unable to deactivate failed new LV. " "Manual intervention required."); - return 0; + return NULL; } revert_new_lv: @@ -4129,6 +4175,37 @@ else backup(vg); - return 0; + return NULL; } +int lv_create_single(struct volume_group *vg, + struct lvcreate_params *lp) +{ + struct logical_volume *lv; + + /* Create thin pool first if necessary */ + if (lp->create_thin_pool) { + if (!seg_is_thin_pool(lp) && + !(lp->segtype = get_segtype_from_string(vg->cmd, "thin_pool"))) + return_0; + + if (!(lv = _lv_create_an_lv(vg, lp, lp->pool))) + return_0; + + if (!lp->thin) + goto out; + + lp->pool = lv->name; + + if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin"))) + return_0; + } + + if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name))) + return_0; + +out: + log_print("Logical volume \"%s\" created", lv->name); + + return 1; +} --- LVM2/lib/metadata/merge.c 2011/08/02 22:07:22 1.45 +++ LVM2/lib/metadata/merge.c 2011/09/06 00:26:43 1.46 @@ -313,7 +313,7 @@ if (!(split_seg = alloc_lv_segment(lv->vg->vgmem, seg->segtype, seg->lv, seg->le, seg->len, seg->status, seg->stripe_size, - seg->log_lv, + seg->log_lv, seg->thin_pool_lv, seg->area_count, seg->area_len, seg->chunk_size, seg->region_size, seg->extents_copied, seg->pvmove_source_seg))) { --- LVM2/lib/metadata/metadata-exported.h 2011/08/26 17:40:53 1.203 +++ LVM2/lib/metadata/metadata-exported.h 2011/09/06 00:26:43 1.204 @@ -513,7 +513,7 @@ const struct segment_type *segtype, uint32_t stripes, uint32_t stripe_size, uint32_t mirrors, uint32_t region_size, - uint32_t extents, + uint32_t extents, const char *thin_pool_name, struct dm_list *allocatable_pvs, alloc_policy_t alloc); /* lv must be part of lv->vg->lvs */ @@ -556,8 +556,8 @@ int activation_monitoring; /* all */ activation_change_t activate; /* non-snapshot, non-mirror */ - char *origin; /* snap */ - char *pool; /* thin */ + const char *origin; /* snap */ + const char *pool; /* thin */ const char *vg_name; /* all */ const char *lv_name; /* all */ --- LVM2/lib/misc/lvm-string.c 2011/08/30 14:55:18 1.29 +++ LVM2/lib/misc/lvm-string.c 2011/09/06 00:26:43 1.30 @@ -137,6 +137,18 @@ return 0; } + if (strstr(name, "_tdata")) { + log_error("Names including \"_tpool\" are reserved. " + "Please choose a different LV name."); + return 0; + } + + if (strstr(name, "_tmeta")) { + log_error("Names including \"_tpool\" are reserved. " + "Please choose a different LV name."); + return 0; + } + return 1; } --- LVM2/lib/thin/thin.c 2011/09/01 10:16:32 1.7 +++ LVM2/lib/thin/thin.c 2011/09/06 00:26:43 1.8 @@ -201,7 +201,8 @@ uint32_t flags; } reg_segtypes[] = { { &_thin_pool_ops, "thin_pool", SEG_THIN_POOL }, - { &_thin_ops, "thin", SEG_THIN_VOLUME } + /* FIXME Maybe use SEG_THIN_VOLUME instead of SEG_VIRTUAL */ + { &_thin_ops, "thin", SEG_THIN_VOLUME | SEG_VIRTUAL } }; struct segment_type *segtype; --- LVM2/man/lvcreate.8.in 2011/08/17 15:15:37 1.21 +++ LVM2/man/lvcreate.8.in 2011/09/06 00:26:43 1.22 @@ -32,11 +32,13 @@ [\-\-noudevsync] [\-\-ignoremonitoring] [\-\-monitor {y|n}] -\-n|\-\-name SnapshotLogicalVolumeName +[--thinpool ThinPoolLogicalVolumeName] +[\-n|\-\-name SnapshotLogicalVolumeName] {{\-s|\-\-snapshot} OriginalLogicalVolumePath | [\-s|\-\-snapshot] -VolumeGroupName \-V|\-\-virtualsize VirtualSize} +VolumeGroupName \-V|\-\-virtualsize VirtualSize | +-T VolumeGroupName[/ThinPoolLogicalVolumeName] \-V|\-\-virtualsize VirtualSize} .SH DESCRIPTION lvcreate creates a new logical volume in a volume group ( see .B vgcreate(8), vgchange(8) --- LVM2/tools/args.h 2011/08/18 19:38:27 1.83 +++ LVM2/tools/args.h 2011/09/06 00:26:43 1.84 @@ -71,6 +71,7 @@ arg(poll_ARG, '\0', "poll", yes_no_arg, 0) arg(stripes_long_ARG, '\0', "stripes", int_arg, 0) arg(sysinit_ARG, '\0', "sysinit", NULL, 0) +arg(thinpool_ARG, '\0', "thinpool", string_arg, 0) /* Allow some variations */ arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0) @@ -133,6 +134,7 @@ arg(stdin_ARG, 's', "stdin", NULL, 0) arg(snapshot_ARG, 's', "snapshot", NULL, 0) arg(short_ARG, 's', "short", NULL, 0) +arg(thin_ARG, 'T', "thin", NULL, 0) arg(test_ARG, 't', "test", NULL, 0) arg(uuid_ARG, 'u', "uuid", NULL, 0) arg(uuidstr_ARG, 'u', "uuid", string_arg, 0) --- LVM2/tools/commands.h 2011/08/18 19:38:27 1.161 +++ LVM2/tools/commands.h 2011/09/06 00:26:43 1.162 @@ -177,6 +177,8 @@ "lvcreate \n" "\t{ {-s|--snapshot} OriginalLogicalVolume[Path] |\n" "\t [-s|--snapshot] VolumeGroupName[Path] -V|--virtualsize VirtualSize}\n" + "\t {-T|--thin} VolumeGroupName[Path][/PoolLogicalVolume] \n" + "\t -V|--virtualsize VirtualSize}\n" "\t[-c|--chunksize]\n" "\t[-A|--autobackup {y|n}]\n" "\t[--addtag Tag]\n" @@ -195,6 +197,7 @@ "\t[-p|--permission {r|rw}]\n" "\t[-r|--readahead ReadAheadSectors|auto|none]\n" "\t[-t|--test]\n" + "\t[--thinpool] PoolLogicalVolume\n" "\t[-v|--verbose]\n" "\t[--version]\n" @@ -205,7 +208,8 @@ minor_ARG, mirrorlog_ARG, mirrors_ARG, monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG, permission_ARG, persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG, stripes_ARG, stripesize_ARG, - test_ARG, type_ARG, virtualoriginsize_ARG, virtualsize_ARG, zero_ARG) + test_ARG, thin_ARG, thinpool_ARG, type_ARG, virtualoriginsize_ARG, + virtualsize_ARG, zero_ARG) xx(lvdisplay, "Display information about a logical volume", --- LVM2/tools/lvcreate.c 2011/08/12 02:16:46 1.234 +++ LVM2/tools/lvcreate.c 2011/09/06 00:26:43 1.235 @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -25,6 +25,24 @@ int pv_count; }; +static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name) +{ + /* Can't do anything */ + if (!vg_name) + return 1; + + /* If VG name already known, ensure this 2nd copy is identical */ + if (lp->vg_name && strcmp(lp->vg_name, vg_name)) { + log_error("Inconsistent volume group names " + "given: \"%s\" and \"%s\"", + lp->vg_name, vg_name); + return 0; + } + lp->vg_name = vg_name; + + return 1; +} + static int _lvcreate_name_params(struct lvcreate_params *lp, struct cmd_context *cmd, int *pargc, char ***pargv) @@ -33,38 +51,88 @@ char **argv = *pargv, *ptr; const char *vg_name; + lp->pool = arg_str_value(cmd, thinpool_ARG, NULL); + + /* If --thinpool contains VG name, extract it. */ + if (lp->pool && strchr(lp->pool, '/')) { + if (!(lp->vg_name = extract_vgname(cmd, lp->pool))) + return 0; + /* Strip VG from pool */ + if ((ptr = strrchr(lp->pool, (int) '/'))) + lp->pool = ptr + 1; + } + lp->lv_name = arg_str_value(cmd, name_ARG, NULL); + /* If --name contains VG name, extract it. */ + if (lp->lv_name && strchr(lp->lv_name, '/')) { + if (!_set_vg_name(lp, extract_vgname(cmd, lp->lv_name))) + return_0; + + /* Strip VG from lv_name */ + if ((ptr = strrchr(lp->lv_name, (int) '/'))) + lp->lv_name = ptr + 1; + } + + /* Need an origin? */ if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) { + /* argv[0] might be origin or vg/origin */ if (!argc) { log_error("Please specify a logical volume to act as " "the snapshot origin."); return 0; } - lp->origin = argv[0]; - (*pargv)++, (*pargc)--; - if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) { + lp->origin = skip_dev_dir(cmd, argv[0], NULL); + if (strrchr(lp->origin, '/')) { + if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin))) + return_0; + + /* Strip the volume group from the origin */ + if ((ptr = strrchr(lp->origin, (int) '/'))) + lp->origin = ptr + 1; + } + + if (!lp->vg_name) { log_error("The origin name should include the " "volume group."); return 0; } - /* Strip the volume group from the origin */ - if ((ptr = strrchr(lp->origin, (int) '/'))) - lp->origin = ptr + 1; + (*pargv)++, (*pargc)--; + } else if (seg_is_thin(lp) && !lp->pool && argc) { + /* argv[0] might be vg or vg/Pool */ + + vg_name = skip_dev_dir(cmd, argv[0], NULL); + if (!strrchr(vg_name, '/')) { + if (!_set_vg_name(lp, vg_name)) + return_0; + } else { + lp->pool = vg_name; + if (!_set_vg_name(lp, extract_vgname(cmd, lp->pool))) + return_0; + + if (!lp->vg_name) { + log_error("The pool name should include the " + "volume group."); + return 0; + } + + /* Strip the volume group */ + if ((ptr = strrchr(lp->pool, (int) '/'))) + lp->pool = ptr + 1; + } + (*pargv)++, (*pargc)--; } else { /* - * If VG not on command line, try -n arg and then - * environment. + * If VG not on command line, try environment default. */ if (!argc) { - if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) { + if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) { log_error("Please provide a volume group name"); return 0; } - } else { vg_name = skip_dev_dir(cmd, argv[0], NULL); if (strrchr(vg_name, '/')) { @@ -73,25 +141,9 @@ return 0; } - /* - * Ensure lv_name doesn't contain a - * different VG. - */ - if (lp->lv_name && strchr(lp->lv_name, '/')) { - if (!(lp->vg_name = - extract_vgname(cmd, lp->lv_name))) - return 0; - - if (strcmp(lp->vg_name, vg_name)) { - log_error("Inconsistent volume group " - "names " - "given: \"%s\" and \"%s\"", - lp->vg_name, vg_name); - return 0; - } - } + if (!_set_vg_name(lp, vg_name)) + return_0; - lp->vg_name = vg_name; (*pargv)++, (*pargc)--; } } @@ -103,9 +155,6 @@ } if (lp->lv_name) { - if ((ptr = strrchr(lp->lv_name, '/'))) - lp->lv_name = ptr + 1; - if (!apply_lvname_restrictions(lp->lv_name)) return_0; @@ -116,6 +165,54 @@ } } + if (lp->pool) { + if (!apply_lvname_restrictions(lp->pool)) + return_0; + + if (!validate_name(lp->pool)) { + log_error("Logical volume name \"%s\" is invalid", + lp->pool); + return 0; + } + + if (lp->lv_name && !strcmp(lp->lv_name, lp->pool)) { + log_error("Logical volume name %s and pool name %s must be different.", + lp->lv_name, lp->pool); + return 0; + } + } + + return 1; +} + +/* + * Normal snapshot or thinly-provisioned snapshot? + */ +static int _determine_snapshot_type(struct volume_group *vg, + struct lvcreate_params *lp) +{ + struct lv_list *lvl; + struct lv_segment *seg; + + if (!(lvl = find_lv_in_vg(vg, lp->origin))) { + log_error("Snapshot origin LV %s not found in Volume group %s.", lp->origin, vg->name); + return 0; + } + + /* FIXME Replace with lv_is_thin_volume() once more flags are added */ + if (seg_is_thin_volume(seg = first_seg(lvl->lv))) { + lp->thin = 1; + if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin"))) + return_0; + + lp->pool = seg->thin_pool_lv->name; + } + + if (!lp->thin && !arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) { + log_error("Please specify either size or extents with snapshots."); + return 0; + } + return 1; } @@ -195,11 +292,16 @@ struct lvcreate_cmdline_params *lcp, struct cmd_context *cmd) { - if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) { + if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) { log_error("Please specify either size or extents (not both)"); return 0; } + if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) { + log_error("Please specify either size or extents"); + return 0; + } + if (arg_count(cmd, extents_ARG)) { if (arg_sign_value(cmd, extents_ARG, 0) == SIGN_MINUS) { log_error("Negative number of extents is invalid"); @@ -219,8 +321,16 @@ lcp->percent = PERCENT_NONE; } + /* If size/extents given with thin, then we are creating a thin pool */ + if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG))) + lp->create_thin_pool = 1; + /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, virtualsize_ARG)) { + if (seg_is_thin_pool(lp)) { + log_error("Virtual size in incompatible with thin_pool segment type."); + return 0; + } if (arg_sign_value(cmd, virtualsize_ARG, 0) == SIGN_MINUS) { log_error("Negative virtual origin size is invalid"); return 0; @@ -231,6 +341,12 @@ log_error("Virtual origin size may not be zero"); return 0; } + } else { + /* No virtual size given, so no thin LV to create. */ + if (!seg_is_thin_pool(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin_pool"))) + return_0; + + lp->thin = 0; } return 1; @@ -357,7 +473,87 @@ * that by checking and warning if they aren't set. */ if (!lp->region_size) { - log_error("Programmer error: lp->region_size not set."); + log_error(INTERNAL_ERROR "region_size not set."); + return 0; + } + + return 1; +} + +static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd) +{ + unsigned pagesize; + + lp->activate = arg_uint_value(cmd, available_ARG, CHANGE_AY); + + if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) { + if (lp->zero && !seg_is_thin(lp)) { + log_error("--available n requires --zero n"); + return 0; + } + } + + /* + * Read ahead. + */ + lp->read_ahead = arg_uint_value(cmd, readahead_ARG, + cmd->default_settings.read_ahead); + pagesize = lvm_getpagesize() >> SECTOR_SHIFT; + if (lp->read_ahead != DM_READ_AHEAD_AUTO && + lp->read_ahead != DM_READ_AHEAD_NONE && + lp->read_ahead % pagesize) { + if (lp->read_ahead < pagesize) + lp->read_ahead = pagesize; + else + lp->read_ahead = (lp->read_ahead / pagesize) * pagesize; + log_warn("WARNING: Overriding readahead to %u sectors, a multiple " + "of %uK page size.", lp->read_ahead, pagesize >> 1); + } + + /* + * Permissions. + */ + lp->permission = arg_uint_value(cmd, permission_ARG, + LVM_READ | LVM_WRITE); + + if (lp->thin && !(lp->permission & LVM_WRITE)) { + log_error("Read-only thin volumes are not currently supported."); + return 0; + } + + /* Must not zero read only volume */ + if (!(lp->permission & LVM_WRITE)) + lp->zero = 0; + + lp->minor = arg_int_value(cmd, minor_ARG, -1); + lp->major = arg_int_value(cmd, major_ARG, -1); + + /* Persistent minor */ + if (arg_count(cmd, persistent_ARG)) { + if (lp->create_thin_pool && !lp->thin) { + log_error("--persistent is not permitted when creating a thin pool device."); + return 0; + } + if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) { + if (lp->minor == -1) { + log_error("Please specify minor number with " + "--minor when using -My"); + return 0; + } + if (lp->major == -1) { + log_error("Please specify major number with " + "--major when using -My"); + return 0; + } + } else { + if ((lp->minor != -1) || (lp->major != -1)) { + log_error("--major and --minor incompatible " + "with -Mn"); + return 0; + } + } + } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) { + log_error("--major and --minor require -My"); return 0; } @@ -370,7 +566,6 @@ int argc, char **argv) { int contiguous; - unsigned pagesize; struct arg_value_group_list *current_group; const char *segtype_str; const char *tag; @@ -382,16 +577,36 @@ /* * Check selected options are compatible and determine segtype */ - segtype_str = "striped"; + if (arg_count(cmd, thin_ARG) && arg_count(cmd,mirrors_ARG)) { + log_error("--thin and --mirrors are incompatible."); + return 0; + } + + /* Set default segtype */ if (arg_count(cmd, mirrors_ARG)) segtype_str = find_config_tree_str(cmd, "global/mirror_segtype_default", DEFAULT_MIRROR_SEGTYPE); + else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) + segtype_str = "thin"; + else + segtype_str = "striped"; lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, segtype_str)); if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) || - arg_count(cmd, virtualsize_ARG)) + (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG))) lp->snapshot = 1; + if (seg_is_thin_pool(lp)) { + if (lp->snapshot) { + log_error("Snapshots are incompatible with thin_pool segment_type."); + return 0; + } + lp->create_thin_pool = 1; + } + + if (seg_is_thin_volume(lp)) + lp->thin = 1; + lp->mirrors = 1; /* Default to 2 mirrored areas if '--type mirror|raid1' */ @@ -408,31 +623,9 @@ } } - if (lp->snapshot) { - if (arg_count(cmd, zero_ARG)) { - log_error("-Z is incompatible with snapshots"); - return 0; - } - if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) { - log_error("Negative chunk size is invalid"); - return 0; - } - lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8); - if (lp->chunk_size < 8 || lp->chunk_size > 1024 || - (lp->chunk_size & (lp->chunk_size - 1))) { - log_error("Chunk size must be a power of 2 in the " - "range 4K to 512K"); - return 0; - } - log_verbose("Setting chunksize to %d sectors.", lp->chunk_size); - - if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) - return_0; - } else { - if (arg_count(cmd, chunksize_ARG)) { - log_error("-c is only available with snapshots"); - return 0; - } + if (lp->snapshot && arg_count(cmd, zero_ARG)) { + log_error("-Z is incompatible with snapshots"); + return 0; } if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) { @@ -476,34 +669,39 @@ !_read_raid_params(lp, cmd)) return_0; - lp->activate = arg_uint_value(cmd, available_ARG, CHANGE_AY); - - /* - * Should we zero the lv. - */ - lp->zero = strcmp(arg_str_value(cmd, zero_ARG, - (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); + if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG)) + log_warn("WARNING: Ignoring --chunksize with thin snapshots."); + else if (lp->thin && !lp->create_thin_pool) { + if (arg_count(cmd, chunksize_ARG)) + log_warn("WARNING: Ignoring --chunksize when using an existing pool."); + } else if (lp->snapshot || lp->create_thin_pool) { + if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) { + log_error("Negative chunk size is invalid"); + return 0; + } + lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8); + if (lp->chunk_size < 8 || lp->chunk_size > 1024 || + (lp->chunk_size & (lp->chunk_size - 1))) { + log_error("Chunk size must be a power of 2 in the " + "range 4K to 512K"); + return 0; + } + log_verbose("Setting chunksize to %d sectors.", lp->chunk_size); - if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) { - if (lp->zero) { - log_error("--available n requires --zero n"); + if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) + return_0; + } else { + if (arg_count(cmd, chunksize_ARG)) { + log_error("-c is only available with snapshots and thin pools"); return 0; } } /* - * Alloc policy + * Should we zero the lv. */ - contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); - - lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; - - lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc); - - if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) { - log_error("Conflicting contiguous and alloc arguments"); - return 0; - } + lp->zero = strcmp(arg_str_value(cmd, zero_ARG, + (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) { log_error("Only up to %d images in mirror supported currently.", @@ -511,58 +709,20 @@ return 0; } - /* - * Read ahead. - */ - lp->read_ahead = arg_uint_value(cmd, readahead_ARG, - cmd->default_settings.read_ahead); - pagesize = lvm_getpagesize() >> SECTOR_SHIFT; - if (lp->read_ahead != DM_READ_AHEAD_AUTO && - lp->read_ahead != DM_READ_AHEAD_NONE && - lp->read_ahead % pagesize) { - if (lp->read_ahead < pagesize) - lp->read_ahead = pagesize; - else - lp->read_ahead = (lp->read_ahead / pagesize) * pagesize; - log_warn("WARNING: Overriding readahead to %u sectors, a multiple " - "of %uK page size.", lp->read_ahead, pagesize >> 1); - } + if (!_read_activation_params(lp, cmd)) + return_0; /* - * Permissions. + * Allocation parameters */ - lp->permission = arg_uint_value(cmd, permission_ARG, - LVM_READ | LVM_WRITE); + contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); - /* Must not zero read only volume */ - if (!(lp->permission & LVM_WRITE)) - lp->zero = 0; + lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; - lp->minor = arg_int_value(cmd, minor_ARG, -1); - lp->major = arg_int_value(cmd, major_ARG, -1); + lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc); - /* Persistent minor */ - if (arg_count(cmd, persistent_ARG)) { - if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) { - if (lp->minor == -1) { - log_error("Please specify minor number with " - "--minor when using -My"); - return 0; - } - if (lp->major == -1) { - log_error("Please specify major number with " - "--major when using -My"); - return 0; - } - } else { - if ((lp->minor != -1) || (lp->major != -1)) { - log_error("--major and --minor incompatible " - "with -Mn"); - return 0; - } - } - } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) { - log_error("--major and --minor require -My"); + if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) { + log_error("Conflicting contiguous and alloc arguments"); return 0; } @@ -576,10 +736,10 @@ } if (!str_list_add(cmd->mem, &lp->tags, tag)) { - log_error("Unable to allocate memory for tag %s", tag); + log_error("Unable to allocate memory for tag %s", tag); return 0; } - } + } lcp->pv_count = argc; lcp->pvs = argv; @@ -587,6 +747,140 @@ return 1; } +static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp, + struct lvcreate_cmdline_params *lcp) +{ + struct lv_list *lvl; + + if (!lp->thin && !lp->create_thin_pool) { + log_error("Please specify device size(s)."); + return 0; + } + + if (lp->thin && !lp->create_thin_pool) { + if (arg_count(vg->cmd, chunksize_ARG)) { + log_error("Only specify --chunksize when originally creating the thin pool."); + return 0; + } + + if (lcp->pv_count) { + log_error("Only specify Physical volumes when allocating the thin pool."); + return 0; + } + + if (arg_count(vg->cmd, alloc_ARG)) { + log_error("--alloc may only be specified when allocating the thin pool."); + return 0; + } + + if (arg_count(vg->cmd, stripesize_ARG)) { + log_error("--stripesize may only be specified when allocating the thin pool."); + return 0; + } + + if (arg_count(vg->cmd, stripes_ARG)) { + log_error("--stripes may only be specified when allocating the thin pool."); + return 0; + } + + if (arg_count(vg->cmd, contiguous_ARG)) { + log_error("--contiguous may only be specified when allocating the thin pool."); + return 0; + } + + if (arg_count(vg->cmd, zero_ARG)) { + log_error("--zero may only be specified when allocating the thin pool."); + return 0; + } + } + + if (lp->create_thin_pool && lp->pool) { + if (find_lv_in_vg(vg, lp->pool)) { + log_error("Pool %s already exists in Volume group %s.", lp->pool, vg->name); + return 0; + } + } else if (lp->pool) { + if (!(lvl = find_lv_in_vg(vg, lp->pool))) { + log_error("Pool %s not found in Volume group %s.", lp->pool, vg->name); + return 0; + } + /* FIXME Use lv_is_thin_pool() */ + if (!seg_is_thin_pool(first_seg(lvl->lv))) { + log_error("Logical volume %s is not a thin pool.", lp->pool); + return 0; + } + } else if (!lp->create_thin_pool) { + log_error("Please specify name of existing pool."); + return 0; + } + + if (!lp->thin && lp->lv_name) { + log_error("--name may only be given when creating a new thin Logical volume or snapshot."); + return 0; + } + + if (!lp->thin) { + if (arg_count(vg->cmd, readahead_ARG)) { + log_error("--readhead may only be given when creating a new thin Logical volume or snapshot."); + return 0; + } + if (arg_count(vg->cmd, permission_ARG)) { + log_error("--permission may only be given when creating a new thin Logical volume or snapshot."); + return 0; + } + if (arg_count(vg->cmd, persistent_ARG)) { + log_error("--persistent may only be given when creating a new thin Logical volume or snapshot."); + return 0; + } + } + + return 1; +} + +/* + * Ensure the set of thin parameters extracted from the command line is consistent. + */ +static int _validate_internal_thin_processing(const struct lvcreate_params *lp) +{ + int r = 1; + + /* + The final state should be one of: + thin create_thin_pool snapshot origin pool + 1 1 0 0 y/n - create new pool and a thin LV in it + 1 0 0 0 y - create new thin LV in existing pool + 0 1 0 0 y/n - create new pool only + 1 0 1 1 y - create thin snapshot of existing thin LV + */ + + if (!lp->create_thin_pool && !lp->pool) { + log_error(INTERNAL_ERROR "--thinpool not identified."); + r = 0; + } + + if ((lp->snapshot && !lp->origin) || (!lp->snapshot && lp->origin)) { + log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified."); + r = 0; + } + + if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) { + log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified."); + r = 0; + } + + if (!lp->thin && !lp->create_thin_pool) { + log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use."); + r = 0; + } + + if (seg_is_thin_pool(lp) && lp->thin) { + log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type."); + r = 0; + } + + return r; +} + int lvcreate(struct cmd_context *cmd, int argc, char **argv) { int r = ECMD_PROCESSED; @@ -605,11 +899,43 @@ return ECMD_FAILED; } + if (lp.snapshot && !_determine_snapshot_type(vg, &lp)) { + r = ECMD_FAILED; + goto_out; + } + + if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) { + r = ECMD_FAILED; + goto_out; + } + if (!_update_extents_params(vg, &lp, &lcp)) { r = ECMD_FAILED; goto_out; } + if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) { + r = ECMD_FAILED; + goto_out; + } + + if (lp.create_thin_pool) + log_verbose("Making thin pool %s in VG %s using segtype %s", + lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name); + + if (lp.thin) + log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s", + lp.lv_name ? : "with generated name", + lp.pool, lp.vg_name, lp.snapshot ? " as snapshot of " : "", + lp.snapshot ? lp.origin : "", lp.segtype->name); + + /* FIXME Remove when thin snapshots are supported. */ + if (lp.thin && lp.snapshot) { + log_error("Thin snapshots are not yet supported."); + r = ECMD_FAILED; + goto_out; + } + if (!lv_create_single(vg, &lp)) { stack; r = ECMD_FAILED; --- LVM2/tools/lvresize.c 2011/08/10 20:25:31 1.134 +++ LVM2/tools/lvresize.c 2011/09/06 00:26:43 1.135 @@ -707,7 +707,7 @@ !lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size, lp->mirrors, first_seg(lv)->region_size, - lp->extents - lv->le_count, + lp->extents - lv->le_count, NULL, pvh, alloc)) { stack; return ECMD_FAILED;