1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvcreate parsing for thin provisioning.

The rest is incomplete so this isn't usable yet.
This commit is contained in:
Alasdair Kergon 2011-09-06 00:26:42 +00:00
parent 58366c058e
commit 9ac61d2ba2
14 changed files with 656 additions and 229 deletions

View File

@ -223,7 +223,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
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 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
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.");

View File

@ -195,7 +195,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
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 @@ static int _add_linear_seg(struct dm_pool *mem,
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");

View File

@ -329,7 +329,7 @@ static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
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;

View File

@ -22,6 +22,7 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
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_mirror_lvs(struct logical_volume *lv,
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);

View File

@ -198,6 +198,22 @@ uint32_t find_free_lvnum(struct logical_volume *lv)
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 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
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 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
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 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
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 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
/* 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 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status,
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 @@ static int _allocate(struct alloc_handle *ah,
}
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 @@ static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
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 @@ static int _lv_insert_empty_sublvs(struct logical_volume *lv,
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 @@ static int _lv_insert_empty_sublvs(struct logical_volume *lv,
}
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 @@ int lv_extend(struct logical_volume *lv,
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 @@ int lv_extend(struct logical_volume *lv,
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 @@ int lv_extend(struct logical_volume *lv,
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 @@ int remove_layer_from_lv(struct logical_volume *lv,
/* 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 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
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 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
/* 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 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
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 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
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 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
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 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
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 lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
(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 @@ int lv_create_single(struct volume_group *vg,
(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 @@ int lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
"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 @@ int lv_create_single(struct volume_group *vg,
!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 @@ int lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
}
}
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 @@ int lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
/* store vg on disk(s) */
if (!vg_write(vg) || !vg_commit(vg))
return_0;
return_NULL;
backup(vg);
@ -4038,12 +4091,12 @@ int lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
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 @@ int lv_create_single(struct volume_group *vg,
/* 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 @@ revert_new_lv:
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;
}

View File

@ -313,7 +313,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
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))) {

View File

@ -513,7 +513,7 @@ int lv_extend(struct logical_volume *lv,
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 @@ struct lvcreate_params {
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 */

View File

@ -137,6 +137,18 @@ int apply_lvname_restrictions(const char *name)
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;
}

View File

@ -201,7 +201,8 @@ int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *segl
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;

View File

@ -32,11 +32,13 @@ VolumeGroupName [PhysicalVolumePath[:PE[-PE]]...]
[\-\-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)

View File

@ -71,6 +71,7 @@ arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
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(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0)
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)

View File

@ -177,6 +177,8 @@ xx(lvcreate,
"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 @@ xx(lvcreate,
"\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 @@ xx(lvcreate,
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",

View File

@ -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 @@ struct lvcreate_cmdline_params {
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 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
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 */
} else {
/*
* If VG not on command line, try -n arg and then
* environment.
*/
if (!argc) {
if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
log_error("Please provide a volume group name");
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 environment default.
*/
if (!argc) {
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 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
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 (!_set_vg_name(lp, vg_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;
}
}
lp->vg_name = vg_name;
(*pargv)++, (*pargc)--;
}
}
@ -103,9 +155,6 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
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 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
}
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 @@ static int _read_size_params(struct lvcreate_params *lp,
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 @@ static int _read_size_params(struct lvcreate_params *lp,
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 @@ static int _read_size_params(struct lvcreate_params *lp,
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 @@ static int _read_raid_params(struct lvcreate_params *lp,
* 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 @@ static int _lvcreate_params(struct lvcreate_params *lp,
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 @@ static int _lvcreate_params(struct lvcreate_params *lp,
/*
* 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 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
}
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,7 +669,33 @@ static int _lvcreate_params(struct lvcreate_params *lp,
!_read_raid_params(lp, cmd))
return_0;
lp->activate = arg_uint_value(cmd, available_ARG, CHANGE_AY);
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->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;
}
}
/*
* Should we zero the lv.
@ -484,15 +703,17 @@ static int _lvcreate_params(struct lvcreate_params *lp,
lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
(lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n");
if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) {
if (lp->zero) {
log_error("--available n requires --zero n");
return 0;
}
if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
log_error("Only up to %d images in mirror supported currently.",
DEFAULT_MIRROR_MAX_IMAGES);
return 0;
}
if (!_read_activation_params(lp, cmd))
return_0;
/*
* Alloc policy
* Allocation parameters
*/
contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
@ -505,67 +726,6 @@ static int _lvcreate_params(struct lvcreate_params *lp,
return 0;
}
if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
log_error("Only up to %d images in mirror supported currently.",
DEFAULT_MIRROR_MAX_IMAGES);
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);
/* 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 (!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;
}
dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
if (!grouped_arg_is_set(current_group->arg_values, addtag_ARG))
continue;
@ -576,10 +736,10 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
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 @@ static int _lvcreate_params(struct lvcreate_params *lp,
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 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
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;

View File

@ -707,7 +707,7 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
!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;