1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-03 05:18:29 +03:00

pvcreate: add prompt when setting dev size

If the device size does not match the size requested
by --setphysicalvolumesize, then prompt the user.

Make the pvcreate checking/prompting code handle
multiple prompts for the same device, since the
new prompt can be in addition to the existing
prompt when the PV is in a VG.
This commit is contained in:
David Teigland 2017-04-27 12:13:09 -05:00
parent 5cf51fb2f7
commit 4f9ff14508
6 changed files with 116 additions and 35 deletions

View File

@ -27,7 +27,7 @@ not grep "$CHECK_MSG" err
vgremove -ff $vg vgremove -ff $vg
# set PV size to 2x dev size # set PV size to 2x dev size
pvcreate --setphysicalvolumesize 16m $dev1 pvcreate --yes --setphysicalvolumesize 16m $dev1
vgcreate $vg $dev1 2>err vgcreate $vg $dev1 2>err
grep "$CHECK_MSG" err grep "$CHECK_MSG" err
pvs 2>err pvs 2>err
@ -36,7 +36,7 @@ vgremove -ff $vg
# should be quiet if requested # should be quiet if requested
aux lvmconf 'metadata/check_pv_device_sizes = 0' aux lvmconf 'metadata/check_pv_device_sizes = 0'
pvcreate --setphysicalvolumesize 16m $dev1 pvcreate --yes --setphysicalvolumesize 16m $dev1
vgcreate $vg $dev1 2>err vgcreate $vg $dev1 2>err
not grep "$CHECK_MSG" err not grep "$CHECK_MSG" err
pvs 2>err pvs 2>err

View File

@ -78,7 +78,7 @@ aux lvmconf "activation/snapshot_autoextend_percent = 20" \
"activation/snapshot_autoextend_threshold = 50" "activation/snapshot_autoextend_threshold = 50"
# Check usability with smallest (1k) extent size ($lv has 15P) # Check usability with smallest (1k) extent size ($lv has 15P)
pvcreate --setphysicalvolumesize 4T "$DM_DEV_DIR/$vg/$lv" pvcreate --yes --setphysicalvolumesize 4T "$DM_DEV_DIR/$vg/$lv"
trap 'cleanup_tail' EXIT trap 'cleanup_tail' EXIT
vgcreate -s 1K $vg1 "$DM_DEV_DIR/$vg/$lv" vgcreate -s 1K $vg1 "$DM_DEV_DIR/$vg/$lv"

View File

@ -402,7 +402,7 @@ arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0,
"to a thin LV. The LV being converted becomes a read-only external origin\n" "to a thin LV. The LV being converted becomes a read-only external origin\n"
"with this name.\n") "with this name.\n")
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0, arg(setphysicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0,
"Overrides the automatically detected size of the PV.\n" "Overrides the automatically detected size of the PV.\n"
"Use with care, or prior to reducing the physical size of the device.\n") "Use with care, or prior to reducing the physical size of the device.\n")

View File

