1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00
lvm2/tools/vgimportdevices.c
David Teigland b65a2c3f3a vgimportdevices: skip lvmlockd locking
Help bootstrapping existing shared vgs into the devices file.
Reading the vg in vgimportdevices would require locking to be
started, but vgchange lockstart won't see the vg if it's not
in the devices file.  The lvmlockd locks are not protecting
vg modifications so skipping them here won't be a problem.
2021-10-25 12:11:17 -05:00

219 lines
6.3 KiB
C

/*
* Copyright (C) 2020 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 "tools.h"
#include "lib/cache/lvmcache.h"
#include "lib/device/device_id.h"
struct vgimportdevices_params {
uint32_t added_devices;
};
static int _vgimportdevices_single(struct cmd_context *cmd,
const char *vg_name,
struct volume_group *vg,
struct processing_handle *handle)
{
struct vgimportdevices_params *vp = (struct vgimportdevices_params *) handle->custom_handle;
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
struct pv_list *pvl;
struct physical_volume *pv;
int update_vg = 1;
int updated_pvs = 0;
const char *idtypestr = NULL; /* deviceidtype_ARG ? */
dm_list_iterate_items(pvl, &vg->pvs) {
if (is_missing_pv(pvl->pv) || !pvl->pv->dev) {
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
log_error("Not importing devices for VG %s with missing PV %s.",
vg->name, pvid);
goto bad;
}
}
/*
* We want to allow importing devices of foreign and shared
* VGs, but we do not want to update device_ids in those VGs.
*
* If --foreign is set, then foreign VGs will be passed
* to this function; add devices but don't update vg.
* shared VGs are passed to this function; add devices
* and do not update.
*/
if (vg_is_foreign(vg) || vg_is_shared(vg))
update_vg = 0;
dm_list_iterate_items(pvl, &vg->pvs) {
pv = pvl->pv;
if (!idtypestr && pv->device_id_type)
idtypestr = pv->device_id_type;
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
device_id_add(cmd, pv->dev, pvid, idtypestr, NULL);
vp->added_devices++;
/* We could skip update if the device_id has not changed. */
if (!update_vg)
continue;
updated_pvs++;
}
if (updated_pvs) {
if (!vg_write(vg) || !vg_commit(vg))
goto_bad;
}
return ECMD_PROCESSED;
bad:
return ECMD_FAILED;
}
/*
* This command always scans all devices on the system,
* any pre-existing devices_file does not limit the scope.
*
* This command adds the VG's devices to whichever
* devices_file is set in config or command line.
* If devices_file doesn't exist, it's created.
*
* If devices_file is "" then this file will scan all devices
* and show the devices that it would otherwise have added to
* the devices_file. The VG is not updated with device_ids.
*
* This command updates the VG metadata to add device_ids
* (if the metadata is missing them), unless an option is
* set to skip that, e.g. --nodeviceidupdate?
*
* If the VG found has a foreign system ID then an error
* will be printed. To import devices from a foreign VG:
* vgimportdevices --foreign -a
* vgimportdevices --foreign VG
*
* If there are duplicate VG names it will do nothing.
*
* If there are duplicate PVIDs related to VG it will do nothing,
* the user would need to add the PVs they want with lvmdevices --add.
*
* vgimportdevices -a (no vg arg) will import all accesible VGs.
*/
int vgimportdevices(struct cmd_context *cmd, int argc, char **argv)
{
struct vgimportdevices_params vp = { 0 };
struct processing_handle *handle;
int ret = ECMD_FAILED;
if (arg_is_set(cmd, foreign_ARG))
cmd->include_foreign_vgs = 1;
cmd->include_shared_vgs = 1;
/* So that we can warn about this. */
cmd->handles_missing_pvs = 1;
if (!lock_global(cmd, "ex"))
return ECMD_FAILED;
/*
* Prepare devices file preemptively because the error path for this
* case from process_each is not as clean.
*/
if (!setup_devices_file(cmd)) {
log_error("Failed to set up devices file.");
return ECMD_FAILED;
}
if (!cmd->enable_devices_file) {
log_error("Devices file not enabled.");
return ECMD_FAILED;
}
if (!devices_file_exists(cmd) && !devices_file_touch(cmd)) {
log_error("Failed to create devices file.");
return ECMD_FAILED;
}
/*
* The hint file is associated with the default/system devices file,
* so don't clear hints when using a different --devicesfile.
*/
if (!cmd->devicesfile)
clear_hint_file(cmd);
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
goto out;
}
handle->custom_handle = &vp;
/*
* import is a case where we do not want to be limited by an existing
* devices file because we want to search outside the devices file for
* new devs to add to it, but we do want devices file entries on
* use_devices so we can update and write out that list.
*
* Ususally when devices file is enabled, we use filter-deviceid and
* skip filter-regex. In this import case it's reversed, and we skip
* filter-deviceid and use filter-regex.
*/
cmd->filter_deviceid_skip = 1;
cmd->filter_regex_with_devices_file = 1;
cmd->create_edit_devices_file = 1;
/*
* This helps a user bootstrap existing shared VGs into the devices
* file. Reading the vg to import devices requires locking, but
* lockstart won't find the vg before it's in the devices file.
* So, allow importing devices without an lvmlockd lock (in a
* a shared vg the vg metadata won't be updated with device ids,
* so the lvmlockd lock isn't protecting vg modification.)
*/
cmd->lockd_gl_disable = 1;
cmd->lockd_vg_disable = 1;
/*
* For each VG:
* device_id_add() each PV in the VG
* update device_ids in the VG (potentially)
*
* process_each_vg->label_scan->setup_devices
* setup_devices sees create_edit_devices_file is 1,
* so it does lock_devices_file(EX), then it creates/reads
* the devices file, then each device_id_add happens
* above, and then device_ids_write happens below.
*/
ret = process_each_vg(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE,
0, handle, _vgimportdevices_single);
if (ret == ECMD_FAILED)
goto out;
if (!vp.added_devices) {
log_print("No devices to add.");
goto out;
}
if (!device_ids_write(cmd)) {
log_print("Failed to update devices file.");
ret = ECMD_FAILED;
goto out;
}
log_print("Added %u devices to devices file.", vp.added_devices);
out:
destroy_processing_handle(cmd, handle);
return ret;
}