mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
7c921f18e2
Only later validation can decide if the volume is actually restricted from being resized (unlike in lvcreate time).
206 lines
5.6 KiB
C
206 lines
5.6 KiB
C
/*
|
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
|
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* This file is part of LVM2.
|
|
*
|
|
* This copyrighted material is made available to anyone wishing to use,
|
|
* modify, copy, or redistribute it subject to the terms and conditions
|
|
* of the GNU Lesser General Public License v.2.1.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "tools.h"
|
|
|
|
static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
|
|
struct lvresize_params *lp)
|
|
{
|
|
const char *cmd_name = command_name(cmd);
|
|
const char *type_str = arg_str_value(cmd, type_ARG, NULL);
|
|
|
|
if (type_str && (lp->segtype = get_segtype_from_string(cmd, type_str)))
|
|
return_0;
|
|
|
|
if (!strcmp(cmd_name, "lvreduce"))
|
|
lp->resize = LV_REDUCE;
|
|
else if (!strcmp(cmd_name, "lvextend"))
|
|
lp->resize = LV_EXTEND;
|
|
else
|
|
lp->resize = LV_ANY;
|
|
|
|
lp->sign = lp->poolmetadata_sign = SIGN_NONE;
|
|
|
|
if ((lp->use_policies = arg_is_set(cmd, usepolicies_ARG))) {
|
|
/* do nothing; lv_resize will handle --use-policies itself */
|
|
if (arg_from_list_is_set(cmd, NULL,
|
|
chunksize_ARG, extents_ARG,
|
|
poolmetadatasize_ARG,
|
|
regionsize_ARG,
|
|
size_ARG,
|
|
stripes_ARG, stripesize_ARG,
|
|
-1))
|
|
log_print_unless_silent("Ignoring size parameters with --use-policies.");
|
|
} else {
|
|
/*
|
|
* Allow omission of extents and size if the user has given us
|
|
* one or more PVs. Most likely, the intent was "resize this
|
|
* LV the best you can with these PVs"
|
|
* If only --poolmetadatasize is specified with list of PVs,
|
|
* then metadata will be extended there.
|
|
*/
|
|
if ((lp->extents = arg_uint_value(cmd, extents_ARG, 0))) {
|
|
lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
|
|
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
|
|
}
|
|
|
|
if (arg_from_list_is_zero(cmd, "may not be zero",
|
|
chunksize_ARG, extents_ARG,
|
|
poolmetadatasize_ARG,
|
|
regionsize_ARG,
|
|
size_ARG,
|
|
stripes_ARG, stripesize_ARG,
|
|
virtualsize_ARG,
|
|
-1))
|
|
return_0;
|
|
|
|
if ((lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0))) {
|
|
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
|
|
if (lp->poolmetadata_sign == SIGN_MINUS) {
|
|
log_error("Can't reduce pool metadata size.");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ((lp->size = arg_uint64_value(cmd, size_ARG, 0))) {
|
|
lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
|
|
lp->percent = PERCENT_NONE;
|
|
}
|
|
|
|
if (lp->size && lp->extents) {
|
|
log_error("Please specify either size or extents but not both.");
|
|
return 0;
|
|
}
|
|
|
|
if (!lp->extents &&
|
|
!lp->size &&
|
|
!lp->poolmetadata_size &&
|
|
(argc >= 2)) {
|
|
lp->extents = 100;
|
|
lp->percent = PERCENT_PVS;
|
|
lp->sign = SIGN_PLUS;
|
|
}
|
|
}
|
|
|
|
if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
|
|
log_error("Negative argument not permitted - use lvreduce.");
|
|
return 0;
|
|
}
|
|
|
|
if (lp->resize == LV_REDUCE &&
|
|
((lp->sign == SIGN_PLUS) ||
|
|
(lp->poolmetadata_sign == SIGN_PLUS))) {
|
|
log_error("Positive sign not permitted - use lvextend.");
|
|
return 0;
|
|
}
|
|
|
|
if (!argc) {
|
|
log_error("Please provide the logical volume name.");
|
|
return 0;
|
|
}
|
|
|
|
lp->lv_name = argv[0];
|
|
|
|
if (!validate_lvname_param(cmd, &lp->vg_name, &lp->lv_name))
|
|
return_0;
|
|
|
|
/* Check for $LVM_VG_NAME */
|
|
if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) {
|
|
log_error("Please specify a logical volume path.");
|
|
return 0;
|
|
}
|
|
|
|
if ((lp->mirrors = arg_count(cmd, mirrors_ARG)) &&
|
|
(arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS)) {
|
|
log_error("Mirrors argument may not be signed.");
|
|
return 0;
|
|
}
|
|
|
|
if ((lp->stripes = arg_uint_value(cmd, stripes_ARG, 0)) &&
|
|
(arg_sign_value(cmd, stripes_ARG, SIGN_NONE) == SIGN_MINUS)) {
|
|
log_error("Stripes argument may not be negative.");
|
|
return 0;
|
|
}
|
|
|
|
if ((lp->stripe_size = arg_uint64_value(cmd, stripesize_ARG, 0)) &&
|
|
(arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS)) {
|
|
log_error("Stripesize may not be negative.");
|
|
return 0;
|
|
}
|
|
|
|
lp->argc = --argc;
|
|
lp->argv = ++argv;
|
|
|
|
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, 0);
|
|
lp->force = arg_is_set(cmd, force_ARG);
|
|
lp->nofsck = arg_is_set(cmd, nofsck_ARG);
|
|
lp->nosync = arg_is_set(cmd, nosync_ARG);
|
|
lp->resizefs = arg_is_set(cmd, resizefs_ARG);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int _lvresize_single(struct cmd_context *cmd, const char *vg_name,
|
|
struct volume_group *vg, struct processing_handle *handle)
|
|
{
|
|
struct lvresize_params *lp = (struct lvresize_params *) handle->custom_handle;
|
|
struct dm_list *pvh;
|
|
struct logical_volume *lv;
|
|
int ret = ECMD_FAILED;
|
|
|
|
/* Does LV exist? */
|
|
if (!(lv = find_lv(vg, lp->lv_name))) {
|
|
log_error("Logical volume %s not found in volume group %s.",
|
|
lp->lv_name, vg->name);
|
|
goto out;
|
|
}
|
|
|
|
if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc, lp->argv, 1) : &vg->pvs))
|
|
goto_out;
|
|
|
|
if (!lv_resize(lv, lp, pvh))
|
|
goto_out;
|
|
|
|
ret = ECMD_PROCESSED;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
|
{
|
|
struct processing_handle *handle;
|
|
struct lvresize_params lp = { 0 };
|
|
int ret;
|
|
|
|
if (!_lvresize_params(cmd, argc, argv, &lp)) {
|
|
stack;
|
|
return EINVALID_CMD_LINE;
|
|
}
|
|
|
|
if (!(handle = init_processing_handle(cmd, NULL))) {
|
|
log_error("Failed to initialize processing handle.");
|
|
return ECMD_FAILED;
|
|
}
|
|
|
|
handle->custom_handle = &lp;
|
|
|
|
ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
|
|
&_lvresize_single);
|
|
|
|
destroy_processing_handle(cmd, handle);
|
|
|
|
return ret;
|
|
}
|