diff options
author | David Teigland <teigland@redhat.com> | 2015-12-15 12:55:48 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2015-12-16 16:44:54 -0600 |
commit | 1540d114bf881fa844ea4891bf12caf73cec657d (patch) | |
tree | c90d282b2fda6a0d886da8309e6f506937a3eed1 | |
parent | 796461a9125a8324a63be154fc998245617e5990 (diff) | |
download | lvm2-dev-dct-pvcreate-2.tar.gz |
pvcreate: restructuring to use toollibdev-dct-pvcreate-2
- Pull out the hidden equivalent of process_each_pv
into an actual top level process_each_pv.
- Pull the prompts to the top level, and out from under
the VG locks.
Previously, pvcreate_vol() was the shared function for
creating a PV for pvcreate, vgcreate, vgextend.
Now, it will be toollib function pvcreate_each_device().
pvcreate_vol() was called effectively as a helper, from
within vgcreate and vgextend code paths.
pvcreate_each_device() will be called at the same level
as other process_each functions.
One of the main problems with pvcreate_vol() is that
it included a hidden equivalent of process_each_pv for
each device being created:
pvcreate_vol() -> _pvcreate_check() ->
find_pv_by_name() -> get_pvs() ->
get_pvs_internal() -> _get_pvs() -> get_vgids() ->
/* equivalent to process_each_pv */
dm_list_iterate_items(vgids)
vg = vg_read_internal()
dm_list_iterate_items(&vg->pvs)
pvcreate_each_device() reorganizes the code so that
each-VG-each-PV loop is done once, and uses the standard
process_each_pv function at the top level of the function.
-rw-r--r-- | lib/metadata/metadata-exported.h | 34 | ||||
-rw-r--r-- | lib/metadata/pv_manip.c | 20 | ||||
-rw-r--r-- | tools/pvcreate.c | 267 | ||||
-rw-r--r-- | tools/toollib.c | 405 | ||||
-rw-r--r-- | tools/tools.h | 2 |
5 files changed, 657 insertions, 71 deletions
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index 8242db17d..a8484e983 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -535,6 +535,40 @@ struct pvcreate_params { struct pvcreate_restorable_params rp; }; +/* + * FIXME: rename this pvcreate_params once the old pvcreate_params is unused. + * This can probably be put in toollib.h. + */ +struct pvcreate_each_params { + int zero; + uint64_t size; + uint64_t data_alignment; + uint64_t data_alignment_offset; + int pvmetadatacopies; + uint64_t pvmetadatasize; + int64_t labelsector; + force_t force; + unsigned yes; + unsigned metadataignore; + + char **pv_names; /* argv */ + uint32_t pv_count; /* argc */ + + const char *restorefile; /* NULL if no --restorefile option */ + const char *uuid_str; /* id in printable format, NULL if no id */ + struct id id; + uint64_t ba_start; + uint64_t ba_size; + uint64_t pe_start; + uint32_t extent_count; + uint32_t extent_size; + + struct dm_list prompts; /* pvcreate_prompt */ + struct dm_list arg_names; /* pvcreate_device, one for each pv_name */ + struct dm_list arg_create; /* pvcreate_device, processing */ + struct dm_list arg_fail; /* pvcreate_device, processing failed */ +}; + struct lvresize_params { const char *vg_name; /* only-used when VG is not yet opened (in /tools) */ const char *lv_name; diff --git a/lib/metadata/pv_manip.c b/lib/metadata/pv_manip.c index e48fe42a1..09000ecde 100644 --- a/lib/metadata/pv_manip.c +++ b/lib/metadata/pv_manip.c @@ -852,23 +852,3 @@ out: return ret; } -int pvcreate_single(struct cmd_context *cmd, const char *pv_name, - struct pvcreate_params *pp) -{ - int r = 0; - - if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) { - log_error("Can't get lock for orphan PVs"); - return 0; - } - - if (!(pvcreate_vol(cmd, pv_name, pp, 1))) - goto_out; - - r = 1; - -out: - unlock_vg(cmd, VG_ORPHANS); - - return r; -} diff --git a/tools/pvcreate.c b/tools/pvcreate.c index 1f45ad91d..711bf7333 100644 --- a/tools/pvcreate.c +++ b/tools/pvcreate.c @@ -15,6 +15,114 @@ #include "tools.h" +int pvcreate_each_params_from_args(struct cmd_context *cmd, struct pvcreate_each_params *pp) +{ + pp->yes = arg_count(cmd, yes_ARG); + pp->force = (force_t) arg_count(cmd, force_ARG); + + if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) { + log_error("labelsector must be less than %lu.", + LABEL_SCAN_SECTORS); + return 0; + } else { + pp->labelsector = arg_int64_value(cmd, labelsector_ARG, + DEFAULT_LABELSECTOR); + } + + if (!(cmd->fmt->features & FMT_MDAS) && + (arg_count(cmd, pvmetadatacopies_ARG) || + arg_count(cmd, metadatasize_ARG) || + arg_count(cmd, dataalignment_ARG) || + arg_count(cmd, dataalignmentoffset_ARG))) { + log_error("Metadata and data alignment parameters only " + "apply to text format."); + return 0; + } + + if (!(cmd->fmt->features & FMT_BAS) && + arg_count(cmd, bootloaderareasize_ARG)) { + log_error("Bootloader area parameters only " + "apply to text format."); + return 0; + } + + if (arg_count(cmd, metadataignore_ARG)) + pp->metadataignore = arg_int_value(cmd, metadataignore_ARG, + DEFAULT_PVMETADATAIGNORE); + else + pp->metadataignore = find_config_tree_bool(cmd, metadata_pvmetadataignore_CFG, NULL); + + if (arg_count(cmd, pvmetadatacopies_ARG) && + !arg_int_value(cmd, pvmetadatacopies_ARG, -1) && + pp->metadataignore) { + log_error("metadataignore only applies to metadatacopies > 0"); + return 0; + } + + pp->zero = arg_int_value(cmd, zero_ARG, 1); + + if (arg_sign_value(cmd, dataalignment_ARG, SIGN_NONE) == SIGN_MINUS) { + log_error("Physical volume data alignment may not be negative."); + return 0; + } + pp->data_alignment = arg_uint64_value(cmd, dataalignment_ARG, UINT64_C(0)); + + if (pp->data_alignment > UINT32_MAX) { + log_error("Physical volume data alignment is too big."); + return 0; + } + + if (arg_sign_value(cmd, dataalignmentoffset_ARG, SIGN_NONE) == SIGN_MINUS) { + log_error("Physical volume data alignment offset may not be negative"); + return 0; + } + pp->data_alignment_offset = arg_uint64_value(cmd, dataalignmentoffset_ARG, UINT64_C(0)); + + if (pp->data_alignment_offset > UINT32_MAX) { + log_error("Physical volume data alignment offset is too big."); + return 0; + } + + if ((pp->data_alignment + pp->data_alignment_offset) && + (pp->pe_start != PV_PE_START_CALC)) { + if ((pp->data_alignment ? pp->pe_start % pp->data_alignment : pp->pe_start) != pp->data_alignment_offset) { + log_warn("WARNING: Ignoring data alignment %s" + " incompatible with restored pe_start value %s)", + display_size(cmd, pp->data_alignment + pp->data_alignment_offset), + display_size(cmd, pp->pe_start)); + pp->data_alignment = 0; + pp->data_alignment_offset = 0; + } + } + + if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { + log_error("Metadata size may not be negative."); + return 0; + } + + if (arg_sign_value(cmd, bootloaderareasize_ARG, SIGN_NONE) == SIGN_MINUS) { + log_error("Bootloader area size may not be negative."); + return 0; + } + + pp->pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0)); + if (!pp->pvmetadatasize) + pp->pvmetadatasize = find_config_tree_int(cmd, metadata_pvmetadatasize_CFG, NULL); + + pp->pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); + if (pp->pvmetadatacopies < 0) + pp->pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL); + + if (pp->pvmetadatacopies > 2) { + log_error("Metadatacopies may only be 0, 1 or 2"); + return 0; + } + + pp->ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->ba_size); + + return 1; +} + /* * Intial sanity checking of recovery-related command-line arguments. * These args are: --restorefile, --uuid, and --physicalvolumesize @@ -22,13 +130,12 @@ * Output arguments: * pp: structure allocated by caller, fields written / validated here */ -static int pvcreate_restore_params_validate(struct cmd_context *cmd, - int argc, char **argv, - struct pvcreate_params *pp) +static int pvcreate_each_restore_params_from_args(struct cmd_context *cmd, int argc, + struct pvcreate_each_params *pp) { const char *uuid = NULL; - struct volume_group *vg; - struct pv_list *existing_pvl; + + pp->restorefile = arg_str_value(cmd, restorefile_ARG, NULL); if (arg_count(cmd, restorefile_ARG) && !arg_count(cmd, uuidstr_ARG)) { log_error("--uuid is required with --restorefile"); @@ -48,35 +155,10 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd, return 0; } - if (arg_count(cmd, uuidstr_ARG)) { - uuid = arg_str_value(cmd, uuidstr_ARG, ""); - if (!id_read_format(&pp->rp.id, uuid)) - return 0; - pp->rp.idp = &pp->rp.id; - lvmcache_seed_infos_from_lvmetad(cmd); /* need to check for UUID dups */ - } - - if (arg_count(cmd, restorefile_ARG)) { - pp->rp.restorefile = arg_str_value(cmd, restorefile_ARG, ""); - /* The uuid won't already exist */ - if (!(vg = backup_read_vg(cmd, NULL, pp->rp.restorefile))) { - log_error("Unable to read volume group from %s", - pp->rp.restorefile); - return 0; - } - if (!(existing_pvl = find_pv_in_vg_by_uuid(vg, pp->rp.idp))) { - release_vg(vg); - log_error("Can't find uuid %s in backup file %s", - uuid, pp->rp.restorefile); + if (arg_count(cmd, uuidstr_ARG)) { + pp->uuid_str = arg_str_value(cmd, uuidstr_ARG, ""); + if (!id_read_format(&pp->id, uuid)) return 0; - } - pp->rp.ba_start = pv_ba_start(existing_pvl->pv); - pp->rp.ba_size = pv_ba_size(existing_pvl->pv); - pp->rp.pe_start = pv_pe_start(existing_pvl->pv); - pp->rp.extent_size = pv_pe_size(existing_pvl->pv); - pp->rp.extent_count = pv_pe_count(existing_pvl->pv); - - release_vg(vg); } if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) { @@ -90,34 +172,119 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd, return 1; } +static int pvcreate_each_restore_params_from_backup(struct cmd_context *cmd, + struct pvcreate_each_params *pep) +{ + struct volume_group *vg; + struct pv_list *existing_pvl; + const char *uuid; + + /* + * When restoring a PV, params need to be read from a backup file. + */ + if (!pep->restorefile) + return 1; + + uuid = arg_str_value(cmd, uuidstr_ARG, ""); + + if (!(vg = backup_read_vg(cmd, NULL, pep->restorefile))) { + log_error("Unable to read volume group from %s", pep->restorefile); + return 0; + } + + if (!(existing_pvl = find_pv_in_vg_by_uuid(vg, &pep->id))) { + release_vg(vg); + log_error("Can't find uuid %s in backup file %s", + uuid, pep->restorefile); + return 0; + } + + pep->ba_start = pv_ba_start(existing_pvl->pv); + pep->ba_size = pv_ba_size(existing_pvl->pv); + pep->pe_start = pv_pe_start(existing_pvl->pv); + pep->extent_size = pv_pe_size(existing_pvl->pv); + pep->extent_count = pv_pe_count(existing_pvl->pv); + + release_vg(vg); + return 1; +} + +void pvcreate_each_params_set_defaults(struct pvcreate_each_params *pep) +{ + pep->zero = 1; + pep->size = 0; + pep->data_alignment = UINT64_C(0); + pep->data_alignment_offset = UINT64_C(0); + pep->pvmetadatacopies = DEFAULT_PVMETADATACOPIES; + pep->pvmetadatasize = DEFAULT_PVMETADATASIZE; + pep->labelsector = DEFAULT_LABELSECTOR; + pep->force = PROMPT; + pep->yes = 0; + pep->metadataignore = DEFAULT_PVMETADATAIGNORE; + pep->rp.restorefile = 0; + pep->rp.idp = 0; + pep->rp.ba_start = 0; + pep->rp.ba_size = 0; + pep->rp.pe_start = PV_PE_START_CALC; + pep->rp.extent_count = 0; + pep->rp.extent_size = 0; + + dm_list_init(&pep->prompts); + dm_list_init(&pep->arg_names); + dm_list_init(&pep->arg_create); + dm_list_init(&pep->arg_fail); +} + int pvcreate(struct cmd_context *cmd, int argc, char **argv) { - int i; - int ret = ECMD_PROCESSED; - struct pvcreate_params pp; + struct pvcreate_each_params pep = { 0 }; + int ret; - /* Needed to change the set of orphan PVs. */ - if (!lockd_gl(cmd, "ex", 0)) - return_ECMD_FAILED; + if (!argc) { + log_error("Please enter a physical volume path."); + return 0; + } - pvcreate_params_set_defaults(&pp); + /* + * Five kinds of pvcreate param values: + * 1. defaults + * 2. normal command line args + * 3. recovery-related command line args + * 4. recovery-related args from backup file + * 5. argc/argv free args specifying devices + */ - if (!pvcreate_restore_params_validate(cmd, argc, argv, &pp)) { + pvcreate_each_params_set_defaults(&pep); + + if (!pvcreate_each_params_from_args(cmd, &pep)) return EINVALID_CMD_LINE; - } - if (!pvcreate_params_validate(cmd, argc, &pp)) { + + if (!pvcreate_each_restore_params_from_args(cmd, argc, &pep)) return EINVALID_CMD_LINE; - } - for (i = 0; i < argc; i++) { - if (sigint_caught()) - return_ECMD_FAILED; + if (!pvcreate_each_restore_params_from_backup(cmd, &pep)) + return EINVALID_CMD_LINE; - dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); + pep->pv_count = argc; + pep->pv_names = argv; - if (!pvcreate_single(cmd, argv[i], &pp)) - ret = ECMD_FAILED; + /* + * Needed to change the set of orphan PVs. + * (disable afterward to prevent process_each_pv from doing + * a shared global lock since it's already acquired it ex.) + */ + if (!lockd_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + cmd->lockd_gl_disable = 1; + + if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) { + log_error("Can't get lock for orphan PVs"); + return 0; } + ret = pvcreate_each_device(cmd, &pep); + + unlock_vg(cmd, VG_ORPHANS); + return ret; } diff --git a/tools/toollib.c b/tools/toollib.c index 728e61d4d..fd43d95dc 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -3289,6 +3289,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, const char *only_this_vgname, uint32_t read_flags, + uint32_t each_flags, struct processing_handle *handle, process_single_pv_fn_t process_single_pv) { @@ -3343,7 +3344,7 @@ int process_each_pv(struct cmd_context *cmd, process_all_pvs = dm_list_empty(&arg_pvnames) && dm_list_empty(&arg_tags); process_all_devices = process_all_pvs && (cmd->command->flags & ENABLE_ALL_DEVS) && - arg_count(cmd, all_ARG); + (each_flags & EACH_ALL); /* Needed for a current listing of the global VG namespace. */ if (!only_this_vgname && !lockd_gl(cmd, "sh", 0)) @@ -3498,3 +3499,405 @@ int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, return ECMD_PROCESSED; } + +struct pvcreate_device { + struct dm_list list; + const char *name; + struct device *dev; +}; + +/* + * When a prompt entry is created, save any strings or info + * in this struct that are needed for the prompt messages. + * The VG/PV structs are not be available when the prompt + * is run. + */ +struct pvcreate_prompt { + struct dm_list list; + uint32_t prompt_type; + const char *pv_name; + const char *vg_name; + struct device *dev; + unsigned answer : 1; + unsigned abort_command : 1; +}; + +static void _run_pvcreate_prompt(struct cmd_context *cmd, + struct pvcreate_each_params *pep, + struct pvcreate_prompt *prompt) +{ + if (prompt->type == PROMPT_PVCREATE_PV_IN_VG) { + if (pep->force != DONT_PROMPT_OVERRIDE) { + pep->answer = 0; + log_error("Can't initialize physical volume \"%s\" of volume group \"%s\" without -ff", + prompt->pv_name, prompt->vg_name); + } else if (pp->yes) { + pep->answer = 1; + } else { + if (yes_no_prompt("Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ", + prompt->pv_name, prompt->vg_name) == 'n') { + pep->answer = 0; + log_error("%s: physical volume not initialized", prompt->pv_name); + } else { + pep->answer = 1; + } + } + } +} + + +static pvcreate_device *_pvcreate_list_find_name(struct dm_list *devices, const char *name) +{ + struct pvcreate_device *pd; + + dm_list_iterate_items(pd, devices) { + if (!strcmp(name, pd->name)) + return pd; + } + return NULL; +} + +/* + * If this function returns ECMD_FAILED, it will + * cause the entire command to fail. + * + * If this function decides that a arg_names entry cannot be + * used, but the command might be able to continue without it, + * then it moves that entry from arg_names to arg_fail + * and returns ECMD_SUCCESS. + * + * If this function decides that an arg_names entry could be used + * (possibly requiring a prompt), then it moves the entry from + * arg_names to arg_create and returns ECMD_SUCCESS. + * + * Any arg_names entries that are not moved to arg_fail or + * arg_create were not found. The caller will decide if the + * command can continue if any arg_names entries were not found, + * or if any were moved to arg_fail. + */ + +static int _pvcreate_check_single(struct cmd_context *cmd, + struct volume_group *vg, + struct physical_volume *pv, + struct processing_handle *handle) +{ + struct pvcreate_each_params *pep = (struct pvcreate_each_params *) handle->custom_handle; + struct pvcreate_device *pd; + struct pvcreate_prompt *prompt; + + /* + * Check if pv uuid matches a uuid specified by the command. + */ + if (pep->uuid_str && id_equal(&pv->id, &pep->id)) { + log_error("uuid %s already in use on \"%s\"", pep->uuid_str, pv_dev_name(pv)); + return ECMD_FAILED; + } + + /* + * Check if pvcreate has asked for this device. + */ + if (!(pd = _pvcreate_list_find_name(&pep->arg_names, pv_dev_name(pv)))) + return ECMD_PROCESSED; + +#if 0 + /* TODO: see code in _pvcreate_check() I don't understand */ + dev = dev_cache_get(pd->name, cmd->full_filter); + /* TODO: Do we need to check if dev is NULL here? */ + /* TODO: obtain_device_list_from_udev, filter_refresh_needed, scan_needed ? */ +#endif + + /* + * This test will fail if the device belongs to an MD array. + */ + if (!dev_test_excl(pv->dev)) { + /* FIXME Detect whether device-mapper itself is still using it */ + log_error("Can't open %s exclusively. Mounted filesystem?", + pv_dev_name(pv)); + dm_list_move(&pep->arg_fail, &pd->list); + return ECMD_PROCESSED; + } + + /* + * pvcreate is being run on this device, and it's not a PV, + * or is an orphan PV. Neither case requires a prompt. + */ + if (!vg || is_orphan(pv)) { + pd->dev = pv->dev; + dm_list_move(&pep->arg_create, &pd->list); + return ECMD_PROCESSED; + } + + /* + * 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)))) { + log_error("prompt alloc failed"); + return ECMD_FAILED; + } + + prompt->pv_name = dm_pool_strdup(cmd->mem, pd->name); + prompt->vg_name = dm_pool_strdup(cmd->mem, vg->name); + prompt->prompt_type = PROMPT_PVCREATE_PV_IN_VG; + dm_list_add(&pep->prompts, &prompt->list); + + pd->dev = pv->dev; + dm_list_move(&pep->arg_create, &pd->list); + return ECMD_PROCESSED; +} + +/* + * This can be used by pvcreate, vgcreate and vgextend to create PVs. + * The callers need to set up the pvcreate_each_params structure based + * on command line args. This includes the pv_names field which specifies + * the devices to create PVs on. + * + * This function is a specialized instance of process_each_pv() and + * should be called from a high level in the command. + * + * This function returns ECMD_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 pvcreated. + * + * This function returns ECMD_PROCESSED if the caller requires all + * specified devices to be created, and all were created, or if + * the caller does not require all specified devices to be created + * and one or more were created. + */ + +int pvcreate_each_device(struct cmd_context *cmd, struct pvcreate_each_params *pep) +{ + struct processing_handle *handle; + struct pvcreate_restorable_params rp; + struct pvcreate_device *pd, *pd2; + struct pvcreate_prompt *prompt, *prompt2; + struct physical_volume *pv; + const char *pv_name; + int must_use_all = (cmd->command->flags & MUST_USE_ALL_ARGS); + int ret; + int i; + + for (i = 0; i < pep->pv_count; i++) { + dm_unescape_colons_and_at_signs(pep->pv_names[i], NULL, NULL); + + if (!(pd = dm_pool_zalloc(cmd->mem, sizeof(*pd)))) { + log_error("alloc failed"); + return ECMD_FAILED; + } + + if (!(pd->name = dm_pool_strdup(cmd->mem, pep->pv_names[i]))) { + log_error("strdup failed"); + return ECMD_FAILED; + } + + dm_list_add(&pep->arg_names, &pd->list); + } + + /* + * process all *existing* PVs and devices - this checks if arg_names + * entries are known devices, and if so, if they are PVs, and if so, + * if they are in a VG. + * + * If an arg_names entry is found, it's moved to arg_create if it + * can be used, or arg_fail if it cannot be used. If it's added + * to arg_create but needs a prompt or force option, then an + * corresponding prompt entry is added to pep->prompts. + * + * We don't want this process_each_pv to look at devices that have + * been filtered out by this command. + * FIXME: does it work that way? + */ + + if (!(handle = init_processing_handle(cmd))) { + log_error("Failed to initialize processing handle."); + return ECMD_FAILED; + } + + handle->custom_handle = pep; + + cmd->command->flags |= ENABLE_ALL_DEVS; + + ret = process_each_pv(cmd, 0, NULL, NULL, 0, EACH_ALL, handle, _pvcreate_check_single); + if (ret == ECMD_FAILED) + return ECMD_FAILED; + + destroy_processing_handle(cmd, handle); + + /* + * Check if all arg_names were found by process_each_pv. + */ + dm_list_iterate_items(pd, &pep->arg_names) + log_error("Device %s not found (or ignored by filtering).", pd->name); + + /* + * Can the command continue if some specified devices were not found? + */ + if (!dm_list_empty(&pep->arg_names) && must_use_all) + return ECMD_FAILED; + + /* + * Can the command continue if some specified devices cannot be used? + */ + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + return ECMD_FAILED; + + /* + * The command cannot continue if there are no devices to create. + */ + if (dm_list_empty(&pep->arg_create)) { + log_error("No devices found."); + return ECMD_FAILED; + } + + /* + * Process any prompts that were gathered during the process_each_pv + * checks. Options can override/force/skip prompts. + */ + dm_list_iterate_items_safe(prompt, prompt2, &pep->prompt_devices) { + _run_pvcreate_prompt(cmd, pep, prompt); + + if (!prompt->answer) { + if ((pd = _pvcreate_list_find_name(&pep->arg_create, prompt->pv_name))) { + dm_list_move(&pep->arg_fail, &pd->list); + } else { + /* should never happen */ + return_ECMD_FAILED; + } + } + + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + break; + + if (prompt->abort_command) + return_ECMD_FAILED; + + if (sigint_caught()) + return_ECMD_FAILED; + } + + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + return ECMD_FAILED; + + /* + * wipe signatures on devices being created (was in _pvcreate_check) + */ + dm_list_iterate_items_safe(pd, pd2, &pep->arg_create) { + if (!wipe_known_signatures(cmd, pd->dev, pd->name, TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER, + 0, pep->yes, pep->force, wiped)) { + dm_list_move(&pep->arg_fail, &pd->list); + } + + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + break; + +#if 0 + /* + * FIXME: is this still needed or need changing? + * FIXME: replace pd->dev with new dev? + * + * wipe_known_signatures fires + * WATCH event to update udev database. But at the moment, + * we have no way to synchronize with such event - we may + * end up still seeing the old info in udev db and pvcreate + * can fail to proceed because of the device still being + * filtered (because of the stale info in udev db). + * Disable udev dev-ext source temporarily here for + * this reason and rescan with DEV_EXT_NONE dev-ext + * source (so filters use DEV_EXT_NONE source). + */ + dev_ext_src = external_device_info_source(); + if (wiped && (dev_ext_src == DEV_EXT_UDEV)) + init_external_device_info_source(DEV_EXT_NONE); + + dev = dev_cache_get(pd->name, cmd->full_filter); + + init_external_device_info_source(dev_ext_src); + + if (!dev) { + log_error("%s: Couldn't find device. Check your filters?", pd->name); + dm_list_move(&pep->arg_fail, &pd->list); + } +#endif + } + + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + return ECMD_FAILED; + + /* + * create pvs on devices + */ + dm_list_iterate_items_safe(pd, pd2, &pep->arg_create) { + + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + break; + + pv_name = pd->name; + + /* FIXME: get rid of rp usage in pv_create to avoid this. */ + rp.restorefile = pep->restorefile; + rp.id = pep->id; + rp.idp = &pdp->id; + rp.ba_start = pep->ba_start; + rp.ba_size = pep->ba_size; + rp.pe_start = pep->pe_start; + rp.extent_count = pep->extent_count; + rp.extent_size = pep->extent_size; + + if (!(pv = pv_create(cmd, pd->dev, pep->size, pep->data_alignment, + pep->data_alignment_offset, pep->labelsector, + pep->pvmetadatacopies, pep->pvmetadatasize, + pep->metadataignore, &rp))) { + log_error("Failed to setup physical volume \"%s\"", pv_name); + dm_list_move(&pep->arg_fail, &pd->list); + continue; + } + + log_verbose("Set up physical volume for \"%s\" with %" PRIu64 + " available sectors", pv_name, pv_size(pv)); + + pv->status |= UNLABELLED_PV; + + if (!label_remove(pv->dev)) { + log_error("Failed to wipe existing label on %s", pv_name); + dm_list_move(&pep->arg_fail, &pd->list); + continue; + + } + + if (pep->zero) { + log_verbose("Zeroing start of device %s", pv_name); + + if (!dev_open_quiet(pv->dev)) { + log_error("%s not opened: device not zeroed", pv_name); + dm_list_move(&pep->arg_fail, &pd->list); + continue; + } + + if (!dev_set(pv->dev, UINT64_C(0), (size_t) 2048, 0)) { + log_error("%s not wiped: aborting", pv_name); + if (!dev_close(dev)) + stack; + dm_list_move(&pep->arg_fail, &pd->list); + continue; + } + if (!dev_close(pv->dev)) + stack; + } + + log_verbose("Writing physical volume data to disk \"%s\"", pv_name); + + if (!pv_write(cmd, pv, 1)) { + log_error("Failed to write physical volume \"%s\"", pv_name); + dm_list_move(&pep->arg_fail, &pd->list); + } + + log_print_unless_silent("Physical volume \"%s\" successfully created", pv_name); + } + + if (!dm_list_empty(&pep->arg_fail) && must_use_all) + return ECMD_FAILED; + + return ECMD_PROCESSED; +} + diff --git a/tools/tools.h b/tools/tools.h index 4179cc8f4..de7064970 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -107,6 +107,8 @@ struct arg_value_group_list { #define NO_METADATA_PROCESSING 0x00000040 /* Command wants to scan for new devices and force labels to be read from them all. */ #define REQUIRES_FULL_LABEL_SCAN 0x00000080 +/* Command must use all specified arg names and fail if all cannot be used. */ +#define MUST_USE_ALL_ARGS 0x00000100 /* a register of the lvm commands */ struct command { |