1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvremove: remove device_id for PVs on LVs

When PVs are created on LVs, remove the devices file entries
for the PVs when the LVs are removed.  In general, the devices
file entries should be removed with lvmdevices --deldev when
the LVs are removed (lvremove is the equivalent of detaching
a device from the system when layering PVs on LVs.)
This change is effectively an automatic lvmdevices --deldev
command that is built into lvremove when the LV has a PV on it.
This commit is contained in:
David Teigland 2024-05-22 15:32:17 -05:00
parent c609dedc2f
commit 47f8bda051
6 changed files with 182 additions and 5 deletions

View File

@ -1861,7 +1861,7 @@ int device_ids_use_devname(struct cmd_context *cmd)
return 0;
}
static int _device_ids_use_lvmlv(struct cmd_context *cmd)
int device_ids_use_lvmlv(struct cmd_context *cmd)
{
struct dev_use *du;
@ -2243,6 +2243,69 @@ void device_id_pvremove(struct cmd_context *cmd, struct device *dev)
}
}
/*
* Remove LVMLV_UUID entries from system.devices for LVs that were removed.
* lvremove vg/lv where a PV exists on vg/lv does an automatic
* lvmdevices --deldev /dev/vg/lv
*/
void device_id_lvremove(struct cmd_context *cmd, struct dm_list *removed_uuids)
{
struct dev_use *du;
struct dm_str_list *sl;
int found = 0;
if (!device_ids_use_lvmlv(cmd))
return;
dm_list_iterate_items(sl, removed_uuids) {
if (!(du = get_du_for_device_id(cmd, DEV_ID_TYPE_LVMLV_UUID, sl->str)))
continue;
found++;
}
if (!found)
return;
if (!lock_devices_file(cmd, LOCK_EX))
return;
/*
* Clear cmd->use_devices which may no longer be an accurate
* representation of system.devices, since another command may have
* changed system.devices after this command read and unlocked it.
*/
free_dus(&cmd->use_devices);
/*
* Reread system.devices, recreating cmd->use_devices.
*/
if (!device_ids_read(cmd)) {
log_debug("Failed to read devices file");
goto out;
}
found = 0;
dm_list_iterate_items(sl, removed_uuids) {
if (!(du = get_du_for_device_id(cmd, DEV_ID_TYPE_LVMLV_UUID, sl->str)))
continue;
log_debug("Removing devices file entry for device_id %s", sl->str);
dm_list_del(&du->list);
free_du(du);
found++;
}
if (!found)
goto out;
if (!device_ids_write(cmd))
log_debug("Failed to write devices file");
out:
unlock_devices_file(cmd);
}
void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg, struct id *old_vg_id)
{
struct dev_use *du;
@ -2260,7 +2323,7 @@ void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg,
return;
/* Check if any devices file entries are stacked on LVs. */
if (!_device_ids_use_lvmlv(cmd))
if (!device_ids_use_lvmlv(cmd))
return;
memcpy(old_vgid, old_vg_id, ID_LEN);

View File

@ -25,11 +25,13 @@ uint16_t idtype_from_str(const char *str);
const char *dev_idtype_for_metadata(struct cmd_context *cmd, struct device *dev);
const char *dev_idname_for_metadata(struct cmd_context *cmd, struct device *dev);
int device_ids_use_devname(struct cmd_context *cmd);
int device_ids_use_lvmlv(struct cmd_context *cmd);
int device_ids_read(struct cmd_context *cmd);
int device_ids_write(struct cmd_context *cmd);
int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid,
const char *idtype_arg, const char *id_arg, int use_idtype_only);
void device_id_pvremove(struct cmd_context *cmd, struct device *dev);
void device_id_lvremove(struct cmd_context *cmd, struct dm_list *removed_uuids);
void device_ids_match(struct cmd_context *cmd);
int device_ids_match_dev(struct cmd_context *cmd, struct device *dev);
void device_ids_match_device_list(struct cmd_context *cmd);

View File

@ -1467,6 +1467,10 @@ struct vgcreate_params {
const char *lock_args;
};
struct lvremove_params {
struct dm_list removed_uuids; /* entries are str_list */
};
int validate_major_minor(const struct cmd_context *cmd,
const struct format_type *fmt,
int32_t major, int32_t minor);

View File

