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

Compare commits

...

24 Commits

Author SHA1 Message Date
Marian Csontos
4b26fb3543 make: generate 2022-01-04 17:15:56 +01:00
David Teigland
61833dd5b6 man lvmautoactivation: replace systemctl with journalctl 2021-12-20 14:22:18 -06:00
David Teigland
af4bfa1f1f lvcreate: include recent options
The permitted option list in lvcreate has not kept
up with command-lines.in.
2021-12-20 14:22:18 -06:00
David Teigland
7631c5b826 man: add section about static autoactivation 2021-12-20 14:22:18 -06:00
David Teigland
357a807e81 device_id: handle wwid with spaces or control characters
non-standard wwid can be reported from sysfs with spaces/etc.
replace with "_"
2021-12-20 14:22:18 -06:00
David Teigland
604fd528fb print warning about unrecognized journal option value 2021-12-20 14:22:18 -06:00
David Teigland
04770589b4 devices file: don't write in test mode 2021-12-20 14:22:18 -06:00
David Teigland
10a4478e9b tests devicesfile-devname.sh drop mdadm chunk 2021-12-20 14:22:17 -06:00
Marian Csontos
c02a086fe7 spec: Add lvmautoactivation man page 2021-12-20 14:22:17 -06:00
David Teigland
25dbe3dd82 man: lvmautoactivation
new topical man page describing autoactivation
2021-12-20 14:22:17 -06:00
David Teigland
7ac0b3c119 fix spelling of pruning 2021-12-20 14:22:17 -06:00
David Teigland
594c1fec16 display: ignore --reportformat
Using the option would do nothing useful but would
print extraneous braces.
2021-12-20 14:22:17 -06:00
David Teigland
9c9bf13186 tests pv-ext-flags: work with devices file 2021-12-20 14:22:17 -06:00
David Teigland
39adf3e513 device_id: searched_devnames improvements
Remove the searched_devnames file in a couple more places:
. When hints need refreshing it's possible that a missing
  devices file entry could be found by searching devices
  again.
. When a devices file entry devname is first found to be
  incorrect, a new search for missing entries may be
  useful.
2021-12-20 14:22:17 -06:00
David Teigland
5533cd7bf4 device_id: fix search on filtered device
When devnames are used as device ids and devnames change,
then new devices need to be located for the PVs.  If the old
devname is now used by a filtered device, this was preventing
the code from searching for the new device, so the PV was
reported as missing.
2021-12-20 14:22:17 -06:00
David Teigland
459d931a9b device_id: match different dm device names
If a devices file entry for a dm device is using the devname
for the device id, then recognize different dm names as matching.
2021-12-20 14:22:17 -06:00
David Teigland
fad2b3dc8c filter-sysfs: support old kernels without sys/dev/block
rhel5 for example doesn't have /sys/dev/block
2021-12-20 14:22:17 -06:00
David Teigland
f732f3d53f lvmdevices: increase open file limit 2021-12-20 14:22:17 -06:00
David Teigland
f73be4480a filter-sysfs: skip when device id is set
When a device id is set for a device, using an idtype other
than devname, it means that sysfs has been used with the device
to match the device id.  So, checking for a sysfs entry for the
device in filter-sysfs is redundant.  For any other cases not
covered by this (e.g. devname ids), have filter-sysfs simply
stat /sys/dev/block/major:minor to test if the device exists
in sysfs.

The extensive processing done by filter-sysfs init is removed.
It was taking an immense amount of time with many devices, e.g.
. 1024 PVs in 520 VGs
. 520 concurrent vgchange -ay <vgname> commands
. vgchange scans only PVs in the named VG (based on pvs_online
  files from a pending patch)

A large number of the vgchange commands were taking over 1 min,
and nearly half of that time was used by filter-sysfs init.
With this patch, the vgchange commands take about half the time.
2021-12-20 14:22:17 -06:00
David Teigland
00ebabfe6e hints: remove the cmd hints list
which is no longer used after commit
"toollib: remove all devices list from process_each_pv"
2021-12-20 14:22:17 -06:00
David Teigland
074fce5c73 vgimportdevices: skip lvmlockd locking
Help bootstrapping existing shared vgs into the devices file.
Reading the vg in vgimportdevices would require locking to be
started, but vgchange lockstart won't see the vg if it's not
in the devices file.  The lvmlockd locks are not protecting
vg modifications so skipping them here won't be a problem.
2021-12-20 14:22:17 -06:00
David Teigland
a5a2d5fa1e pvscan: fix messages from coverity changes 2021-12-20 14:22:17 -06:00
David Teigland
2091305b79 Revert "pvscan: only add device args to dev cache"
This reverts commit 33e47182f7.
2021-12-20 14:22:17 -06:00
David Teigland
63c4458aaf Revert "new udev autoactivation"
This reverts commit 67722b3123.
2021-12-20 14:22:02 -06:00
34 changed files with 739 additions and 1178 deletions

View File

@@ -1143,19 +1143,6 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
* Update MAX_FILTERS definition above when adding new filters.
*/
/*
* sysfs filter. Only available on 2.6 kernels. Non-critical.
* Listed first because it's very efficient at eliminating
* unavailable devices.
*
* TODO: I suspect that using the lvm_type and device_id
* filters before this one may be more efficient.
*/
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
if ((filters[nr_filt] = sysfs_filter_create()))
nr_filt++;
}
/* internal filter used by command processing. */
if (!(filters[nr_filt] = internal_filter_create())) {
log_error("Failed to create internal device filter");
@@ -1195,6 +1182,17 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
}
nr_filt++;
/*
* sysfs filter. Only available on 2.6 kernels. Non-critical.
* Eliminates unavailable devices.
* TODO: this may be unnecessary now with device ids
* (currently not used for devs match to device id using syfs)
*/
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
if ((filters[nr_filt] = sysfs_filter_create()))
nr_filt++;
}
/* usable device filter. Required. */
if (!(filters[nr_filt] = usable_filter_create(cmd, cmd->dev_types, FILTER_MODE_NO_LVMETAD))) {
log_error("Failed to create usabled device filter");
@@ -1605,7 +1603,6 @@ struct cmd_context *create_config_context(void)
dm_list_init(&cmd->config_files);
dm_list_init(&cmd->tags);
dm_list_init(&cmd->hints);
if (!_init_lvm_conf(cmd))
goto_out;
@@ -1670,7 +1667,6 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
dm_list_init(&cmd->formats);
dm_list_init(&cmd->segtypes);
dm_list_init(&cmd->tags);
dm_list_init(&cmd->hints);
dm_list_init(&cmd->config_files);
label_init();

View File

@@ -206,7 +206,6 @@ struct cmd_context {
* Devices and filtering.
*/
struct dev_filter *filter;
struct dm_list hints;
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */

View File

@@ -1852,7 +1852,7 @@ int setup_devices_file(struct cmd_context *cmd)
* Add all system devices to dev-cache, and attempt to
* match all devices_file entries to dev-cache entries.
*/
int setup_devices(struct cmd_context *cmd)
static int _setup_devices(struct cmd_context *cmd, int no_file_match)
{
int file_exists;
int lock_mode = 0;
@@ -1979,6 +1979,13 @@ int setup_devices(struct cmd_context *cmd)
*/
dev_cache_scan(cmd);
/*
* The caller uses "no_file_match" if it wants to match specific devs
* itself, instead of matching everything in device_ids_match.
*/
if (no_file_match && cmd->enable_devices_file)
return 1;
/*
* Match entries from cmd->use_devices with device structs in dev-cache.
*/
@@ -1987,6 +1994,16 @@ int setup_devices(struct cmd_context *cmd)
return 1;
}
int setup_devices(struct cmd_context *cmd)
{
return _setup_devices(cmd, 0);
}
int setup_devices_no_file_match(struct cmd_context *cmd)
{
return _setup_devices(cmd, 1);
}
/*
* The alternative to setup_devices() when the command is interested
* in using only one PV.
@@ -2055,188 +2072,3 @@ int setup_device(struct cmd_context *cmd, const char *devname)
return 1;
}
/*
* pvscan --cache is specialized/optimized to look only at command args,
* so this just sets up the devices file, then individual devices are
* added to dev-cache and matched with device_ids later in pvscan.
*/
int setup_devices_for_pvscan_cache(struct cmd_context *cmd)
{
if (cmd->enable_devices_list) {
if (!_setup_devices_list(cmd))
return_0;
return 1;
}
if (!setup_devices_file(cmd))
return_0;
if (!cmd->enable_devices_file)
return 1;
if (!devices_file_exists(cmd)) {
log_debug("Devices file not found, ignoring.");
cmd->enable_devices_file = 0;
return 1;
}
if (!lock_devices_file(cmd, LOCK_SH)) {
log_error("Failed to lock the devices file to read.");
return 0;
}
if (!device_ids_read(cmd)) {
log_error("Failed to read the devices file.");
unlock_devices_file(cmd);
return 0;
}
unlock_devices_file(cmd);
return 1;
}
/* Get a device name from a devno. */
static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
{
char path[PATH_MAX];
char devname[PATH_MAX];
char namebuf[NAME_LEN];
char line[1024];
int major = MAJOR(devno);
int minor = MINOR(devno);
int line_major;
int line_minor;
uint64_t line_blocks;
DIR *dir;
struct dirent *dirent;
FILE *fp;
/*
* $ ls /sys/dev/block/8:0/device/block/
* sda
*/
if (major_is_scsi_device(cmd->dev_types, major)) {
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/device/block",
dm_sysfs_dir(), major, minor) < 0) {
return NULL;
}
if (!(dir = opendir(path)))
return NULL;
while ((dirent = readdir(dir))) {
if (dirent->d_name[0] == '.')
continue;
if (dm_snprintf(devname, sizeof(devname), "/dev/%s", dirent->d_name) < 0) {
devname[0] = '\0';
stack;
}
break;
}
closedir(dir);
if (devname[0]) {
log_debug("Found %s for %d:%d from sys", devname, major, minor);
return _strdup(devname);
}
return NULL;
}
/*
* $ cat /sys/dev/block/253:3/dm/name
* mpatha
*/
if (major == cmd->dev_types->device_mapper_major) {
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/name",
dm_sysfs_dir(), major, minor) < 0) {
return NULL;
}
if (!get_sysfs_value(path, namebuf, sizeof(namebuf), 0))
return NULL;
if (dm_snprintf(devname, sizeof(devname), "/dev/mapper/%s", namebuf) < 0) {
devname[0] = '\0';
stack;
}
if (devname[0]) {
log_debug("Found %s for %d:%d from sys", devname, major, minor);
return _strdup(devname);
}
return NULL;
}
/*
* /proc/partitions lists
* major minor #blocks name
*/
if (!(fp = fopen("/proc/partitions", "r")))
return NULL;
while (fgets(line, sizeof(line), fp)) {
if (sscanf(line, "%u %u %llu %s", &line_major, &line_minor, (unsigned long long *)&line_blocks, namebuf) != 4)
continue;
if (line_major != major)
continue;
if (line_minor != minor)
continue;
if (dm_snprintf(devname, sizeof(devname), "/dev/%s", namebuf) < 0) {
devname[0] = '\0';
stack;
}
break;
}
fclose(fp);
if (devname[0]) {
log_debug("Found %s for %d:%d from proc", devname, major, minor);
return _strdup(devname);
}
/*
* If necessary, this could continue searching by stat'ing /dev entries.
*/
return NULL;
}
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname)
{
struct stat buf;
struct device *dev;
if (stat(devname, &buf) < 0) {
log_error("Cannot access device %s.", devname);
return 0;
}
if (!S_ISBLK(buf.st_mode)) {
log_error("Invaild device type %s.", devname);
return 0;
}
if (!_insert_dev(devname, buf.st_rdev))
return_0;
if (!(dev = (struct device *) dm_hash_lookup(_cache.names, devname)))
return_0;
return 1;
}
int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno)
{
const char *devname;
if (!(devname = _get_devname_from_devno(cmd, devno)))
return_0;
return setup_devname_in_dev_cache(cmd, devname);
}

