mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
pvcreate/pvremove: reimplement device checks
Reorganize checking the device args for pvcreate/pvremove to prepare for future changes. There should be no change in behavior. Stop the inverted use of process_each_pv, which pulled in a lot of unnecessary processing, and call the check functions on each device directly.
This commit is contained in:
parent
46e5908759
commit
d1b7438c9f
542
tools/toollib.c
542
tools/toollib.c
@ -4869,113 +4869,84 @@ static struct pvcreate_device *_pvcreate_list_find_name(struct dm_list *devices,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this function decides that a arg_devices entry cannot be used, but the
|
||||
* command might be able to continue without it, then it moves that entry from
|
||||
* arg_devices to arg_fail.
|
||||
*
|
||||
* If this function decides that an arg_devices entry could be used (possibly
|
||||
* requiring a prompt), then it moves the entry from arg_devices to arg_process.
|
||||
*
|
||||
* Any arg_devices entries that are not moved to arg_fail or arg_process were
|
||||
* not found. The caller will decide if the command can continue if any
|
||||
* arg_devices entries were not found, or if any were moved to arg_fail.
|
||||
*
|
||||
* This check does not need to look at PVs in foreign, shared or clustered VGs.
|
||||
* If pvcreate/vgcreate/vgextend specifies a device in a
|
||||
* foreign/shared/clustered VG, that VG will not be processed by this function,
|
||||
* and the arg will be reported as not found.
|
||||
*/
|
||||
static int _pvcreate_check_single(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv,
|
||||
struct processing_handle *handle)
|
||||
static int _pvcreate_check_used(struct cmd_context *cmd,
|
||||
struct pvcreate_params *pp,
|
||||
struct pvcreate_device *pd)
|
||||
{
|
||||
struct pvcreate_params *pp = (struct pvcreate_params *) handle->custom_handle;
|
||||
struct pvcreate_device *pd;
|
||||
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;
|
||||
struct lvmcache_info *info;
|
||||
const char *vgname;
|
||||
|
||||
if (!pv->dev)
|
||||
return 1;
|
||||
log_debug("Checking %s for pvcreate %.32s.",
|
||||
dev_name(pd->dev), pd->dev->pvid[0] ? pd->dev->pvid : "");
|
||||
|
||||
/*
|
||||
* Check if one of the command args in arg_devices
|
||||
* matches this device.
|
||||
* Since the device is likely not a PV yet, it was probably not
|
||||
* scanned by label_scan at the start of the command, so that
|
||||
* needs to be done first to find if there's a PV label or metadata
|
||||
* on it. If there's a PV label, it sets dev->pvid.
|
||||
* If a VG is using the dev, it adds basic VG info for it to
|
||||
* lvmcache.
|
||||
*/
|
||||
dm_list_iterate_items(pd, &pp->arg_devices) {
|
||||
if (pd->dev != pv->dev)
|
||||
continue;
|
||||
label_read(pd->dev);
|
||||
|
||||
if (pv->dev->pvid[0])
|
||||
strncpy(pd->pvid, pv->dev->pvid, ID_LEN);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the uuid specified for the new PV is used by another PV.
|
||||
*/
|
||||
if (!found && pv->dev && pp->uuid_str && id_equal(&pv->id, &pp->pva.id)) {
|
||||
log_error("UUID %s already in use on \"%s\".", pp->uuid_str, pv_dev_name(pv));
|
||||
pp->check_failed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
if (!pd->dev->pvid[0]) {
|
||||
log_debug("Check pvcreate arg %s no PVID found", dev_name(pd->dev));
|
||||
pd->is_not_pv = 1;
|
||||
return 1;
|
||||
|
||||
log_debug("Checking pvcreate arg %s which has existing PVID: %.32s.",
|
||||
pv_dev_name(pv), pv->dev->pvid[0] ? pv->dev->pvid : "<none>");
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow using a device with duplicates.
|
||||
*/
|
||||
if (lvmcache_pvid_in_unused_duplicates(pd->dev->pvid)) {
|
||||
log_error("Cannot use device %s with duplicates.", pd->name);
|
||||
log_error("Cannot use device %s with duplicates.", dev_name(pd->dev));
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_info_from_pvid(pd->dev->pvid, pd->dev, 0))) {
|
||||
log_error("Failed to read lvm info for %s PVID %s.", dev_name(pd->dev), pd->dev->pvid);
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vgname = lvmcache_vgname_from_info(info);
|
||||
|
||||
/*
|
||||
* What kind of device is this: an orphan PV, an uninitialized/unused
|
||||
* device, a PV used in a VG.
|
||||
*/
|
||||
if (vg && !is_orphan_vg(vg->name)) {
|
||||
if (vgname && !is_orphan_vg(vgname)) {
|
||||
/* Device is a PV used in a VG. */
|
||||
log_debug("Found pvcreate arg %s: pv is used in %s.", pd->name, vg->name);
|
||||
log_debug("Check pvcreate arg %s found vg %s.", dev_name(pd->dev), vgname);
|
||||
pd->is_vg_pv = 1;
|
||||
pd->vg_name = dm_pool_strdup(cmd->mem, vg->name);
|
||||
} else if (vg && is_orphan_vg(vg->name)) {
|
||||
if (is_used_pv(pv)) {
|
||||
pd->vg_name = dm_pool_strdup(cmd->mem, vgname);
|
||||
} else if (!vgname || (vgname && is_orphan_vg(vgname))) {
|
||||
uint32_t ext_flags = lvmcache_ext_flags(info);
|
||||
if (ext_flags & PV_EXT_USED) {
|
||||
/* Device is used in an unknown VG. */
|
||||
log_debug("Found pvcreate arg %s: PV is used in unknown VG.", pd->name);
|
||||
log_debug("Check pvcreate arg %s found EXT_USED flag.", dev_name(pd->dev));
|
||||
pd->is_used_unknown_pv = 1;
|
||||
} else {
|
||||
/* Device is an orphan PV. */
|
||||
log_debug("Found pvcreate arg %s: PV is orphan in %s.", pd->name, vg->name);
|
||||
log_debug("Check pvcreate arg %s is orphan.", dev_name(pd->dev));
|
||||
pd->is_orphan_pv = 1;
|
||||
}
|
||||
|
||||
pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME;
|
||||
} else {
|
||||
log_debug("Found pvcreate arg %s: device is not a PV.", pd->name);
|
||||
/* Device is not a PV. */
|
||||
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));
|
||||
if (!dev_get_size(pd->dev, &size)) {
|
||||
log_error("Can't get device size of %s.", dev_name(pd->dev));
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (new_size != size)
|
||||
@ -4994,26 +4965,22 @@ static int _pvcreate_check_single(struct cmd_context *cmd,
|
||||
else
|
||||
need_vg_prompt = 1;
|
||||
|
||||
if (!need_size_prompt && !need_vg_prompt) {
|
||||
pd->dev = pv->dev;
|
||||
dm_list_move(&pp->arg_process, &pd->list);
|
||||
if (!need_size_prompt && !need_vg_prompt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(prompt = dm_pool_zalloc(cmd->mem, sizeof(*prompt)))) {
|
||||
log_error("prompt alloc failed.");
|
||||
pp->check_failed = 1;
|
||||
return 0;
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return_0;
|
||||
}
|
||||
prompt->dev = pd->dev;
|
||||
prompt->pv_name = dm_pool_strdup(cmd->mem, pd->name);
|
||||
prompt->pv_name = dm_pool_strdup(cmd->mem, dev_name(pd->dev));
|
||||
prompt->size = size;
|
||||
prompt->new_size = new_size;
|
||||
|
||||
if (pd->is_used_unknown_pv)
|
||||
prompt->vg_name_unknown = 1;
|
||||
else if (need_vg_prompt)
|
||||
prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name);
|
||||
prompt->vg_name = dm_pool_strdup(cmd->mem, vgname);
|
||||
|
||||
if (need_size_prompt)
|
||||
prompt->type |= PROMPT_PVCREATE_DEV_SIZE;
|
||||
@ -5022,149 +4989,44 @@ static int _pvcreate_check_single(struct cmd_context *cmd,
|
||||
prompt->type |= PROMPT_PVCREATE_PV_IN_VG;
|
||||
|
||||
dm_list_add(&pp->prompts, &prompt->list);
|
||||
pd->dev = pv->dev;
|
||||
dm_list_move(&pp->arg_process, &pd->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This repeats the first check -- devices should be found, and should not have
|
||||
* changed since the first check. If they were changed/used while the orphans
|
||||
* lock was not held (during prompting), then they can't be used any more and
|
||||
* are moved to arg_fail. If they are not found by this loop, that also
|
||||
* disqualifies them from being used. Each arg_confirm entry that's found and
|
||||
* is ok, is moved to arg_process. Those not found will remain in arg_confirm.
|
||||
*
|
||||
* This check does not need to look in foreign/shared/clustered VGs. If a
|
||||
* device from arg_confirm was used in a foreign/shared/clustered VG during the
|
||||
* prompts, then it will not be found during this check.
|
||||
*/
|
||||
|
||||
static int _pv_confirm_single(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv,
|
||||
struct processing_handle *handle)
|
||||
static int _pvremove_check_used(struct cmd_context *cmd,
|
||||
struct pvcreate_params *pp,
|
||||
struct pvcreate_device *pd)
|
||||
{
|
||||
struct pvcreate_params *pp = (struct pvcreate_params *) handle->custom_handle;
|
||||
struct pvcreate_device *pd;
|
||||
int found = 0;
|
||||
|
||||
dm_list_iterate_items(pd, &pp->arg_confirm) {
|
||||
if (pd->dev != pv->dev)
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* What kind of device is this: an orphan PV, an uninitialized/unused
|
||||
* device, a PV used in a VG.
|
||||
*/
|
||||
if (vg && !is_orphan_vg(vg->name)) {
|
||||
/* Device is a PV used in a VG. */
|
||||
|
||||
if (pd->is_orphan_pv || pd->is_not_pv || pd->is_used_unknown_pv) {
|
||||
/* In check_single it was an orphan or unused. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pd->is_vg_pv && pd->vg_name && strcmp(pd->vg_name, vg->name)) {
|
||||
/* In check_single it was in a different VG. */
|
||||
goto fail;
|
||||
}
|
||||
} else if (is_orphan(pv)) {
|
||||
/* Device is an orphan PV. */
|
||||
|
||||
if (pd->is_not_pv) {
|
||||
/* In check_single it was not a PV. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pd->is_vg_pv) {
|
||||
/* In check_single it was in a VG. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (is_used_pv(pv) != pd->is_used_unknown_pv) {
|
||||
/* In check_single it was different. */
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
/* Device is not a PV. */
|
||||
if (pd->is_orphan_pv || pd->is_used_unknown_pv) {
|
||||
/* In check_single it was an orphan PV. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pd->is_vg_pv) {
|
||||
/* In check_single it was in a VG. */
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Device is unchanged from check_single. */
|
||||
dm_list_move(&pp->arg_process, &pd->list);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
log_error("Cannot use device %s: it changed during prompt.", pd->name);
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pvremove_check_single(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct pvcreate_params *pp = (struct pvcreate_params *) handle->custom_handle;
|
||||
struct pvcreate_device *pd;
|
||||
struct pvcreate_prompt *prompt;
|
||||
int found = 0;
|
||||
|
||||
if (!pv->dev)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Check if one of the command args in arg_devices
|
||||
* matches this device.
|
||||
*/
|
||||
dm_list_iterate_items(pd, &pp->arg_devices) {
|
||||
if (pd->dev != pv->dev)
|
||||
continue;
|
||||
|
||||
if (pv->dev->pvid[0])
|
||||
strncpy(pd->pvid, pv->dev->pvid, ID_LEN);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return 1;
|
||||
|
||||
log_debug("Checking device %s for pvremove %.32s.",
|
||||
pv_dev_name(pv), pv->dev->pvid[0] ? pv->dev->pvid : "");
|
||||
struct lvmcache_info *info;
|
||||
const char *vgname = NULL;
|
||||
|
||||
log_debug("Checking %s for pvremove %.32s.",
|
||||
dev_name(pd->dev), pd->dev->pvid[0] ? pd->dev->pvid : "");
|
||||
|
||||
/*
|
||||
* Is there a pv here already?
|
||||
* If not, this is an error unless you used -f.
|
||||
*/
|
||||
if (!lvmcache_has_dev_info(pv->dev)) {
|
||||
if (pp->force) {
|
||||
dm_list_move(&pp->arg_process, &pd->list);
|
||||
|
||||
if (!pd->dev->pvid[0]) {
|
||||
log_debug("Check pvremove arg %s no PVID found", dev_name(pd->dev));
|
||||
if (pp->force)
|
||||
return 1;
|
||||
} else {
|
||||
pd->is_not_pv = 1;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_info_from_pvid(pd->dev->pvid, pd->dev, 0))) {
|
||||
if (pp->force)
|
||||
return 1;
|
||||
log_error("Failed to read lvm info for %s PVID %s.", dev_name(pd->dev), pd->dev->pvid);
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info)
|
||||
vgname = lvmcache_vgname_from_info(info);
|
||||
|
||||
/*
|
||||
* What kind of device is this: an orphan PV, an uninitialized/unused
|
||||
* device, a PV used in a VG.
|
||||
@ -5172,49 +5034,40 @@ static int _pvremove_check_single(struct cmd_context *cmd,
|
||||
|
||||
if (pd->is_not_pv) {
|
||||
/* Device is not a PV. */
|
||||
log_debug("Found pvremove arg %s: device is not a PV.", pd->name);
|
||||
log_debug("Check pvremove arg %s device is not a PV.", dev_name(pd->dev));
|
||||
|
||||
} else if (vg && !is_orphan_vg(vg->name)) {
|
||||
} else if (vgname && !is_orphan_vg(vgname)) {
|
||||
/* Device is a PV used in a VG. */
|
||||
log_debug("Found pvremove arg %s: pv is used in %s.", pd->name, vg->name);
|
||||
log_debug("Check pvremove arg %s found vg %s.", dev_name(pd->dev), vgname);
|
||||
pd->is_vg_pv = 1;
|
||||
pd->vg_name = dm_pool_strdup(cmd->mem, vg->name);
|
||||
pd->vg_name = dm_pool_strdup(cmd->mem, vgname);
|
||||
|
||||
} else if (vg && is_orphan_vg(vg->name)) {
|
||||
if (is_used_pv(pv)) {
|
||||
} else if (info && (!vgname || (vgname && is_orphan_vg(vgname)))) {
|
||||
uint32_t ext_flags = lvmcache_ext_flags(info);
|
||||
if (ext_flags & PV_EXT_USED) {
|
||||
/* Device is used in an unknown VG. */
|
||||
log_debug("Found pvremove arg %s: pv is used in unknown VG.", pd->name);
|
||||
log_debug("Check pvremove arg %s found EXT_USED flag.", dev_name(pd->dev));
|
||||
pd->is_used_unknown_pv = 1;
|
||||
} else {
|
||||
/* Device is an orphan PV. */
|
||||
log_debug("Found pvremove arg %s: pv is orphan in %s.", pd->name, vg->name);
|
||||
log_debug("Check pvremove arg %s is orphan.", dev_name(pd->dev));
|
||||
pd->is_orphan_pv = 1;
|
||||
}
|
||||
|
||||
pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME;
|
||||
} else {
|
||||
/* FIXME: is it possible to reach here? */
|
||||
log_debug("Found pvremove arg %s: device is not a PV.", pd->name);
|
||||
/* Device is not a PV. */
|
||||
pd->is_not_pv = 1;
|
||||
}
|
||||
|
||||
if (pd->is_not_pv) {
|
||||
pd->dev = pv->dev;
|
||||
log_error("No PV found on device %s.", pd->name);
|
||||
log_error("No PV found on device %s.", dev_name(pd->dev));
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* pvremove is being run on this device, and it's not a PV,
|
||||
* or is an orphan PV. Neither case requires a prompt.
|
||||
*/
|
||||
if (pd->is_orphan_pv) {
|
||||
pd->dev = pv->dev;
|
||||
dm_list_move(&pp->arg_process, &pd->list);
|
||||
if (pd->is_orphan_pv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pvremove is being run on this device, but the device is in a VG.
|
||||
@ -5222,22 +5075,104 @@ static int _pvremove_check_single(struct cmd_context *cmd,
|
||||
*/
|
||||
|
||||
if (!(prompt = dm_pool_zalloc(cmd->mem, sizeof(*prompt)))) {
|
||||
log_error("prompt alloc failed.");
|
||||
pp->check_failed = 1;
|
||||
return 0;
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return_0;
|
||||
}
|
||||
prompt->dev = pd->dev;
|
||||
prompt->pv_name = dm_pool_strdup(cmd->mem, pd->name);
|
||||
prompt->pv_name = dm_pool_strdup(cmd->mem, dev_name(pd->dev));
|
||||
if (pd->is_used_unknown_pv)
|
||||
prompt->vg_name_unknown = 1;
|
||||
else
|
||||
prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name);
|
||||
prompt->vg_name = dm_pool_strdup(cmd->mem, vgname);
|
||||
prompt->type |= PROMPT_PVREMOVE_PV_IN_VG;
|
||||
dm_list_add(&pp->prompts, &prompt->list);
|
||||
|
||||
pd->dev = pv->dev;
|
||||
dm_list_move(&pp->arg_process, &pd->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _confirm_check_used(struct cmd_context *cmd,
|
||||
struct pvcreate_params *pp,
|
||||
struct pvcreate_device *pd)
|
||||
{
|
||||
struct lvmcache_info *info = NULL;
|
||||
const char *vgname = NULL;
|
||||
int is_not_pv = 0;
|
||||
|
||||
log_debug("Checking %s to confirm %.32s.",
|
||||
dev_name(pd->dev), pd->dev->pvid[0] ? pd->dev->pvid : "");
|
||||
|
||||
if (!pd->dev->pvid[0]) {
|
||||
log_debug("Check confirm arg %s no PVID found", dev_name(pd->dev));
|
||||
is_not_pv = 1;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_info_from_pvid(pd->dev->pvid, pd->dev, 0))) {
|
||||
log_debug("Check confirm arg %s no info.", dev_name(pd->dev));
|
||||
is_not_pv = 1;
|
||||
}
|
||||
|
||||
if (info)
|
||||
vgname = lvmcache_vgname_from_info(info);
|
||||
|
||||
|
||||
/*
|
||||
* What kind of device is this: an orphan PV, an uninitialized/unused
|
||||
* device, a PV used in a VG.
|
||||
*/
|
||||
if (vgname && !is_orphan_vg(vgname)) {
|
||||
/* Device is a PV used in a VG. */
|
||||
|
||||
if (pd->is_orphan_pv || pd->is_not_pv || pd->is_used_unknown_pv) {
|
||||
/* In first check it was an orphan or unused. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pd->is_vg_pv && pd->vg_name && strcmp(pd->vg_name, vgname)) {
|
||||
/* In first check it was in a different VG. */
|
||||
goto fail;
|
||||
}
|
||||
} else if (info && (!vgname || is_orphan_vg(vgname))) {
|
||||
uint32_t ext_flags = lvmcache_ext_flags(info);
|
||||
|
||||
/* Device is an orphan PV. */
|
||||
|
||||
if (pd->is_not_pv) {
|
||||
/* In first check it was not a PV. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pd->is_vg_pv) {
|
||||
/* In first check it was in a VG. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ext_flags & PV_EXT_USED) && !pd->is_used_unknown_pv) {
|
||||
/* In first check it was different. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(ext_flags & PV_EXT_USED) && pd->is_used_unknown_pv) {
|
||||
/* In first check it was different. */
|
||||
goto fail;
|
||||
}
|
||||
} else if (is_not_pv) {
|
||||
/* Device is not a PV. */
|
||||
if (pd->is_orphan_pv || pd->is_used_unknown_pv) {
|
||||
/* In first check it was an orphan PV. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pd->is_vg_pv) {
|
||||
/* In first check it was in a VG. */
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
log_error("Cannot use device %s: it changed during prompt.", dev_name(pd->dev));
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -5247,10 +5182,6 @@ static int _pvremove_check_single(struct cmd_context *cmd,
|
||||
* line args. This includes the pv_names field which specifies the devices to
|
||||
* create PVs on.
|
||||
*
|
||||
* This uses process_each_pv() and should be called from a high level in the
|
||||
* command -- the same level at which other instances of process_each are
|
||||
* called.
|
||||
*
|
||||
* This function returns 0 (failed) if the caller requires all specified
|
||||
* devices to be created, and any of those devices are not found, or any of
|
||||
* them cannot be created.
|
||||
@ -5278,6 +5209,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
unsigned int physical_block_size, logical_block_size;
|
||||
unsigned int prev_pbs = 0, prev_lbs = 0;
|
||||
int must_use_all = (cmd->cname->flags & MUST_USE_ALL_ARGS);
|
||||
int unlocked_for_prompts = 0;
|
||||
int found;
|
||||
unsigned i;
|
||||
|
||||
@ -5313,17 +5245,28 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
/*
|
||||
* Translate arg names into struct device's.
|
||||
*/
|
||||
dm_list_iterate_items(pd, &pp->arg_devices)
|
||||
dm_list_iterate_items_safe(pd, pd2, &pp->arg_devices) {
|
||||
pd->dev = dev_cache_get(cmd, pd->name, cmd->filter);
|
||||
if (!pd->dev) {
|
||||
log_error("Device %s not found.", pd->name);
|
||||
dm_list_del(&pd->list);
|
||||
dm_list_add(&pp->arg_fail, &pd->list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Can the command continue if some specified devices were not found?
|
||||
*/
|
||||
if (must_use_all && !dm_list_empty(&pp->arg_fail)) {
|
||||
log_error("Command requires all devices to be found.");
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for consistent block sizes.
|
||||
*/
|
||||
if (pp->check_consistent_block_size) {
|
||||
dm_list_iterate_items(pd, &pp->arg_devices) {
|
||||
if (!pd->dev)
|
||||
continue;
|
||||
|
||||
logical_block_size = 0;
|
||||
physical_block_size = 0;
|
||||
|
||||
@ -5361,58 +5304,48 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use process_each_pv to search all existing PVs and devices.
|
||||
*
|
||||
* This is a slightly different way to use process_each_pv, because the
|
||||
* command args (arg_devices) are not being processed directly by
|
||||
* process_each_pv (argc and argv are not passed). Instead,
|
||||
* process_each_pv is processing all existing PVs and devices, and the
|
||||
* single function is matching each of those against the command args
|
||||
* (arg_devices).
|
||||
*
|
||||
* If an arg_devices entry is found during process_each_pv, it's moved
|
||||
* to arg_process if it can be used, or arg_fail if it cannot be used.
|
||||
* If it's added to arg_process but needs a prompt or force option, then
|
||||
* a corresponding prompt entry is added to pp->prompts.
|
||||
*/
|
||||
process_each_pv(cmd, 0, NULL, NULL, 1, PROCESS_SKIP_SCAN,
|
||||
handle, pp->is_remove ? _pvremove_check_single : _pvcreate_check_single);
|
||||
/* check_used moves pd entries into the arg_fail list if pvcreate/pvremove is disallowed */
|
||||
dm_list_iterate_items_safe(pd, pd2, &pp->arg_devices) {
|
||||
if (pp->is_remove)
|
||||
_pvremove_check_used(cmd, pp, pd);
|
||||
else
|
||||
_pvcreate_check_used(cmd, pp, pd);
|
||||
}
|
||||
|
||||
/*
|
||||
* A fatal error was found while checking.
|
||||
* If the user specified a uuid for the new PV, check
|
||||
* if a PV on another dev is already using that uuid.
|
||||
*/
|
||||
if (pp->check_failed)
|
||||
goto_bad;
|
||||
if (!pp->is_remove && pp->uuid_str) {
|
||||
struct device *dev;
|
||||
if ((dev = lvmcache_device_from_pvid(cmd, &pp->pva.id, NULL))) {
|
||||
dm_list_iterate_items_safe(pd, pd2, &pp->arg_devices) {
|
||||
if (pd->dev != dev) {
|
||||
log_error("UUID %s already in use on \"%s\".", pp->uuid_str, dev_name(dev));
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case: pvremove -ff is allowed to clear a duplicate device in
|
||||
* the unchosen duplicates list. PVs in the unchosen duplicates list
|
||||
* won't be found by normal process_each searches -- they are not in
|
||||
* lvmcache and can't be processed normally. We save them here and
|
||||
* erase them below without going through the normal processing code.
|
||||
* the unchosen duplicates list. We save them here and erase them below.
|
||||
*/
|
||||
if (pp->is_remove && (pp->force == DONT_PROMPT_OVERRIDE) &&
|
||||
!dm_list_empty(&pp->arg_devices) && lvmcache_has_duplicate_devs()) {
|
||||
dm_list_iterate_items_safe(pd, pd2, &pp->arg_devices) {
|
||||
if (lvmcache_dev_is_unused_duplicate(pd->dev)) {
|
||||
log_debug("Found pvremove arg %s: device is a duplicate.", pd->name);
|
||||
log_debug("Check pvremove arg %s device is a duplicate.", dev_name(pd->dev));
|
||||
dm_list_move(&remove_duplicates, &pd->list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if all arg_devices were found by process_each_pv.
|
||||
* Any devices not moved to arg_fail can be processed.
|
||||
*/
|
||||
dm_list_iterate_items(pd, &pp->arg_devices)
|
||||
log_error("Device %s %s.", pd->name, dev_cache_filtered_reason(pd->name));
|
||||
|
||||
/*
|
||||
* Can the command continue if some specified devices were not found?
|
||||
*/
|
||||
if (!dm_list_empty(&pp->arg_devices) && must_use_all)
|
||||
goto_bad;
|
||||
dm_list_splice(&pp->arg_process, &pp->arg_devices);
|
||||
|
||||
/*
|
||||
* Can the command continue if some specified devices cannot be used?
|
||||
@ -5468,8 +5401,10 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
|
||||
lockf_global(cmd, "un");
|
||||
|
||||
unlocked_for_prompts = 1;
|
||||
|
||||
/*
|
||||
* Process prompts that require asking the user. The orphans lock is
|
||||
* Process prompts that require asking the user. The global lock is
|
||||
* not held, so there's no harm in waiting for a user to respond.
|
||||
*/
|
||||
dm_list_iterate_items_safe(prompt, prompt2, &pp->prompts) {
|
||||
@ -5500,7 +5435,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
|
||||
/*
|
||||
* Reacquire the lock that was released above before waiting, then
|
||||
* check again that the devices can still be used. If the second loop
|
||||
* check again that the devices can still be used. If the second check
|
||||
* finds them changed, or can't find them any more, then they aren't
|
||||
* used. Use a non-blocking request when reacquiring to avoid
|
||||
* potential deadlock since this is not the normal locking sequence.
|
||||
@ -5511,41 +5446,6 @@ int pvcreate_each_device(struct cmd_context *cmd,
|
||||
goto_out;
|
||||
}
|
||||
|
||||
lvmcache_label_scan(cmd);
|
||||
|
||||
/*
|
||||
* The device args began on the arg_devices list, then the first check
|
||||
* loop moved those entries to arg_process as they were found. Devices
|
||||
* not found during the first loop are not being used, and remain on
|
||||
* arg_devices.
|
||||
*
|
||||
* Now, the arg_process entries are moved to arg_confirm, and the second
|
||||
* check loop moves them back to arg_process as they are found and are
|
||||
* unchanged. Like the first loop, the second loop moves an entry to
|
||||
* arg_fail if it cannot be used. After the second loop, any devices
|
||||
* remaining on arg_confirm were not found and are not used.
|
||||
*/
|
||||
dm_list_splice(&pp->arg_confirm, &pp->arg_process);
|
||||
|
||||
process_each_pv(cmd, 0, NULL, NULL, 1, PROCESS_SKIP_SCAN,
|
||||
handle, _pv_confirm_single);
|
||||
|
||||
dm_list_iterate_items(pd, &pp->arg_confirm)
|
||||
log_error("Device %s %s.", pd->name, dev_cache_filtered_reason(pd->name));
|
||||
|
||||
/* Some devices were not found during the second check. */
|
||||
if (!dm_list_empty(&pp->arg_confirm) && must_use_all)
|
||||
goto_bad;
|
||||
|
||||
/* Some devices changed during the second check. */
|
||||
if (!dm_list_empty(&pp->arg_fail) && must_use_all)
|
||||
goto_bad;
|
||||
|
||||
if (dm_list_empty(&pp->arg_process)) {
|
||||
log_debug("No devices to process.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
do_command:
|
||||
|
||||
dm_list_iterate_items(pd, &pp->arg_process) {
|
||||
@ -5561,6 +5461,25 @@ do_command:
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the global lock was unlocked to wait for prompts, then
|
||||
* devs could have changed while unlocked, so confirm that
|
||||
* the devs are unchanged since check_used.
|
||||
* Changed pd entries are moved to arg_fail.
|
||||
*/
|
||||
if (unlocked_for_prompts) {
|
||||
dm_list_iterate_items_safe(pd, pd2, &pp->arg_process)
|
||||
_confirm_check_used(cmd, pp, pd);
|
||||
|
||||
if (!dm_list_empty(&pp->arg_fail) && must_use_all)
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (dm_list_empty(&pp->arg_process)) {
|
||||
log_debug("No devices to process.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reorder arg_process entries to match the original order of args.
|
||||
*/
|
||||
@ -5579,6 +5498,7 @@ do_command:
|
||||
* Wipe signatures on devices being created.
|
||||
*/
|
||||
dm_list_iterate_items_safe(pd, pd2, &pp->arg_create) {
|
||||
/* FIXME: won't all already be open excl from label_scan_devs_excl above? */
|
||||
label_scan_open_excl(pd->dev);
|
||||
|
||||
log_verbose("Wiping signatures on new PV %s.", pd->name);
|
||||
@ -5658,6 +5578,7 @@ do_command:
|
||||
|
||||
pv_name = pd->name;
|
||||
|
||||
/* FIXME: won't all already be open excl from label_scan_devs_excl above? */
|
||||
label_scan_open_excl(pd->dev);
|
||||
|
||||
log_debug("Creating a new PV on %s.", pv_name);
|
||||
@ -5671,7 +5592,6 @@ do_command:
|
||||
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
|
||||
" available sectors.", pv_name, pv_size(pv));
|
||||
|
||||
|
||||
if (!label_remove(pv->dev)) {
|
||||
log_error("Failed to wipe existing label on %s.", pv_name);
|
||||
dm_list_move(&pp->arg_fail, &pd->list);
|
||||
|
Loading…
Reference in New Issue
Block a user