1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-10-28 03:27:58 +03:00
lvm2/tools/lvresize.c
2016-02-11 18:35:07 +01:00

221 lines
5.9 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;
char *st;
int use_policy = arg_count(cmd, usepolicies_ARG);
lp->sign = SIGN_NONE;
lp->poolmetadatasign = SIGN_NONE;
lp->resize = LV_ANY;
cmd_name = command_name(cmd);
if (!strcmp(cmd_name, "lvreduce"))
lp->resize = LV_REDUCE;
if (!strcmp(cmd_name, "lvextend"))
lp->resize = LV_EXTEND;
if (use_policy) {
/* do nothing; _lvresize will handle --use-policies itself */
lp->extents = 0;
lp->sign = SIGN_PLUS;
lp->percent = PERCENT_LV;
} 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.
*/
lp->sizeargs = arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG);
if (arg_count(cmd, poolmetadatasize_ARG)) {
lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, 0);
lp->poolmetadatasign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
if (lp->poolmetadatasign == SIGN_MINUS) {
log_error("Can't reduce pool metadata size.");
return 0;
}
}
if ((lp->sizeargs == 0) && (argc >= 2)) {
lp->extents = 100;
lp->percent = PERCENT_PVS;
lp->sign = SIGN_PLUS;
lp->sizeargs = !lp->poolmetadatasize ? 1 : 0;
} else if ((lp->sizeargs != 1) &&
((lp->sizeargs == 2) ||
!arg_count(cmd, poolmetadatasize_ARG))) {
log_error("Please specify either size or extents but not "
"both.");
return 0;
}
if (arg_count(cmd, extents_ARG)) {
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);
}
/* Size returned in kilobyte units; held in sectors */
if (arg_count(cmd, size_ARG)) {
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->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->poolmetadatasign == SIGN_PLUS))) {
log_error("Positive sign not permitted - use lvextend");
return 0;
}
lp->resizefs = arg_is_set(cmd, resizefs_ARG);
lp->nofsck = arg_is_set(cmd, nofsck_ARG);
if (!argc) {
log_error("Please provide the logical volume name");
return 0;
}
lp->lv_name = argv[0];
argv++;
argc--;
if (!(lp->lv_name = skip_dev_dir(cmd, lp->lv_name, NULL)) ||
!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
log_error("Please provide a volume group name");
return 0;
}
if (!validate_name(lp->vg_name)) {
log_error("Volume group name %s has invalid characters",
lp->vg_name);
return 0;
}
if ((st = strrchr(lp->lv_name, '/')))
lp->lv_name = st + 1;
lp->argc = argc;
lp->argv = argv;
lp->ac_policy = arg_count(cmd, usepolicies_ARG);
lp->ac_stripes = arg_count(cmd, stripes_ARG);
if (lp->ac_stripes) {
lp->ac_stripes_value = arg_uint_value(cmd, stripes_ARG, 1);
} else {
lp->ac_stripes_value = 0;
}
lp->ac_mirrors = arg_count(cmd, mirrors_ARG);
if (lp->ac_mirrors) {
if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Mirrors argument may not be negative");
return 0;
}
lp->ac_mirrors_value = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
} else {
lp->ac_mirrors_value = 0;
}
lp->ac_stripesize = arg_count(cmd, stripesize_ARG);
if (lp->ac_stripesize) {
if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Stripesize may not be negative.");
return 0;
}
lp->ac_stripesize_value = arg_uint64_value(cmd, stripesize_ARG, 0);
}
lp->ac_no_sync = arg_count(cmd, nosync_ARG);
lp->ac_alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, 0);
lp->ac_type = arg_str_value(cmd, type_ARG, NULL);
lp->ac_force = arg_count(cmd, force_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, lp->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_prepare(cmd, lv, lp, pvh)) {
ret = EINVALID_CMD_LINE;
goto_out;
}
if (!lv_resize(cmd, 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 = ECMD_FAILED;
if (!_lvresize_params(cmd, argc, argv, &lp))
return EINVALID_CMD_LINE;
if (!(handle = init_processing_handle(cmd))) {
log_error("Failed to initialize processing handle.");
return ECMD_FAILED;
}
handle->custom_handle = &lp;
ret = process_each_vg(cmd, 0, NULL, lp.vg_name, READ_FOR_UPDATE, handle,
&_lvresize_single);
destroy_processing_handle(cmd, handle);
return ret;
}