@ -52,11 +52,11 @@ static int pvcreate_restore_params_from_args(struct cmd_context *cmd, int argc,
pp->pva.idp = &pp->pva.id; pp->pva.idp = &pp->pva.id;
} }
if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) { if (arg_sign_value(cmd, setphysicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical volume size may not be negative"); log_error("Physical volume size may not be negative");
return 0; return 0;
} }
pp->pva.size = arg_uint64_value(cmd, physicalvolumesize_ARG, UINT64_C(0)); pp->pva.size = arg_uint64_value(cmd, setphysicalvolumesize_ARG, UINT64_C(0));
if (arg_is_set(cmd, restorefile_ARG) || arg_is_set(cmd, uuidstr_ARG)) if (arg_is_set(cmd, restorefile_ARG) || arg_is_set(cmd, uuidstr_ARG))
pp->zero = 0; pp->zero = 0;

View File

@ -72,13 +72,13 @@ int pvresize(struct cmd_context *cmd, int argc, char **argv)
goto out; goto out;
} }
if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) { if (arg_sign_value(cmd, setphysicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical volume size may not be negative"); log_error("Physical volume size may not be negative");
ret = EINVALID_CMD_LINE; ret = EINVALID_CMD_LINE;
goto out; goto out;
} }
params.new_size = arg_uint64_value(cmd, physicalvolumesize_ARG, params.new_size = arg_uint64_value(cmd, setphysicalvolumesize_ARG,
UINT64_C(0)); UINT64_C(0));
params.done = 0; params.done = 0;

View File

@ -4751,6 +4751,7 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
enum { enum {
PROMPT_PVCREATE_PV_IN_VG = 1, PROMPT_PVCREATE_PV_IN_VG = 1,
PROMPT_PVREMOVE_PV_IN_VG = 2, PROMPT_PVREMOVE_PV_IN_VG = 2,
PROMPT_PVCREATE_DEV_SIZE = 4,
}; };
enum { enum {
@ -4767,6 +4768,8 @@ enum {
struct pvcreate_prompt { struct pvcreate_prompt {
struct dm_list list; struct dm_list list;
uint32_t type; uint32_t type;
uint64_t size;
uint64_t new_size;
const char *pv_name; const char *pv_name;
const char *vg_name; const char *vg_name;
struct device *dev; struct device *dev;
@ -4808,12 +4811,14 @@ static void _check_pvcreate_prompt(struct cmd_context *cmd,
{ {
const char *vgname = prompt->vg_name ? prompt->vg_name : "<unknown>"; const char *vgname = prompt->vg_name ? prompt->vg_name : "<unknown>";
const char *pvname = prompt->pv_name; const char *pvname = prompt->pv_name;
int answer_yes = 0;
int answer_no = 0;
/* The VG name can be unknown when the PV is used but metadata is not available */ /* The VG name can be unknown when the PV is used but metadata is not available */
if (prompt->type == PROMPT_PVCREATE_PV_IN_VG) { if (prompt->type & PROMPT_PVCREATE_PV_IN_VG) {
if (pp->force != DONT_PROMPT_OVERRIDE) { if (pp->force != DONT_PROMPT_OVERRIDE) {
prompt->answer = PROMPT_ANSWER_NO; answer_no = 1;
if (prompt->vg_name_unknown) { if (prompt->vg_name_unknown) {
log_error("PV %s is used by a VG but its metadata is missing.", pvname); log_error("PV %s is used by a VG but its metadata is missing.", pvname);
@ -4825,20 +4830,39 @@ static void _check_pvcreate_prompt(struct cmd_context *cmd,
log_error("Unable to add physical volume '%s' to volume group '%s'", pvname, vgname); log_error("Unable to add physical volume '%s' to volume group '%s'", pvname, vgname);
} }
} else if (pp->yes) { } else if (pp->yes) {
prompt->answer = PROMPT_ANSWER_YES; answer_yes = 1;
} else if (ask) { } else if (ask) {
if (yes_no_prompt("Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ", pvname, vgname) == 'n') { if (yes_no_prompt("Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ", pvname, vgname) == 'n') {
prompt->answer = PROMPT_ANSWER_NO; answer_no = 1;
log_error("%s: physical volume not initialized", pvname);
} else { } else {
prompt->answer = PROMPT_ANSWER_YES; answer_yes = 1;
log_warn("WARNING: Forcing physical volume creation on %s of volume group \"%s\"", pvname, vgname); log_warn("WARNING: Forcing physical volume creation on %s of volume group \"%s\"", pvname, vgname);
} }
} }
} else if (prompt->type == PROMPT_PVREMOVE_PV_IN_VG) { }
if (prompt->type & PROMPT_PVCREATE_DEV_SIZE) {
if (pp->yes) {
log_warn("WARNING: Faking size of PV %s. Don't write outside real device.", pvname);
answer_yes = 1;
} else if (ask) {
if (prompt->new_size != prompt->size) {
if (yes_no_prompt("WARNING: %s: device size %s does not match requested size %s. Proceed? [y/n]: ", pvname,
display_size(cmd, (uint64_t)prompt->size),
display_size(cmd, (uint64_t)prompt->new_size)) == 'n') {
answer_no = 1;
} else {
answer_yes = 1;
log_warn("WARNING: Faking size of PV %s. Don't write outside real device.", pvname);
}
}
}
}
if (prompt->type & PROMPT_PVREMOVE_PV_IN_VG) {
if (pp->force != DONT_PROMPT_OVERRIDE) { if (pp->force != DONT_PROMPT_OVERRIDE) {
prompt->answer = PROMPT_ANSWER_NO; answer_no = 1;
if (prompt->vg_name_unknown) if (prompt->vg_name_unknown)
log_error("PV %s is used by a VG but its metadata is missing.", pvname); log_error("PV %s is used by a VG but its metadata is missing.", pvname);
@ -4847,20 +4871,51 @@ static void _check_pvcreate_prompt(struct cmd_context *cmd,
log_error("(If you are certain you need pvremove, then confirm by using --force twice.)"); log_error("(If you are certain you need pvremove, then confirm by using --force twice.)");
} else if (pp->yes) { } else if (pp->yes) {
log_warn("WARNING: PV %s is used by VG %s", pvname, vgname); log_warn("WARNING: PV %s is used by VG %s", pvname, vgname);
prompt->answer = PROMPT_ANSWER_YES; answer_yes = 1;
} else if (ask) { } else if (ask) {
log_warn("WARNING: PV %s is used by VG %s", pvname, vgname); log_warn("WARNING: PV %s is used by VG %s", pvname, vgname);
if (yes_no_prompt("Really WIPE LABELS from physical volume \"%s\" of volume group \"%s\" [y/n]? ", pvname, vgname) == 'n') { if (yes_no_prompt("Really WIPE LABELS from physical volume \"%s\" of volume group \"%s\" [y/n]? ", pvname, vgname) == 'n')
prompt->answer = PROMPT_ANSWER_NO; answer_no = 1;
log_error("%s: physical volume label not removed", pvname); else
} else { answer_yes = 1;
prompt->answer = PROMPT_ANSWER_YES;
} }
} }
if ((prompt->answer == PROMPT_ANSWER_YES) && (pp->force == DONT_PROMPT_OVERRIDE)) if (answer_yes && answer_no) {
log_warn("WARNING: Wiping physical volume label from %s of volume group \"%s\"", pvname, vgname); log_warn("WARNING: prompt answer yes is overriden by prompt answer no.");
answer_yes = 0;
} }
/*
* no answer is valid when not asking the user.
* the caller uses this to check if all the prompts
* can be answered automatically without prompts.
*/
if (!ask && !answer_yes && !answer_no)
return;
if (answer_no)
prompt->answer = PROMPT_ANSWER_NO;
else if (answer_yes)
prompt->answer = PROMPT_ANSWER_YES;
/*
* Mostly historical messages. Other messages above could be moved
* here to separate the answer logic from the messages.
*/
if ((prompt->type & (PROMPT_PVCREATE_DEV_SIZE | PROMPT_PVCREATE_PV_IN_VG)) &&
(prompt->answer == PROMPT_ANSWER_NO))
log_error("%s: physical volume not initialized.", pvname);
if ((prompt->type & PROMPT_PVREMOVE_PV_IN_VG) &&
(prompt->answer == PROMPT_ANSWER_NO))
log_error("%s: physical volume label not removed.", pvname);
if ((prompt->type & PROMPT_PVREMOVE_PV_IN_VG) &&
(prompt->answer == PROMPT_ANSWER_YES) &&
(pp->force == DONT_PROMPT_OVERRIDE))
log_warn("WARNING: Wiping physical volume label from %s of volume group \"%s\".", pvname, vgname);
} }
static struct pvcreate_device *_pvcreate_list_find_dev(struct dm_list *devices, struct device *dev) static struct pvcreate_device *_pvcreate_list_find_dev(struct dm_list *devices, struct device *dev)
@ -4912,6 +4967,10 @@ static int _pvcreate_check_single(struct cmd_context *cmd,
struct pvcreate_params *pp = (struct pvcreate_params *) handle->custom_handle; struct pvcreate_params *pp = (struct pvcreate_params *) handle->custom_handle;
struct pvcreate_device *pd; struct pvcreate_device *pd;
struct pvcreate_prompt *prompt; struct pvcreate_prompt *prompt;
uint64_t size = 0;
uint64_t new_size = 0;
int need_size_prompt = 0;
int need_vg_prompt = 0;
int found = 0; int found = 0;
if (!pv->dev) if (!pv->dev)
@ -4996,35 +5055,57 @@ static int _pvcreate_check_single(struct cmd_context *cmd,
pd->is_not_pv = 1; pd->is_not_pv = 1;
} }
if (arg_is_set(cmd, setphysicalvolumesize_ARG)) {
new_size = arg_uint64_value(cmd, setphysicalvolumesize_ARG, UINT64_C(0));
if (!dev_get_size(pv->dev, &size)) {
log_error("Can't get device size of %s.", pv_dev_name(pv));
dm_list_move(&pp->arg_fail, &pd->list);
return 1;
} else if (new_size != size)
need_size_prompt = 1;
}
/* /*
* pvcreate is being run on this device, and it's not a PV, * pvcreate is being run on this device, and it's not a PV,
* or is an orphan PV. Neither case requires a prompt. * or is an orphan PV. Neither case requires a prompt.
* Or, pvcreate is being run on this device, but the device
* is already a PV in a VG. A prompt or force option is required
* to use it.
*/ */
if (pd->is_orphan_pv || pd->is_not_pv) { if (pd->is_orphan_pv || pd->is_not_pv)
need_vg_prompt = 0;
else
need_vg_prompt = 1;
if (!need_size_prompt && !need_vg_prompt) {
pd->dev = pv->dev; pd->dev = pv->dev;
dm_list_move(&pp->arg_process, &pd->list); dm_list_move(&pp->arg_process, &pd->list);
return 1; return 1;
} }
/*
* pvcreate is being run on this device, but the device is already
* a PV in a VG. A prompt or force option is required to use it.
*/
if (!(prompt = dm_pool_zalloc(cmd->mem, sizeof(*prompt)))) { if (!(prompt = dm_pool_zalloc(cmd->mem, sizeof(*prompt)))) {
log_error("prompt alloc failed."); log_error("prompt alloc failed.");
pp->check_failed = 1; pp->check_failed = 1;
return 0; return 0;
} }
prompt->dev = pd->dev; prompt->dev = pd->dev;
prompt->type = PROMPT_PVCREATE_PV_IN_VG;
prompt->pv_name = dm_pool_strdup(cmd->mem, pd->name); prompt->pv_name = dm_pool_strdup(cmd->mem, pd->name);
prompt->size = size;
prompt->new_size = new_size;
if (pd->is_used_unknown_pv) if (pd->is_used_unknown_pv)
prompt->vg_name_unknown = 1; prompt->vg_name_unknown = 1;
else else if (need_vg_prompt)
prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name); prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name);
dm_list_add(&pp->prompts, &prompt->list);
if (need_size_prompt)
prompt->type |= PROMPT_PVCREATE_DEV_SIZE;
if (need_vg_prompt)
prompt->type |= PROMPT_PVCREATE_PV_IN_VG;
dm_list_add(&pp->prompts, &prompt->list);
pd->dev = pv->dev; pd->dev = pv->dev;
dm_list_move(&pp->arg_process, &pd->list); dm_list_move(&pp->arg_process, &pd->list);
@ -5254,7 +5335,7 @@ static int _pvremove_check_single(struct cmd_context *cmd,
prompt->vg_name_unknown = 1; prompt->vg_name_unknown = 1;
else else
prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name); prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name);
prompt->type = PROMPT_PVREMOVE_PV_IN_VG; prompt->type |= PROMPT_PVREMOVE_PV_IN_VG;
dm_list_add(&pp->prompts, &prompt->list); dm_list_add(&pp->prompts, &prompt->list);
pd->dev = pv->dev; pd->dev = pv->dev;