diff options
-rw-r--r-- | lib/label/label.c | 3 | ||||
-rw-r--r-- | tools/toollib.c | 525 |
2 files changed, 230 insertions, 298 deletions
diff --git a/lib/label/label.c b/lib/label/label.c index 4d37ceff6..ed6e0171c 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -684,7 +684,8 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f, if (!_scan_dev_open(devl->dev)) { log_debug_devs("Scan failed to open %s.", dev_name(devl->dev)); dm_list_del(&devl->list); - dm_list_add(&reopen_devs, &devl->list); + lvmcache_del_dev(devl->dev); + scan_failed_count++; continue; } } diff --git a/tools/toollib.c b/tools/toollib.c index 89b637407..9640f003e 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -4719,111 +4719,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; - - 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; + struct lvmcache_info *info; + const char *vgname; - if (pv->dev->pvid[0]) - strncpy(pd->pvid, pv->dev->pvid, ID_LEN); - found = 1; - break; - } + log_debug("Checking %s for pvcreate %.32s.", + dev_name(pd->dev), pd->dev->pvid[0] ? pd->dev->pvid : ""); /* - * Check if the uuid specified for the new PV is used by another PV. + * 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. */ - 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; - } + label_read(pd->dev); - 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; } + if (!(info = lvmcache_info_from_pvid(pd->dev->pvid, pd->dev, 0))) { + /* FIXME: is this an orphan PV if there's a PVID? */ + log_debug("Check pvcreate arg %s no info.", dev_name(pd->dev)); + pd->is_not_pv = 1; + return 1; + } + + 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; } @@ -4844,26 +4817,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; @@ -4872,149 +4841,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; + struct lvmcache_info *info; + const char *vgname = NULL; - if (!pv->dev) - return 1; + log_debug("Checking %s for pvremove %.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. + * Is there a pv here already? + * If not, this is an error unless you used -f. */ - 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 (!pd->dev->pvid[0]) { + log_debug("Check pvremove arg %s no PVID found", dev_name(pd->dev)); + if (pp->force) + return 1; + pd->is_not_pv = 1; } - if (!found) - return 1; - - log_debug("Checking device %s for pvremove %.32s.", - pv_dev_name(pv), pv->dev->pvid[0] ? pv->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 (!(info = lvmcache_info_from_pvid(pd->dev->pvid, pd->dev, 0))) { + /* FIXME: is this an orphan PV if there's a PVID? */ + log_debug("Check pvremove arg %s no info.", dev_name(pd->dev)); + if (pp->force) return 1; - } else { - pd->is_not_pv = 1; - } + pd->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. @@ -5022,36 +4886,30 @@ 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; } @@ -5060,11 +4918,8 @@ static int _pvremove_check_single(struct cmd_context *cmd, * 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. @@ -5072,22 +4927,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; } @@ -5128,6 +5065,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; @@ -5163,8 +5101,22 @@ 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_print("No device found for %s", 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. @@ -5211,29 +5163,29 @@ 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 @@ -5246,23 +5198,16 @@ int pvcreate_each_device(struct cmd_context *cmd, !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? @@ -5318,8 +5263,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) { @@ -5350,7 +5297,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. @@ -5361,41 +5308,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) { @@ -5412,6 +5324,25 @@ do_command: } /* + * 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. */ dm_list_splice(&arg_sort, &pp->arg_process); |