1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-27 05:44:18 +03:00

Compare commits

...

6 Commits

Author SHA1 Message Date
Marian Csontos
4a1f6173d2 make: generate 2022-02-08 15:29:23 +01:00
David Teigland
61706793de lvmdevices: make deldev work for missing device 2022-02-07 10:45:53 -06:00
David Teigland
84503342f7 remove static autoactivation
event based autoactivation is now the only method that lvm
provides for autoactivation.

Setting lvm.conf event_activation=0 can still be used to disable
event based autoactivation commands, but doing so will no longer
enable static autoactivation.
2022-02-07 10:45:19 -06:00
David Teigland
b8c7810617 lvmdevices: fix checks when adding entries
Removes some incorrect and unnecessary checks for other entries
when adding a new devices.  The removed checks and corrections were
mostly redundant with what is already done by device id matching.
Other checking is reworked so the warnings are a bit different.
2022-02-07 10:45:09 -06:00
David Teigland
ba16b6f227 device_id: fix search for renamed device when the wwid is ignored
When a device has a wwid (from sysfs), but lvm ignores the wwid,
e.g. because it contains an unreliable "QEMU" value, then lvm
falls back to using IDTYPE=devname (the device name) as the
device id.  If the device name changes after reboot, then lvm
automatically searches for the PV on other devices to find the
new device name and correct system.devices.  When searching for
the PV, lvm skips looking at devices that would use other id types,
e.g. if a device would use a wwid and not a devname, then it
skips checking it.  However, it failed to account for the fact
that a device may have wwid that was ignored, in which case it
should be checked.
2022-02-07 10:44:57 -06:00
David Teigland
185c7dcbeb lvmdevices check: error exit if update is needed
. error exit means that lvmdevices --update would make a change.

. remove check of PART field from --check because it isn't used.

. unlink searched_devnames file to ensure check|update will search
2022-02-07 10:44:41 -06:00
27 changed files with 205 additions and 1106 deletions

View File

@@ -1151,16 +1151,11 @@ global {
# lvdisplay_shows_full_device_path = 0
# Configuration option global/event_activation.
# Activate LVs based on system-generated device events.
# When a PV appears on the system, a system-generated uevent triggers
# the lvm2-pvscan service which runs the pvscan --cache -aay command.
# If the new PV completes a VG, pvscan autoactivates LVs in the VG.
# When event_activation is disabled, the lvm2-activation services are
# generated and run at fixed points during system startup. These
# services run vgchange -aay to autoactivate LVs in VGs that happen
# to be present at that point in time.
# See the --setautoactivation option or the auto_activation_volume_list
# setting to configure autoactivation for specific VGs or LVs.
# Disable event based autoactivation commands.
# WARNING: setting this to zero may cause machine startup to fail.
# Previously, setting this to zero would enable static autoactivation
# services (via the lvm2-activation-generator), but the autoactivation
# services and generator have been removed.
# This configuration option has an automatic default value.
# event_activation = 1

View File

@@ -1119,16 +1119,11 @@ cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_pa
"was never a valid path in the /dev filesystem.\n")
cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 1), 0, 0, NULL,
"Activate LVs based on system-generated device events.\n"
"When a PV appears on the system, a system-generated uevent triggers\n"
"the lvm2-pvscan service which runs the pvscan --cache -aay command.\n"
"If the new PV completes a VG, pvscan autoactivates LVs in the VG.\n"
"When event_activation is disabled, the lvm2-activation services are\n"
"generated and run at fixed points during system startup. These\n"
"services run vgchange -aay to autoactivate LVs in VGs that happen\n"
"to be present at that point in time.\n"
"See the --setautoactivation option or the auto_activation_volume_list\n"
"setting to configure autoactivation for specific VGs or LVs.\n")
"Disable event based autoactivation commands.\n"
"WARNING: setting this to zero may cause machine startup to fail.\n"
"Previously, setting this to zero would enable static autoactivation\n"
"services (via the lvm2-activation-generator), but the autoactivation\n"
"services and generator have been removed.\n")
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL,
NULL)

View File