View File

@@ -77,11 +77,7 @@ int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
int setup_devices_file(struct cmd_context *cmd);
int setup_devices(struct cmd_context *cmd);
int setup_devices_no_file_match(struct cmd_context *cmd);
int setup_device(struct cmd_context *cmd, const char *devname);
/* Normal device setup functions are split up for pvscan optimization. */
int setup_devices_for_pvscan_cache(struct cmd_context *cmd);
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname);
int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno);
#endif

View File

@@ -74,6 +74,8 @@ void unlink_searched_devnames(struct cmd_context *cmd)
if (unlink(_searched_file))
log_debug("unlink %s errno %d", _searched_file, errno);
else
log_debug("unlink %s", _searched_file);
}
static int _searched_devnames_exists(struct cmd_context *cmd)
@@ -302,6 +304,7 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
{
char sysbuf[PATH_MAX] = { 0 };
const char *idname = NULL;
int i;
if (idtype == DEV_ID_TYPE_SYS_WWID) {
read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
@@ -309,10 +312,6 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
if (!sysbuf[0])
read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
/* scsi_debug wwid begins "t10.Linux scsi_debug ..." */
if (strstr(sysbuf, "scsi_debug"))
sysbuf[0] = '\0';
/* qemu wwid begins "t10.ATA QEMU HARDDISK ..." */
if (strstr(sysbuf, "QEMU HARDDISK"))
sysbuf[0] = '\0';
@@ -353,6 +352,11 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
return idname;
}
for (i = 0; i < strlen(sysbuf); i++) {
if (isblank(sysbuf[i]) || isspace(sysbuf[i]) || iscntrl(sysbuf[i]))
sysbuf[i] = '_';
}
if (!sysbuf[0])
goto_bad;
@@ -671,6 +675,9 @@ int device_ids_write(struct cmd_context *cmd)
cmd->enable_devices_file = 1;
}
if (test_mode())
return 1;
if (_devices_file_version[0]) {
if (sscanf(_devices_file_version, "%u.%u.%u", &df_major, &df_minor, &df_counter) != 3) {
/* don't update a file we can't parse */
@@ -780,7 +787,7 @@ static void _device_ids_update_try(struct cmd_context *cmd)
/* Defer updates to non-pvscan-cache commands. */
if (cmd->pvscan_cache_single) {
log_print("pvscan[%d] skip updating devices file.", getpid());
log_print("Devices file update skipped.");
return;
}
@@ -1360,6 +1367,10 @@ void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg,
static int _idtype_compatible_with_major_number(struct cmd_context *cmd, int idtype, int major)
{
/* devname can be used with any kind of device */
if (idtype == DEV_ID_TYPE_DEVNAME)
return 1;
if (idtype == DEV_ID_TYPE_MPATH_UUID ||
idtype == DEV_ID_TYPE_CRYPT_UUID ||
idtype == DEV_ID_TYPE_LVMLV_UUID)
@@ -1388,6 +1399,43 @@ static int _idtype_compatible_with_major_number(struct cmd_context *cmd, int idt
return 1;
}
static int _match_dm_devnames(struct cmd_context *cmd, struct device *dev,
struct dev_id *id, struct dev_use *du)
{
struct stat buf;
if (MAJOR(dev->dev) != cmd->dev_types->device_mapper_major)
return 0;
if (id->idname && du->idname && !strcmp(id->idname, du->idname))
return 1;
if (du->idname && !strcmp(du->idname, dev_name(dev))) {
log_debug("Match device_id %s %s to %s: ignoring idname %s",
idtype_to_str(du->idtype), du->idname, dev_name(dev), id->idname ?: ".");
return 1;
}
if (!du->idname)
return 0;
/* detect that a du entry is for a dm device */
if (!strncmp(du->idname, "/dev/dm-", 8) || !strncmp(du->idname, "/dev/mapper/", 12)) {
if (stat(du->idname, &buf))
return 0;
if ((MAJOR(buf.st_rdev) == cmd->dev_types->device_mapper_major) &&
(MINOR(buf.st_rdev) == MINOR(dev->dev))) {
log_debug("Match device_id %s %s to %s: using other dm name, ignoring %s",
idtype_to_str(du->idtype), du->idname, dev_name(dev), id->idname ?: ".");
return 1;
}
}
return 0;
}
/*
* check for dev->ids entry with du->idtype, if found compare it,
* if not, system_read of this type and add entry to dev->ids, compare it.
@@ -1400,43 +1448,74 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
const char *idname;
int part;
if (!du->idname || !du->idtype)
/*
* The idname will be removed from an entry with devname type when the
* devname is read and found to hold a different PVID than the PVID in
* the entry. At that point we only have the PVID and no known
* location for it.
*/
if (!du->idname || !du->idtype) {
/*
log_debug("Mismatch device_id %s %s %s to %s",
du->idtype ? idtype_to_str(du->idtype) : "idtype_missing",
du->idname ? du->idname : "idname_missing",
du->devname ? du->devname : "devname_missing",
dev_name(dev));
*/
return 0;
}
/*
* Some idtypes can only match devices with a specific major number,
* so we can skip trying to match certain du entries based simply on
* the major number of dev.
*/
if (!_idtype_compatible_with_major_number(cmd, du->idtype, (int)MAJOR(dev->dev)))
if (!_idtype_compatible_with_major_number(cmd, du->idtype, (int)MAJOR(dev->dev))) {
/*
log_debug("Mismatch device_id %s %s to %s: wrong major",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev));
*/
return 0;
}
if (!dev_get_partition_number(dev, &part)) {
log_debug("compare %s failed to get dev partition", dev_name(dev));
/*
log_debug("Mismatch device_id %s %s to %s: no partition",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev));
*/
return 0;
}
if (part != du->part) {
/*
log_debug("compare mis %s %s part %d to %s part %d",
idtype_to_str(du->idtype), du->idname ?: ".", du->part, dev_name(dev), part);
log_debug("Mismatch device_id %s %s to %s: wrong partition %d vs %d",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev), du->part, part);
*/
return 0;
}
dm_list_iterate_items(id, &dev->ids) {
if (id->idtype == du->idtype) {
if (id->idname && !strcmp(id->idname, du->idname)) {
if ((id->idtype == DEV_ID_TYPE_DEVNAME) && _match_dm_devnames(cmd, dev, id, du)) {
/* dm devs can have differing names that we know still match */
du->dev = dev;
dev->id = id;
dev->flags |= DEV_MATCHED_USE_ID;
log_debug("Match device_id %s %s to %s: dm names",
idtype_to_str(du->idtype), du->idname, dev_name(dev));
return 1;
} else if (id->idname && !strcmp(id->idname, du->idname)) {
du->dev = dev;
dev->id = id;
dev->flags |= DEV_MATCHED_USE_ID;
log_debug("Match device_id %s %s to %s",
idtype_to_str(du->idtype), du->idname, dev_name(dev));
return 1;
} else {
/*
log_debug("compare mis %s %s to %s %s",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev),
((id->idtype != DEV_ID_TYPE_DEVNAME) && id->idname) ? id->idname : "");
log_debug("Mismatch device_id %s %s to %s: idname %s",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev), id->idname ?: ":");
*/
return 0;
}
@@ -1456,7 +1535,7 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
id->dev = dev;
dm_list_add(&dev->ids, &id->list);
/*
log_debug("compare mis %s %s to %s no idtype",
log_debug("Mismatch device_id %s %s to %s: no idtype",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev));
*/
return 0;
@@ -1481,9 +1560,8 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
}
/*
log_debug("compare mis %s %s to %s %s",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev),
((id->idtype != DEV_ID_TYPE_DEVNAME) && id->idname) ? id->idname : "");
log_debug("Mismatch device_id %s %s to %s: idname %s",
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev), idname);
*/
return 0;
}
@@ -1534,22 +1612,6 @@ int device_ids_match_dev(struct cmd_context *cmd, struct device *dev)
* passes the filter.
*/
void device_ids_match_device_list(struct cmd_context *cmd)
{
struct dev_use *du;
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->dev)
continue;
if (!(du->dev = dev_cache_get(cmd, du->devname, NULL))) {
log_warn("Device not found for %s.", du->devname);
} else {
/* Should we set dev->id? Which idtype? Use --deviceidtype? */
du->dev->flags |= DEV_MATCHED_USE_ID;
}
}
}
void device_ids_match(struct cmd_context *cmd)
{
struct dev_iter *iter;
@@ -1557,7 +1619,16 @@ void device_ids_match(struct cmd_context *cmd)
struct device *dev;
if (cmd->enable_devices_list) {
device_ids_match_device_list(cmd);
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->dev)
continue;
if (!(du->dev = dev_cache_get(cmd, du->devname, NULL))) {
log_warn("Device not found for %s.", du->devname);
} else {
/* Should we set dev->id? Which idtype? Use --deviceidtype? */
du->dev->flags |= DEV_MATCHED_USE_ID;
}
}
return;
}
@@ -1907,6 +1978,14 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
*device_ids_invalid = 1;
}
/*
* When a new devname/pvid mismatch is discovered, a new search for the
* pvid should be permitted (searched_devnames may exist to suppress
* searching for other pvids.)
*/
if (update_file)
unlink_searched_devnames(cmd);
/* FIXME: for wrong devname cases, wait to write new until device_ids_find_renamed_devs? */
/*
@@ -1975,12 +2054,19 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
search_auto = !strcmp(cmd->search_for_devnames, "auto");
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->dev)
continue;
if (!du->pvid)
continue;
if (du->idtype != DEV_ID_TYPE_DEVNAME)
continue;
/*
* if the old incorrect devname is now a device that's
* filtered and not scanned, e.g. an mpath component,
* then we want to look for the pvid on a new device.
*/
if (du->dev && !du->dev->filtered_flags)
continue;
if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil))))
continue;
@@ -2005,6 +2091,11 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
* the searched file, so a subsequent lvm command will do the search
* again. In future perhaps we could add a policy to automatically
* remove a devices file entry that's not been found for some time.
*
* TODO: like the hint file, add a hash of all devnames to the searched
* file so it can be ignored and removed if the devs/hash change.
* If hints are enabled, the hints invalidation could also remove the
* searched file.
*/
if (_searched_devnames_exists(cmd)) {
log_debug("Search for PVIDs skipped for %s", _searched_file);

View File

@@ -32,7 +32,6 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid,
void device_id_pvremove(struct cmd_context *cmd, struct device *dev);
void device_ids_match(struct cmd_context *cmd);
int device_ids_match_dev(struct cmd_context *cmd, struct device *dev);
void device_ids_match_device_list(struct cmd_context *cmd);
void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, int *device_ids_invalid, int noupdate);
int device_ids_version_unchanged(struct cmd_context *cmd);
void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count, int noupdate);