@ -0,0 +1,62 @@
# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
#
# 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 General Public License v.2.
#
# You should have received a copy of the GNU 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
test_description='devices file'
SKIP_WITH_LVMPOLLD=1
. lib/inittest
aux prepare_devs 1
# The tests run with system dir of "/etc" but lvm when running
# normally has cmd->system_dir set to "/etc/lvm".
DFDIR="$LVM_SYSTEM_DIR/devices"
mkdir -p "$DFDIR" || true
DF="$DFDIR/system.devices"
aux lvmconf 'devices/use_devicesfile = 1'
aux lvmconf 'devices/scan_lvs = 1'
rm -f "$DF"
touch "$DF"
vgcreate $vg1 "$dev1"
lvcreate -n $lv1 -L 8M $vg1
lvcreate -n $lv2 -L 8M $vg1
pvcreate $DM_DEV_DIR/$vg1/$lv1
pvcreate $DM_DEV_DIR/$vg1/$lv2
vgcreate $vg2 $DM_DEV_DIR/$vg1/$lv1 $DM_DEV_DIR/$vg1/$lv2
pvs $DM_DEV_DIR/$vg1/$lv1
pvs $DM_DEV_DIR/$vg1/$lv2
grep "$dev1" "$DF"
grep $DM_DEV_DIR/$vg1/$lv1 "$DF" | tee out1
grep "IDTYPE=lvmlv_uuid" out1
grep "IDNAME=LVM-" out1
grep $DM_DEV_DIR/$vg1/$lv2 "$DF" | tee out2
grep "IDTYPE=lvmlv_uuid" out2
grep "IDNAME=LVM-" out2
lvremove -y $vg1/$lv1
not grep $DM_DEV_DIR/$vg1/$lv1 "$DF"
lvremove -y $vg1/$lv2
not grep $DM_DEV_DIR/$vg1/$lv2 "$DF"
grep "$dev1" "$DF"
not grep "IDTYPE=lvmlv_uuid" "$DF"
not grep "IDNAME=LVM-" "$DF"
vgremove -y $vg1

View File

@ -17,6 +17,10 @@
int lvremove(struct cmd_context *cmd, int argc, char **argv)
{
struct processing_handle *handle = NULL;
struct lvremove_params lp = { 0 };
int ret;
if (!argc && !arg_is_set(cmd, select_ARG)) {
log_error("Please enter one or more logical volume paths "
"or use --select for selection.");
@ -26,6 +30,22 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv)
cmd->handles_missing_pvs = 1;
cmd->include_historical_lvs = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL,
NULL, &lvremove_single);
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
return ECMD_FAILED;
}
dm_list_init(&lp.removed_uuids);
handle->custom_handle = &lp;
ret = process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, handle,
NULL, &lvremove_single);
if (cmd->scan_lvs && cmd->enable_devices_file)
device_id_lvremove(cmd, &lp.removed_uuids);
destroy_processing_handle(cmd, handle);
return ret;
}

View File

@ -18,6 +18,7 @@
#include "lib/label/hints.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include "libdm/misc/dm-ioctl.h"
#include <sys/stat.h>
#include <signal.h>
@ -4782,9 +4783,31 @@ out:
return ret_max;
}
int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle __attribute__((unused)))
static void _lvremove_save_uuid(struct cmd_context *cmd, struct logical_volume *lv,
struct lvremove_params *lp)
{
char dm_uuid[DM_UUID_LEN] = { 0 };
/*
* Create the dm/uuid string that would be displayed
* in sysfs for this LV.
*
* DM_UUID_LEN is 129
* ID_LEN is 32
*/
memcpy(dm_uuid, "LVM-", 4);
memcpy(dm_uuid+4, &lv->vg->id, ID_LEN);
memcpy(dm_uuid+4+ID_LEN, &lv->lvid.id[1], ID_LEN);
if (!str_list_add(cmd->mem, &lp->removed_uuids, dm_pool_strdup(cmd->mem, dm_uuid)))
stack;
}
int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle)
{
struct lvremove_params *lp = (struct lvremove_params *) handle->custom_handle;
/*
* Single force is equivalent to single --yes
* Even multiple --yes are equivalent to single --force
@ -4796,6 +4819,9 @@ int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!lv_remove_with_dependencies(cmd, lv, force, 0))
return_ECMD_FAILED;
if (cmd->scan_lvs && cmd->enable_devices_file)
_lvremove_save_uuid(cmd, lv, lp);
return ECMD_PROCESSED;
}