mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
206 lines
5.8 KiB
C
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;
|
|
}
|
|
|