View File

@@ -15,268 +15,41 @@
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
static int _sys_dev_block_found;
#ifdef __linux__
#include <sys/sysmacros.h>
#include <dirent.h>
static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
unsigned *sysfs_depth)
{
struct stat info;
unsigned i;
static const struct dir_class {
const char path[32];
int depth;
} classes[] = {
/*
* unified classification directory for all kernel subsystems
*
* /sys/subsystem/block/devices
* |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
* |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
* `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
*
*/
{ "subsystem/block/devices", 0 },
/*
* block subsystem as a class
*
* /sys/class/block
* |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
* |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
* `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
*
*/
{ "class/block", 0 },
/*
* old block subsystem layout with nested directories
*
* /sys/block/
* |-- sda
* | |-- capability
* | |-- dev
* ...
* | |-- sda1
* | | |-- dev
* ...
* |
* `-- sr0
* |-- capability
* |-- dev
* ...
*
*/
{ "block", 1 }
};
for (i = 0; i < DM_ARRAY_SIZE(classes); ++i)
if ((dm_snprintf(path, len, "%s%s", sysfs_dir, classes[i].path) >= 0) &&
(stat(path, &info) == 0)) {
*sysfs_depth = classes[i].depth;
return 1;
}
return 0;
}
/*----------------------------------------------------------------
* We need to store a set of dev_t.
*--------------------------------------------------------------*/
struct entry {
struct entry *next;
dev_t dev;
};
#define SET_BUCKETS 64
struct dev_set {
struct dm_pool *mem;
const char *sys_block;
unsigned sysfs_depth;
int initialised;
struct entry *slots[SET_BUCKETS];
};
static struct dev_set *_dev_set_create(struct dm_pool *mem,
const char *sys_block,
unsigned sysfs_depth)
{
struct dev_set *ds;
if (!(ds = dm_pool_zalloc(mem, sizeof(*ds))))
return NULL;
ds->mem = mem;
if (!(ds->sys_block = dm_pool_strdup(mem, sys_block)))
return NULL;
ds->sysfs_depth = sysfs_depth;
ds->initialised = 0;
return ds;
}
static unsigned _hash_dev(dev_t dev)
{
return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
}
/*
* Doesn't check that the set already contains dev.
*/
static int _set_insert(struct dev_set *ds, dev_t dev)
{
struct entry *e;
unsigned h = _hash_dev(dev);
if (!(e = dm_pool_alloc(ds->mem, sizeof(*e))))
return 0;
e->next = ds->slots[h];
e->dev = dev;
ds->slots[h] = e;
return 1;
}
static int _set_lookup(struct dev_set *ds, dev_t dev)
{
unsigned h = _hash_dev(dev);
struct entry *e;
for (e = ds->slots[h]; e; e = e->next)
if (e->dev == dev)
return 1;
return 0;
}
/*----------------------------------------------------------------
* filter methods
*--------------------------------------------------------------*/
static int _parse_dev(const char *file, FILE *fp, dev_t *result)
{
unsigned major, minor;
char buffer[64];
if (!fgets(buffer, sizeof(buffer), fp)) {
log_error("Empty sysfs device file: %s", file);
return 0;
}
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
log_error("Incorrect format for sysfs device file: %s.", file);
return 0;
}
*result = makedev(major, minor);
return 1;
}
static int _read_dev(const char *file, dev_t *result)
{
int r;
FILE *fp;
if (!(fp = fopen(file, "r"))) {
log_sys_error("fopen", file);
return 0;
}
r = _parse_dev(file, fp, result);
if (fclose(fp))
log_sys_error("fclose", file);
return r;
}
/*
* Recurse through sysfs directories, inserting any devs found.
*/
static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth)
{
struct dirent *d;
DIR *dr;
struct stat info;
char path[PATH_MAX];
char file[PATH_MAX];
dev_t dev = { 0 };
int r = 1;
if (!(dr = opendir(dir))) {
log_sys_error("opendir", dir);
return 0;
}
while ((d = readdir(dr))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
d->d_name) < 0) {
log_warn("WARNING: sysfs path name too long: %s in %s.",
d->d_name, dir);
continue;
}
/* devices have a "dev" file */
if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) {
log_warn("WARNING: sysfs path name too long: %s in %s.",
d->d_name, dir);
continue;
}
if (!stat(file, &info)) {
/* recurse if we found a device and expect subdirs */
if (sysfs_depth)
_read_devs(ds, path, sysfs_depth - 1);
/* add the device we have found */
if (_read_dev(file, &dev))
_set_insert(ds, dev);
}
}
if (closedir(dr))
log_sys_debug("closedir", dir);
return r;
}
static int _init_devs(struct dev_set *ds)
{
if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) {
ds->initialised = -1;
return 0;
}
ds->initialised = 1;
return 1;
}
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct dev_set *ds = (struct dev_set *) f->private;
char path[PATH_MAX];
const char *sysfs_dir;
struct stat info;
if (!_sys_dev_block_found)
return 1;
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
if (!ds->initialised)
_init_devs(ds);
/* Pass through if initialisation failed */
if (ds->initialised != 1)
/*
* Any kind of device id other than devname has been set
* using sysfs so we know that sysfs info exists for dev.
*/
if (dev->id && dev->id->idtype && (dev->id->idtype != DEV_ID_TYPE_DEVNAME))
return 1;
if (!_set_lookup(ds, dev->dev)) {
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_SYSFS;
return 0;
sysfs_dir = dm_sysfs_dir();
if (sysfs_dir && *sysfs_dir) {
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_debug("failed to create sysfs path");
return 1;
}
if (lstat(path, &info)) {
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_SYSFS;
return 0;
}
}
return 1;
@@ -284,21 +57,34 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
static void _destroy(struct dev_filter *f)
{
struct dev_set *ds = (struct dev_set *) f->private;
if (f->use_count)
log_error(INTERNAL_ERROR "Destroying sysfs filter while in use %u times.", f->use_count);
free(f);
}
dm_pool_destroy(ds->mem);
static void _check_sys_dev_block(void)
{
char path[PATH_MAX];
const char *sysfs_dir;
struct stat info;
sysfs_dir = dm_sysfs_dir();
if (sysfs_dir && *sysfs_dir) {
if (dm_snprintf(path, sizeof(path), "%sdev/block", sysfs_dir) < 0)
return;
if (lstat(path, &info)) {
log_debug("filter-sysfs disabled: /sys/dev/block not found");
_sys_dev_block_found = 0;
} else {
_sys_dev_block_found = 1;
}
}
}
struct dev_filter *sysfs_filter_create(void)
{
const char *sysfs_dir = dm_sysfs_dir();
char sys_block[PATH_MAX];
unsigned sysfs_depth;
struct dm_pool *mem;
struct dev_set *ds;
struct dev_filter *f;
if (!*sysfs_dir) {
@@ -306,26 +92,15 @@ struct dev_filter *sysfs_filter_create(void)
return NULL;
}
if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth))
return NULL;
/* support old kernels that don't have this */
_check_sys_dev_block();
if (!(mem = dm_pool_create("sysfs", 256))) {
log_error("sysfs pool creation failed");
return NULL;
}
if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) {
log_error("sysfs dev_set creation failed");
goto bad;
}
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
if (!(f = zalloc(sizeof(*f))))
goto_bad;
f->passes_filter = _accept_p;
f->destroy = _destroy;
f->use_count = 0;
f->private = ds;
f->name = "sysfs";
log_debug_devs("Sysfs filter initialised.");
@@ -333,7 +108,6 @@ struct dev_filter *sysfs_filter_create(void)
return f;
bad:
dm_pool_destroy(mem);
return NULL;
}

