1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/tools/vgimportdevices.c
2021-03-10 01:29:44 +01:00

206 lines
5.8 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;
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) {
log_error("Not importing devices for VG %s with missing PV %32s.",
vg->name, (const char *)&pvl->pv->id.uuid);
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;
device_id_add(cmd, pv->dev, (const char *)&pvl->pv->id.uuid, 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;
backup(vg);
}
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;
/*
* 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;
}