@@ -315,7 +315,6 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
/* qemu wwid begins "t10.ATA QEMU HARDDISK ..." */
if (strstr(sysbuf, "QEMU HARDDISK"))
sysbuf[0] = '\0';
}
else if (idtype == DEV_ID_TYPE_SYS_SERIAL)
@@ -366,7 +365,6 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
return idname;
bad:
log_debug("No idtype %s for %s", idtype_to_str(idtype), dev_name(dev));
return NULL;
}
@@ -378,20 +376,40 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
{
char sysbuf[PATH_MAX] = { 0 };
struct dev_id *id;
const char *idname;
/*
* An idtype other than DEVNAME is stable, i.e. it doesn't change after
* reboot or device reattach.
* An id on dev->ids with idtype set and !idname means that idtype does
* not exist for the dev. (Optimization to avoid repeated negative
* system_read.)
*/
dm_list_iterate_items(id, &dev->ids) {
if (id->idtype != DEV_ID_TYPE_DEVNAME)
if ((id->idtype != DEV_ID_TYPE_DEVNAME) && id->idname)
return 1;
}
if (read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
return 1;
/*
* Use device_id_system_read() instead of read_sys_block() when
* system_read ignores some values from sysfs.
*/
if (read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
if ((idname = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID))) {
free((void*)idname);
return 1;
}
if (read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
if ((idname = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_SERIAL))) {
free((void*)idname);
return 1;
}
if ((MAJOR(dev->dev) == cmd->dev_types->loop_major) &&
(idname = device_id_system_read(cmd, dev, DEV_ID_TYPE_LOOP_FILE))) {
free((void*)idname);
return 1;
}
if ((MAJOR(dev->dev) == cmd->dev_types->device_mapper_major)) {
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
@@ -409,9 +427,6 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
return 1;
if ((MAJOR(dev->dev) == cmd->dev_types->loop_major) &&
read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
return 1;
out:
/* DEV_ID_TYPE_DEVNAME would be used for this dev. */
return 0;
@@ -894,7 +909,7 @@ struct dev_use *get_du_for_pvid(struct cmd_context *cmd, const char *pvid)
return NULL;
}
static struct dev_use *_get_du_for_devname(struct cmd_context *cmd, const char *devname)
struct dev_use *get_du_for_devname(struct cmd_context *cmd, const char *devname)
{
struct dev_use *du;
@@ -935,6 +950,10 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
struct dev_use *du, *update_du = NULL, *du_dev, *du_pvid, *du_devname, *du_devid;
struct dev_id *id;
int found_id = 0;
int part = 0;
if (!dev_get_partition_number(dev, &part))
return_0;
/*
* When enable_devices_file=0 and pending_devices_file=1 we let
@@ -953,10 +972,6 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
*/
memcpy(&pvid, pvid_arg, ID_LEN);
du_dev = get_du_for_dev(cmd, dev);
du_pvid = get_du_for_pvid(cmd, pvid);
du_devname = _get_du_for_devname(cmd, dev_name(dev));
/*
* Choose the device_id type for the device being added.
*
@@ -1072,6 +1087,9 @@ id_done:
idtype = 0;
/*
* "dev" is the device we are adding.
* "id" is the device_id it's using, set in dev->id.
*
* Update the cmd->use_devices list for the new device. The
* use_devices list will be used to update the devices file.
*
@@ -1083,23 +1101,57 @@ id_done:
* those other entries to fix any incorrect info.
*/
/* Is there already an entry matched to this device? */
du_dev = get_du_for_dev(cmd, dev);
/* Is there already an entry matched to this device's pvid? */
du_pvid = get_du_for_pvid(cmd, pvid);
/* Is there already an entry using this device's name? */
du_devname = get_du_for_devname(cmd, dev_name(dev));
/* Is there already an entry using the device_id for this device? */
du_devid = _get_du_for_device_id(cmd, id->idtype, id->idname);
if (du_dev)
log_debug("device_id_add %s pvid %s matches du_dev %p dev %s",
log_debug("device_id_add %s pvid %s matches entry %p dev %s",
dev_name(dev), pvid, du_dev, dev_name(du_dev->dev));
if (du_pvid)
log_debug("device_id_add %s pvid %s matches du_pvid %p dev %s pvid %s",
log_debug("device_id_add %s pvid %s matches entry %p dev %s with same pvid %s",
dev_name(dev), pvid, du_pvid, du_pvid->dev ? dev_name(du_pvid->dev) : ".",
du_pvid->pvid);
if (du_devid)
log_debug("device_id_add %s pvid %s matches du_devid %p dev %s pvid %s",
log_debug("device_id_add %s pvid %s matches entry %p dev %s with same device_id %d %s",
dev_name(dev), pvid, du_devid, du_devid->dev ? dev_name(du_devid->dev) : ".",
du_devid->pvid);
du_devid->idtype, du_devid->idname);
if (du_devname)
log_debug("device_id_add %s pvid %s matches du_devname %p dev %s pvid %s",
log_debug("device_id_add %s pvid %s matches entry %p dev %s with same devname %s",
dev_name(dev), pvid, du_devname, du_devname->dev ? dev_name(du_devname->dev) : ".",
du_devname->pvid);
du_devname->devname);
if (du_pvid && (du_pvid->dev != dev))
log_warn("WARNING: adding device %s with PVID %s which is already used for %s.",
dev_name(dev), pvid, du_pvid->dev ? dev_name(du_pvid->dev) : "missing device");
if (du_devid && (du_devid->dev != dev)) {
if (!du_devid->dev) {
log_warn("WARNING: adding device %s with idname %s which is already used for missing device.",
dev_name(dev), id->idname);
} else {
int ret1, ret2;
dev_t devt1, devt2;
/* Check if both entries are partitions of the same device. */
ret1 = dev_get_primary_dev(cmd->dev_types, dev, &devt1);
ret2 = dev_get_primary_dev(cmd->dev_types, du_devid->dev, &devt2);
if ((ret1 == 2) && (ret2 == 2) && (devt1 == devt2)) {
log_debug("Using separate entries for partitions of same device %s part %d %s part %d.",
dev_name(dev), part, dev_name(du_devid->dev), du_devid->part);
} else {
log_warn("WARNING: adding device %s with idname %s which is already used for %s.",
dev_name(dev), id->idname, dev_name(du_devid->dev));
}
}
}
/*
* If one of the existing entries (du_dev, du_pvid, du_devid, du_devname)
@@ -1112,29 +1164,6 @@ id_done:
dm_list_del(&update_du->list);
update_matching_kind = "device";
update_matching_name = dev_name(dev);
if (du_devid && (du_devid != du_dev)) {
log_warn("WARNING: device %s (%s) and %s (%s) have duplicate device ID.",
dev_name(dev), id->idname,
(du_pvid && du_pvid->dev) ? dev_name(du_pvid->dev) : "none",
du_pvid ? du_pvid->idname : "");
}
if (du_pvid && (du_pvid != du_dev)) {
log_warn("WARNING: device %s (%s) and %s (%s) have duplicate PVID %s",
dev_name(dev), id->idname,
du_pvid->dev ? dev_name(du_pvid->dev) : "none", du_pvid->idname,
pvid);
}
if (du_devname && (du_devname != du_dev)) {
/* clear devname in another entry with our devname */
log_warn("Devices file PVID %s clearing wrong DEVNAME %s.",
du_devname->pvid, du_devname->devname);
free(du_devname->devname);
du_devname->devname = NULL;
}
} else if (du_pvid) {
/*
* If the device_id of the existing entry for PVID is the same
@@ -1154,11 +1183,6 @@ id_done:
update_matching_kind = "PVID";
update_matching_name = pvid;
} else {
log_warn("WARNING: device %s (%s) and %s (%s) have duplicate PVID %s",
dev_name(dev), id->idname,
du_pvid->dev ? dev_name(du_pvid->dev) : "none", du_pvid->idname,
pvid);
if (!cmd->current_settings.yes &&
yes_no_prompt("Add device with duplicate PV to devices file?") == 'n') {
log_print("Device not added.");
@@ -1166,21 +1190,6 @@ id_done:
return 1;
}
}
if (du_devid && (du_devid != du_pvid)) {
/* warn about another entry using the same device_id */
log_warn("WARNING: duplicate device_id %s for PVIDs %s %s",
du_devid->idname, du_devid->pvid, du_pvid->pvid);
}
if (du_devname && (du_devname != du_pvid)) {
/* clear devname in another entry with our devname */
log_warn("Devices file PVID %s clearing wrong DEVNAME %s.",
du_devname->pvid, du_devname->devname);
free(du_devname->devname);
du_devname->devname = NULL;
}
} else if (du_devid) {
/*
* Do we create a new du or update the existing du?
@@ -1195,64 +1204,13 @@ id_done:
* the same device_id (create a new du for dev.)
* If not, then update the existing du_devid.
*/
if (du_devid->dev != dev)
check_idname = device_id_system_read(cmd, du_devid->dev, id->idtype);
if (check_idname && !strcmp(check_idname, id->idname)) {
int ret1, ret2;
dev_t devt1, devt2;
/*
* two different devices have the same device_id,
* create a new du for the device being added
*/
/* dev_is_partitioned() the dev open to read it. */
if (!label_scan_open(du_devid->dev))
log_warn("Cannot open %s", dev_name(du_devid->dev));
if (dev_is_partitioned(cmd, du_devid->dev)) {
/* Check if existing entry is whole device and new entry is a partition of it. */
ret1 = dev_get_primary_dev(cmd->dev_types, dev, &devt1);
if ((ret1 == 2) && (devt1 == du_devid->dev->dev))
log_warn("Remove partitioned device %s from devices file.", dev_name(du_devid->dev));
} else {
/* Check if both entries are partitions of the same device. */
ret1 = dev_get_primary_dev(cmd->dev_types, dev, &devt1);
ret2 = dev_get_primary_dev(cmd->dev_types, du_devid->dev, &devt2);
if ((ret1 == 2) && (ret2 == 2) && (devt1 == devt2)) {
log_warn("Partitions %s %s have same device_id %s",
dev_name(dev), dev_name(du_devid->dev), id->idname);
} else {
log_warn("Duplicate device_id %s %s for %s and %s",
idtype_to_str(id->idtype), check_idname,
dev_name(dev), dev_name(du_devid->dev));
}
}
} else {
if (du_devid->dev == dev) {
/* update the existing entry with matching devid */
update_du = du_devid;
dm_list_del(&update_du->list);
update_matching_kind = "device_id";
update_matching_name = id->idname;
}
if (du_devname && (du_devname != du_devid)) {
/* clear devname in another entry with our devname */
log_warn("Devices file PVID %s clearing wrong DEVNAME %s",
du_devname->pvid, du_devname->devname);
free(du_devname->devname);
du_devname->devname = NULL;
}
} else if (du_devname) {
/* clear devname in another entry with our devname */
log_warn("Devices file PVID %s clearing wrong DEVNAME %s",
du_devname->pvid, du_devname->devname);
free(du_devname->devname);
du_devname->devname = NULL;
}
free((void *)check_idname);
@@ -1571,7 +1529,7 @@ int device_ids_match_dev(struct cmd_context *cmd, struct device *dev)
struct dev_use *du;
/* First check the du entry with matching devname since it's likely correct. */
if ((du = _get_du_for_devname(cmd, dev_name(dev)))) {
if ((du = get_du_for_devname(cmd, dev_name(dev)))) {
if (_match_du_to_dev(cmd, du, dev))
return 1;
}
@@ -2169,6 +2127,12 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
*
* TODO: in auto mode should we look in other non-system
* devices files and skip any devs included in those?
*
* Note that a user can override a stable id type and use
* devname for a device's id, in which case this optimization
* can prevent a search from finding a renamed dev. So, if a
* user forces a devname id, then they should probably also
* set search_for_devnames=all.
*/
if (search_auto && _dev_has_stable_id(cmd, dev)) {
other_idtype++;
@@ -2278,7 +2242,8 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
continue;
}
log_warn("Devices file PVID %s updating IDNAME to %s.", dev->pvid, devname);
if (!noupdate)
log_warn("Devices file PVID %s updating IDNAME to %s.", dev->pvid, devname);
free(du->idname);
free(du->devname);

View File

@@ -41,6 +41,7 @@ void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg,
struct dev_use *get_du_for_dev(struct cmd_context *cmd, struct device *dev);
struct dev_use *get_du_for_pvid(struct cmd_context *cmd, const char *pvid);
struct dev_use *get_du_for_devname(struct cmd_context *cmd, const char *devname);
char *devices_file_version(void);
int devices_file_exists(struct cmd_context *cmd);

View File

@@ -47,7 +47,6 @@ MAN8=lvm.8 lvmdump.8 lvm-fullreport.8 lvm-lvpoll.8 \
MAN8SO=lvm-config.8 lvm-dumpconfig.8
MAN8DM=dmsetup.8 dmstats.8
MAN8CLUSTER=
MAN8SYSTEMD_GENERATORS=lvm2-activation-generator.8
ifeq (,$(findstring $(MAKECMDGOALS), distclean all_man install_all_man))
MAN7 += lvmcache.7 lvmthin.7 lvmvdo.7
@@ -119,7 +118,7 @@ TESTMAN=test.gen
include $(top_builddir)/make.tmpl
CLEAN_TARGETS+=$(MAN5) $(MAN7) $(MAN8) $(MAN8SO) $(MAN8:%.8=%.8_gen) $(MAN8CLUSTER) \
$(MAN8SYSTEMD_GENERATORS) $(MAN8DM) $(TESTMAN)
$(MAN8DM) $(TESTMAN)
all: man device-mapper
@@ -127,11 +126,11 @@ all: man device-mapper
device-mapper: $(MAN8DM)
man: $(MAN5) $(MAN7) $(MAN8) $(MAN8SO) $(MAN8CLUSTER) $(MAN8SYSTEMD_GENERATORS)
man: $(MAN5) $(MAN7) $(MAN8) $(MAN8SO) $(MAN8CLUSTER)
all_man: man
$(MAN5) $(MAN7) $(MAN8) $(MAN8SO) $(MAN8DM) $(MAN8CLUSTER) $(MAN8SYSTEMD_GENERATORS): Makefile
$(MAN5) $(MAN7) $(MAN8) $(MAN8SO) $(MAN8DM) $(MAN8CLUSTER): Makefile
$(MANGENERATOR):
@echo " [MAKE] $<"
@@ -289,11 +288,6 @@ install_device-mapper: $(MAN8DM)
$(Q) $(INSTALL) -d $(MAN8DIR)
$(Q) $(INSTALL_DATA) $^ $(MAN8DIR)/
install_systemd_generators: $(MAN8SYSTEMD_GENERATORS)
@echo " [INSTALL] $^"
$(Q) $(INSTALL) -d $(MAN8DIR)
$(Q) $(INSTALL_DATA) $^ $(MAN8DIR)/
install: install_lvm2 install_device-mapper install_cluster
install_all_man: install install_systemd_generators

View File

@@ -61,8 +61,6 @@ and more, using a more compact and configurable output format.
.br
[ \fB--readonly\fP ]
.br
[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ]
.br
[ \fB--segments\fP ]
.br
[ \fB--separator\fP \fIString\fP ]
@@ -332,16 +330,6 @@ device-mapper kernel driver, so this option is unable to report whether
or not LVs are actually in use.
.
.HP
\fB--reportformat\fP \fBbasic\fP|\fBjson\fP
.br
Overrides current output format for reports which is defined globally by
the report/output_format setting in \fBlvm.conf\fP(5).
\fBbasic\fP is the original format with columns and rows.
If there is more than one report per command, each report is prefixed
with the report name for identification. \fBjson\fP produces report
output in JSON format. See \fBlvmreport\fP(7) for more information.
.
.HP
\fB--segments\fP
.br
.

View File

@@ -563,7 +563,6 @@ Prepends source file name and code line number with libdm debugging.
.P
.BR lvm-fullreport (8),
.BR lvm-lvpoll (8),
.BR lvm2-activation-generator (8),
.BR blkdeactivate (8),
.BR lvmdump (8),
.P

View File

@@ -1,58 +0,0 @@
.TH "LVM2-ACTIVATION-GENERATOR" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
.
.SH "NAME"
.
lvm2-activation-generator - generator for systemd units to activate LVM volumes on boot
.
.SH SYNOPSIS
.
.B #SYSTEMD_GENERATOR_DIR#/lvm2-activation-generator
.
.SH DESCRIPTION
.
The lvm2-activation-generator is called by \fBsystemd\fP(1) on boot to
generate systemd units at runtime to activate LVM Logical Volumes (LVs)
when global/event_activation=0 is set in \fBlvm.conf\fP(5). These units use
\fBvgchange -aay\fP to activate LVs.
.P
If event_activation=1, the lvm2-activation-generator exits immediately without
generating any systemd units, and LVM fully relies on event-based
activation to activate LVs. In this case, event-generated
.B pvscan --cache -aay
commands activate LVs.
.P
These systemd units are generated by lvm2-activation-generator:
.P
.I lvm2-activation-early.service
is run before systemd's special \fBcryptsetup.target\fP to activate
LVs that are not layered on top of encrypted devices.
.P
.I lvm2-activation.service
is run after systemd's special \fBcryptsetup.target\fP to activate
LVs that are layered on top of encrypted devices.
.P
.I lvm2-activation-net.service
is run after systemd's special \fBremote-fs-pre.target\fP to activate
LVs that are layered on attached remote devices.
.P
Note that all the underlying LVM devices (Physical Volumes) need to be
present when the service is run. If the there are any devices that appear
to the system later, LVs using these devices need to be activated directly
by \fBlvchange\fP(8) or \fBvgchange\fP(8).
.P
The lvm2-activation-generator implements the \fBGenerators Specification\fP
as referenced in \fBsystemd\fP(1).
.
.SH SEE ALSO
.nh
.ad l
.BR lvm.conf (5),
.BR vgchange (8),
.BR lvchange (8),
.BR pvscan (8),
.P
.BR systemd (1),
.BR systemd.target (5),
.BR systemd.special (7),
.P
.BR udev (7)

View File

@@ -17,13 +17,11 @@ is another way to limit autoactivation.
.
.SS event autoactivation
.P
The most common form of autoactivation is "event based", in which complete
VGs are activated in response to uevents which occur during system startup
or at any time after the system has started. Another form of
autoactivation is "static" in which complete VGs are activated at a fixed
point during system startup by a systemd service, and not in response to
events. This can be controlled with the lvm.conf setting
event_activation.
LVM autoactivation is "event based", in which complete VGs are activated
in response to uevents which occur during system startup or at any time
after the system has started. An old form of autoactivation was "static"
in which complete VGs are activated at a fixed point during system startup
by a systemd service, and not in response to events.
.P
Event based autoactivation is driven by udev, udev rules, and systemd.
When a device is attached to a machine, a uevent is generated by the
@@ -32,7 +30,7 @@ rules to process the new device. Udev rules use blkid to identify the
device as an LVM PV and then execute the lvm-specific udev rule for the
device, which triggers autoactivation.
.P
There are two variations of event baed autoactivation that may be used on
There are two variations of event based autoactivation that may be used on
a system, depending on the LVM udev rule that is installed (found in
/lib/udev/rules.d/.) The following summarizes the steps in each rule
which lead to autoactivation:
@@ -179,35 +177,12 @@ concurrent commands attempt to activate a VG at once.
.
.SS static autoactivation
.P
When event autoactivation is disabled by setting lvm.conf
event_activation=0, autoactivation is performed at one or more static
points during system startup. At these points, a vgchange -aay command is
run to activate complete VGs from devices that are present on the system
at that time. pvscan commands (and lvm2-pvscan services) do not perform
autoactivation in this mode. pvscan commands may still be run from
uevents but will do nothing when they read the event_activation=0 setting.
.P
The static vgchange -aay commands are run by three systemd services at
three points during startup: lvm2-activation-early, lvm2-activation, and
lvm2-activation-net. These static activation services are "generated
services", so the service files are created at run time by the
lvm2-activation-generator command (run by systemd).
lvm2-activation-generator creates the services if lvm.conf
event_activation=0.
.P
The limitation of this method is that devices may not be attached to the
system (or set up) at a reliable point in time during startup, and they
may not be present when the services run vgchange. In this case, the VGs
will not be autoactivated. So, the timing of device attachment/setup
determines whether static autoactivation will produce the same results as
event autoactivation. For this reason, static autoactivation is not
recommended.
.P
Sometimes, static autoactivation is mistakenly expected to disable all
autoactivation of particular VGs. This may appear to be effective if those
VGs are slow to be attached or set up. But, the only correct and reliable
way to disable autoactivation is using vgchange/lvchange
--setautoactivation n, or lvm.conf auto_activation_volume_list.
A static autoactivation method is no longer provided by lvm.
Setting event_activation=0 still disables event based autoactivation.
WARNING: disabling event activation without an alternative may prevent a
system from booting. A custom systemd service could be written to run
autoactivation during system startup, in which case disabling event
autoactivation may be useful.
.
.SH EXAMPLES
.P

View File

@@ -322,7 +322,8 @@ Find a device with the PVID and add the device to the devices file.
.HP
\fB--check\fP
.br
Check the content of the devices file.
Checks the content of the devices file.
Reports incorrect device names or PVIDs for entries.
.
.HP
\fB--commandprofile\fP \fIString\fP

View File

@@ -61,8 +61,6 @@ and more, using a more compact and configurable output format.
.br
[ \fB--readonly\fP ]
.br
[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ]
.br
[ \fB--separator\fP \fIString\fP ]
.br
[ \fB--shared\fP ]
@@ -320,16 +318,6 @@ device-mapper kernel driver, so this option is unable to report whether
or not LVs are actually in use.
.
.HP
\fB--reportformat\fP \fBbasic\fP|\fBjson\fP
.br
Overrides current output format for reports which is defined globally by
the report/output_format setting in \fBlvm.conf\fP(5).
\fBbasic\fP is the original format with columns and rows.
If there is more than one report per command, each report is prefixed
with the report name for identification. \fBjson\fP produces report
output in JSON format. See \fBlvmreport\fP(7) for more information.
.
.HP
\fB-S\fP|\fB--select\fP \fIString\fP
.br
Select objects for processing and reporting based on specified criteria.

View File

@@ -15,6 +15,8 @@ pvscan \(em List all physical volumes
.P
.ad l
\fB-a\fP|\fB--activate\fP \fBy\fP|\fBn\fP|\fBay\fP
.br
\fB--autoactivation\fP \fIString\fP
.br
\fB--cache\fP
.br
@@ -91,59 +93,50 @@ like
or
.BR pvdisplay (8).
.P
When the --cache and -aay options are used, pvscan records which PVs are
available on the system, and activates LVs in completed VGs. A VG is
complete when pvscan sees that the final PV in the VG has appeared. This
is used by event-based system startup (systemd, udev) to activate LVs.
.P
The four main variations of this are:
When --cache is used, pvscan updates runtime lvm state on the system, or
with -aay performs autoactivation.
.P
.B pvscan --cache
.I device
.P
If device is present, lvm adds a record that the PV on device is online.
If device is present, lvm records that the PV on device is online.
If device is not present, lvm removes the online record for the PV.
In most cases, the pvscan will only read the named devices.
.P
.B pvscan --cache -aay
.IR device ...
.P
This begins by performing the same steps as above. Afterward, if the VG
for the specified PV is complete, then pvscan will activate LVs in the VG
(the same as vgchange -aay vgname would do.)
pvscan only reads the named device.
.P
.B pvscan --cache
.P
This first clears all existing PV online records, then scans all devices
on the system, adding PV online records for any PVs that are found.
Updates the runtime state for all lvm devices.
.P
.B pvscan --cache -aay
.I device
.P
Performs the --cache steps for the device, then checks if the VG using the
device is complete. If so, LVs in the VG are autoactivated, the same as
vgchange -aay vgname would do. (A device name may be replaced with major
and minor numbers.)
.P
.B pvscan --cache -aay
.P
This begins by performing the same steps as pvscan --cache. Afterward, it
activates LVs in any complete VGs.
Performs the --cache steps for all devices, then autoactivates any complete VGs.
.P
To prevent devices from being scanned by pvscan --cache, add them
to
.BR lvm.conf (5)
.B devices/global_filter.
For more information, see:
.br
.B lvmconfig --withcomments devices/global_filter
.B pvscan --cache --listvg|--listlvs
.I device
.P
Auto-activation of VGs or LVs can be enabled/disabled using:
.br
Performs the --cache steps for the device, then prints the name of the VG
using the device, or the names of LVs using the device. --checkcomplete
is usually included to check if all PVs for the VG or LVs are online.
When this command is called by a udev rule, the output must conform to
udev rule specifications (see --udevoutput.) The udev rule will use the
results to perform autoactivation.
.P
Autoactivation of VGs or LVs can be enabled/disabled using vgchange or
lvchange with --setautoactivation y|n, or by adding names to
.BR lvm.conf (5)
.B activation/auto_activation_volume_list
.P
For more information, see:
.br
.B lvmconfig --withcomments activation/auto_activation_volume_list
.P
To disable auto-activation, explicitly set this list to an empty list,
i.e. auto_activation_volume_list = [ ].
.P
When this setting is undefined (e.g. commented), then all LVs are
auto-activated.
See
.BR lvmautoactivation (7)
for more information about how pvscan is used for autoactivation.
.
.SH USAGE
.
@@ -215,6 +208,8 @@ Record that a PV is online and autoactivate the VG if complete.
.br
[ \fB--noudevsync\fP ]
.br
[ \fB--autoactivation\fP \fIString\fP ]
.br
[ COMMON_OPTIONS ]
.ad b
.RE
@@ -239,6 +234,8 @@ Record that a PV is online and list the VG using the PV.
.br
[ \fB--udevoutput\fP ]
.br
[ \fB--autoactivation\fP \fIString\fP ]
.br
[ COMMON_OPTIONS ]
.ad b
.RE
@@ -342,6 +339,14 @@ Auto-activate LVs in a VG when the PVs scanned have completed the VG.
(Only \fBay\fP is applicable.)
.
.HP
\fB--autoactivation\fP \fIString\fP
.br
Specify if autoactivation is being used from an event.
This allows the command to apply settings that are specific
to event activation, such as device scanning optimizations
using pvs_online files created by event-based pvscans.
.
.HP
\fB--cache\fP
.br
Scan one or more devices and record that they are online.

View File

@@ -53,7 +53,6 @@
.P
.BR lvm-fullreport (8),
.BR lvm-lvpoll (8),
.BR lvm2-activation-generator (8),
.BR blkdeactivate (8),
.BR lvmdump (8),
.P

View File

@@ -24,6 +24,8 @@ vgchange \(em Change volume group attributes
.nh
\%\fBcontiguous\fP|\:\fBcling\fP|\:\fBcling_by_tags\fP|\:\fBnormal\fP|\:\fBanywhere\fP|\:\fBinherit\fP
.hy
.br
\fB--autoactivation\fP \fIString\fP
.br
\fB-A\fP|\fB--autobackup\fP \fBy\fP|\fBn\fP
.br
@@ -286,6 +288,8 @@ Activate or deactivate LVs.
.br
[ \fB--poll\fP \fBy\fP|\fBn\fP ]
.br
[ \fB--autoactivation\fP \fIString\fP ]
.br
[ \fB--ignoremonitoring\fP ]
.br
[ \fB--noudevsync\fP ]
@@ -516,6 +520,14 @@ which PVs the command will use for allocation.
See \fBlvm\fP(8) for more information about allocation.
.
.HP
\fB--autoactivation\fP \fIString\fP
.br
Specify if autoactivation is being used from an event.
This allows the command to apply settings that are specific
to event activation, such as device scanning optimizations
using pvs_online files created by event-based pvscans.
.
.HP
\fB-A\fP|\fB--autobackup\fP \fBy\fP|\fBn\fP
.br
Specifies if metadata should be backed up automatically after a change.

View File

@@ -58,8 +58,6 @@ and more, using a more compact and configurable output format.
.br
[ \fB--readonly\fP ]
.br
[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ]
.br
[ \fB--shared\fP ]
.br
[ \fB--separator\fP \fIString\fP ]
@@ -312,16 +310,6 @@ device-mapper kernel driver, so this option is unable to report whether
or not LVs are actually in use.
.
.HP
\fB--reportformat\fP \fBbasic\fP|\fBjson\fP
.br
Overrides current output format for reports which is defined globally by
the report/output_format setting in \fBlvm.conf\fP(5).
\fBbasic\fP is the original format with columns and rows.
If there is more than one report per command, each report is prefixed
with the report name for identification. \fBjson\fP produces report
output in JSON format. See \fBlvmreport\fP(7) for more information.
.
.HP
\fB-S\fP|\fB--select\fP \fIString\fP
.br
Select objects for processing and reporting based on specified criteria.

View File

@@ -15,9 +15,6 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvm2_activation_generator_systemd_red_hat.c
TARGETS = lvm2_activation_generator_systemd_red_hat
include $(top_builddir)/make.tmpl
ifeq ("@BUILD_DMEVENTD@", "yes")
@@ -78,17 +75,6 @@ ifeq ("@BLKDEACTIVATE@", "yes")
$(Q) $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability
endif
CFLAGS_lvm2_activation_generator_systemd_red_hat.o += $(EXTRA_EXEC_CFLAGS)
lvm2_activation_generator_systemd_red_hat: $(OBJECTS) $(LVMINTERNAL_LIBS)
@echo " [CC] $@"
$(Q) $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) $(LVMINTERNAL_LIBS) $(LIBS)
install_systemd_generators:
@echo " [INSTALL] systemd_generators"
$(Q) $(INSTALL_DIR) $(systemd_generator_dir)
$(Q) $(INSTALL_PROGRAM) lvm2_activation_generator_systemd_red_hat $(systemd_generator_dir)/lvm2-activation-generator
install_systemd_units: install_dbus_service
@echo " [INSTALL] systemd_units"
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)

View File

@@ -1,7 +1,7 @@
[Unit]
Description=Availability of block devices
Before=shutdown.target
After=lvm2-activation.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
After=iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
DefaultDependencies=no
Conflicts=shutdown.target

View File

@@ -1,221 +0,0 @@
/*
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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
*/
// This file contains the unit testable parts of
// lvm2_activation_generator_systemd_red_hat
#include "device_mapper/all.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h> /* For PATH_MAX for musl libc */
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
//----------------------------------------------------------------
static void _error(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
//----------------------------------------------------------------
// I'm rolling my own version of popen() here because I do not want to
// go through the shell.
struct child_process {
pid_t pid;
FILE *fp;
};
static bool _open_child(struct child_process *child, const char *cmd, const char *argv[])
{
int r, pipe_fd[2];
r = pipe(pipe_fd);
if (r < 0) {
_error("call to pipe() failed: %d\n", r);
return false;
}
child->pid = fork();
if (child->pid < 0) {
(void) close(pipe_fd[0]);
(void) close(pipe_fd[1]);
_error("call to fork() failed: %d\n", r);
return false;
}
if (child->pid == 0) {
// child
(void) close(pipe_fd[0]);
if (pipe_fd[1] != STDOUT_FILENO) {
(void) dup2(pipe_fd[1], STDOUT_FILENO);
(void) close(pipe_fd[1]);
}
/* Suppressing any use of syslog */
(void) setenv("LVM_SUPPRESS_SYSLOG", "1", 1);
if (execv(cmd, (char *const *) argv) < 0)
_error("execv failed: %s\n", strerror(errno));
// Shouldn't get here unless exec failed.
exit(1);
} else {
// parent
(void) close(pipe_fd[1]);
child->fp = fdopen(pipe_fd[0], "r");
if (!child->fp) {
_error("call to fdopen() failed\n");
return false;
}
}
return true;
}
// Returns the child's exit status
static bool _close_child(struct child_process *child)
{
int status;
(void) fclose(child->fp);
while (waitpid(child->pid, &status, 0) < 0)
if (errno != EINTR)
return -1;
if (WIFEXITED(status) && !WEXITSTATUS(status))
return true;
return false;
}
//----------------------------------------------------------------
// Aquiring config from the lvmconfig process
#define LVM_CONF_EVENT_ACTIVATION "global/event_activation"
#define LVM_CONF_USE_LVMPOLLD "global/use_lvmpolld"
struct config {
bool event_activation;
bool sysinit_needed;
};
static bool _begins_with(const char *line, const char *prefix, const char **rest)
{
size_t len = strlen(prefix);
if (strlen(line) < len)
return false;
if (strncmp(line, prefix, len))
return false;
*rest = line + len;
return true;
}
static bool _parse_bool(const char *val, bool * result)
{
const char *b = val, *e;
while (*b && isspace(*b))
b++;
if (!*b)
goto parse_error;
e = b;
while (*e && !isspace(*e))
e++;
if ((e - b) != 1)
goto parse_error;
// We only handle '1', or '0'
if (*b == '1') {
*result = true;
return true;
} else if (*b == '0') {
*result = false;
return true;
}
// Fallthrough
parse_error:
_error("couldn't parse bool value '%s'\n", val);
return false;
}
static bool _parse_line(const char *line, struct config *cfg)
{
const char *val;
if (_begins_with(line, "event_activation=", &val)) {
return _parse_bool(val, &cfg->event_activation);
} else if (_begins_with(line, "use_lvmpolld=", &val)) {
bool r;
if (!_parse_bool(val, &r))
return false;
cfg->sysinit_needed = !r;
return true;
}
return false;
}
static bool _get_config(struct config *cfg, const char *lvmconfig_path)
{
static const char *_argv[] = {
"lvmconfig", "--type", "full",
LVM_CONF_EVENT_ACTIVATION, LVM_CONF_USE_LVMPOLLD, NULL
};
bool r = true;
char buffer[256];
struct child_process child;
cfg->event_activation = false;
cfg->sysinit_needed = true;
if (!_open_child(&child, lvmconfig_path, _argv)) {
_error("couldn't open lvmconfig process\n");
return false;
}
while (fgets(buffer, sizeof(buffer), child.fp)) {
if (!_parse_line(buffer, cfg)) {
_error("_parse_line() failed\n");
r = false;
}
}
if (!_close_child(&child)) {
_error("lvmconfig failed\n");
r = false;
}
return r;
}

View File

@@ -1,233 +0,0 @@
/*
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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
*/
// Code in this file gets included in the unit tests.
#include "generator-internals.c"
// Logging
#define KMSG_DEV_PATH "/dev/kmsg"
static int _kmsg_fd;
static void _log_init(void)
{
// failing is harmless
_kmsg_fd = open(KMSG_DEV_PATH, O_WRONLY | O_NOCTTY);
}
static void _log_exit(void)
{
if (_kmsg_fd != -1)
(void) close(_kmsg_fd);
}
__attribute__ ((format(printf, 1, 2)))
static void _error(const char *format, ...)
{
int n;
va_list ap;
char message[PATH_MAX + 30]; /* +3 for '<n>' where n is the log level and +27 for lvm2-activation-generator: " prefix */
snprintf(message, 31, "<%d>lvm2-activation-generator: ", LOG_ERR);
va_start(ap, format);
n = vsnprintf(message + 30, PATH_MAX, format, ap);
va_end(ap);
if (_kmsg_fd < 0 || (n < 0 || ((unsigned) n + 1 > PATH_MAX)))
return;
/* The n+31: +30 for "<n>lvm2-activation-generator: " prefix and +1 for '\0' suffix */
if (write(_kmsg_fd, message, n + 31) < 0)
_error("Failed to write activation message %s: %m.\n", message);
}
//----------------------------------------------------------------
#define UNIT_TARGET_LOCAL_FS "local-fs-pre.target"
#define UNIT_TARGET_REMOTE_FS "remote-fs-pre.target"
struct generator {
const char *dir;
struct config cfg;
int kmsg_fd;
char unit_path[PATH_MAX];
char target_path[PATH_MAX];
};
enum {
UNIT_EARLY,
UNIT_MAIN,
UNIT_NET
};
static const char *_unit_names[] = {
[UNIT_EARLY] = "lvm2-activation-early.service",
[UNIT_MAIN] = "lvm2-activation.service",
[UNIT_NET] = "lvm2-activation-net.service"
};
//----------------------------------------------------------------
static int register_unit_with_target(struct generator *gen, const char *unit,
const char *target)
{
int r = 1;
if (dm_snprintf(gen->target_path, PATH_MAX, "%s/%s.wants", gen->dir, target) < 0) {
r = 0;
goto out;
}
(void) dm_prepare_selinux_context(gen->target_path, S_IFDIR);
if (mkdir(gen->target_path, 0755) < 0 && errno != EEXIST) {
_error("Failed to create target directory %s: %m.\n", gen->target_path);
r = 0;
goto out;
}
if (dm_snprintf
(gen->target_path, PATH_MAX, "%s/%s.wants/%s", gen->dir, target, unit) < 0) {
r = 0;
goto out;
}
(void) dm_prepare_selinux_context(gen->target_path, S_IFLNK);
if (symlink(gen->unit_path, gen->target_path) < 0) {
_error("Failed to create symlink for unit %s: %m.\n", unit);
r = 0;
}
out:
dm_prepare_selinux_context(NULL, 0);
return r;
}
static int generate_unit(struct generator *gen, int unit)
{
FILE *f;
const char *unit_name = _unit_names[unit];
const char *target_name =
unit == UNIT_NET ? UNIT_TARGET_REMOTE_FS : UNIT_TARGET_LOCAL_FS;
if (dm_snprintf(gen->unit_path, PATH_MAX, "%s/%s", gen->dir, unit_name)
< 0)
return 0;
if (!(f = fopen(gen->unit_path, "wxe"))) {
_error("Failed to create unit file %s: %m.\n", unit_name);
return 0;
}
fputs("# Automatically generated by lvm2-activation-generator.\n"
"#\n"
"# This unit is responsible for direct activation of LVM logical volumes\n"
"# if event-based activation not used (global/event_activation=0 in\n"
"# lvm.conf). Direct LVM activation requires udev to be settled!\n\n"
"[Unit]\n"
"Description=LVM direct activation of logical volumes\n"
"Documentation=man:lvm2-activation-generator(8)\n"
"SourcePath=/etc/lvm/lvm.conf\n" "DefaultDependencies=no\n", f);
fputs("Conflicts=shutdown.target\n", f);
if (unit == UNIT_NET) {
fprintf(f, "After=%s iscsi.service fcoe.service rbdmap.service\n"
"Before=remote-fs-pre.target shutdown.target\n\n"
"[Service]\n"
"ExecStartPre=/usr/bin/udevadm settle\n", _unit_names[UNIT_MAIN]);
} else {
if (unit == UNIT_EARLY)
fputs("After=systemd-udev-settle.service\n"
"Before=cryptsetup.target\n", f);
else
fprintf(f, "After=%s cryptsetup.target\n", _unit_names[UNIT_EARLY]);
fputs("Before=local-fs-pre.target shutdown.target\n"
"Wants=systemd-udev-settle.service\n\n" "[Service]\n", f);
}
fputs("ExecStart=" LVM_PATH " vgchange -aay", f);
if (gen->cfg.sysinit_needed)
fputs(" --sysinit", f);
fputs("\nType=oneshot\n", f);
if (fclose(f) < 0) {
_error("Failed to write unit file %s: %m.\n", unit_name);
return 0;
}
if (!register_unit_with_target(gen, unit_name, target_name)) {
_error("Failed to register unit %s with target %s.\n",
unit_name, target_name);
return 0;
}
return 1;
}
static bool _parse_command_line(struct generator *gen, int argc, const char **argv)
{
if (argc != 4) {
_error("Incorrect number of arguments for activation generator.\n");
return false;
}
gen->dir = argv[1];
return true;
}
static bool _run(int argc, const char **argv)
{
bool r;
mode_t old_mask;
struct generator gen;
if (!_parse_command_line(&gen, argc, argv))
return false;
if (_get_config(&gen.cfg, LVMCONFIG_PATH)) {
if (gen.cfg.event_activation)
// If event_activation=1, pvscan --cache -aay does activation.
return true;
}
/*
* Create the activation units if:
* - _get_config succeeded and event_activation=0
* - _get_config failed, then this is a failsafe fallback
*/
/* mark lvm2-activation.*.service as world-accessible */
old_mask = umask(0022);
r = generate_unit(&gen, UNIT_EARLY) &&
generate_unit(&gen, UNIT_MAIN) && generate_unit(&gen, UNIT_NET);
umask(old_mask);
return r;
}
int main(int argc, const char **argv)
{
bool r;
_log_init();
r = _run(argc, argv);
if (!r)
_error("Activation generator failed.\n");
_log_exit();
return r ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -2,7 +2,7 @@
Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
Requires=dm-event.socket
After=dm-event.socket dm-event.service lvm2-activation.service
After=dm-event.socket dm-event.service
Before=local-fs-pre.target shutdown.target
DefaultDependencies=no
Conflicts=shutdown.target

View File

@@ -101,9 +101,6 @@ fi
%{_mandir}/man8/lvm-config.8.gz
%{_mandir}/man8/lvm-dumpconfig.8.gz
%{_mandir}/man8/lvm.8.gz
%if %{enable_systemd}
%{_mandir}/man8/lvm2-activation-generator.8.gz
%endif
%{_mandir}/man8/lvmconfig.8.gz
%{_mandir}/man8/lvmdevices.8.gz
%{_mandir}/man8/lvmdiskscan.8.gz
@@ -190,7 +187,6 @@ fi
%{_tmpfilesdir}/%{name}.conf
%{_unitdir}/blk-availability.service
%{_unitdir}/lvm2-monitor.service
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
%if %{have_service lvmpolld}
%{_unitdir}/lvm2-lvmpolld.service
%{_unitdir}/lvm2-lvmpolld.socket

View File

@@ -423,7 +423,7 @@ sed "s/$pvid1/badpvid/" "$DF.orig" |tee $DF
not grep $pvid1 $DF
grep $did1 $DF
lvmdevices --check 2>&1|tee out
not lvmdevices --check 2>&1|tee out
grep $dev1 out
grep badpvid out
grep $pvid1 out
@@ -493,7 +493,7 @@ rm $DF
d1=$(basename $dev1)
d3=$(basename $dev3)
sed "s/$d1/$d3/" "$DF.orig" |tee $DF
lvmdevices --check 2>&1 |tee out
not lvmdevices --check 2>&1 |tee out
grep $dev1 out
lvmdevices --update
@@ -515,7 +515,7 @@ sed "s/$d1/tmp/" "$DF.orig" |tee ${DF}_1
sed "s/$d2/$d1/" "${DF}_1" |tee ${DF}_2
sed "s/tmp/$d2/" "${DF}_2" |tee $DF
rm ${DF}_1 ${DF}_2
lvmdevices --check 2>&1 |tee out
not lvmdevices --check 2>&1 |tee out
grep $dev1 out
grep $dev2 out
@@ -536,7 +536,7 @@ rm $DF
d1=$(basename $dev1)
d3=$(basename $dev3)
sed "s/$d1/$d3/" "$DF.orig" |tee $DF
lvmdevices --check 2>&1 |tee out
not lvmdevices --check 2>&1 |tee out
grep $dev1 out
pvs -o+uuid,deviceid | grep $vg |tee out

View File

@@ -16,7 +16,6 @@
UNIT_SOURCE=\
device_mapper/vdo/status.c \
\
test/unit/activation-generator_t.c \
test/unit/bcache_t.c \
test/unit/bcache_utils_t.c \
test/unit/bitset_t.c \

View File

@@ -1,268 +0,0 @@
/*
* Copyright (C) 2018 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 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
*/
#include "units.h"
#include "scripts/generator-internals.c"
//----------------------------------------------------------------
static void _error(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
//----------------------------------------------------------------
struct bw_test {
const char *input;
const char *prefix;
const char *val;
};
static void _test_begins_with(void *fixture)
{
static struct bw_test _tests[] = {
{"", "foo", NULL},
{"lskdj", "foo", NULL},
{"foo", "foobar", NULL},
{"fish", "fish", ""},
{"foo=bar ", "foo=", "bar "},
};
unsigned i;
for (i = 0; i < DM_ARRAY_SIZE(_tests); i++) {
const char *val;
struct bw_test *t = _tests + i;
if (t->val) {
if (!_begins_with(t->input, t->prefix, &val))
test_fail("_begins_with('%s', '%s') failed", t->input, t->prefix);
if (strcmp(val, t->val))
test_fail("_begins_with('%s', '%s') -> '%s', expected '%s'",
t->input, t->prefix, val, t->val);
} else {
if (_begins_with(t->input, t->prefix, &val))
test_fail("_begins_with('%s', '%s') unexpectedly succeeded",
t->input, t->prefix);
}
}
}
struct pb_test {
const char *input;
bool parsed;
bool result;
};
static const char *_bool(bool v)
{
return v ? "true" : "false";
}
static void _test_parse_bool(void *fixture)
{
static struct pb_test _tests[] = {
{"", false, false},
{"fish", false, false},
{"true", false, false},
{"false", false, false},
{"1", true, true},
{" \t 1\t\t", true, true},
{"0", true, false},
{" \t0 ", true, false}
};
unsigned i;
for (i = 0; i < DM_ARRAY_SIZE(_tests); i++) {
bool result;
struct pb_test *t = _tests + i;
if (t->parsed) {
if (!_parse_bool(t->input, &result))
test_fail("_parse_bool('%s') unexpectedly failed", t->input);
if (result != t->result)
test_fail("_parse_bool('%s') -> %s", t->input, _bool(result));
} else {
if (_parse_bool(t->input, &result))
test_fail("_parse_bool('%s') unexpectedly succeeded", t->input);
}
}
}
struct pl_test {
const char *input;
bool success;
bool event_activation;
bool sysinit_needed;
};
static void _test_parse_line(void *fixture)
{
static struct pl_test _tests[] = {
{"", false, false, false},
{"sldkjfs", false, false, false},
{"event_activation=1", true, true, true},
{"event_activation=0", true, false, true},
{"use_lvmpolld=1", true, false, false},
{"use_lvmpolld=0", true, false, true}
};
unsigned i;
for (i = 0; i< DM_ARRAY_SIZE(_tests); i++) {
bool r;
struct config cfg = {
.sysinit_needed = true
};
struct pl_test *t = _tests + i;
r = _parse_line(t->input, &cfg);
if (t->success) {
if (!r)
test_fail("_parse_line('%s') failed", t->input);
if (cfg.event_activation != t->event_activation)
test_fail("_parse_line('%s') -> event_activation='%s'",
t->input, _bool(cfg.event_activation));
if (cfg.sysinit_needed != t->sysinit_needed)
test_fail("_parse_line('%s') -> sysinit_needed='%s'",
t->input, _bool(cfg.sysinit_needed));
} else if (r)
test_fail("_parse_line('%s') succeeded", t->input);
}
}
static void _test_get_config_bad_path(void *fixture)
{
struct config cfg;
if (_get_config(&cfg, "/usr/bin/no-such-file"))
test_fail("_get_config() succeeded despite a bad lvmconfig path");
}
static void _test_get_config_bad_exit(void *fixture)
{
struct config cfg;
if (_get_config(&cfg, "/usr/bin/false"))
test_fail("_get_config() succeeded despite a bad lvmconfig exit");
}
struct gc_test {
const char *output;
bool success;
bool event_activation;
bool sysinit_needed;
};
static const char *_fake_lvmconfig(const char *output)
{
const char *path = "./fake-lvmconfig";
FILE *fp = fopen(path, "w");
if (!fp)
return NULL;
fprintf(fp, "#!/usr/bin/env bash\n");
fprintf(fp, "cat <<EOF\n");
fprintf(fp, "%s", output);
fprintf(fp, "EOF\n");
(void) fclose(fp);
if (chmod(path, 0770))
test_fail("chmod 0777 failed on path %s", path);
return path;
}
static void _test_get_config(void *fixture)
{
static struct gc_test _tests[] = {
{"", true, false, true},
{"lsdjkf\n\n\n", false, false, false},
{"event_activation=0\nuse_lvmpolld=1\n", true, false, false},
{"event_activation=1\nuse_lvmpolld=1\n", true, true, false},
{"event_activation=1\nuse_lvmpolld=0\n", true, true, true},
};
bool r;
unsigned i;
const char *path;
for (i = 0; i < DM_ARRAY_SIZE(_tests); i++) {
struct gc_test *t = _tests + i;
struct config cfg = {
.sysinit_needed = true
};
path = _fake_lvmconfig(t->output);
if (!path)
test_fail("couldn't create fake lvmconfig");
r = _get_config(&cfg, path);
if (t->success) {
if (!r)
test_fail("_get_config() <- '%s' failed", t->output);
if (t->event_activation != cfg.event_activation)
test_fail("_get_config() <- '%s', event_activation = %s",
t->output, _bool(cfg.event_activation));
if (t->sysinit_needed != cfg.sysinit_needed)
test_fail("_get_config() <- '%s', sysinit = %s",
t->output, _bool(cfg.sysinit_needed));
} else {
if (r)
test_fail("_get_config() <- '%s' unexpectedly succeeded", t->output);
}
(void) unlink(path);
}
}
//----------------------------------------------------------------
#define T(path, desc, fn) register_test(ts, "/activation-generator/" path, desc, fn)
static struct test_suite *_tests(void)
{
struct test_suite *ts = test_suite_create(NULL, NULL);
if (!ts) {
fprintf(stderr, "out of memory\n");
exit(1);
};
T("begins-with", "Test cases for _begins_with()", _test_begins_with);
T("parse-bool", "Test cases for _parse_bool()", _test_parse_bool);
T("parse-line", "Test cases for _parse_line()", _test_parse_line);
T("get-config-bad-path", "_get_config() needs a valid lvmconfig path", _test_get_config_bad_path);
T("get-config-bad-exit", "lvmconfig bad exit code gets propagated", _test_get_config_bad_exit);
T("get-config", "Test cases for _get_config()", _test_get_config);
return ts;
}
void activation_generator_tests(struct dm_list *all_tests)
{
dm_list_add(all_tests, &_tests()->list);
}
//----------------------------------------------------------------

View File

@@ -20,7 +20,6 @@
//-----------------------------------------------------------------
// Declare the function that adds tests suites here ...
void activation_generator_tests(struct dm_list *suites);
void bcache_tests(struct dm_list *suites);
void bcache_utils_tests(struct dm_list *suites);
void bitset_tests(struct dm_list *suites);
@@ -37,7 +36,6 @@ void vdo_tests(struct dm_list *suites);
// ... and call it in here.
static inline void register_all_tests(struct dm_list *suites)
{
activation_generator_tests(suites);
bcache_tests(suites);
bcache_utils_tests(suites);
bitset_tests(suites);

View File

@@ -159,7 +159,8 @@ arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0,
"The size of cache to use.\n")
arg(check_ARG, '\0', "check", 0, 0, 0,
"Check the content of the devices file.\n")
"Checks the content of the devices file.\n"
"Reports incorrect device names or PVIDs for entries.\n")
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0,
"The command profile to use for command configuration.\n"

View File

@@ -128,7 +128,6 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
struct device *dev;
struct dev_use *du, *du2;
const char *deviceidtype;
int changes = 0;
dm_list_init(&search_pvids);
dm_list_init(&found_devs);
@@ -184,8 +183,11 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (arg_is_set(cmd, check_ARG) || arg_is_set(cmd, update_ARG)) {
int search_count = 0;
int update_needed = 0;
int invalid = 0;
unlink_searched_devnames(cmd);
label_scan_setup_bcache();
dm_list_iterate_items(du, &cmd->use_devices) {
@@ -225,6 +227,8 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
* run just above.
*/
device_ids_validate(cmd, NULL, &invalid, 1);
if (invalid)
update_needed = 1;
/*
* Find and fix any devname entries that have moved to a
@@ -240,33 +244,24 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
label_scan_invalidate(du->dev);
}
/*
* check du->part
*/
dm_list_iterate_items(du, &cmd->use_devices) {
int part = 0;
if (!du->dev)
continue;
dev = du->dev;
dev_get_partition_number(dev, &part);
if (part != du->part) {
log_warn("Device %s partition %u has incorrect PART in devices file (%u)",
dev_name(dev), part, du->part);
du->part = part;
changes++;
}
}
if (arg_is_set(cmd, update_ARG)) {
if (invalid || !dm_list_empty(&found_devs)) {
if (update_needed || !dm_list_empty(&found_devs)) {
if (!device_ids_write(cmd))
goto_bad;
log_print("Updated devices file to version %s", devices_file_version());
} else {
log_print("No update for devices file is needed.");
}
} else {
/*
* --check exits with an error if the devices file
* needs updates, i.e. running --update would make
* changes.
*/
if (update_needed) {
log_error("Updates needed for devices file.");
goto bad;
}
}
goto out;
}
@@ -388,28 +383,27 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
* No filter because we always want to allow removing a device
* by name from the devices file.
*/
if (!(dev = dev_cache_get(cmd, devname, NULL))) {
log_error("No device found for %s.", devname);
goto bad;
}
/*
* dev_cache_scan uses sysfs to check if an LV is using each dev
* and sets this flag is so.
*/
if (dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", devname) == 'n') {
log_error("Device not removed.");
goto bad;
if ((dev = dev_cache_get(cmd, devname, NULL))) {
/*
* dev_cache_scan uses sysfs to check if an LV is using each dev
* and sets this flag is so.
*/
if (dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", devname) == 'n') {
log_error("Device not removed.");
goto bad;
}
}
if ((du = get_du_for_dev(cmd, dev)))
goto dev_del;
}
if (!(du = get_du_for_dev(cmd, dev))) {
log_error("Device not found in devices file.");
if (!(du = get_du_for_devname(cmd, devname))) {
log_error("No devices file entry for %s.", devname);
goto bad;
}
dev_del:
dm_list_del(&du->list);
free_du(du);
device_ids_write(cmd);