View File

@@ -219,7 +219,7 @@ static void _remove_expired(const char *dir, const char *vgname,
sum /= 1024 * 1024;
if (sum > 128 || archives_size > 8192)
log_print_unless_silent("Consider prunning %s VG archive with more then %u MiB in %u files (check archiving is needed in lvm.conf).",
log_print_unless_silent("Consider pruning %s VG archive with more then %u MiB in %u files (check archiving is needed in lvm.conf).",
vgname, (unsigned)sum, archives_size);
}

View File

@@ -365,7 +365,6 @@ static void _unlock_hints(struct cmd_context *cmd)
void hints_exit(struct cmd_context *cmd)
{
free_hints(&cmd->hints);
if (_hints_fd == -1)
return;
_unlock_hints(cmd);
@@ -1391,6 +1390,16 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
log_debug("get_hints: needs refresh");
free_hints(&hints_list);
/*
* This is not related to hints, and is probably unnecessary,
* but it could possibly help. When hints become invalid it's
* usually becaues devs on the system have changed, and that
* also means that a missing devices file entry might be found
* by searching devices again. (the searched_devnames
* mechanism should eventually be replaced)
*/
unlink_searched_devnames(cmd);
if (!_lock_hints(cmd, LOCK_EX, NONBLOCK))
return 0;

View File

@@ -891,7 +891,7 @@ static int _setup_bcache(void)
#define BASE_FD_COUNT 32 /* Number of open files we want apart from devs */
static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
{
#ifdef HAVE_PRLIMIT
struct rlimit old = { 0 }, new;
@@ -1165,7 +1165,7 @@ int label_scan(struct cmd_context *cmd)
* which we want to keep open) is higher than the current
* soft limit.
*/
_prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
/*
* Do the main scan.
@@ -1207,8 +1207,6 @@ int label_scan(struct cmd_context *cmd)
(unsigned long long)want_size_kb);
}
dm_list_init(&cmd->hints);
/*
* If we're using hints to limit which devs we scanned, verify
* that those hints were valid, and if not we need to scan the
@@ -1220,18 +1218,16 @@ int label_scan(struct cmd_context *cmd)
_scan_list(cmd, cmd->filter, &all_devs, 0, NULL);
/* scan_devs are the devs that have been scanned */
dm_list_splice(&scan_devs, &all_devs);
free_hints(&hints_list);
using_hints = 0;
create_hints = 0;
/* invalid hints means a new dev probably appeared and
we should search for any missing pvids again. */
unlink_searched_devnames(cmd);
} else {
/* The hints may be used by another device iteration. */
dm_list_splice(&cmd->hints, &hints_list);
}
}
free_hints(&hints_list);
/*
* Check if the devices_file content is up to date and
* if not update it.

View File

@@ -134,4 +134,6 @@ void dev_invalidate(struct device *dev);
void dev_set_last_byte(struct device *dev, uint64_t offset);
void dev_unset_last_byte(struct device *dev);
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs);
#endif

View File

@@ -892,6 +892,7 @@ uint32_t log_journal_str_to_val(const char *str)
return LOG_JOURNAL_OUTPUT;
if (!strcasecmp(str, "debug"))
return LOG_JOURNAL_DEBUG;
log_warn("Ignoring unrecognized journal value.");
return 0;
}

View File

@@ -33,7 +33,7 @@ CMIRRORDMAN = cmirrord.8
LVMDBUSDMAN = lvmdbusd.8
MAN5=lvm.conf.5
MAN7=lvmsystemid.7 lvmreport.7 lvmraid.7
MAN7=lvmsystemid.7 lvmreport.7 lvmraid.7 lvmautoactivation.7
MAN8=lvm.8 lvmdump.8 lvm-fullreport.8 lvm-lvpoll.8 \
lvcreate.8 lvchange.8 lvmconfig.8 lvconvert.8 lvdisplay.8 \

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

@@ -579,6 +579,7 @@ Prepends source file name and code line number with libdm debugging.
.BR lvmraid (7),
.BR lvmthin (7),
.BR lvmcache (7),
.BR lvmautoactivation (7),
.P
.BR dmsetup (8),
.BR dmstats (8),

View File

@@ -0,0 +1,314 @@
.TH "LVMAUTOACTIVATION" "7" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
.
.SH NAME
.
lvmautoactivation \(em LVM autoactivation
.
.SH DESCRIPTION
.
Autoactivation is the activation of LVs performed automatically by the
system in response to LVM devices being attached to the machine. When all
PVs in a VG have been attached, the VG is complete, and LVs in the VG are
activated.
.P
Autoactivation of VGs, or specific LVs, can be prevented using vgchange or
lvchange --setautoactivation n. The lvm.conf auto_activation_volume_list
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.
.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
kernel to notify userspace of the new device. systemd-udev runs udev
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
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:
.P
.B 69-dm-lvm-metad.rules
.
.IP \[bu] 2
device /dev/name with major:minor X:Y is attached to the machine
.
.IP \[bu] 2
systemd/udev runs blkid to identify /dev/name as an LVM PV
.
.IP \[bu] 2
udev rule 69-dm-lvm-metad.rules is run for /dev/name
.
.IP \[bu] 2
the lvm udev rule runs the systemd service lvm2-pvscan@X:Yservice
.
.IP \[bu] 2
the lvm2-pvscan service runs:
.br
pvscan --cache -aay --major X --minor Y
.
.IP \[bu] 2
pvscan reads the device, records that the PV is online
(see pvs_online), and checks if the VG is complete.
.
.IP \[bu] 2
if the VG is complete, pvscan creates the vgs_online temp file,
and activates the VG.
.
.IP \[bu] 2
the activation command output can be seen from
systemctl status lvm2-pvscan*
.P
.B 69-dm-lvm.rules
.
.IP \[bu] 2
device /dev/name with major:minor X:Y is attached to the machine
.
.IP \[bu] 2
systemd/udev runs blkid to identify /dev/name as an LVM PV
.
.IP \[bu] 2
udev rule 69-dm-lvm.rules is run for /dev/name
.
.IP \[bu] 2
the lvm udev rule runs:
.br
pvscan --cache --listvg --checkcomplete --vgonline
.br
--autoactivation event --udevoutput --journal=output /dev/name
.
.IP \[bu] 2
pvscan reads the device, records that the PV is online
(see pvs_online), and checks if the VG is complete.
.
.IP \[bu] 2
if the VG is complete, pvscan creates the vgs_online temp file,
and prints the name of the VG for the udev rule to import:
LVM_VG_NAME_COMPLETE='vgname'
.
.IP \[bu] 2
if the lvm udev rule sees LVM_VG_NAME_COMPLETE from pvscan,
it activates the VG using a transient systemd service named
lvm-activate-<vgname>.
.
.IP \[bu] 2
the lvm-activate-<vgname> service runs
.br
vgchange -aay --autoactivation event <vgname>
.
.IP \[bu] 2
the activation command output can be seen from
journalctl -u lvm-activate-<vgname>
.P
.
.SS pvscan options
.P
.B --cache
.br
Read the <device> arg (and only that device), and record that
the PV is online by creating the /run/lvm/pvs_online/<pvid>
file containing the name of the VG and the device for the PV.
.P
.B -aay
.br
Activate the VG from the pvscan command
(includes implicit --checkcomplete and --vgonline.)
.P
.B --checkcomplete
.br
Check if the VG is complete, i.e. all PVs are present on
the system, by checking /run/lvm/pvs_online/<pvid> files.
.P
.B --vgonline
.br
Create /run/lvm/vgs_online/<vgname> if the VG is complete
(used to ensure only one command performs activation.)
.P
.B --autoactivation event
.br
Inform the command it is used for event based autoactivation.
.P
.B --listvg
.br
Print the name of the VG using the device.
.P
.B --udevoutput
.br
Only print output that can be imported to the udev rule,
using the udev environment key format, i.e. NAME='value'.
.P
.B --journal=output
.br
Send standard command output to the journal (when stdout
is reserved for udev output.)
.P
.SS run files
.P
Autoactivation commands use a number of temp files in /run/lvm (with the
expectation that /run is cleared between boots.)
.P
.B pvs_online
.br
pvscan --cache creates a file here for each PV that is attached. The file
is named with the PVID and contains the VG name and device information.
The existence of the file is used to determine when all PVs for a given VG
are present. The device information in these files is also used to
optimize locating devices for a VG when the VG is activated.
.P
.B pvs_lookup
.br
pvscan --cache creates a file here named for a VG (if one doesn't already
exist.) The file contains a list of PVIDs in the VG. This is needed when
a PV is processed which has no VG metadata, in which case the list of
PVIDs from the lookup file is used to check if the VG is complete.
.P
.B vgs_online
.br
The first activation command (pvscan or vgchange) to create a file here,
named for the VG, will activate the VG. This resolves a race when
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.
.
.SH EXAMPLES
.P
VG "vg" contains two PVs:
.nf
$ pvs -o name,vgname,uuid /dev/sdb /dev/sdc
PV VG PV UUID
/dev/sdb vg 1uKpaT-lFOZ-NLHX-j4jI-OBi1-QpdE-HZ5hZY
/dev/sdc vg 5J3tM8-aIPe-2vbd-DBe7-bvRq-TGj0-DaKV2G
.fi
.P
use of --cache:
.nf
$ pvscan --cache /dev/sdb
pvscan[12922] PV /dev/sdb online.
$ pvscan --cache /dev/sdc
pvscan[12923] PV /dev/sdc online.
$ cat /run/lvm/pvs_online/1uKpaTlFOZNLHXj4jIOBi1QpdEHZ5hZY
8:16
vg:vg
dev:/dev/sdb
$ cat /run/lvm/pvs_online/5J3tM8aIPe2vbdDBe7bvRqTGj0DaKV2G
8:32
vg:vg
dev:/dev/sdc
.fi
.P
use of -aay:
.nf
$ pvscan --cache -aay /dev/sdb
pvscan[12935] PV /dev/sdb online, VG vg incomplete (need 1).
$ pvscan --cache -aay /dev/sdc
pvscan[12936] PV /dev/sdc online, VG vg is complete.
pvscan[12936] VG vg run autoactivation.
1 logical volume(s) in volume group "vg" now active
$ cat /run/lvm/pvs_online/1uKpaTlFOZNLHXj4jIOBi1QpdEHZ5hZY
8:16
vg:vg
dev:/dev/sdb
$ cat /run/lvm/pvs_online/5J3tM8aIPe2vbdDBe7bvRqTGj0DaKV2G
8:32
vg:vg
dev:/dev/sdc
$ ls /run/lvm/vgs_online/vg
/run/lvm/vgs_online/vg
.fi
.P
use of --listvg:
.nf
$ pvscan --cache --listvg /dev/sdb
VG vg
$ pvscan --cache --listvg /dev/sdc
VG vg
$ cat /run/lvm/pvs_online/1uKpaTlFOZNLHXj4jIOBi1QpdEHZ5hZY
8:16
vg:vg
dev:/dev/sdb
$ cat /run/lvm/pvs_online/5J3tM8aIPe2vbdDBe7bvRqTGj0DaKV2G
8:32
vg:vg
dev:/dev/sdc
.fi
.P
use of --checkcomplete:
.nf
$ pvscan --cache --listvg --checkcomplete --vgonline /dev/sdb
pvscan[12996] PV /dev/sdb online, VG vg incomplete (need 1).
VG vg incomplete
$ pvscan --cache --listvg --checkcomplete --vgonline /dev/sdc
pvscan[12997] PV /dev/sdc online, VG vg is complete.
VG vg complete
.fi
.P
use of --udevoutput:
.nf
$ pvscan --cache --listvg --checkcomplete --vgonline --udevoutput /dev/sdb
LVM_VG_NAME_INCOMPLETE='vg'
$ pvscan --cache --listvg --checkcomplete --vgonline --udevoutput /dev/sdc
LVM_VG_NAME_COMPLETE='vg'
.fi
.P
use of --listlvs:
.nf
$ lvs -o name,devices vg
LV Devices
lvol0 /dev/sdb(0)
lvol1 /dev/sdc(0)
lvol2 /dev/sdb(1),/dev/sdc(1)
$ pvscan --cache --listlvs --checkcomplete /dev/sdb
pvscan[13288] PV /dev/sdb online, VG vg incomplete (need 1).
VG vg incomplete
LV vg/lvol0 complete
LV vg/lvol2 incomplete
$ pvscan --cache --listlvs --checkcomplete /dev/sdc
pvscan[13289] PV /dev/sdc online, VG vg is complete.
VG vg complete
LV vg/lvol1 complete
LV vg/lvol2 complete
.fi

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

@@ -4,56 +4,47 @@ 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.

View File

@@ -91,59 +91,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
.

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

@@ -92,6 +92,7 @@ install_systemd_generators:
install_systemd_units: install_dbus_service
@echo " [INSTALL] systemd_units"
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
$(Q) $(INSTALL_DATA) lvm2-pvscan.service $(systemd_unit_dir)/lvm2-pvscan@.service
ifeq ("@BUILD_DMEVENTD@", "yes")
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service

View File

@@ -88,6 +88,7 @@ fi
%{_sbindir}/lvmpolld
%endif
%{_mandir}/man5/lvm.conf.5.gz
%{_mandir}/man7/lvmautoactivation.7.gz
%{_mandir}/man7/lvmsystemid.7.gz
%{_mandir}/man7/lvmreport.7.gz
%{_mandir}/man7/lvmraid.7.gz
@@ -163,7 +164,7 @@ fi
%endif
%if %{enable_udev}
%{_udevdir}/11-dm-lvm.rules
%{_udevdir}/69-dm-lvm.rules
%{_udevdir}/69-dm-lvm-metad.rules
%endif
%dir %{_sysconfdir}/lvm
%ghost %{_sysconfdir}/lvm/cache/.cache
@@ -189,6 +190,7 @@ fi
%{_tmpfilesdir}/%{name}.conf
%{_unitdir}/blk-availability.service
%{_unitdir}/lvm2-monitor.service
%{_unitdir}/lvm2-pvscan@.service
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
%if %{have_service lvmpolld}
%{_unitdir}/lvm2-lvmpolld.service

View File

@@ -283,7 +283,7 @@ not ls "$RUNDIR/lvm/pvs_online/$PVID3"
# arg in devices list
_clear_online_files
pvscan --devices "$dev3" --cache -aay "$dev3"
pvscan --devices "$dev4","$dev3" --cache -aay "$dev4"
pvscan --devices "$dev4" --cache -aay "$dev4"
check lv_field $vg2/$lv2 lv_active "active"
vgchange -an $vg2

View File

@@ -545,4 +545,73 @@ grep "$PVID2" "$DF" |tee out
grep "$dev2" out
not grep "$dev1" out
vgchange -an $vg1
vgchange -an $vg2
vgremove -ff $vg1
vgremove -ff $vg2
# devnames change so the new devname now refers to a filtered device,
# e.g. an mpath or md component, which is not scanned
wait_md_create() {
local md=$1
while :; do
if ! grep "$(basename $md)" /proc/mdstat; then
echo "$md not ready"
cat /proc/mdstat
sleep 2
else
break
fi
done
echo "$md" > WAIT_MD_DEV
}
aux wipefs_a "$dev1"
aux wipefs_a "$dev2"
aux wipefs_a "$dev3"
aux wipefs_a "$dev4"
mddev="/dev/md33"
not grep $mddev /proc/mdstat || skip
rm "$DF"
touch "$DF"
vgcreate $vg1 "$dev1" "$dev2"
cat "$DF"
cp "$DF" "$ORIG"
# PVID with dashes for matching pvs -o+uuid output
OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
# PVID without dashes for matching devices file fields
PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
mdadm --create --metadata=1.0 "$mddev" --level 1 --raid-devices=2 "$dev3" "$dev4"
wait_md_create "$mddev"
sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > tmp1.devices
sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" tmp1.devices > "$DF"
cat "$DF"
pvs -o+uuid |tee out
grep "$dev1" out
grep "$dev2" out
grep "$OPVID1" out
grep "$OPVID2" out
not grep "$dev3" out
not grep "$dev4" out
grep "$dev1" "$DF"
grep "$dev2" "$DF"
grep "$PVID1" "$DF"
grep "$PVID2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
mdadm --stop "$mddev"
aux udev_wait
vgremove -ff $vg1

View File

@@ -57,9 +57,11 @@ dd if="$dev1" of=dev1_backup bs=1M
# pvcreate and pvremove can be forced even if the PV is marked as used
pvremove -ff -y "$dev1"
lvmdevices --deldev "$dev1" || true
dd if=dev1_backup of="$dev1" bs=1M
pvcreate -ff -y "$dev1"
dd if=dev1_backup of="$dev1" bs=1M
lvmdevices --adddev "$dev1" || true
# prepare a VG with $dev1 and $dev both having 1 MDA
aux enable_dev "$dev2"
@@ -116,9 +118,11 @@ dd if="$dev1" of=dev1_backup bs=1M
# pvcreate and pvremove can be forced even if the PV is marked as used
pvremove -ff -y "$dev1"
lvmdevices --deldev "$dev1" || true
dd if=dev1_backup of="$dev1" bs=1M
pvcreate -ff -y "$dev1"
dd if=dev1_backup of="$dev1" bs=1M
lvmdevices --adddev "$dev1" || true
# prepare a VG with $dev1 and $dev both having 1 MDA
aux enable_dev "$dev2"

View File

@@ -1,403 +0,0 @@
#!/usr/bin/env bash
# Copyright (C) 2021 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='udev rule and systemd unit run vgchange'
SKIP_WITH_LVMPOLLD=1
SKIP_WITH_LVMLOCKD=1
. lib/inittest
#
# $ cat /tmp/devs
# /dev/sdb
# /dev/sdc
# /dev/sdd
#
# Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs
# when running the test.
#
# This test will wipe these devices.
#
if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then echo "LVM_TEST_DEVICE_LIST is unset" && skip; else echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"; fi
test -e "$LVM_TEST_DEVICE_LIST" || skip
num_devs=$(cat $LVM_TEST_DEVICE_LIST | wc -l)
RUNDIR="/run"
test -d "$RUNDIR" || RUNDIR="/var/run"
PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
_clear_online_files() {
# wait till udev is finished
aux udev_wait
rm -f "$PVS_ONLINE_DIR"/*
rm -f "$VGS_ONLINE_DIR"/*
rm -f "$PVS_LOOKUP_DIR"/*
}
test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
_clear_online_files
aux prepare_real_devs
aux lvmconf 'devices/dir = "/dev"'
aux lvmconf 'devices/use_devicesfile = 1'
DFDIR="$LVM_SYSTEM_DIR/devices"
DF="$DFDIR/system.devices"
mkdir $DFDIR || true
not ls $DF
get_real_devs
wipe_all() {
for dev in "${REAL_DEVICES[@]}"; do
wipefs -a $dev
done
}
# udevadm trigger runs udev rule which runs systemd-run --no-wait vgchange -aay
# Because of --no-wait, we need to wait for the transient systemd
# service to be gone before checking the effects of the vgchange.
wait_lvm_activate() {
local vgw=$1
local wait=0
while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
sleep .2
wait=$(( wait + 1 ))
done
}
# Test requires 3 devs
test $num_devs -gt 2 || skip
BDEV1=$(basename "$dev1")
BDEV2=$(basename "$dev2")
BDEV3=$(basename "$dev3")
wipe_all
touch $DF
for dev in "${REAL_DEVICES[@]}"; do
pvcreate $dev
done
# 1 dev, 1 vg, 1 lv
vgcreate $vg1 "$dev1"
lvcreate -l1 -an -n $lv1 $vg1 "$dev1"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEV1
wait_lvm_activate $vg1
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/vgs_online/$vg1"
journalctl -u lvm-activate-$vg1 | tee out || true
grep "now active" out
check lv_field $vg1/$lv1 lv_active "active"
vgchange -an $vg1
vgremove -y $vg1
# 2 devs, 1 vg, 2 lvs
vgcreate $vg2 "$dev1" "$dev2"
lvcreate -l1 -an -n $lv1 $vg2 "$dev1"
lvcreate -l1 -an -n $lv2 $vg2 "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEV1
ls "$RUNDIR/lvm/pvs_online/$PVID1"
not ls "$RUNDIR/lvm/vgs_online/$vg2"
journalctl -u lvm-activate-$vg2 | tee out || true
not grep "now active" out
check lv_field $vg2/$lv1 lv_active ""
check lv_field $vg2/$lv2 lv_active ""
udevadm trigger --settle -c add /sys/block/$BDEV2
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/vgs_online/$vg2"
wait_lvm_activate $vg2
journalctl -u lvm-activate-$vg2 | tee out || true
grep "now active" out
check lv_field $vg2/$lv1 lv_active "active"
check lv_field $vg2/$lv2 lv_active "active"
vgchange -an $vg2
vgremove -y $vg2
# 3 devs, 1 vg, 4 lvs, concurrent pvscans
# (attempting to have the pvscans run concurrently and race
# to activate the VG)
vgcreate $vg3 "$dev1" "$dev2" "$dev3"
lvcreate -l1 -an -n $lv1 $vg3 "$dev1"
lvcreate -l1 -an -n $lv2 $vg3 "$dev2"
lvcreate -l1 -an -n $lv3 $vg3 "$dev3"
lvcreate -l8 -an -n $lv4 -i 2 $vg3 "$dev1" "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg3
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg3"
journalctl -u lvm-activate-$vg3 | tee out || true
grep "now active" out
check lv_field $vg3/$lv1 lv_active "active"
check lv_field $vg3/$lv2 lv_active "active"
check lv_field $vg3/$lv3 lv_active "active"
check lv_field $vg3/$lv4 lv_active "active"
vgchange -an $vg3
vgremove -y $vg3
# 3 devs, 1 vg, 4 lvs, concurrent pvscans, metadata on only 1 PV
wipe_all
rm $DF
touch $DF
pvcreate --metadatacopies 0 "$dev1"
pvcreate --metadatacopies 0 "$dev2"
pvcreate "$dev3"
vgcreate $vg4 "$dev1" "$dev2" "$dev3"
lvcreate -l1 -an -n $lv1 $vg4 "$dev1"
lvcreate -l1 -an -n $lv2 $vg4 "$dev2"
lvcreate -l1 -an -n $lv3 $vg4 "$dev3"
lvcreate -l8 -an -n $lv4 -i 2 $vg4 "$dev1" "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg4
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg4"
journalctl -u lvm-activate-$vg4 | tee out || true
grep "now active" out
check lv_field $vg4/$lv1 lv_active "active"
check lv_field $vg4/$lv2 lv_active "active"
check lv_field $vg4/$lv3 lv_active "active"
check lv_field $vg4/$lv4 lv_active "active"
vgchange -an $vg4
vgremove -y $vg4
# 3 devs, 3 vgs, 2 lvs in each vg, concurrent pvscans
wipe_all
rm $DF
touch $DF
vgcreate $vg5 "$dev1"
vgcreate $vg6 "$dev2"
vgcreate $vg7 "$dev3"
lvcreate -l1 -an -n $lv1 $vg5
lvcreate -l1 -an -n $lv2 $vg5
lvcreate -l1 -an -n $lv1 $vg6
lvcreate -l1 -an -n $lv2 $vg6
lvcreate -l1 -an -n $lv1 $vg7
lvcreate -l1 -an -n $lv2 $vg7
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg5
wait_lvm_activate $vg6
wait_lvm_activate $vg7
ls "$RUNDIR/lvm/vgs_online/$vg5"
ls "$RUNDIR/lvm/vgs_online/$vg6"
ls "$RUNDIR/lvm/vgs_online/$vg7"
journalctl -u lvm-activate-$vg5 | tee out || true
grep "now active" out
journalctl -u lvm-activate-$vg6 | tee out || true
grep "now active" out
journalctl -u lvm-activate-$vg7 | tee out || true
grep "now active" out
check lv_field $vg5/$lv1 lv_active "active"
check lv_field $vg5/$lv2 lv_active "active"
check lv_field $vg6/$lv1 lv_active "active"
check lv_field $vg6/$lv2 lv_active "active"
check lv_field $vg7/$lv1 lv_active "active"
check lv_field $vg7/$lv2 lv_active "active"
vgchange -an $vg5
vgremove -y $vg5
vgchange -an $vg6
vgremove -y $vg6
vgchange -an $vg7
vgremove -y $vg7
# 3 devs, 1 vg, 1000 LVs
wipe_all
rm $DF
touch $DF
pvcreate --metadatacopies 0 "$dev1"
pvcreate "$dev2"
pvcreate "$dev3"
vgcreate -s 128K $vg8 "$dev1" "$dev2" "$dev3"
# Number of LVs to create
TEST_DEVS=1000
# On low-memory boxes let's not stress too much
test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256
vgcfgbackup -f data $vg8
# Generate a lot of devices (size of 1 extent)
awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
printf("\t}\n\tlogical_volumes {\n");
cnt=0;
for (i = 0; i < TEST_DEVS; i++) {
printf("\t\tlvol%06d {\n", i);
printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
print "\t\t\tsegment_count = 1";
print "\t\t\tsegment1 {";
print "\t\t\t\tstart_extent = 0";
print "\t\t\t\textent_count = 1";
print "\t\t\t\ttype = \"striped\"";
print "\t\t\t\tstripe_count = 1";
print "\t\t\t\tstripes = [";
print "\t\t\t\t\t\"pv0\", " cnt++;
printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
}
}
{print}
' data >data_new
vgcfgrestore -f data_new $vg8
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg8
ls "$RUNDIR/lvm/vgs_online/$vg8"
journalctl -u lvm-activate-$vg8 | tee out || true
grep "now active" out
num_active=$(lvs $vg8 --noheading -o active | grep active | wc -l)
test $num_active -eq $TEST_DEVS
vgchange -an $vg8
vgremove -y $vg8
# 1 pv on an md dev, 1 vg
wait_md_create() {
local md=$1
while :; do
if ! grep "$(basename $md)" /proc/mdstat; then
echo "$md not ready"
cat /proc/mdstat
sleep 2
else
break
fi
done
echo "$md" > WAIT_MD_DEV
}
test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \
modprobe raid1 || skip
mddev="/dev/md33"
not grep $mddev /proc/mdstat || skip
wipe_all
rm $DF
touch $DF
mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
wait_md_create "$mddev"
vgcreate $vg9 "$mddev"
PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
BDEVMD=$(basename "$mddev")
lvcreate -l1 -an -n $lv1 $vg9
lvcreate -l1 -an -n $lv2 $vg9
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEVMD
wait_lvm_activate $vg9
ls "$RUNDIR/lvm/vgs_online/$vg9"
journalctl -u lvm-activate-$vg9 | tee out || true
grep "now active" out
check lv_field $vg9/$lv1 lv_active "active"
check lv_field $vg9/$lv2 lv_active "active"
vgchange -an $vg9
vgremove -y $vg9
mdadm --stop "$mddev"
aux udev_wait
wipe_all

View File

@@ -1359,10 +1359,10 @@ OO: --aligned, --all, --binary, --colon, --columns,
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
--logonly, --maps, --noheadings,
--nosuffix, --options String, --sort String, --readonly,
--reportformat ReportFmt, --segments, --select String, --separator String,
--segments, --select String, --separator String,
--shared, --unbuffered, --units Units
OP: VG|LV|Tag ...
IO: --partial, --ignoreskippedcluster
IO: --partial, --ignoreskippedcluster, --reportformat ReportFmt
ID: lvdisplay_general
---
@@ -1590,10 +1590,10 @@ pvdisplay
OO: --aligned, --all, --binary, --colon, --columns, --configreport ConfigReport,
--foreign, --ignorelockingfailure,
--logonly, --maps, --noheadings, --nosuffix, --options String,
--readonly, --reportformat ReportFmt, --select String, --separator String, --shared,
--readonly, --select String, --separator String, --shared,
--short, --sort String, --unbuffered, --units Units
OP: PV|Tag ...
IO: --ignoreskippedcluster
IO: --ignoreskippedcluster, --reportformat ReportFmt
ID: pvdisplay_general
---
@@ -1809,10 +1809,10 @@ vgdisplay
OO: --activevolumegroups, --aligned, --binary, --colon, --columns,
--configreport ConfigReport, --foreign, --ignorelockingfailure,
--logonly, --noheadings, --nosuffix,
--options String, --readonly, --reportformat ReportFmt, --select String,
--options String, --readonly, --select String,
--shared, --short, --separator String, --sort String, --unbuffered, --units Units
OP: VG|Tag ...
IO: --partial, --ignoreskippedcluster
IO: --partial, --ignoreskippedcluster, --reportformat ReportFmt
ID: vgdisplay_general
---

View File

@@ -824,12 +824,16 @@ static int _lvcreate_params(struct cmd_context *cmd,
autobackup_ARG,\
available_ARG,\
contiguous_ARG,\
devices_ARG,\
devicesfile_ARG,\
ignoreactivationskip_ARG,\
ignoremonitoring_ARG,\
journal_ARG,\
metadataprofile_ARG,\
monitor_ARG,\
mirrors_ARG,\
name_ARG,\
nohints_ARG,\
noudevsync_ARG,\
permission_ARG,\
persistent_ARG,\

View File

@@ -3058,6 +3058,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
int i;
int skip_hyphens;
int refresh_done = 0;
int io;
/* Avoid excessive access to /etc/localtime and set TZ variable for glibc
* so it does not need to check /etc/localtime everytime that needs that info */
@@ -3140,6 +3141,20 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
return EINVALID_CMD_LINE;
/*
* If option --foo is set which is listed in IO (ignore option) in
* command-lines.in, then unset foo. Commands won't usually use an
* ignored option, but there can be shared code that checks for --foo,
* and should not find it to be set.
*/
for (io = 0; io < cmd->command->io_count; io++) {
int opt = cmd->command->ignore_opt_args[io].opt;
if (arg_is_set(cmd, opt)) {
log_debug("Ignore opt %d", opt);
cmd->opt_arg_values[opt].count = 0;
}
}
/*
* Remaining position args after command name and --options are removed.
*/

