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:
parent
58366c058e
commit
9ac61d2ba2
@ -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.");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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))) {
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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",
|
||||
|
598
tools/lvcreate.c
598
tools/lvcreate.c
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user