diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c index 56eb1ca5e..1bc95572c 100644 --- a/lib/format_text/archiver.c +++ b/lib/format_text/archiver.c @@ -329,28 +329,113 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd, return vg; } -/* ORPHAN and VG locks held before calling this */ -int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, int drop_lvmetad) +static int _restore_vg_should_write_pv(struct physical_volume *pv, struct pvcreate_params *pp) { - struct pv_list *pvl; + struct lvmcache_info *info; + + if (pp) + return 1; + + if (!(pv->fmt->features & FMT_PV_FLAGS)) + return 0; + + if (!(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) { + log_error("Failed to find cached info for PV %s.", pv_dev_name(pv)); + return -1; + } + + /* + * We're restoring a VG and if the PV_EXT_USED + * flag is not set yet in PV, we need to set it now! + * This may happen if we have plain PVs without a VG + * and we're restoring former VG from backup on top + * of these PVs. + */ + if (!(lvmcache_ext_flags(info) & PV_EXT_USED)) + return 1; + + return 0; +} + +/* ORPHAN and VG locks held before calling this */ +int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, + struct pvcreate_params *pp, int drop_lvmetad) +{ + struct dm_list new_pvs; + struct pv_list *pvl, *new_pvl; + struct physical_volume *existing_pv, *pv; + struct dm_list *pvs = &vg->pvs;; struct format_instance *fid; struct format_instance_ctx fic; + int should_write_pv; struct pv_to_write *pvw; - uint32_t tmp; + uint32_t tmp_extent_size; /* * FIXME: Check that the PVs referenced in the backup are * not members of other existing VGs. */ + /* Prepare new PVs if needed. */ + if (pp) { + dm_list_init(&new_pvs); + + dm_list_iterate_items(pvl, &vg->pvs) { + existing_pv = pvl->pv; + + pp->rp.id = existing_pv->id; + pp->rp.idp = &pp->rp.id; + pp->rp.pe_start = pv_pe_start(existing_pv); + pp->rp.extent_count = pv_pe_count(existing_pv); + pp->rp.extent_size = pv_pe_size(existing_pv); + /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1 */ + + if (!(pv = pv_create(cmd, pv_dev(existing_pv), + 0, 0, 0, + pp->labelsector, + pp->pvmetadatacopies, + pp->pvmetadatasize, + 0, &pp->rp))) { + log_error("Failed to setup physical volume \"%s\".", + pv_dev_name(existing_pv)); + return 0; + } + pv->vg_name = vg->name; + pv->vgid = vg->id; + + if (!(new_pvl = dm_pool_zalloc(vg->vgmem, sizeof(*new_pvl)))) { + log_error("Failed to allocate PV list item for \"%s\".", + pv_dev_name(pvl->pv)); + return 0; + } + new_pvl->pv = pv; + dm_list_add(&new_pvs, &new_pvl->list); + + log_verbose("Set up physical volume for \"%s\" with %" PRIu64 + " available sectors.", pv_dev_name(pv), pv_size(pv)); + } + + pvs = &new_pvs; + } + /* Attempt to write out using currently active format */ fic.type = FMT_INSTANCE_AUX_MDAS; fic.context.vg_ref.vg_name = vg->name; fic.context.vg_ref.vg_id = NULL; if (!(fid = cmd->fmt->ops->create_instance(cmd->fmt, &fic))) { - log_error("Failed to allocate format instance"); + log_error("Failed to allocate format instance."); return 0; } + + if (pp) { + log_verbose("Deleting existing metadata for VG %s.", vg->name); + if (!vg_remove_mdas(vg)) { + cmd->fmt->ops->destroy_instance(fid); + log_error("Removal of existing metadata for VG %s failed.", vg->name); + return 0; + } + } + vg_set_fid(vg, fid); /* @@ -363,25 +448,36 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, int drop } /* Add any metadata areas on the PVs */ - dm_list_iterate_items(pvl, &vg->pvs) { - if (pvl->pv->fmt->features & FMT_PV_FLAGS) { + dm_list_iterate_items(pvl, pvs) { + if ((should_write_pv = _restore_vg_should_write_pv(pvl->pv, pp)) < 0) + return_0; + + if (should_write_pv) { if (!(pvw = dm_pool_zalloc(vg->vgmem, sizeof(*pvw)))) { - log_error("pv_to_write allocation for '%s' failed", pv_dev_name(pvl->pv)); + log_error("Failed to allocate structure for scheduled " + "writing of PV '%s'.", pv_dev_name(pvl->pv)); return 0; } + + if (pp) { + pvw->new_pv = 1; + pvw->pp = pp; + } + pvw->pv = pvl->pv; dm_list_add(&vg->pvs_to_write, &pvw->list); } - tmp = vg->extent_size; + /* Add any metadata areas on the PV. */ + tmp_extent_size = vg->extent_size; vg->extent_size = 0; if (!vg->fid->fmt->ops->pv_setup(vg->fid->fmt, pvl->pv, vg)) { - vg->extent_size = tmp; - log_error("Format-specific setup for %s failed", + vg->extent_size = tmp_extent_size; + log_error("Format-specific setup for %s failed.", pv_dev_name(pvl->pv)); return 0; } - vg->extent_size = tmp; + vg->extent_size = tmp_extent_size; } if (!vg_write(vg)) @@ -435,7 +531,7 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, missing_pvs = vg_missing_pv_count(vg); if (missing_pvs == 0) - r = backup_restore_vg(cmd, vg, 1); + r = backup_restore_vg(cmd, vg, NULL, 1); else log_error("Cannot restore Volume Group %s with %i PVs " "marked as missing.", vg->name, missing_pvs); diff --git a/lib/format_text/archiver.h b/lib/format_text/archiver.h index c283420c9..f85e5afc7 100644 --- a/lib/format_text/archiver.h +++ b/lib/format_text/archiver.h @@ -51,7 +51,8 @@ int backup_remove(struct cmd_context *cmd, const char *vg_name); struct volume_group *backup_read_vg(struct cmd_context *cmd, const char *vg_name, const char *file); -int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, int drop_lvmetad); +int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, + struct pvcreate_params *pp, int drop_lvmetad); int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, const char *file, int force); int backup_restore(struct cmd_context *cmd, const char *vg_name, int force); diff --git a/tools/vgconvert.c b/tools/vgconvert.c index 0b680b93c..de21a4794 100644 --- a/tools/vgconvert.c +++ b/tools/vgconvert.c @@ -19,14 +19,9 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, struct processing_handle *handle __attribute__((unused))) { - struct physical_volume *pv, *existing_pv; - struct pvcreate_restorable_params rp; + struct pvcreate_params pp; struct logical_volume *lv; struct lv_list *lvl; - int pvmetadatacopies = 0; - uint64_t pvmetadatasize = 0; - struct pv_list *pvl; - int change_made = 0; struct lvinfo info; int active = 0; @@ -39,21 +34,22 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, return ECMD_FAILED; } + pvcreate_params_set_defaults(&pp); + if (cmd->fmt->features & FMT_MDAS) { if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Metadata size may not be negative"); return EINVALID_CMD_LINE; } - pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, - UINT64_C(0)); - if (!pvmetadatasize) - pvmetadatasize = + 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); - pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); - if (pvmetadatacopies < 0) - pvmetadatacopies = + pp.pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1); + if (pp.pvmetadatacopies < 0) + pp.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL); } @@ -63,9 +59,11 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, return EINVALID_CMD_LINE; } - rp.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, UINT64_C(0)); + pp.rp.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, UINT64_C(0)); } + pp.labelsector = arg_int64_value(cmd, labelsector_ARG, DEFAULT_LABELSECTOR); + if (!vg_check_new_extent_size(cmd->fmt, vg->extent_size)) return_ECMD_FAILED; @@ -124,67 +122,6 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, if (active) return_ECMD_FAILED; - dm_list_iterate_items(pvl, &vg->pvs) { - existing_pv = pvl->pv; - - rp.id = existing_pv->id; - rp.idp = &rp.id; - rp.pe_start = pv_pe_start(existing_pv); - rp.extent_count = pv_pe_count(existing_pv); - rp.extent_size = pv_pe_size(existing_pv); - - /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1; */ - - if (!(pv = pv_create(cmd, pv_dev(existing_pv), - 0, 0, 0, - arg_int64_value(cmd, labelsector_ARG, - DEFAULT_LABELSECTOR), - pvmetadatacopies, pvmetadatasize, 0, &rp))) { - log_error("Failed to setup physical volume \"%s\"", - pv_dev_name(existing_pv)); - if (change_made) - log_error("Use pvcreate and vgcfgrestore to " - "repair from archived metadata."); - return ECMD_FAILED; - } - - /* Need to revert manually if it fails after this point */ - change_made = 1; - - log_verbose("Set up physical volume for \"%s\" with %" PRIu64 - " available sectors", pv_dev_name(pv), pv_size(pv)); - - /* Wipe existing label first */ - if (!label_remove(pv_dev(pv))) { - log_error("Failed to wipe existing label on %s", - pv_dev_name(pv)); - log_error("Use pvcreate and vgcfgrestore to repair " - "from archived metadata."); - return ECMD_FAILED; - } - - log_very_verbose("Writing physical volume data to disk \"%s\"", - pv_dev_name(pv)); - if (!(pv_write(cmd, pv, 0))) { - log_error("Failed to write physical volume \"%s\"", - pv_dev_name(pv)); - log_error("Use pvcreate and vgcfgrestore to repair " - "from archived metadata."); - return ECMD_FAILED; - } - log_verbose("Physical volume \"%s\" successfully created", - pv_dev_name(pv)); - } - - log_verbose("Deleting existing metadata for VG %s", vg_name); - if (!vg_remove_mdas(vg)) { - log_error("Removal of existing metadata for %s failed.", - vg_name); - log_error("Use pvcreate and vgcfgrestore to repair " - "from archived metadata."); - return ECMD_FAILED; - } - /* FIXME Cache the label format change so we don't have to skip this */ if (test_mode()) { log_verbose("Test mode: Skipping metadata writing for VG %s in" @@ -194,7 +131,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, log_verbose("Writing metadata for VG %s using format %s", vg_name, cmd->fmt->name); - if (!backup_restore_vg(cmd, vg, 0)) { + if (!backup_restore_vg(cmd, vg, &pp, 0)) { log_error("Conversion failed for volume group %s.", vg_name); log_error("Use pvcreate and vgcfgrestore to repair from " "archived metadata.");