diff options
author | David Teigland <teigland@redhat.com> | 2016-05-26 14:25:53 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2016-05-26 16:11:36 -0500 |
commit | fb36792b0a6cfda78daa1778febfefe2d4ca819d (patch) | |
tree | 934cbfbcbeba46401d3b219d9f41351d000b8d4c | |
parent | 29d47efc549c3eef56621e03e87eff5377b273d5 (diff) | |
download | lvm2-dev-dct-lvm2app-ifdef.tar.gz |
liblvm2app: move applib code into separate source filedev-dct-lvm2app-ifdef
-rw-r--r-- | lib/Makefile.in | 1 | ||||
-rw-r--r-- | lib/metadata/applib.c | 907 | ||||
-rw-r--r-- | lib/metadata/metadata.c | 707 | ||||
-rw-r--r-- | lib/metadata/metadata.h | 8 | ||||
-rw-r--r-- | lib/metadata/pv_manip.c | 180 |
5 files changed, 924 insertions, 879 deletions
diff --git a/lib/Makefile.in b/lib/Makefile.in index 467ef9077..0aefcb0f0 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -90,6 +90,7 @@ SOURCES =\ locking/locking.c \ locking/no_locking.c \ log/log.c \ + metadata/applib.c \ metadata/cache_manip.c \ metadata/lv.c \ metadata/lv_manip.c \ diff --git a/lib/metadata/applib.c b/lib/metadata/applib.c new file mode 100644 index 000000000..89dafbaad --- /dev/null +++ b/lib/metadata/applib.c @@ -0,0 +1,907 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "lib.h" +#include "device.h" +#include "metadata.h" +#include "toolcontext.h" +#include "lvm-string.h" +#include "lvm-file.h" +#include "lvm-signal.h" +#include "lvmcache.h" +#include "lvmetad.h" +#include "memlock.h" +#include "str_list.h" +#include "pv_alloc.h" +#include "segtype.h" +#include "activate.h" +#include "display.h" +#include "locking.h" +#include "archiver.h" +#include "defaults.h" +#include "lvmlockd.h" +#include "time.h" +#include "lvmnotify.h" + +#include <math.h> +#include <sys/param.h> + + +#ifdef APPLIB_SUPPORT + +/* + * Extend a VG by a single PV / device path + * + * Parameters: + * - vg: handle of volume group to extend by 'pv_name' + * - pv_name: device path of PV to add to VG + * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate + * - max_phys_block_size: largest physical block size found amongst PVs in a VG + * + */ +static int vg_extend_single_pv(struct volume_group *vg, char *pv_name, + struct pvcreate_params *pp, + unsigned int *max_phys_block_size) +{ + struct physical_volume *pv; + struct pv_to_write *pvw; + int new_pv = 0; + + pv = find_pv_by_name(vg->cmd, pv_name, 1, 1); + + if (!pv && !pp) { + log_error("%s not identified as an existing " + "physical volume", pv_name); + return 0; + } else if (!pv && pp) { + if (!(pv = pvcreate_vol(vg->cmd, pv_name, pp, 0))) + return_0; + new_pv = 1; + } + + if (!(check_dev_block_size_for_vg(pv->dev, (const struct volume_group *) vg, + max_phys_block_size))) + goto_bad; + + if (!add_pv_to_vg(vg, pv_name, pv, new_pv)) + goto_bad; + + if ((pv->fmt->features & FMT_PV_FLAGS) || + (pv->status & UNLABELLED_PV)) { + if (!(pvw = dm_pool_zalloc(vg->vgmem, sizeof(*pvw)))) { + log_error("pv_to_write allocation for '%s' failed", pv_name); + return 0; + } + pvw->pv = pv; + pvw->pp = new_pv ? pp : NULL; + pvw->new_pv = new_pv; + dm_list_add(&vg->pvs_to_write, &pvw->list); + } + + return 1; +bad: + free_pv_fid(pv); + return 0; +} + +/* + * Extend a VG by a single PV / device path + * + * Parameters: + * - vg: handle of volume group to extend by 'pv_name' + * - pv_count: count of device paths of PVs + * - pv_names: device paths of PVs to add to VG + * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate + * + */ +int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names, + struct pvcreate_params *pp) +{ + int i; + char *pv_name; + unsigned int max_phys_block_size = 0; + + if (!vg_check_status(vg, RESIZEABLE_VG)) + return_0; + + /* attach each pv */ + for (i = 0; i < pv_count; i++) { + if (!(pv_name = dm_strdup(pv_names[i]))) { + log_error("Failed to duplicate pv name %s.", pv_names[i]); + return 0; + } + dm_unescape_colons_and_at_signs(pv_name, NULL, NULL); + if (!vg_extend_single_pv(vg, pv_name, pp, &max_phys_block_size)) { + log_error("Unable to add physical volume '%s' to " + "volume group '%s'.", pv_name, vg->name); + dm_free(pv_name); + return 0; + } + dm_free(pv_name); + } + + (void) check_pv_dev_sizes(vg); + +/* FIXME Decide whether to initialise and add new mdahs to format instance */ + + return 1; +} + +int vg_reduce(struct volume_group *vg, const char *pv_name) +{ + struct physical_volume *pv; + struct pv_list *pvl; + + if (!(pvl = find_pv_in_vg(vg, pv_name))) { + log_error("Physical volume %s not in volume group %s.", + pv_name, vg->name); + return 0; + } + + pv = pvl->pv; + + if (vgreduce_single(vg->cmd, vg, pv, 0)) { + dm_list_add(&vg->removed_pvs, &pvl->list); + return 1; + } + + log_error("Unable to remove physical volume '%s' from " + "volume group '%s'.", pv_name, vg->name); + + return 0; +} + +/* + * See if we may pvcreate on this device. + * 0 indicates we may not. + */ +static int _pvcreate_check(struct cmd_context *cmd, const char *name, + struct pvcreate_params *pp, int *wiped) +{ + static const char really_init_msg[] = "Really INITIALIZE physical volume"; + static const char not_init_msg[] = "physical volume not initialized"; + struct physical_volume *pv; + struct device *dev; + int r = 0; + int scan_needed = 0; + int filter_refresh_needed = 0; + int used; + + /* FIXME Check partition type is LVM unless --force is given */ + + *wiped = 0; + + /* Is there a pv here already? */ + pv = find_pv_by_name(cmd, name, 1, 1); + + /* Allow partial & exported VGs to be destroyed. */ + /* We must have -ff to overwrite a non orphan */ + if (pv) { + if (!is_orphan(pv) && pp->force != DONT_PROMPT_OVERRIDE) { + log_error("Can't initialize physical volume \"%s\" of " + "volume group \"%s\" without -ff.", name, pv_vg_name(pv)); + goto out; + } + + if ((used = is_used_pv(pv)) < 0) + goto_out; + + if (used && pp->force != DONT_PROMPT_OVERRIDE) { + log_error("PV %s is used by a VG but its metadata is missing.", name); + log_error("Can't initialize PV '%s' without -ff.", name); + goto out; + } + } + + /* prompt */ + if (pv && !pp->yes) { + if (is_orphan(pv)) { + if (used) { + if (yes_no_prompt("%s \"%s\" that is marked as belonging to a VG [y/n]? ", + really_init_msg, name) == 'n') { + log_error("%s: %s", name, not_init_msg); + goto out; + } + } + } else { + if (yes_no_prompt("%s \"%s\" of volume group \"%s\" [y/n]? ", + really_init_msg, name, pv_vg_name(pv)) == 'n') { + log_error("%s: %s", name, not_init_msg); + goto out; + } + } + } + + if (sigint_caught()) + goto_out; + + dev = dev_cache_get(name, cmd->full_filter); + + /* + * Refresh+rescan at the end is needed if: + * - we don't obtain device list from udev, + * hence persistent cache file is used + * and we need to trash it and reevaluate + * for any changes done outside - adding + * any new foreign signature which may affect + * filtering - before we do pvcreate, we + * need to be sure that we have up-to-date + * view for filters + * + * - we have wiped existing foreign signatures + * from dev as this may affect what's filtered + * as well + * + * + * Only rescan at the end is needed if: + * - we've just checked whether dev is fileterd + * by MD filter. We do the refresh in-situ, + * so no need to require the refresh at the + * end of this fn. This is to allow for + * wiping MD signature during pvcreate for + * the dev - the dev would normally be + * filtered because of MD filter. + * This is an exception. + */ + + /* Is there an md superblock here? */ + if (!dev && md_filtering()) { + if (!refresh_filters(cmd)) + goto_out; + + init_md_filtering(0); + dev = dev_cache_get(name, cmd->full_filter); + init_md_filtering(1); + + scan_needed = 1; + } else if (!obtain_device_list_from_udev()) + filter_refresh_needed = scan_needed = 1; + + if (!dev) { + log_error("Device %s not found (or ignored by filtering).", name); + goto out; + } + + /* + * This test will fail if the device belongs to an MD array. + */ + if (!dev_test_excl(dev)) { + /* FIXME Detect whether device-mapper itself is still using it */ + log_error("Can't open %s exclusively. Mounted filesystem?", + name); + goto out; + } + + if (!wipe_known_signatures(cmd, dev, name, + TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER, + 0, pp->yes, pp->force, wiped)) { + log_error("Aborting pvcreate on %s.", name); + goto out; + } + + if (*wiped) + filter_refresh_needed = scan_needed = 1; + + if (sigint_caught()) + goto_out; + + if (pv && !is_orphan(pv) && pp->force) + log_warn("WARNING: Forcing physical volume creation on " + "%s%s%s%s", name, + !is_orphan(pv) ? " of volume group \"" : "", + pv_vg_name(pv), + !is_orphan(pv) ? "\"" : ""); + + r = 1; + +out: + if (filter_refresh_needed) + if (!refresh_filters(cmd)) { + stack; + r = 0; + } + + if (scan_needed) { + lvmcache_force_next_label_scan(); + if (!lvmcache_label_scan(cmd)) { + stack; + r = 0; + } + } + + free_pv_fid(pv); + return r; +} + +int pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw) +{ + struct physical_volume *pv = pvw->pv; + struct device *dev = pv->dev; + const char *pv_name = dev_name(dev); + + if (pvw->new_pv) { + /* Wipe existing label first */ + if (!label_remove(pv_dev(pv))) { + log_error("Failed to wipe existing label on %s", pv_name); + return 0; + } + + if (pvw->pp->zero) { + log_verbose("Zeroing start of device %s", pv_name); + if (!dev_open_quiet(dev)) { + log_error("%s not opened: device not zeroed", pv_name); + return 0; + } + + if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) { + log_error("%s not wiped: aborting", pv_name); + if (!dev_close(dev)) + stack; + return 0; + } + if (!dev_close(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); + return 0; + } + + if (pvw->new_pv) + log_print_unless_silent("Physical volume \"%s\" successfully created", pv_name); + else + log_verbose("Physical volume \"%s\" successfully written", pv_name); + + return 1; +} + +static int _verify_pv_create_params(struct pvcreate_params *pp) +{ + /* + * FIXME: Some of these checks are duplicates in pvcreate_params_validate. + */ + if (pp->pva.pvmetadatacopies > 2) { + log_error("Metadatacopies may only be 0, 1 or 2"); + return 0; + } + + if (pp->pva.data_alignment > UINT32_MAX) { + log_error("Physical volume data alignment is too big."); + return 0; + } + + if (pp->pva.data_alignment_offset > UINT32_MAX) { + log_error("Physical volume data alignment offset is too big."); + return 0; + } + + return 1; +} + +/* + * pvcreate_vol() - initialize a device with PV label and metadata area + * + * Parameters: + * - pv_name: device path to initialize + * - pp: parameters to pass to pv_create; if NULL, use default values + * + * Returns: + * NULL: error + * struct physical_volume * (non-NULL): handle to physical volume created + */ +struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_name, + struct pvcreate_params *pp, int write_now) +{ + struct physical_volume *pv = NULL; + struct device *dev; + int wiped = 0; + struct dm_list mdas; + struct pvcreate_params default_pp; + char buffer[64] __attribute__((aligned(8))); + dev_ext_t dev_ext_src; + + pvcreate_params_set_defaults(&default_pp); + if (!pp) + pp = &default_pp; + + if (!_verify_pv_create_params(pp)) { + goto bad; + } + + if (pp->pva.idp) { + if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL, NULL)) && + (dev != dev_cache_get(pv_name, cmd->full_filter))) { + if (!id_write_format((const struct id*)&pp->pva.idp->uuid, + buffer, sizeof(buffer))) + goto_bad; + log_error("uuid %s already in use on \"%s\"", buffer, + dev_name(dev)); + goto bad; + } + } + + if (!_pvcreate_check(cmd, pv_name, pp, &wiped)) + goto_bad; + + if (sigint_caught()) + goto_bad; + + /* + * wipe_known_signatures called in _pvcreate_check 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(pv_name, cmd->full_filter); + + init_external_device_info_source(dev_ext_src); + + if (!dev) { + log_error("%s: Couldn't find device. Check your filters?", + pv_name); + goto bad; + } + + dm_list_init(&mdas); + + if (!(pv = pv_create(cmd, dev, &pp->pva))) { + log_error("Failed to setup physical volume \"%s\"", pv_name); + goto bad; + } + + log_verbose("Set up physical volume for \"%s\" with %" PRIu64 + " available sectors", pv_name, pv_size(pv)); + + pv->status |= UNLABELLED_PV; + if (write_now) { + struct pv_to_write pvw; + pvw.pp = pp; + pvw.pv = pv; + pvw.new_pv = 1; + if (!pvcreate_write(cmd, &pvw)) + goto bad; + } + + return pv; + +bad: + return NULL; +} + +/* FIXME: liblvm todo - make into function that returns handle */ +struct physical_volume *find_pv_by_name(struct cmd_context *cmd, + const char *pv_name, + int allow_orphan, int allow_unformatted) +{ + struct device *dev; + struct pv_list *pvl; + struct dm_list *pvslist; + struct physical_volume *pv = NULL; + + lvmcache_seed_infos_from_lvmetad(cmd); + + if (!(dev = dev_cache_get(pv_name, cmd->filter))) { + if (!allow_unformatted) + log_error("Physical volume %s not found", pv_name); + return_NULL; + } + + if (!(pvslist = get_pvs(cmd))) + return_NULL; + + dm_list_iterate_items(pvl, pvslist) + if (pvl->pv->dev == dev) + pv = pvl->pv; + else + free_pv_fid(pvl->pv); + + if (!pv && !allow_unformatted) + log_error("Physical volume %s not found", pv_name); + + if (pv && !allow_orphan && is_orphan_vg(pv->vg_name)) { + log_error("Physical volume %s not in a volume group", pv_name); + goto bad; + } + + return pv; + +bad: + free_pv_fid(pv); + return NULL; +} + +const char *find_vgname_from_pvid(struct cmd_context *cmd, + const char *pvid) +{ + char *vgname; + struct lvmcache_info *info; + + vgname = lvmcache_vgname_from_pvid(cmd, pvid); + + if (is_orphan_vg(vgname)) { + if (!(info = lvmcache_info_from_pvid(pvid, 0))) { + return_NULL; + } + /* + * If an orphan PV has no MDAs, or it has MDAs but the + * MDA is ignored, it may appear to be an orphan until + * the metadata is read off another PV in the same VG. + * Detecting this means checking every VG by scanning + * every PV on the system. + */ + if (lvmcache_uncertain_ownership(info)) { + if (!scan_vgs_for_pvs(cmd, WARN_PV_READ)) { + log_error("Rescan for PVs without " + "metadata areas failed."); + return NULL; + } + /* + * Ask lvmcache again - we may have a non-orphan + * name now + */ + vgname = lvmcache_vgname_from_pvid(cmd, pvid); + } + } + return vgname; +} + +const char *find_vgname_from_pvname(struct cmd_context *cmd, + const char *pvname) +{ + const char *pvid; + + pvid = lvmcache_pvid_from_devname(cmd, pvname); + if (!pvid) + /* Not a PV */ + return NULL; + + return find_vgname_from_pvid(cmd, pvid); +} + +static int _get_pvs(struct cmd_context *cmd, uint32_t warn_flags, + struct dm_list *pvslist, struct dm_list *vgslist) +{ + struct dm_str_list *strl; + const char *vgname, *vgid; + struct pv_list *pvl, *pvl_copy; + struct dm_list *vgids; + struct volume_group *vg; + int consistent = 0; + int old_pvmove; + struct vg_list *vgl_item = NULL; + int have_pv = 0; + + lvmcache_label_scan(cmd); + + /* Get list of VGs */ + if (!(vgids = get_vgids(cmd, 1))) { + log_error("get_pvs: get_vgids failed"); + return 0; + } + + /* Read every VG to ensure cache consistency */ + /* Orphan VG is last on list */ + old_pvmove = pvmove_mode(); + init_pvmove(1); + dm_list_iterate_items(strl, vgids) { + vgid = strl->str; + if (!vgid) + continue; /* FIXME Unnecessary? */ + consistent = 0; + if (!(vgname = lvmcache_vgname_from_vgid(NULL, vgid))) { + stack; + continue; + } + + /* + * When we are retrieving a list to return toliblvm we need + * that list to contain VGs that are modifiable as we are using + * the vgmem pool in the vg to provide allocation for liblvm. + * This is a hack to prevent the vg from getting cached as the + * vgid will be NULL. + * FIXME Remove this hack. + */ + + warn_flags |= WARN_INCONSISTENT; + + if (!(vg = vg_read_internal(cmd, vgname, (!vgslist) ? vgid : NULL, warn_flags, &consistent))) { + stack; + continue; + } + + /* Move PVs onto results list */ + if (pvslist) + dm_list_iterate_items(pvl, &vg->pvs) { + if (!(pvl_copy = copy_pvl(cmd->mem, pvl))) { + log_error("PV list allocation failed"); + release_vg(vg); + return 0; + } + /* If we are going to release the VG, don't + * store a pointer to it in the PV structure. + */ + if (!vgslist) + pvl_copy->pv->vg = NULL; + else + /* + * Make sure the vg mode indicates + * writeable. + * FIXME Rework function to take a + * parameter to control this + */ + pvl_copy->pv->vg->open_mode = 'w'; + have_pv = 1; + dm_list_add(pvslist, &pvl_copy->list); + } + + /* + * In the case of the library we want to preserve the embedded + * volume group as subsequent calls to retrieve data about the + * PV require it. + */ + if (!vgslist || !have_pv) + release_vg(vg); + else { + /* + * Add VG to list of VG objects that will be returned + */ + vgl_item = dm_pool_alloc(cmd->mem, sizeof(*vgl_item)); + if (!vgl_item) { + log_error("VG list element allocation failed"); + return 0; + } + vgl_item->vg = vg; + vg = NULL; + dm_list_add(vgslist, &vgl_item->list); + } + have_pv = 0; + } + init_pvmove(old_pvmove); + + if (!pvslist) + dm_pool_free(cmd->mem, vgids); + + return 1; +} + +/* + * Retrieve a list of all physical volumes. + * @param cmd Command context + * @param pvslist Set to NULL if you want memory for list created, + * else valid memory + * @param vgslist Set to NULL if you need the pv structures to contain + * valid vg pointer. This is the list of VGs + * @returns NULL on errors, else pvslist which will equal passed-in value if + * supplied. + */ +struct dm_list *get_pvs_internal(struct cmd_context *cmd, + struct dm_list *pvslist, + struct dm_list *vgslist) +{ + struct dm_list *results = pvslist; + + if (NULL == results) { + if (!(results = dm_pool_alloc(cmd->mem, sizeof(*results)))) { + log_error("PV list allocation failed"); + return 0; + } + + dm_list_init(results); + } + + if (!_get_pvs(cmd, WARN_PV_READ, results, vgslist)) { + if (!pvslist) + dm_pool_free(cmd->mem, results); + return NULL; + } + return results; +} + +int scan_vgs_for_pvs(struct cmd_context *cmd, uint32_t warn_flags) +{ + return _get_pvs(cmd, warn_flags, NULL, NULL); +} + +/* + * Decide whether it is "safe" to wipe the labels on this device. + * 0 indicates we may not. + */ +static int pvremove_check(struct cmd_context *cmd, const char *name, + unsigned force_count, unsigned prompt, struct dm_list *pvslist) +{ + static const char really_wipe_msg[] = "Really WIPE LABELS from physical volume"; + struct device *dev; + struct label *label; + struct pv_list *pvl; + struct physical_volume *pv = NULL; + int used; + int r = 0; + + /* FIXME Check partition type is LVM unless --force is given */ + + if (!(dev = dev_cache_get(name, cmd->filter))) { + log_error("Device %s not found.", name); + return 0; + } + + /* Is there a pv here already? */ + /* If not, this is an error unless you used -f. */ + if (!label_read(dev, &label, 0)) { + if (force_count) + return 1; + log_error("No PV label found on %s.", name); + return 0; + } + + dm_list_iterate_items(pvl, pvslist) + if (pvl->pv->dev == dev) + pv = pvl->pv; + + if (!pv) { + log_error(INTERNAL_ERROR "Physical Volume %s has a label, " + "but is neither in a VG nor orphan.", name); + goto out; /* better safe than sorry */ + } + + if (is_orphan(pv)) { + if ((used = is_used_pv(pv)) < 0) + goto_out; + + if (used) { + log_warn("WARNING: PV %s is used by a VG but its metadata is missing.", name); + + if (force_count < 2) + goto_bad; + + if (!prompt && + yes_no_prompt("%s \"%s\" that is marked as belonging to a VG [y/n]? ", + really_wipe_msg, name) == 'n') + goto_bad; + } + } else { + log_warn("WARNING: PV %s is used by VG %s (consider using vgreduce).", name, pv_vg_name(pv)); + + if (force_count < 2) + goto_bad; + + if (!prompt && + yes_no_prompt("%s \"%s\" of volume group \"%s\" [y/n]? ", + really_wipe_msg, name, pv_vg_name(pv)) == 'n') + goto_bad; + } + + if (force_count) + log_warn("WARNING: Wiping physical volume label from " + "%s%s%s%s", name, + !is_orphan(pv) ? " of volume group \"" : "", + pv_vg_name(pv), + !is_orphan(pv) ? "\"" : ""); + + r = 1; +bad: + if (!r) { + log_error("%s: physical volume label not removed.", name); + + if (force_count < 2) /* Show hint as log_error() */ + log_error("(If you are certain you need pvremove, " + "then confirm by using --force twice.)"); + } +out: + return r; +} + +int pvremove_single(struct cmd_context *cmd, const char *pv_name, + void *handle __attribute__((unused)), unsigned force_count, + unsigned prompt, struct dm_list *pvslist) +{ + struct device *dev; + struct lvmcache_info *info; + int r = 0; + + if (!pvremove_check(cmd, pv_name, force_count, prompt, pvslist)) + goto out; + + if (!(dev = dev_cache_get(pv_name, cmd->filter))) { + log_error("%s: Couldn't find device. Check your filters?", + pv_name); + goto out; + } + + info = lvmcache_info_from_pvid(dev->pvid, 0); + + if (!dev_test_excl(dev)) { + /* FIXME Detect whether device-mapper is still using the device */ + log_error("Can't open %s exclusively - not removing. " + "Mounted filesystem?", dev_name(dev)); + goto out; + } + + /* Wipe existing label(s) */ + if (!label_remove(dev)) { + log_error("Failed to wipe existing label(s) on %s", pv_name); + goto out; + } + + if (info) + lvmcache_del(info); + + if (!lvmetad_pv_gone_by_dev(dev)) + goto_out; + + log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped", + pv_name); + + r = 1; + +out: + return r; +} + +int pvremove_many(struct cmd_context *cmd, struct dm_list *pv_names, + unsigned force_count, unsigned prompt) +{ + int ret = 1; + struct dm_list *pvslist = NULL; + struct pv_list *pvl; + const struct dm_str_list *pv_name; + + if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) { + log_error("Can't get lock for orphan PVs"); + return 0; + } + + lvmcache_seed_infos_from_lvmetad(cmd); + + if (!(pvslist = get_pvs(cmd))) { + ret = 0; + goto_out; + } + + dm_list_iterate_items(pv_name, pv_names) { + if (!pvremove_single(cmd, pv_name->str, NULL, force_count, prompt, pvslist)) { + stack; + ret = 0; + } + if (sigint_caught()) { + ret = 0; + goto_out; + } + } + +out: + unlock_vg(cmd, VG_ORPHANS); + + if (pvslist) + dm_list_iterate_items(pvl, pvslist) + free_pv_fid(pvl->pv); + + return ret; +} + +#endif /* APPLIB_SUPPORT */ diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 22f6601a3..65264c806 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -177,7 +177,7 @@ void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl) * 1 - success * FIXME: remove pv_name - obtain safely from pv */ -static int add_pv_to_vg(struct volume_group *vg, const char *pv_name, +int add_pv_to_vg(struct volume_group *vg, const char *pv_name, struct physical_volume *pv, int new_pv) { struct pv_list *pvl; @@ -312,7 +312,7 @@ static int _copy_pv(struct dm_pool *pvmem, return 1; } -static struct pv_list *_copy_pvl(struct dm_pool *pvmem, struct pv_list *pvl_from) +struct pv_list *copy_pvl(struct dm_pool *pvmem, struct pv_list *pvl_from) { struct pv_list *pvl_to = NULL; @@ -667,7 +667,7 @@ int vg_check_pv_dev_block_sizes(const struct volume_group *vg) return 1; } -static int _check_pv_dev_sizes(struct volume_group *vg) +int check_pv_dev_sizes(struct volume_group *vg) { struct pv_list *pvl; uint64_t dev_size, size; @@ -729,7 +729,7 @@ int vg_extend_each_pv(struct volume_group *vg, struct pvcreate_params *pp) } } - (void) _check_pv_dev_sizes(vg); + (void) check_pv_dev_sizes(vg); dm_list_splice(&vg->pv_write_list, &pp->pvs); @@ -2968,7 +2968,7 @@ int vg_write(struct volume_group *vg) struct pv_to_write *pv_to_write, *pv_to_write_safe; dm_list_iterate_items_safe(pv_to_write, pv_to_write_safe, &vg->pvs_to_write) { - if (!_pvcreate_write(vg->cmd, pv_to_write)) + if (!pvcreate_write(vg->cmd, pv_to_write)) return_0; dm_list_del(&pv_to_write->list); } @@ -3329,7 +3329,7 @@ static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struc /* * PV is not on list so add it. */ - if (!(pvl2 = _copy_pvl(pvmem, pvl))) { + if (!(pvl2 = copy_pvl(pvmem, pvl))) { log_error("pv_list allocation for '%s' failed", pv_dev_name(pvl->pv)); return 0; @@ -4240,7 +4240,7 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, consistent, 0))) goto_out; - if (!_check_pv_dev_sizes(vg)) + if (!check_pv_dev_sizes(vg)) log_warn("One or more devices used as PVs in VG %s " "have changed sizes.", vg->name); @@ -4709,7 +4709,7 @@ int vg_flag_write_locked(struct volume_group *vg) * * FIXME Remove the unnecessary duplicate definitions and return bits directly. */ -static uint32_t _vg_bad_status_bits(const struct volume_group *vg, +uint32_t _vg_bad_status_bits(const struct volume_group *vg, uint64_t status) { uint32_t failure = 0; @@ -5662,694 +5662,3 @@ int vg_strip_outdated_historical_lvs(struct volume_group *vg) { return 1; } -#ifdef APPLIB_SUPPORT - -/* - * Extend a VG by a single PV / device path - * - * Parameters: - * - vg: handle of volume group to extend by 'pv_name' - * - pv_name: device path of PV to add to VG - * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate - * - max_phys_block_size: largest physical block size found amongst PVs in a VG - * - */ -static int vg_extend_single_pv(struct volume_group *vg, char *pv_name, - struct pvcreate_params *pp, - unsigned int *max_phys_block_size) -{ - struct physical_volume *pv; - struct pv_to_write *pvw; - int new_pv = 0; - - pv = find_pv_by_name(vg->cmd, pv_name, 1, 1); - - if (!pv && !pp) { - log_error("%s not identified as an existing " - "physical volume", pv_name); - return 0; - } else if (!pv && pp) { - if (!(pv = pvcreate_vol(vg->cmd, pv_name, pp, 0))) - return_0; - new_pv = 1; - } - - if (!(check_dev_block_size_for_vg(pv->dev, (const struct volume_group *) vg, - max_phys_block_size))) - goto_bad; - - if (!add_pv_to_vg(vg, pv_name, pv, new_pv)) - goto_bad; - - if ((pv->fmt->features & FMT_PV_FLAGS) || - (pv->status & UNLABELLED_PV)) { - if (!(pvw = dm_pool_zalloc(vg->vgmem, sizeof(*pvw)))) { - log_error("pv_to_write allocation for '%s' failed", pv_name); - return 0; - } - pvw->pv = pv; - pvw->pp = new_pv ? pp : NULL; - pvw->new_pv = new_pv; - dm_list_add(&vg->pvs_to_write, &pvw->list); - } - - return 1; -bad: - free_pv_fid(pv); - return 0; -} - -/* - * Extend a VG by a single PV / device path - * - * Parameters: - * - vg: handle of volume group to extend by 'pv_name' - * - pv_count: count of device paths of PVs - * - pv_names: device paths of PVs to add to VG - * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate - * - */ -int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names, - struct pvcreate_params *pp) -{ - int i; - char *pv_name; - unsigned int max_phys_block_size = 0; - - if (_vg_bad_status_bits(vg, RESIZEABLE_VG)) - return_0; - - /* attach each pv */ - for (i = 0; i < pv_count; i++) { - if (!(pv_name = dm_strdup(pv_names[i]))) { - log_error("Failed to duplicate pv name %s.", pv_names[i]); - return 0; - } - dm_unescape_colons_and_at_signs(pv_name, NULL, NULL); - if (!vg_extend_single_pv(vg, pv_name, pp, &max_phys_block_size)) { - log_error("Unable to add physical volume '%s' to " - "volume group '%s'.", pv_name, vg->name); - dm_free(pv_name); - return 0; - } - dm_free(pv_name); - } - - (void) _check_pv_dev_sizes(vg); - -/* FIXME Decide whether to initialise and add new mdahs to format instance */ - - return 1; -} - -int vg_reduce(struct volume_group *vg, const char *pv_name) -{ - struct physical_volume *pv; - struct pv_list *pvl; - - if (!(pvl = find_pv_in_vg(vg, pv_name))) { - log_error("Physical volume %s not in volume group %s.", - pv_name, vg->name); - return 0; - } - - pv = pvl->pv; - - if (vgreduce_single(vg->cmd, vg, pv, 0)) { - dm_list_add(&vg->removed_pvs, &pvl->list); - return 1; - } - - log_error("Unable to remove physical volume '%s' from " - "volume group '%s'.", pv_name, vg->name); - - return 0; -} - -/* - * See if we may pvcreate on this device. - * 0 indicates we may not. - */ -static int _pvcreate_check(struct cmd_context *cmd, const char *name, - struct pvcreate_params *pp, int *wiped) -{ - static const char really_init_msg[] = "Really INITIALIZE physical volume"; - static const char not_init_msg[] = "physical volume not initialized"; - struct physical_volume *pv; - struct device *dev; - int r = 0; - int scan_needed = 0; - int filter_refresh_needed = 0; - int used; - - /* FIXME Check partition type is LVM unless --force is given */ - - *wiped = 0; - - /* Is there a pv here already? */ - pv = find_pv_by_name(cmd, name, 1, 1); - - /* Allow partial & exported VGs to be destroyed. */ - /* We must have -ff to overwrite a non orphan */ - if (pv) { - if (!is_orphan(pv) && pp->force != DONT_PROMPT_OVERRIDE) { - log_error("Can't initialize physical volume \"%s\" of " - "volume group \"%s\" without -ff.", name, pv_vg_name(pv)); - goto out; - } - - if ((used = is_used_pv(pv)) < 0) - goto_out; - - if (used && pp->force != DONT_PROMPT_OVERRIDE) { - log_error("PV %s is used by a VG but its metadata is missing.", name); - log_error("Can't initialize PV '%s' without -ff.", name); - goto out; - } - } - - /* prompt */ - if (pv && !pp->yes) { - if (is_orphan(pv)) { - if (used) { - if (yes_no_prompt("%s \"%s\" that is marked as belonging to a VG [y/n]? ", - really_init_msg, name) == 'n') { - log_error("%s: %s", name, not_init_msg); - goto out; - } - } - } else { - if (yes_no_prompt("%s \"%s\" of volume group \"%s\" [y/n]? ", - really_init_msg, name, pv_vg_name(pv)) == 'n') { - log_error("%s: %s", name, not_init_msg); - goto out; - } - } - } - - if (sigint_caught()) - goto_out; - - dev = dev_cache_get(name, cmd->full_filter); - - /* - * Refresh+rescan at the end is needed if: - * - we don't obtain device list from udev, - * hence persistent cache file is used - * and we need to trash it and reevaluate - * for any changes done outside - adding - * any new foreign signature which may affect - * filtering - before we do pvcreate, we - * need to be sure that we have up-to-date - * view for filters - * - * - we have wiped existing foreign signatures - * from dev as this may affect what's filtered - * as well - * - * - * Only rescan at the end is needed if: - * - we've just checked whether dev is fileterd - * by MD filter. We do the refresh in-situ, - * so no need to require the refresh at the - * end of this fn. This is to allow for - * wiping MD signature during pvcreate for - * the dev - the dev would normally be - * filtered because of MD filter. - * This is an exception. - */ - - /* Is there an md superblock here? */ - if (!dev && md_filtering()) { - if (!refresh_filters(cmd)) - goto_out; - - init_md_filtering(0); - dev = dev_cache_get(name, cmd->full_filter); - init_md_filtering(1); - - scan_needed = 1; - } else if (!obtain_device_list_from_udev()) - filter_refresh_needed = scan_needed = 1; - - if (!dev) { - log_error("Device %s not found (or ignored by filtering).", name); - goto out; - } - - /* - * This test will fail if the device belongs to an MD array. - */ - if (!dev_test_excl(dev)) { - /* FIXME Detect whether device-mapper itself is still using it */ - log_error("Can't open %s exclusively. Mounted filesystem?", - name); - goto out; - } - - if (!wipe_known_signatures(cmd, dev, name, - TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER, - 0, pp->yes, pp->force, wiped)) { - log_error("Aborting pvcreate on %s.", name); - goto out; - } - - if (*wiped) - filter_refresh_needed = scan_needed = 1; - - if (sigint_caught()) - goto_out; - - if (pv && !is_orphan(pv) && pp->force) - log_warn("WARNING: Forcing physical volume creation on " - "%s%s%s%s", name, - !is_orphan(pv) ? " of volume group \"" : "", - pv_vg_name(pv), - !is_orphan(pv) ? "\"" : ""); - - r = 1; - -out: - if (filter_refresh_needed) - if (!refresh_filters(cmd)) { - stack; - r = 0; - } - - if (scan_needed) { - lvmcache_force_next_label_scan(); - if (!lvmcache_label_scan(cmd)) { - stack; - r = 0; - } - } - - free_pv_fid(pv); - return r; -} - -static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw) -{ - struct physical_volume *pv = pvw->pv; - struct device *dev = pv->dev; - const char *pv_name = dev_name(dev); - - if (pvw->new_pv) { - /* Wipe existing label first */ - if (!label_remove(pv_dev(pv))) { - log_error("Failed to wipe existing label on %s", pv_name); - return 0; - } - - if (pvw->pp->zero) { - log_verbose("Zeroing start of device %s", pv_name); - if (!dev_open_quiet(dev)) { - log_error("%s not opened: device not zeroed", pv_name); - return 0; - } - - if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) { - log_error("%s not wiped: aborting", pv_name); - if (!dev_close(dev)) - stack; - return 0; - } - if (!dev_close(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); - return 0; - } - - if (pvw->new_pv) - log_print_unless_silent("Physical volume \"%s\" successfully created", pv_name); - else - log_verbose("Physical volume \"%s\" successfully written", pv_name); - - return 1; -} - -static int _verify_pv_create_params(struct pvcreate_params *pp) -{ - /* - * FIXME: Some of these checks are duplicates in pvcreate_params_validate. - */ - if (pp->pva.pvmetadatacopies > 2) { - log_error("Metadatacopies may only be 0, 1 or 2"); - return 0; - } - - if (pp->pva.data_alignment > UINT32_MAX) { - log_error("Physical volume data alignment is too big."); - return 0; - } - - if (pp->pva.data_alignment_offset > UINT32_MAX) { - log_error("Physical volume data alignment offset is too big."); - return 0; - } - - return 1; -} - -/* - * pvcreate_vol() - initialize a device with PV label and metadata area - * - * Parameters: - * - pv_name: device path to initialize - * - pp: parameters to pass to pv_create; if NULL, use default values - * - * Returns: - * NULL: error - * struct physical_volume * (non-NULL): handle to physical volume created - */ -struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_name, - struct pvcreate_params *pp, int write_now) -{ - struct physical_volume *pv = NULL; - struct device *dev; - int wiped = 0; - struct dm_list mdas; - struct pvcreate_params default_pp; - char buffer[64] __attribute__((aligned(8))); - dev_ext_t dev_ext_src; - - pvcreate_params_set_defaults(&default_pp); - if (!pp) - pp = &default_pp; - - if (!_verify_pv_create_params(pp)) { - goto bad; - } - - if (pp->pva.idp) { - if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL, NULL)) && - (dev != dev_cache_get(pv_name, cmd->full_filter))) { - if (!id_write_format((const struct id*)&pp->pva.idp->uuid, - buffer, sizeof(buffer))) - goto_bad; - log_error("uuid %s already in use on \"%s\"", buffer, - dev_name(dev)); - goto bad; - } - } - - if (!_pvcreate_check(cmd, pv_name, pp, &wiped)) - goto_bad; - - if (sigint_caught()) - goto_bad; - - /* - * wipe_known_signatures called in _pvcreate_check 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(pv_name, cmd->full_filter); - - init_external_device_info_source(dev_ext_src); - - if (!dev) { - log_error("%s: Couldn't find device. Check your filters?", - pv_name); - goto bad; - } - - dm_list_init(&mdas); - - if (!(pv = pv_create(cmd, dev, &pp->pva))) { - log_error("Failed to setup physical volume \"%s\"", pv_name); - goto bad; - } - - log_verbose("Set up physical volume for \"%s\" with %" PRIu64 - " available sectors", pv_name, pv_size(pv)); - - pv->status |= UNLABELLED_PV; - if (write_now) { - struct pv_to_write pvw; - pvw.pp = pp; - pvw.pv = pv; - pvw.new_pv = 1; - if (!_pvcreate_write(cmd, &pvw)) - goto bad; - } - - return pv; - -bad: - return NULL; -} - -/* FIXME: liblvm todo - make into function that returns handle */ -struct physical_volume *find_pv_by_name(struct cmd_context *cmd, - const char *pv_name, - int allow_orphan, int allow_unformatted) -{ - struct device *dev; - struct pv_list *pvl; - struct dm_list *pvslist; - struct physical_volume *pv = NULL; - - lvmcache_seed_infos_from_lvmetad(cmd); - - if (!(dev = dev_cache_get(pv_name, cmd->filter))) { - if (!allow_unformatted) - log_error("Physical volume %s not found", pv_name); - return_NULL; - } - - if (!(pvslist = get_pvs(cmd))) - return_NULL; - - dm_list_iterate_items(pvl, pvslist) - if (pvl->pv->dev == dev) - pv = pvl->pv; - else - free_pv_fid(pvl->pv); - - if (!pv && !allow_unformatted) - log_error("Physical volume %s not found", pv_name); - - if (pv && !allow_orphan && is_orphan_vg(pv->vg_name)) { - log_error("Physical volume %s not in a volume group", pv_name); - goto bad; - } - - return pv; - -bad: - free_pv_fid(pv); - return NULL; -} - -const char *find_vgname_from_pvid(struct cmd_context *cmd, - const char *pvid) -{ - char *vgname; - struct lvmcache_info *info; - - vgname = lvmcache_vgname_from_pvid(cmd, pvid); - - if (is_orphan_vg(vgname)) { - if (!(info = lvmcache_info_from_pvid(pvid, 0))) { - return_NULL; - } - /* - * If an orphan PV has no MDAs, or it has MDAs but the - * MDA is ignored, it may appear to be an orphan until - * the metadata is read off another PV in the same VG. - * Detecting this means checking every VG by scanning - * every PV on the system. - */ - if (lvmcache_uncertain_ownership(info)) { - if (!scan_vgs_for_pvs(cmd, WARN_PV_READ)) { - log_error("Rescan for PVs without " - "metadata areas failed."); - return NULL; - } - /* - * Ask lvmcache again - we may have a non-orphan - * name now - */ - vgname = lvmcache_vgname_from_pvid(cmd, pvid); - } - } - return vgname; -} - -const char *find_vgname_from_pvname(struct cmd_context *cmd, - const char *pvname) -{ - const char *pvid; - - pvid = lvmcache_pvid_from_devname(cmd, pvname); - if (!pvid) - /* Not a PV */ - return NULL; - - return find_vgname_from_pvid(cmd, pvid); -} - -static int _get_pvs(struct cmd_context *cmd, uint32_t warn_flags, - struct dm_list *pvslist, struct dm_list *vgslist) -{ - struct dm_str_list *strl; - const char *vgname, *vgid; - struct pv_list *pvl, *pvl_copy; - struct dm_list *vgids; - struct volume_group *vg; - int consistent = 0; - int old_pvmove; - struct vg_list *vgl_item = NULL; - int have_pv = 0; - - lvmcache_label_scan(cmd); - - /* Get list of VGs */ - if (!(vgids = get_vgids(cmd, 1))) { - log_error("get_pvs: get_vgids failed"); - return 0; - } - - /* Read every VG to ensure cache consistency */ - /* Orphan VG is last on list */ - old_pvmove = pvmove_mode(); - init_pvmove(1); - dm_list_iterate_items(strl, vgids) { - vgid = strl->str; - if (!vgid) - continue; /* FIXME Unnecessary? */ - consistent = 0; - if (!(vgname = lvmcache_vgname_from_vgid(NULL, vgid))) { - stack; - continue; - } - - /* - * When we are retrieving a list to return toliblvm we need - * that list to contain VGs that are modifiable as we are using - * the vgmem pool in the vg to provide allocation for liblvm. - * This is a hack to prevent the vg from getting cached as the - * vgid will be NULL. - * FIXME Remove this hack. - */ - - warn_flags |= WARN_INCONSISTENT; - - if (!(vg = vg_read_internal(cmd, vgname, (!vgslist) ? vgid : NULL, warn_flags, &consistent))) { - stack; - continue; - } - - /* Move PVs onto results list */ - if (pvslist) - dm_list_iterate_items(pvl, &vg->pvs) { - if (!(pvl_copy = _copy_pvl(cmd->mem, pvl))) { - log_error("PV list allocation failed"); - release_vg(vg); - return 0; - } - /* If we are going to release the VG, don't - * store a pointer to it in the PV structure. - */ - if (!vgslist) - pvl_copy->pv->vg = NULL; - else - /* - * Make sure the vg mode indicates - * writeable. - * FIXME Rework function to take a - * parameter to control this - */ - pvl_copy->pv->vg->open_mode = 'w'; - have_pv = 1; - dm_list_add(pvslist, &pvl_copy->list); - } - - /* - * In the case of the library we want to preserve the embedded - * volume group as subsequent calls to retrieve data about the - * PV require it. - */ - if (!vgslist || !have_pv) - release_vg(vg); - else { - /* - * Add VG to list of VG objects that will be returned - */ - vgl_item = dm_pool_alloc(cmd->mem, sizeof(*vgl_item)); - if (!vgl_item) { - log_error("VG list element allocation failed"); - return 0; - } - vgl_item->vg = vg; - vg = NULL; - dm_list_add(vgslist, &vgl_item->list); - } - have_pv = 0; - } - init_pvmove(old_pvmove); - - if (!pvslist) - dm_pool_free(cmd->mem, vgids); - - return 1; -} - -/* - * Retrieve a list of all physical volumes. - * @param cmd Command context - * @param pvslist Set to NULL if you want memory for list created, - * else valid memory - * @param vgslist Set to NULL if you need the pv structures to contain - * valid vg pointer. This is the list of VGs - * @returns NULL on errors, else pvslist which will equal passed-in value if - * supplied. - */ -struct dm_list *get_pvs_internal(struct cmd_context *cmd, - struct dm_list *pvslist, - struct dm_list *vgslist) -{ - struct dm_list *results = pvslist; - - if (NULL == results) { - if (!(results = dm_pool_alloc(cmd->mem, sizeof(*results)))) { - log_error("PV list allocation failed"); - return 0; - } - - dm_list_init(results); - } - - if (!_get_pvs(cmd, WARN_PV_READ, results, vgslist)) { - if (!pvslist) - dm_pool_free(cmd->mem, results); - return NULL; - } - return results; -} - -int scan_vgs_for_pvs(struct cmd_context *cmd, uint32_t warn_flags) -{ - return _get_pvs(cmd, warn_flags, NULL, NULL); -} - -#endif /* APPLIB_SUPPORT */ - diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 31c93460a..92346fbfc 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -512,4 +512,12 @@ struct id pv_vgid(const struct physical_volume *pv); uint64_t find_min_mda_size(struct dm_list *mdas); char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl); +/* used by applib.c from metadata.c */ +struct pv_list *copy_pvl(struct dm_pool *pvmem, struct pv_list *pvl_from); +int add_pv_to_vg(struct volume_group *vg, const char *pv_name, struct physical_volume *pv, int new_pv); +int check_pv_dev_sizes(struct volume_group *vg); + +/* used by metadata.c from applib.c */ +int pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw); + #endif diff --git a/lib/metadata/pv_manip.c b/lib/metadata/pv_manip.c index 5aeedbfc5..93a0434c1 100644 --- a/lib/metadata/pv_manip.c +++ b/lib/metadata/pv_manip.c @@ -686,183 +686,3 @@ out: "to repair from archived metadata."); return r; } - -#ifdef APPLIB_SUPPORT - -/* - * Decide whether it is "safe" to wipe the labels on this device. - * 0 indicates we may not. - */ -static int pvremove_check(struct cmd_context *cmd, const char *name, - unsigned force_count, unsigned prompt, struct dm_list *pvslist) -{ - static const char really_wipe_msg[] = "Really WIPE LABELS from physical volume"; - struct device *dev; - struct label *label; - struct pv_list *pvl; - struct physical_volume *pv = NULL; - int used; - int r = 0; - - /* FIXME Check partition type is LVM unless --force is given */ - - if (!(dev = dev_cache_get(name, cmd->filter))) { - log_error("Device %s not found.", name); - return 0; - } - - /* Is there a pv here already? */ - /* If not, this is an error unless you used -f. */ - if (!label_read(dev, &label, 0)) { - if (force_count) - return 1; - log_error("No PV label found on %s.", name); - return 0; - } - - dm_list_iterate_items(pvl, pvslist) - if (pvl->pv->dev == dev) - pv = pvl->pv; - - if (!pv) { - log_error(INTERNAL_ERROR "Physical Volume %s has a label, " - "but is neither in a VG nor orphan.", name); - goto out; /* better safe than sorry */ - } - - if (is_orphan(pv)) { - if ((used = is_used_pv(pv)) < 0) - goto_out; - - if (used) { - log_warn("WARNING: PV %s is used by a VG but its metadata is missing.", name); - - if (force_count < 2) - goto_bad; - - if (!prompt && - yes_no_prompt("%s \"%s\" that is marked as belonging to a VG [y/n]? ", - really_wipe_msg, name) == 'n') - goto_bad; - } - } else { - log_warn("WARNING: PV %s is used by VG %s (consider using vgreduce).", name, pv_vg_name(pv)); - - if (force_count < 2) - goto_bad; - - if (!prompt && - yes_no_prompt("%s \"%s\" of volume group \"%s\" [y/n]? ", - really_wipe_msg, name, pv_vg_name(pv)) == 'n') - goto_bad; - } - - if (force_count) - log_warn("WARNING: Wiping physical volume label from " - "%s%s%s%s", name, - !is_orphan(pv) ? " of volume group \"" : "", - pv_vg_name(pv), - !is_orphan(pv) ? "\"" : ""); - - r = 1; -bad: - if (!r) { - log_error("%s: physical volume label not removed.", name); - - if (force_count < 2) /* Show hint as log_error() */ - log_error("(If you are certain you need pvremove, " - "then confirm by using --force twice.)"); - } -out: - return r; -} - -int pvremove_single(struct cmd_context *cmd, const char *pv_name, - void *handle __attribute__((unused)), unsigned force_count, - unsigned prompt, struct dm_list *pvslist) -{ - struct device *dev; - struct lvmcache_info *info; - int r = 0; - - if (!pvremove_check(cmd, pv_name, force_count, prompt, pvslist)) - goto out; - - if (!(dev = dev_cache_get(pv_name, cmd->filter))) { - log_error("%s: Couldn't find device. Check your filters?", - pv_name); - goto out; - } - - info = lvmcache_info_from_pvid(dev->pvid, 0); - - if (!dev_test_excl(dev)) { - /* FIXME Detect whether device-mapper is still using the device */ - log_error("Can't open %s exclusively - not removing. " - "Mounted filesystem?", dev_name(dev)); - goto out; - } - - /* Wipe existing label(s) */ - if (!label_remove(dev)) { - log_error("Failed to wipe existing label(s) on %s", pv_name); - goto out; - } - - if (info) - lvmcache_del(info); - - if (!lvmetad_pv_gone_by_dev(dev)) - goto_out; - - log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped", - pv_name); - - r = 1; - -out: - return r; -} - -int pvremove_many(struct cmd_context *cmd, struct dm_list *pv_names, - unsigned force_count, unsigned prompt) -{ - int ret = 1; - struct dm_list *pvslist = NULL; - struct pv_list *pvl; - const struct dm_str_list *pv_name; - - if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) { - log_error("Can't get lock for orphan PVs"); - return 0; - } - - lvmcache_seed_infos_from_lvmetad(cmd); - - if (!(pvslist = get_pvs(cmd))) { - ret = 0; - goto_out; - } - - dm_list_iterate_items(pv_name, pv_names) { - if (!pvremove_single(cmd, pv_name->str, NULL, force_count, prompt, pvslist)) { - stack; - ret = 0; - } - if (sigint_caught()) { - ret = 0; - goto_out; - } - } - -out: - unlock_vg(cmd, VG_ORPHANS); - - if (pvslist) - dm_list_iterate_items(pvl, pvslist) - free_pv_fid(pvl->pv); - - return ret; -} - -#endif /* APPLIB_SUPPORT */ |