mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-27 05:44:18 +03:00
Compare commits
6 Commits
v2_03_26
...
dev-rhel90
Author | SHA1 | Date | |
---|---|---|---|
|
4a1f6173d2 | ||
|
61706793de | ||
|
84503342f7 | ||
|
b8c7810617 | ||
|
ba16b6f227 | ||
|
185c7dcbeb |
@@ -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
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
.
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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;
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 \
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
@@ -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);
|
||||
|
@@ -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"
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user