View File

@@ -176,6 +176,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
log_error("Failed to read the devices file.");
return ECMD_FAILED;
}
prepare_open_file_limit(cmd, dm_list_size(&cmd->use_devices));
dev_cache_scan(cmd);
device_ids_match(cmd);

View File

@@ -857,21 +857,11 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
devno = MKDEV(file_major, file_minor);
if (!setup_devno_in_dev_cache(cmd, devno)) {
log_error_pvscan(cmd, "No device set up for %d:%d PVID %s", file_major, file_minor, pvid);
goto bad;
}
if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
log_error_pvscan(cmd, "No device found for %d:%d PVID %s", file_major, file_minor, pvid);
goto bad;
}
/*
* Do not need to match device_id here, see comment after
* get_devs_from_saved_vg about relying on pvid online file.
*/
name1 = dev_name(dev);
name2 = pvl->pv->device_hint;
@@ -1109,11 +1099,17 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
* PROCESS_SKIP_SCAN: we have already done lvmcache_label_scan
* so tell process_each to skip it.
*/
if (do_all)
read_flags |= PROCESS_SKIP_SCAN;
/*
* When the command is processing specific devs (not all), it
* has done setup_devices_no_file_match() to avoid matching ids
* fo all devs unnecessarily, but now that we're falling back
* to process_each_vg() we need to complete the id matching.
*/
if (!do_all)
lvmcache_label_scan(cmd);
read_flags |= PROCESS_SKIP_SCAN;
device_ids_match(cmd);
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, read_flags, 0, handle, _pvscan_aa_single);
}
@@ -1196,15 +1192,11 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args,
/* in common usage, no dev will be found for a devno */
dm_list_iterate_items(arg, pvscan_args) {
if (arg->devname) {
if (!setup_devname_in_dev_cache(cmd, arg->devname))
log_error_pvscan(cmd, "No device set up for name arg %s", arg->devname);
if (arg->devname)
arg->dev = dev_cache_get(cmd, arg->devname, NULL);
} else if (arg->devno) {
if (!setup_devno_in_dev_cache(cmd, arg->devno))
log_error_pvscan(cmd, "No device set up for devno arg %d", (int)arg->devno);
else if (arg->devno)
arg->dev = dev_cache_get_by_devt(cmd, arg->devno, NULL, NULL);
} else
else
return_0;
}
@@ -1362,7 +1354,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
devsize = dev->size;
if (!devsize &&
!dev_get_size(dev, &devsize)) {
log_print("pvscan[%d] PV %s can get device size.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s missing device size.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1680,13 +1672,11 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
cmd->pvscan_cache_single = 1;
/*
* Special pvscan-specific setup steps to avoid looking
* at any devices except for device args.
* Read devices file and determine if devices file will be used.
* Does not do dev_cache_scan (adds nothing to dev-cache), and
* does not do any device id matching.
* "no_file_match" means that when the devices file is used,
* setup_devices will skip matching devs to devices file entries.
* Specific devs must be matched later with device_ids_match_dev().
*/
if (!setup_devices_for_pvscan_cache(cmd)) {
if (!setup_devices_no_file_match(cmd)) {
log_error_pvscan(cmd, "Failed to set up devices.");
return 0;
}
@@ -1745,21 +1735,17 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
log_debug("pvscan_cache_args: filter devs nodata");
/*
* Match dev args with the devices file because special/optimized
* device setup was used above which does not check the devices file.
* If a match fails here do not exclude it, that will be done below by
* passes_filter() which runs filter-deviceid. The
* relax_deviceid_filter case needs to be able to work around
* Match dev args with the devices file because
* setup_devices_no_file_match() was used above which skipped checking
* the devices file. If a match fails here do not exclude it, that
* will be done below by passes_filter() which runs filter-deviceid.
* The relax_deviceid_filter case needs to be able to work around
* unmatching devs.
*/
if (cmd->enable_devices_file) {
dm_list_iterate_items(devl, &pvscan_devs)
dm_list_iterate_items_safe(devl, devl2, &pvscan_devs)
device_ids_match_dev(cmd, devl->dev);
}
if (cmd->enable_devices_list)
device_ids_match_device_list(cmd);
if (cmd->enable_devices_file && device_ids_use_devname(cmd)) {
relax_deviceid_filter = 1;
@@ -1800,7 +1786,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
int has_pvid;
if (!label_read_pvid(devl->dev, &has_pvid)) {
log_print("pvscan[%d] %s cannot read.", getpid(), dev_name(devl->dev));
log_print_pvscan(cmd, "%s cannot read label.", dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}

View File

@@ -172,6 +172,17 @@ int vgimportdevices(struct cmd_context *cmd, int argc, char **argv)
cmd->filter_regex_with_devices_file = 1;
cmd->create_edit_devices_file = 1;
/*
* This helps a user bootstrap existing shared VGs into the devices
* file. Reading the vg to import devices requires locking, but
* lockstart won't find the vg before it's in the devices file.
* So, allow importing devices without an lvmlockd lock (in a
* a shared vg the vg metadata won't be updated with device ids,
* so the lvmlockd lock isn't protecting vg modification.)
*/
cmd->lockd_gl_disable = 1;
cmd->lockd_vg_disable = 1;
/*
* For each VG:
* device_id_add() each PV in the VG

View File

@@ -1,87 +0,0 @@
# Copyright (C) 2012,2021 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM.
#
# This rule requires blkid to be called on block devices before so only devices
# used as LVM PVs are processed (ID_FS_TYPE="LVM2_member").
SUBSYSTEM!="block", GOTO="lvm_end"
(LVM_EXEC_RULE)
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="lvm_end"
# Only process devices already marked as a PV - this requires blkid to be called before.
ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
ACTION=="remove", GOTO="lvm_end"
# Create /dev/disk/by-id/lvm-pv-uuid-<PV_UUID> symlink for each PV
ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-id/lvm-pv-uuid-$env{ID_FS_UUID_ENC}"
# If the PV is a special device listed below, scan only if the device is
# properly activated. These devices are not usable after an ADD event,
# but they require an extra setup and they are ready after a CHANGE event.
# Also support coldplugging with ADD event but only if the device is already
# properly activated.
# This logic should be eventually moved to rules where those particular
# devices are processed primarily (MD and loop).
# DM device:
KERNEL!="dm-[0-9]*", GOTO="next"
ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}=="1", GOTO="lvm_scan"
GOTO="lvm_end"
# MD device:
LABEL="next"
KERNEL!="md[0-9]*", GOTO="next"
IMPORT{db}="LVM_MD_PV_ACTIVATED"
ACTION=="add", ENV{LVM_MD_PV_ACTIVATED}=="1", GOTO="lvm_scan"
ACTION=="change", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1", GOTO="lvm_scan"
ACTION=="add", KERNEL=="md[0-9]*p[0-9]*", GOTO="lvm_scan"
ENV{LVM_MD_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
GOTO="lvm_end"
# Loop device:
LABEL="next"
KERNEL!="loop[0-9]*", GOTO="next"
ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan"
ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan"
ENV{LVM_LOOP_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
GOTO="lvm_end"
LABEL="next"
ACTION!="add", GOTO="lvm_end"
LABEL="lvm_scan"
ENV{SYSTEMD_READY}="1"
# pvscan will check if this device completes a VG,
# i.e. all PVs in the VG are now present with the
# arrival of this PV. If so, it prints to stdout:
# LVM_VG_NAME_COMPLETE='foo'
#
# When the VG is complete it can be activated, so
# vgchange -aay <vgname> is run. It is run via
# systemd since it can take longer to run than
# udev wants to block when processing rules.
# (if there are hundreds of LVs to activate,
# the vgchange can take many seconds.)
#
# pvscan only reads the single device specified,
# and uses temp files under /run/lvm to check if
# other PVs in the VG are present.
#
# If event_activation=0 in lvm.conf, this pvscan
# (using checkcomplete) will do nothing, so that
# no event-based autoactivation will be happen.
#
# TODO: adjust the output of vgchange -aay so that
# it's better suited to appearing in the journal.
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}"
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} lvm vgchange -aay --nohints $env{LVM_VG_NAME_COMPLETE}"
GOTO="lvm_end"
LABEL="lvm_end"

View File

@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
include $(top_builddir)/make.tmpl
DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
LVM_RULES=11-dm-lvm.rules 69-dm-lvm.rules
LVM_RULES=11-dm-lvm.rules 69-dm-lvm-metad.rules
DM_DIR=$(shell $(GREP) "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | $(AWK) '{print $$3}')