main - vgchange: move autoactivation setup code
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=92e741eda060b4712fa...
Commit: 92e741eda060b4712fab5b37e0bee2cc5e155a57
Parent: d608837b2a88d0ed0c7ef7d8e6135e2d37687ff1
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Nov 10 14:44:11 2021 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Nov 10 14:44:11 2021 -0600
vgchange: move autoactivation setup code
into its own function, no functional change.
---
tools/vgchange.c | 159 +++++++++++++++++++++++++++++++++++--------------------
1 file changed, 102 insertions(+), 57 deletions(-)
diff --git a/tools/vgchange.c b/tools/vgchange.c
index acdde97a8..bbb565643 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -735,12 +735,18 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ret;
}
-static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command)
+static int _vgchange_autoactivation_setup(struct cmd_context *cmd,
+ struct vgchange_params *vp,
+ int *skip_command,
+ const char **vgname_ret,
+ uint32_t *flags)
{
const char *aa;
+ char *vgname = NULL;
+ int found_none = 0, found_all = 0, found_incomplete = 0;
if (!(aa = arg_str_value(cmd, autoactivation_ARG, NULL)))
- return 1;
+ return_0;
if (strcmp(aa, "event")) {
log_print("Skip vgchange for unknown autoactivation value.");
@@ -755,9 +761,99 @@ static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params
}
vp->vg_complete_to_activate = 1;
-
cmd->use_hints = 0;
+ get_single_vgname_cmd_arg(cmd, NULL, &vgname);
+
+ /*
+ * Special label scan optimized for autoactivation that is based on
+ * info read from /run/lvm/ files created by pvscan --cache during
+ * autoactivation. Add an option to disable this optimization? e.g.
+ * "online_skip" in --autoactivation / auto_activation_settings
+ *
+ * In some cases it might be useful to strictly follow the online
+ * files, and not fall back to a standard label scan when no pvs or
+ * incomplete pvs are found from the online files. Add option for
+ * that? e.g.
+ * "online_only" in --autoactivation / auto_activation_settings
+ *
+ * Generally the way that vgchange -aay --autoactivation event is
+ * currently used, it will not be called until pvscan --cache has found
+ * the VG is complete, so it will not generally be following the paths
+ * that fall back to standard label_scan.
+ *
+ * TODO: Like pvscan_aa_quick, this could do lock_vol(vgname) before
+ * label_scan_vg_online, then set cmd->can_use_one_scan=1 to avoid
+ * rescanning in _vg_read called by process_each_vg.
+ */
+
+ /*
+ * Perform label_scan on PVs that are online (per /run/lvm files)
+ * for the given VG (or when no VG name is given, all online PVs.)
+ * If this fails, the caller will do a normal process_each_vg without
+ * optimizations (which will do a full label_scan.)
+ */
+ if (!label_scan_vg_online(cmd, vgname, &found_none, &found_all, &found_incomplete)) {
+ log_print("PVs online error%s%s, using all devices.", vgname ? " for VG " : "", vgname ?: "");
+ return 1;
+ }
+
+ /*
+ * Not the expected usage, activate any VGs that are complete based on
+ * pvs_online. Only online pvs are used.
+ */
+ if (!vgname) {
+ *flags |= PROCESS_SKIP_SCAN;
+ return 1;
+ }
+
+ /*
+ * The expected and optimal usage, because the udev rule calls
+ * vgchange -aay --autoactivation event vgname when all PVs
+ * for vgname are found online. Only online pvs are used.
+ */
+ if (found_all) {
+ *flags |= PROCESS_SKIP_SCAN;
+ *vgname_ret = vgname;
+ return 1;
+ }
+
+ /*
+ * Possible option to only activate from only online pvs even if they
+ * are not all found, and not fall back to a full label_scan.
+ */
+ /*
+ if (online_only) {
+ log_print("PVs online %s.", found_none ? "not found" : "incomplete");
+ return vgname ? 0 : 1;
+ }
+ */
+
+ /*
+ * Not expected usage, no online pvs for the vgname were found. The
+ * caller will fall back to process_each doing a full label_scan to
+ * look for the VG. (No optimization used.)
+ */
+ if (found_none) {
+ log_print("PVs online not found for VG %s, using all devices.", vgname);
+ return 1;
+ }
+
+ /*
+ * Not expected usage, only some online pvs for the vgname were found.
+ * The caller will fall back to process_each doing a full label_scan to
+ * look for all PVs in the VG. (No optimization used.)
+ */
+ if (found_incomplete) {
+ log_print("PVs online incomplete for VG %s, using all devicess.", vgname);
+ return 1;
+ }
+
+ /*
+ * Shouldn't happen, the caller will fall back to standard
+ * process_each. (No optimization used.)
+ */
+ log_print("PVs online unknown for VG %s, using all devices.", vgname);
return 1;
}
@@ -765,7 +861,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
{
struct vgchange_params vp = { 0 };
struct processing_handle *handle;
- char *vgname = NULL;
+ const char *vgname = NULL;
uint32_t flags = 0;
int ret;
@@ -879,62 +975,11 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
}
if (arg_is_set(cmd, autoactivation_ARG)) {
- int found_none = 0, found_all = 0, found_incomplete = 0;
int skip_command = 0;
-
- if (!_check_autoactivation(cmd, &vp, &skip_command))
+ if (!_vgchange_autoactivation_setup(cmd, &vp, &skip_command, &vgname, &flags))
return ECMD_FAILED;
if (skip_command)
return ECMD_PROCESSED;
-
- /*
- * Special label scan optimized for autoactivation
- * that is based on info read from /run/lvm/ files
- * created by pvscan --cache during autoactivation.
- * Add an option to disable this optimization? e.g.
- * "online_skip" in --autoactivation / auto_activation_settings
- *
- * In some cases it might be useful to strictly follow
- * the online files, and not fall back to a standard
- * label scan when no pvs or incomplete pvs are found
- * from the online files. Add option for that? e.g.
- * "online_only" in --autoactivation / auto_activation_settings
- *
- * Generally the way that vgchange -aay --autoactivation event
- * is currently used, it will not be called until pvscan --cache
- * has found the VG is complete, so it will not generally be
- * following the paths that fall back to standard label_scan.
- *
- * TODO: Like pvscan_aa_quick, this could do lock_vol(vgname)
- * before label_scan_vg_online, then set cmd->can_use_one_scan=1
- * to avoid rescanning in _vg_read called by process_each_vg.
- */
- get_single_vgname_cmd_arg(cmd, NULL, &vgname);
- if (!label_scan_vg_online(cmd, vgname, &found_none, &found_all, &found_incomplete)) {
- log_print("PVs online error%s%s, using all devices.", vgname ? " for VG " : "", vgname ?: "");
- } else {
- if (!vgname) {
- /* Not expected usage, activate any VGs that are complete based on pvs_online. */
- flags |= PROCESS_SKIP_SCAN;
- } else if (found_all) {
- /* The expected and optimal usage, only online PVs are read. */
- flags |= PROCESS_SKIP_SCAN;
- /*
- } else if (online_only) {
- log_print("PVs online %s.", found_none ? "not found" : "incomplete");
- return vgname ? ECMD_FAILED : ECMD_PROCESSED;
- */
- } else if (found_none) {
- /* Not expected usage, use full label_scan in process_each */
- log_print("PVs online not found for VG %s, using all devices.", vgname);
- } else if (found_incomplete) {
- /* Not expected usage, use full label_scan in process_each */
- log_print("PVs online incomplete for VG %s, using all devicess.", vgname);
- } else {
- /* Shouldn't happen */
- log_print("PVs online unknown for VG %s, using all devices.", vgname);
- }
- }
}
if (update)
@@ -949,7 +994,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
handle->custom_handle = &vp;
- ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_single);
+ ret = process_each_vg(cmd, argc, argv, vgname, NULL, flags, 0, handle, &_vgchange_single);
destroy_processing_handle(cmd, handle);
return ret;
2 years, 5 months
main - filter-sysfs: support old kernels without sys/dev/block
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d608837b2a88d0ed0c7...
Commit: d608837b2a88d0ed0c7ef7d8e6135e2d37687ff1
Parent: 73b4602f219767850a2834c6b15bdb5e6d636870
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Nov 9 11:54:48 2021 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Nov 9 11:54:48 2021 -0600
filter-sysfs: support old kernels without sys/dev/block
rhel5 for example doesn't have /sys/dev/block
---
lib/filters/filter-sysfs.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/lib/filters/filter-sysfs.c b/lib/filters/filter-sysfs.c
index 672211057..d8de7940b 100644
--- a/lib/filters/filter-sysfs.c
+++ b/lib/filters/filter-sysfs.c
@@ -15,6 +15,8 @@
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
+static int _sys_dev_block_found;
+
#ifdef __linux__
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
@@ -23,6 +25,9 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
const char *sysfs_dir;
struct stat info;
+ if (!_sys_dev_block_found)
+ return 1;
+
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
/*
@@ -57,6 +62,26 @@ static void _destroy(struct dev_filter *f)
free(f);
}
+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();
@@ -67,6 +92,9 @@ struct dev_filter *sysfs_filter_create(void)
return NULL;
}
+ /* support old kernels that don't have this */
+ _check_sys_dev_block();
+
if (!(f = zalloc(sizeof(*f))))
goto_bad;
2 years, 5 months
main - pvs_online: include devname in pvid files
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=73b4602f219767850a2...
Commit: 73b4602f219767850a2834c6b15bdb5e6d636870
Parent: 024ce50f06feff2dae53dce83398911bef071a6e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Nov 8 16:02:48 2021 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Nov 9 11:26:26 2021 -0600
pvs_online: include devname in pvid files
Include the device name in the /run/lvm/pvs_online/pvid files.
Commands using the pvid file can use the devname to more quickly
find the correct device, vs finding the device using the
major:minor number. If the devname in the pvid file is missing
or incorrect, fall back to using the devno.
---
lib/device/dev-cache.c | 50 ++++++++++++++++++
lib/device/dev-cache.h | 1 +
lib/device/online.c | 138 +++++++++++++++++++++++++++++++++++++------------
lib/device/online.h | 3 +-
lib/label/label.c | 18 ++-----
tools/pvscan.c | 41 +++++++--------
6 files changed, 182 insertions(+), 69 deletions(-)
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 525dae31e..b5f355484 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -2241,3 +2241,53 @@ int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno)
return setup_devname_in_dev_cache(cmd, devname);
}
+struct device *setup_dev_in_dev_cache(struct cmd_context *cmd, dev_t devno, const char *devname)
+{
+ struct device *dev;
+ struct stat buf;
+ int major = (int)MAJOR(devno);
+ int minor = (int)MINOR(devno);
+
+ if (devname) {
+ if (stat(devname, &buf) < 0) {
+ log_error("Cannot access device %s for %d:%d.", devname, major, minor);
+ if (!(devname = _get_devname_from_devno(cmd, devno))) {
+ log_error("No device name found from %d:%d.", major, minor);
+ return_NULL;
+ }
+ if (stat(devname, &buf) < 0) {
+ log_error("Cannot access device %s from %d:%d.", devname, major, minor);
+ return_NULL;
+ }
+ }
+ } else {
+ if (!(devname = _get_devname_from_devno(cmd, devno))) {
+ log_error("No device name found from %d:%d.", major, minor);
+ return_NULL;
+ }
+ if (stat(devname, &buf) < 0) {
+ log_error("Cannot access device %s from %d:%d.", devname, major, minor);
+ return_NULL;
+ }
+ }
+
+ if (!S_ISBLK(buf.st_mode)) {
+ log_error("Invaild device type %s.", devname);
+ return_NULL;
+ }
+
+ if (devno && (buf.st_rdev != devno)) {
+ log_warn("Found %s devno %d:%d expected %d:%d.", devname,
+ (int)MAJOR(buf.st_rdev), (int)MINOR(buf.st_rdev), major, minor);
+ }
+
+ if (!_insert_dev(devname, buf.st_rdev))
+ return_NULL;
+
+ if (!(dev = (struct device *) dm_hash_lookup(_cache.names, devname))) {
+ log_error("Device lookup failed for %d:%d %s", major, minor, devname);
+ return_NULL;
+ }
+
+ return dev;
+}
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 175c0a3e3..449bfeb75 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -82,5 +82,6 @@ int setup_device(struct cmd_context *cmd, const char *devname);
int setup_devices_for_online_autoactivation(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);
+struct device *setup_dev_in_dev_cache(struct cmd_context *cmd, dev_t devno, const char *devname);
#endif
diff --git a/lib/device/online.c b/lib/device/online.c
index 58696871e..c67f45001 100644
--- a/lib/device/online.c
+++ b/lib/device/online.c
@@ -21,35 +21,50 @@
#include <dirent.h>
-static char *_vgname_in_pvid_file_buf(char *buf)
+/*
+ * file contains:
+ * <major>:<minor>\n
+ * vg:<vgname>\n
+ * dev:<devname>\n\0
+ *
+ * It's possible that vg and dev may not exist.
+ */
+
+static int _copy_pvid_file_field(const char *field, char *buf, int bufsize, char *out, int outsize)
{
- char *p, *n;
+ char *p;
+ int i = 0;
+
+ if (!(p = strstr(buf, field)))
+ return 0;
- /*
- * file contains:
- * <major>:<minor>\n
- * vg:<vgname>\n\0
- */
+ p += strlen(field);
- if (!(p = strchr(buf, '\n')))
- return NULL;
+ while (1) {
+ if (*p == '\n')
+ break;
+ if (*p == '\0')
+ break;
- p++; /* skip \n */
+ if (p >= (buf + bufsize))
+ return 0;
+ if (i >= outsize-1)
+ return 0;
- if (*p && !strncmp(p, "vg:", 3)) {
- if ((n = strchr(p, '\n')))
- *n = '\0';
- return p + 3;
+ out[i] = *p;
+
+ i++;
+ p++;
}
- return NULL;
+
+ return i ? 1 : 0;
}
#define MAX_PVID_FILE_SIZE 512
-int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
+int online_pvid_file_read(char *path, int *major, int *minor, char *vgname, char *devname)
{
char buf[MAX_PVID_FILE_SIZE] = { 0 };
- char *name;
int fd, rv;
fd = open(path, O_RDONLY);
@@ -72,12 +87,47 @@ int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
return 0;
}
- /* vgname points to an offset in buf */
- if ((name = _vgname_in_pvid_file_buf(buf)))
- strncpy(vgname, name, NAME_LEN);
- else
- log_debug("No vgname in %s", path);
+ if (vgname) {
+ if (!strstr(buf, "vg:")) {
+ log_debug("No vgname in %s", path);
+ vgname[0] = '\0';
+ goto copy_dev;
+ }
+
+ if (!_copy_pvid_file_field("vg:", buf, MAX_PVID_FILE_SIZE, vgname, NAME_LEN)) {
+ log_warn("Ignoring invalid vg field in %s", path);
+ vgname[0] = '\0';
+ goto copy_dev;
+ }
+
+ if (!validate_name(vgname)) {
+ log_warn("Ignoring invalid vgname in %s (%s)", path, vgname);
+ vgname[0] = '\0';
+ goto copy_dev;
+ }
+ }
+
+ copy_dev:
+ if (devname) {
+ if (!strstr(buf, "dev:")) {
+ log_debug("No devname in %s", path);
+ devname[0] = '\0';
+ goto out;
+ }
+
+ if (!_copy_pvid_file_field("dev:", buf, MAX_PVID_FILE_SIZE, devname, NAME_LEN)) {
+ log_warn("Ignoring invalid devname field in %s", path);
+ devname[0] = '\0';
+ goto out;
+ }
+ if (strncmp(devname, "/dev/", 5)) {
+ log_warn("Ignoring invalid devname in %s (%s)", path, devname);
+ devname[0] = '\0';
+ goto out;
+ }
+ }
+ out:
return 1;
}
@@ -95,6 +145,7 @@ int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
+ char file_devname[NAME_LEN];
DIR *dir;
struct dirent *de;
struct pv_online *po;
@@ -116,8 +167,9 @@ int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
file_major = 0;
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
+ memset(file_devname, 0, sizeof(file_devname));
- if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
+ if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname, file_devname))
continue;
if (vgname && strcmp(file_vgname, vgname))
@@ -130,15 +182,18 @@ int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
if (file_major || file_minor)
po->devno = MKDEV(file_major, file_minor);
if (file_vgname[0])
- strncpy(po->vgname, file_vgname, NAME_LEN-1);
+ strncpy(po->vgname, file_vgname, NAME_LEN);
+ if (file_devname[0])
+ strncpy(po->devname, file_devname, NAME_LEN);
+ log_debug("Found PV online %s for VG %s %s", path, vgname, file_devname);
dm_list_add(pvs_online, &po->list);
}
if (closedir(dir))
log_sys_debug("closedir", PVS_ONLINE_DIR);
- log_debug("PVs online found %d for %s", dm_list_size(pvs_online), vgname ?: "all");
+ log_debug("Found PVs online %d for %s", dm_list_size(pvs_online), vgname ?: "all");
return 1;
}
@@ -195,6 +250,9 @@ int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const c
char path[PATH_MAX];
char buf[MAX_PVID_FILE_SIZE] = { 0 };
char file_vgname[NAME_LEN];
+ char file_devname[NAME_LEN];
+ char devname[NAME_LEN];
+ int devnamelen;
int file_major = 0, file_minor = 0;
int major, minor;
int fd;
@@ -202,6 +260,7 @@ int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const c
int len;
int len1 = 0;
int len2 = 0;
+ int len3 = 0;
major = (int)MAJOR(dev->dev);
minor = (int)MINOR(dev->dev);
@@ -218,13 +277,22 @@ int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const c
if (vgname) {
if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
- log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
+ log_print("Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
/* can still continue without vgname */
len2 = 0;
}
}
- len = len1 + len2;
+ devnamelen = dm_snprintf(devname, sizeof(devname), "%s", dev_name(dev));
+ if ((devnamelen > 5) && (devnamelen < NAME_LEN-1)) {
+ if ((len3 = dm_snprintf(buf + len1 + len2, sizeof(buf) - len1 - len2, "dev:%s\n", devname)) < 0) {
+ log_print("Incomplete devname in online file for %s.", dev_name(dev));
+ /* can continue without devname */
+ len3 = 0;
+ }
+ }
+
+ len = len1 + len2 + len3;
log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(dev));
@@ -269,8 +337,9 @@ check_duplicate:
*/
memset(file_vgname, 0, sizeof(file_vgname));
+ memset(file_devname, 0, sizeof(file_devname));
- online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
+ online_pvid_file_read(path, &file_major, &file_minor, file_vgname, file_devname);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Existing online file for %d:%d", major, minor);
@@ -280,8 +349,8 @@ check_duplicate:
/* Don't know how vgname might not match, but it's not good so fail. */
if ((file_major != major) || (file_minor != minor))
- log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
- dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
+ log_error_pvscan(cmd, "PV %s %d:%d is duplicate for PVID %s on %d:%d %s.",
+ dev_name(dev), major, minor, dev->pvid, file_major, file_minor, file_devname);
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
@@ -319,6 +388,7 @@ int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
char line[64];
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char file_vgname[NAME_LEN];
+ char file_devname[NAME_LEN];
struct pv_online *po;
int file_major = 0, file_minor = 0;
FILE *fp;
@@ -340,8 +410,9 @@ int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
file_major = 0;
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
+ memset(file_devname, 0, sizeof(file_devname));
- if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
+ if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname, file_devname))
goto_bad;
if (vgname && strcmp(file_vgname, vgname))
@@ -355,11 +426,14 @@ int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
po->devno = MKDEV(file_major, file_minor);
if (file_vgname[0])
strncpy(po->vgname, file_vgname, NAME_LEN-1);
+ if (file_devname[0])
+ strncpy(po->devname, file_devname, NAME_LEN-1);
+ log_debug("Found PV online lookup %s for VG %s on %s", path, vgname, file_devname);
dm_list_add(pvs_online, &po->list);
}
- log_debug("PVs online lookup found %d for %s", dm_list_size(pvs_online), vgname);
+ log_debug("Found PVs online lookup %d for %s", dm_list_size(pvs_online), vgname);
fclose(fp);
return 1;
diff --git a/lib/device/online.h b/lib/device/online.h
index 25a176854..850b03db8 100644
--- a/lib/device/online.h
+++ b/lib/device/online.h
@@ -21,6 +21,7 @@ struct pv_online {
dev_t devno;
char pvid[ID_LEN + 1];
char vgname[NAME_LEN];
+ char devname[NAME_LEN];
};
/*
@@ -44,7 +45,7 @@ do \
log_error("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
-int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
+int online_pvid_file_read(char *path, int *major, int *minor, char *vgname, char *devname);
int online_vg_file_create(struct cmd_context *cmd, const char *vgname);
void online_vg_file_remove(const char *vgname);
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname);
diff --git a/lib/label/label.c b/lib/label/label.c
index 9875b5f02..324cfd034 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -1073,26 +1073,18 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
}
/*
- * For each po devno add a struct dev to dev-cache. This is a faster
+ * For each po add a struct dev to dev-cache. This is a faster
* alternative to the usual dev_cache_scan() which looks at all
* devices. If this optimization fails, then fall back to the usual
* dev_cache_scan().
*/
dm_list_iterate_items(po, &pvs_online) {
- if (!setup_devno_in_dev_cache(cmd, po->devno)) {
- log_debug("No device set up for quick mapping of %d:%d PVID %s",
- (int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
+ if (!(po->dev = setup_dev_in_dev_cache(cmd, po->devno, po->devname[0] ? po->devname : NULL))) {
+ log_debug("No device found for quick mapping of online PV %d:%d %s PVID %s",
+ (int)MAJOR(po->devno), (int)MINOR(po->devno), po->devname, po->pvid);
try_dev_scan = 1;
- break;
- }
-
- if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
- log_debug("No device found for quick mapping of %d:%d PVID %s",
- (int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
- try_dev_scan = 1;
- break;
+ continue;
}
-
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
goto_bad;
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 6fd86e486..df1722c45 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -223,7 +223,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
- online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
+ online_pvid_file_read(path, &file_major, &file_minor, file_vgname, NULL);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Unlink pv online %s", path);
@@ -509,6 +509,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
+ char file_devname[NAME_LEN];
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char uuidstr[64] __attribute__((aligned(8)));
struct pv_list *pvl;
@@ -538,8 +539,9 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
file_major = 0;
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
+ memset(file_devname, 0, sizeof(file_devname));
- online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
+ online_pvid_file_read(path, &file_major, &file_minor, file_vgname, file_devname);
if (file_vgname[0] && strcmp(vgname, file_vgname)) {
log_error_pvscan(cmd, "Wrong VG found for %d:%d PVID %s: %s vs %s",
@@ -549,13 +551,8 @@ 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);
+ if (!(dev = setup_dev_in_dev_cache(cmd, devno, file_devname[0] ? file_devname : NULL))) {
+ log_error_pvscan(cmd, "No device set up for online PV %d:%d %s PVID %s", file_major, file_minor, file_devname, pvid);
goto bad;
}
@@ -888,16 +885,12 @@ 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);
- 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);
- arg->dev = dev_cache_get_by_devt(cmd, arg->devno, NULL, NULL);
- } else
+ if (!arg->devname && !arg->devno)
return_0;
+ if (!(arg->dev = setup_dev_in_dev_cache(cmd, arg->devno, arg->devname))) {
+ log_error_pvscan(cmd, "No device set up for arg %s %d:%d",
+ arg->devname ?: "", (int)MAJOR(arg->devno), (int)MINOR(arg->devno));
+ }
}
dm_list_iterate_items(arg, pvscan_args) {
@@ -917,6 +910,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
+ char file_devname[NAME_LEN];
char pvid[ID_LEN+1] = { 0 };
struct pv_list *pvl;
struct device *dev;
@@ -944,9 +938,10 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
major = 0;
minor = 0;
- file_vgname[0] = '\0';
+ memset(file_vgname, 0, sizeof(file_vgname));
+ memset(file_devname, 0, sizeof(file_devname));
- online_pvid_file_read(path, &major, &minor, file_vgname);
+ online_pvid_file_read(path, &major, &minor, file_vgname, file_devname);
if (file_vgname[0] && strcmp(vg->name, file_vgname)) {
log_warn("WARNING: VG %s PV %s wrong vgname in online file %s",
@@ -957,9 +952,9 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
devno = MKDEV(major, minor);
- if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
- log_print_pvscan(cmd, "VG %s PV %s no device found for %d:%d",
- vg->name, pvid, major, minor);
+ if (!(dev = setup_dev_in_dev_cache(cmd, devno, file_devname[0] ? file_devname : NULL))) {
+ log_print_pvscan(cmd, "VG %s PV %s no device found for online PV %d:%d %s",
+ vg->name, pvid, major, minor, file_devname);
pvl->pv->status |= MISSING_PV;
continue;
}
2 years, 5 months
main - vgchange -aay: improve unexpected command variations
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=024ce50f06feff2dae5...
Commit: 024ce50f06feff2dae53dce83398911bef071a6e
Parent: 14b68ea313865041433e18bac92a6dfcf6128b15
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Nov 8 11:30:25 2021 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Nov 8 15:19:25 2021 -0600
vgchange -aay: improve unexpected command variations
For completeness and consistency, adjust the behavior
for some variations of:
vgchange -aay --autoactivation event [vgname]
The current standard use is with a VG name arg, and the
command is only called when all pvs_online files exist.
This is the optimal case, in which only pvs_online devs
are read. This remains the same.
Clean up behaviors for some other unexpected uses of the
command:
. With no VG name arg, the command activates any VGs
that are complete according to pvs_online. If no
pvs_online files exist, it does nothing.
. If a VG name is used but no PVs online files exist for
the VG, or the PVs online files are incomplete, then
consider there could be a problem with the pvs_online
files, and fall back to a full label scan prior to
attempting the activation.
---
lib/device/dev-cache.c | 2 +-
lib/device/online.c | 6 ++
lib/label/label.c | 48 +++++++++++-----
lib/label/label.h | 4 +-
test/shell/vgchange-pvs-online.sh | 112 +++++++++++++++++++++++++++++++-------
tools/vgchange.c | 47 ++++++++++++++--
6 files changed, 178 insertions(+), 41 deletions(-)
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index e71cef38d..525dae31e 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -2164,7 +2164,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (devname[0]) {
- log_debug("Found %s for %d:%d from sys", devname, major, minor);
+ log_debug("Found %s for %d:%d from sys dm", devname, major, minor);
return _strdup(devname);
}
return NULL;
diff --git a/lib/device/online.c b/lib/device/online.c
index cd89d72e3..58696871e 100644
--- a/lib/device/online.c
+++ b/lib/device/online.c
@@ -134,8 +134,12 @@ int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
dm_list_add(pvs_online, &po->list);
}
+
if (closedir(dir))
log_sys_debug("closedir", PVS_ONLINE_DIR);
+
+ log_debug("PVs online found %d for %s", dm_list_size(pvs_online), vgname ?: "all");
+
return 1;
}
@@ -355,6 +359,8 @@ int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
dm_list_add(pvs_online, &po->list);
}
+ log_debug("PVs online lookup found %d for %s", dm_list_size(pvs_online), vgname);
+
fclose(fp);
return 1;
diff --git a/lib/label/label.c b/lib/label/label.c
index 2f9b5c371..9875b5f02 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -1023,13 +1023,13 @@ int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev
/*
* Use files under /run/lvm/, created by pvscan --cache autoactivation,
- * to optimize device setup/scanning for a command that is run for a
- * specific vg name. autoactivation happens during system startup
- * when the hints file is not useful, so this uses the online files as
- * an alternative.
- */
-
-int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
+ * to optimize device setup/scanning. autoactivation happens during
+ * system startup when the hints file is not useful, but he pvs_online
+ * files can provide a similar optimization to the hints file.
+ */
+
+int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
+ int *found_none, int *found_all, int *found_incomplete)
{
struct dm_list pvs_online;
struct dm_list devs;
@@ -1042,6 +1042,8 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
dm_list_init(&pvs_online);
dm_list_init(&devs);
+ log_debug_devs("Finding online devices to scan");
+
/* reads devices file, does not populate dev-cache */
if (!setup_devices_for_online_autoactivation(cmd))
return 0;
@@ -1055,11 +1057,21 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
* info from the online files tell us which devices those PVs are
* located on.
*/
- if (!get_pvs_lookup(&pvs_online, vgname)) {
- if (!get_pvs_online(&pvs_online, vgname))
+ if (vgname) {
+ if (!get_pvs_lookup(&pvs_online, vgname)) {
+ if (!get_pvs_online(&pvs_online, vgname))
+ goto bad;
+ }
+ } else {
+ if (!get_pvs_online(&pvs_online, NULL))
goto bad;
}
+ if (dm_list_empty(&pvs_online)) {
+ *found_none = 1;
+ return 1;
+ }
+
/*
* For each po devno add a struct dev to dev-cache. This is a faster
* alternative to the usual dev_cache_scan() which looks at all
@@ -1201,8 +1213,10 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
free_po_list(&pvs_online);
- if (dm_list_empty(&devs))
+ if (dm_list_empty(&devs)) {
+ *found_none = 1;
return 1;
+ }
/*
* Scan devs to populate lvmcache info, which includes the mda info that's
@@ -1220,13 +1234,17 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
* be able to fall back to a standard label scan if the online hints
* gave fewer PVs than listed in VG metadata.
*/
- metadata_pv_count = lvmcache_pvsummary_count(vgname);
- if (metadata_pv_count != dm_list_size(&devs)) {
- log_debug("Incorrect PV list from online files %d metadata %d.",
- dm_list_size(&devs), metadata_pv_count);
- return 0;
+ if (vgname) {
+ metadata_pv_count = lvmcache_pvsummary_count(vgname);
+ if (metadata_pv_count > dm_list_size(&devs)) {
+ log_debug("Incomplete PV list from online files %d metadata %d.",
+ dm_list_size(&devs), metadata_pv_count);
+ *found_incomplete = 1;
+ return 1;
+ }
}
+ *found_all = 1;
return 1;
bad:
free_po_list(&pvs_online);
diff --git a/lib/label/label.h b/lib/label/label.h
index 55ebfde45..3cda1818c 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -118,7 +118,9 @@ int label_scan_open_excl(struct device *dev);
int label_scan_open_rw(struct device *dev);
int label_scan_reopen_rw(struct device *dev);
int label_read_pvid(struct device *dev, int *has_pvid);
-int label_scan_vg_online(struct cmd_context *cmd, const char *vgname);
+int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
+ int *found_none, int *found_all, int *found_incomplete);
+
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out);
diff --git a/test/shell/vgchange-pvs-online.sh b/test/shell/vgchange-pvs-online.sh
index bdc481ced..c2ebe7327 100644
--- a/test/shell/vgchange-pvs-online.sh
+++ b/test/shell/vgchange-pvs-online.sh
@@ -19,61 +19,135 @@ _clear_online_files() {
aux prepare_devs 4
+# Because mapping devno to devname gets dm name from sysfs
+aux lvmconf 'devices/scan = "/dev"'
+base1=$(basename $dev1)
+base2=$(basename $dev2)
+base3=$(basename $dev3)
+base4=$(basename $dev4)
+aux extend_filter "a|/dev/mapper/$base1|"
+aux extend_filter "a|/dev/mapper/$base2|"
+aux extend_filter "a|/dev/mapper/$base3|"
+aux extend_filter "a|/dev/mapper/$base4|"
+
vgcreate $vg1 "$dev1" "$dev2"
vgcreate $vg2 "$dev3"
pvcreate "$dev4"
lvcreate -l1 -n $lv1 -an $vg1
+lvcreate -l1 -n $lv2 -an $vg1
lvcreate -l1 -n $lv1 -an $vg2
-# With no pv online files, vgchange that uses online files
-# will find no PVs to activate from.
+# Expected use, with vg name and all online files exist for vgchange.
_clear_online_files
-not vgchange -aay --autoactivation event $vg1
-not vgchange -aay --autoactivation event $vg2
-vgchange -aay --autoactivation event
+pvscan --cache "$dev1"
+pvscan --cache "$dev2"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache "$dev3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+# Count io to check the pvs_online optimization
+# is working to limit scanning.
+
+vgchange -an
+_clear_online_files
+
+pvscan --cache "$dev1"
+pvscan --cache "$dev2"
+strace -e io_submit vgchange -aay --autoactivation event $vg1 2>&1|tee trace.out
+test "$(grep io_submit trace.out | wc -l)" -eq 4
+rm trace.out
+
+strace -e io_submit pvscan --cache "$dev3" 2>&1|tee trace.out
+test "$(grep io_submit trace.out | wc -l)" -eq 1
+rm trace.out
+
+strace -e io_submit vgchange -aay --autoactivation event $vg2 2>&1|tee trace.out
+test "$(grep io_submit trace.out | wc -l)" -eq 2
+rm trace.out
+# non-standard usage: no VG name arg, vgchange will only used pvs_online files
+
+vgchange -an
+_clear_online_files
+
+vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg1/$lv2 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
-# incomplete vg will not be activated
-
pvscan --cache "$dev1"
-vgchange -aay --autoactivation event $vg1
-# VG foo is incomplete
+vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg1/$lv2 lv_active ""
+check lv_field $vg2/$lv1 lv_active ""
-# complete vg is activated
+pvscan --cache "$dev2"
+vgchange -aay --autoactivation event
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev3"
-vgchange -aay --autoactivation event $vg2
+vgchange -aay --autoactivation event
check lv_field $vg2/$lv1 lv_active "active"
-pvscan --cache "$dev2"
+# non-standard usage: include VG name arg, but missing or incomplete pvs_online files
+
+vgchange -an
+_clear_online_files
+
+# all missing pvs_online, vgchange falls back to full label scan
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
-vgchange -an $vg1
-vgchange -an $vg2
+vgchange -an
+_clear_online_files
-# the same tests but using command options matching udev rule
+# incomplete pvs_online, vgchange falls back to full label scan
+pvscan --cache "$dev1"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+vgchange -an
_clear_online_files
-pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev1"
+# incomplete pvs_online, pvs_online from different vg,
+# no pvs_online found for vg arg so vgchange falls back to full label scan
+
+pvscan --cache "$dev3"
vgchange -aay --autoactivation event $vg1
-# VG foo is incomplete
-check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
-pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev3"
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
+vgchange -an
+_clear_online_files
+
+# same tests but using command options matching udev rule
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev1"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev2"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
vgchange -an $vg1
vgchange -an $vg2
diff --git a/tools/vgchange.c b/tools/vgchange.c
index e20026e4d..acdde97a8 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -879,7 +879,9 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
}
if (arg_is_set(cmd, autoactivation_ARG)) {
+ int found_none = 0, found_all = 0, found_incomplete = 0;
int skip_command = 0;
+
if (!_check_autoactivation(cmd, &vp, &skip_command))
return ECMD_FAILED;
if (skip_command)
@@ -889,14 +891,49 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
* Special label scan optimized for autoactivation
* that is based on info read from /run/lvm/ files
* created by pvscan --cache during autoactivation.
- * (Add an option to disable this optimization?)
+ * Add an option to disable this optimization? e.g.
+ * "online_skip" in --autoactivation / auto_activation_settings
+ *
+ * In some cases it might be useful to strictly follow
+ * the online files, and not fall back to a standard
+ * label scan when no pvs or incomplete pvs are found
+ * from the online files. Add option for that? e.g.
+ * "online_only" in --autoactivation / auto_activation_settings
+ *
+ * Generally the way that vgchange -aay --autoactivation event
+ * is currently used, it will not be called until pvscan --cache
+ * has found the VG is complete, so it will not generally be
+ * following the paths that fall back to standard label_scan.
+ *
+ * TODO: Like pvscan_aa_quick, this could do lock_vol(vgname)
+ * before label_scan_vg_online, then set cmd->can_use_one_scan=1
+ * to avoid rescanning in _vg_read called by process_each_vg.
*/
get_single_vgname_cmd_arg(cmd, NULL, &vgname);
- if (vgname) {
- if (!label_scan_vg_online(cmd, vgname))
- log_debug("Standard label_scan required in place of online scan.");
- else
+ if (!label_scan_vg_online(cmd, vgname, &found_none, &found_all, &found_incomplete)) {
+ log_print("PVs online error%s%s, using all devices.", vgname ? " for VG " : "", vgname ?: "");
+ } else {
+ if (!vgname) {
+ /* Not expected usage, activate any VGs that are complete based on pvs_online. */
+ flags |= PROCESS_SKIP_SCAN;
+ } else if (found_all) {
+ /* The expected and optimal usage, only online PVs are read. */
flags |= PROCESS_SKIP_SCAN;
+ /*
+ } else if (online_only) {
+ log_print("PVs online %s.", found_none ? "not found" : "incomplete");
+ return vgname ? ECMD_FAILED : ECMD_PROCESSED;
+ */
+ } else if (found_none) {
+ /* Not expected usage, use full label_scan in process_each */
+ log_print("PVs online not found for VG %s, using all devices.", vgname);
+ } else if (found_incomplete) {
+ /* Not expected usage, use full label_scan in process_each */
+ log_print("PVs online incomplete for VG %s, using all devicess.", vgname);
+ } else {
+ /* Shouldn't happen */
+ log_print("PVs online unknown for VG %s, using all devices.", vgname);
+ }
}
}
2 years, 5 months
main - vgchange -aay: fall back to dev_cache_scan if optimization fails
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=14b68ea313865041433...
Commit: 14b68ea313865041433e18bac92a6dfcf6128b15
Parent: b4067e84c7884f2b46effdf31418f66cc0b902bb
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Nov 5 17:01:34 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Nov 5 17:07:13 2021 -0500
vgchange -aay: fall back to dev_cache_scan if optimization fails
Part of the optimization to avoid a full dev_cache_scan requires
translating major:minor numbers to a device name. If this devno
translation fails, then fall back to doing a full dev_cache_scan
which is slower but certain to provide the info. This preserves
the most important part of the label scanning optimization in the
vgchange aay (avoiding dev_cache_scan is a relatively small part
of the optimized activation compared to label scanning.)
---
lib/label/label.c | 43 +++++++++++++++++++++++++++++++++++++------
1 file changed, 37 insertions(+), 6 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index 709ae8fc1..2f9b5c371 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -1037,6 +1037,7 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
struct device_list *devl, *devl2;
int relax_deviceid_filter = 0;
int metadata_pv_count;
+ int try_dev_scan = 0;
dm_list_init(&pvs_online);
dm_list_init(&devs);
@@ -1059,19 +1060,25 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
goto bad;
}
- /* for each po devno add a struct dev to dev-cache */
-
+ /*
+ * For each po devno add a struct dev to dev-cache. This is a faster
+ * alternative to the usual dev_cache_scan() which looks at all
+ * devices. If this optimization fails, then fall back to the usual
+ * dev_cache_scan().
+ */
dm_list_iterate_items(po, &pvs_online) {
if (!setup_devno_in_dev_cache(cmd, po->devno)) {
- log_error("No device set up for %d:%d PVID %s",
+ log_debug("No device set up for quick mapping of %d:%d PVID %s",
(int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
- goto bad;
+ try_dev_scan = 1;
+ break;
}
if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
- log_error("No device found for %d:%d PVID %s",
+ log_debug("No device found for quick mapping of %d:%d PVID %s",
(int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
- goto bad;
+ try_dev_scan = 1;
+ break;
}
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
@@ -1081,6 +1088,30 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
dm_list_add(&devs, &devl->list);
}
+ /*
+ * Translating a devno (major:minor) into a device name can be
+ * problematic for some devices that have unusual sysfs layouts, so if
+ * this happens, do a full dev_cache_scan, which is slower, but is
+ * sure to find the device.
+ */
+ if (try_dev_scan) {
+ dev_cache_scan(cmd);
+ dm_list_iterate_items(po, &pvs_online) {
+ if (po->dev)
+ continue;
+ if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
+ log_error("No device found for %d:%d PVID %s",
+ (int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
+ goto bad;
+ }
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ goto_bad;
+
+ devl->dev = po->dev;
+ dm_list_add(&devs, &devl->list);
+ }
+ }
+
/*
* factor code common to pvscan_cache_args
*/
2 years, 5 months
main - fix device name from devno for partitions
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=b4067e84c7884f2b46e...
Commit: b4067e84c7884f2b46effdf31418f66cc0b902bb
Parent: 62533ae3fad9fece6f27e3fae7b56e40c66438fa
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Nov 5 16:21:23 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Nov 5 16:21:23 2021 -0500
fix device name from devno for partitions
sysfs files for partitions are different from
whole devices and will require more work to translate
to device names.
---
lib/device/dev-cache.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index ce82a9303..e71cef38d 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -2125,7 +2125,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (!(dir = opendir(path)))
- return NULL;
+ goto try_partition;
while ((dirent = readdir(dir))) {
if (dirent->d_name[0] == '.')
@@ -2175,6 +2175,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
* major minor #blocks name
*/
+try_partition:
if (!(fp = fopen("/proc/partitions", "r")))
return NULL;
2 years, 5 months
main - vgchange -aay: optimize device list using pvs_online files
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=62533ae3fad9fece6f2...
Commit: 62533ae3fad9fece6f27e3fae7b56e40c66438fa
Parent: 5f7cb977438891a073227d75029f61970b1710bd
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Nov 5 12:19:35 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Nov 5 12:19:35 2021 -0500
vgchange -aay: optimize device list using pvs_online files
Port another optimization from pvscan -aay to vgchange -aay:
"pvscan: only add device args to dev cache"
This optimization avoids doing a full dev_cache_scan, and
instead populates dev-cache with only the devices in the
VG being activated.
This involves shifting the use of pvs_online files from
the hints interface up to the higher level label_scan
interface. This specialized label_scan is structured
around creating a list of devices from the pvs_online
files. Previously, a list of all devices was created
first, and then reduced based on the pvs_online files.
The initial step of listing all devices was slow when
thousands of devices are present on the system.
This optimization extends the previous optimization that
used pvs_online files to limit the devices that were
actually scanned (i.e. reading to identify the device):
"vgchange -aay: optimize device scan using pvs_online files"
---
lib/cache/lvmcache.c | 10 ++
lib/cache/lvmcache.h | 2 +
lib/commands/toolcontext.h | 1 -
lib/device/dev-cache.c | 6 +-
lib/device/dev-cache.h | 3 +-
lib/device/online.c | 116 ++++++++++++++++++++++-
lib/device/online.h | 11 +++
lib/label/hints.c | 129 ++------------------------
lib/label/hints.h | 3 +
lib/label/label.c | 182 +++++++++++++++++++++++++++++++++++++
lib/label/label.h | 1 +
test/shell/udev-pvscan-vgchange.sh | 3 +
tools/lvmcmdline.c | 2 -
tools/pvscan.c | 2 +-
tools/vgchange.c | 21 ++++-
15 files changed, 357 insertions(+), 135 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index bee63ebb4..81b9b0ec9 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -572,6 +572,16 @@ static const char *_get_pvsummary_device_id(const char *pvid_arg, const char **d
return NULL;
}
+int lvmcache_pvsummary_count(const char *vgname)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
+ return_0;
+
+ return dm_list_size(&vginfo->pvsummaries);
+}
+
/*
* Check if any PVs in vg->pvs have the same PVID as any
* entries in _unused_duplicates.
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 9511bb9e9..4c4903136 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -229,4 +229,6 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
unsigned int lvmcache_vg_info_count(void);
+int lvmcache_pvsummary_count(const char *vgname);
+
#endif
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index b3de65702..fb7182db6 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -183,7 +183,6 @@ struct cmd_context {
unsigned enable_hints:1; /* hints are enabled for cmds in general */
unsigned use_hints:1; /* if hints are enabled this cmd can use them */
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
- unsigned hints_pvs_online:1; /* hints="pvs_online" */
unsigned scan_lvs:1;
unsigned wipe_outdated_pvs:1;
unsigned enable_devices_list:1; /* command is using --devices option */
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 33b75a9a9..ce82a9303 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -2056,12 +2056,12 @@ int setup_device(struct cmd_context *cmd, const char *devname)
}
/*
- * pvscan --cache is specialized/optimized to look only at command args,
+ * autoactivation 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.
+ * added to dev-cache and matched with device_ids.
*/
-int setup_devices_for_pvscan_cache(struct cmd_context *cmd)
+int setup_devices_for_online_autoactivation(struct cmd_context *cmd)
{
if (cmd->enable_devices_list) {
if (!_setup_devices_list(cmd))
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 143848d6d..175c0a3e3 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -79,8 +79,7 @@ int setup_devices_file(struct cmd_context *cmd);
int setup_devices(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_devices_for_online_autoactivation(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);
diff --git a/lib/device/online.c b/lib/device/online.c
index 28e97d9fe..cd89d72e3 100644
--- a/lib/device/online.c
+++ b/lib/device/online.c
@@ -81,6 +81,64 @@ int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
return 1;
}
+void free_po_list(struct dm_list *list)
+{
+ struct pv_online *po, *po2;
+
+ dm_list_iterate_items_safe(po, po2, list) {
+ dm_list_del(&po->list);
+ free(po);
+ }
+}
+
+int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
+{
+ char path[PATH_MAX];
+ char file_vgname[NAME_LEN];
+ DIR *dir;
+ struct dirent *de;
+ struct pv_online *po;
+ int file_major = 0, file_minor = 0;
+
+ if (!(dir = opendir(PVS_ONLINE_DIR)))
+ return 0;
+
+ while ((de = readdir(dir))) {
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (strlen(de->d_name) != ID_LEN)
+ continue;
+
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, de->d_name);
+
+ file_major = 0;
+ file_minor = 0;
+ memset(file_vgname, 0, sizeof(file_vgname));
+
+ if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
+ continue;
+
+ if (vgname && strcmp(file_vgname, vgname))
+ continue;
+
+ if (!(po = zalloc(sizeof(*po))))
+ continue;
+
+ memcpy(po->pvid, de->d_name, ID_LEN);
+ if (file_major || file_minor)
+ po->devno = MKDEV(file_major, file_minor);
+ if (file_vgname[0])
+ strncpy(po->vgname, file_vgname, NAME_LEN-1);
+
+ dm_list_add(pvs_online, &po->list);
+ }
+ if (closedir(dir))
+ log_sys_debug("closedir", PVS_ONLINE_DIR);
+ return 1;
+}
+
/*
* When a PV goes offline, remove the vg online file for that VG
* (even if other PVs for the VG are still online). This means
@@ -250,6 +308,62 @@ int online_pvid_file_exists(const char *pvid)
return 0;
}
+int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
+{
+ char lookup_path[PATH_MAX] = { 0 };
+ char path[PATH_MAX] = { 0 };
+ char line[64];
+ char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
+ char file_vgname[NAME_LEN];
+ struct pv_online *po;
+ int file_major = 0, file_minor = 0;
+ FILE *fp;
+
+ if (dm_snprintf(lookup_path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0)
+ return_0;
+
+ if (!(fp = fopen(lookup_path, "r")))
+ return_0;
+
+ while (fgets(line, sizeof(line), fp)) {
+ memcpy(pvid, line, ID_LEN);
+ if (strlen(pvid) != ID_LEN)
+ goto_bad;
+
+ memset(path, 0, sizeof(path));
+ snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
+
+ file_major = 0;
+ file_minor = 0;
+ memset(file_vgname, 0, sizeof(file_vgname));
+
+ if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
+ goto_bad;
+
+ if (vgname && strcmp(file_vgname, vgname))
+ goto_bad;
+
+ if (!(po = zalloc(sizeof(*po))))
+ goto_bad;
+
+ memcpy(po->pvid, pvid, ID_LEN);
+ if (file_major || file_minor)
+ po->devno = MKDEV(file_major, file_minor);
+ if (file_vgname[0])
+ strncpy(po->vgname, file_vgname, NAME_LEN-1);
+
+ dm_list_add(pvs_online, &po->list);
+ }
+
+ fclose(fp);
+ return 1;
+
+bad:
+ free_po_list(pvs_online);
+ fclose(fp);
+ return 0;
+}
+
void online_dir_setup(struct cmd_context *cmd)
{
struct stat st;
@@ -301,6 +415,4 @@ do_lookup:
if ((rv < 0) && stat(PVS_LOOKUP_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", PVS_LOOKUP_DIR, errno);
-
-
}
diff --git a/lib/device/online.h b/lib/device/online.h
index 0a5076f7d..25a176854 100644
--- a/lib/device/online.h
+++ b/lib/device/online.h
@@ -15,6 +15,14 @@
#ifndef _ONLINE_H
#define _ONLINE_H
+struct pv_online {
+ struct dm_list list;
+ struct device *dev;
+ dev_t devno;
+ char pvid[ID_LEN + 1];
+ char vgname[NAME_LEN];
+};
+
/*
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
* FIXME: this should probably replace if (udevoutput) with
@@ -42,5 +50,8 @@ void online_vg_file_remove(const char *vgname);
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname);
int online_pvid_file_exists(const char *pvid);
void online_dir_setup(struct cmd_context *cmd);
+int get_pvs_online(struct dm_list *pvs_online, const char *vgname);
+int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname);
+void free_po_list(struct dm_list *list);
#endif
diff --git a/lib/label/hints.c b/lib/label/hints.c
index 85e5ab1cb..9a7c280eb 100644
--- a/lib/label/hints.c
+++ b/lib/label/hints.c
@@ -1214,8 +1214,8 @@ void invalidate_hints(struct cmd_context *cmd)
* probably want to exclude that command from attempting this optimization,
* because it would be difficult to know what VG that command wanted to use.
*/
-static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
- struct dm_list *hints, char **vgname)
+void get_single_vgname_cmd_arg(struct cmd_context *cmd,
+ struct dm_list *hints, char **vgname)
{
struct hint *hint;
char namebuf[NAME_LEN];
@@ -1264,6 +1264,11 @@ static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
return;
check:
+ if (!hints) {
+ *vgname = name;
+ return;
+ }
+
/*
* Only use this vgname hint if there are hints that contain this
* vgname. This might happen if we aren't able to properly extract the
@@ -1280,109 +1285,6 @@ check:
free(name);
}
-static int _get_hints_from_pvs_online(struct cmd_context *cmd, struct dm_list *hints_out,
- struct dm_list *devs_in, struct dm_list *devs_out)
-{
- char path[PATH_MAX];
- char file_vgname[NAME_LEN];
- struct dm_list hints_list;
- struct hint file_hint;
- struct hint *alloc_hint;
- struct hint *hint, *hint2;
- struct device_list *devl, *devl2;
- int file_major, file_minor;
- int found = 0;
- DIR *dir;
- struct dirent *de;
- char *vgname = NULL;
- char *pvid;
-
- dm_list_init(&hints_list);
-
- if (!(dir = opendir(PVS_ONLINE_DIR)))
- return 0;
-
- while ((de = readdir(dir))) {
- if (de->d_name[0] == '.')
- continue;
-
- pvid = de->d_name;
-
- if (strlen(pvid) != ID_LEN) /* 32 */
- continue;
-
- memset(path, 0, sizeof(path));
- snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
-
- memset(&file_hint, 0, sizeof(file_hint));
- memset(file_vgname, 0, sizeof(file_vgname));
- file_major = 0;
- file_minor = 0;
-
- if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
- continue;
-
- if (!dm_strncpy(file_hint.pvid, pvid, sizeof(file_hint.pvid)))
- continue;
-
- file_hint.devt = makedev(file_major, file_minor);
-
- if (file_vgname[0] && validate_name(file_vgname)) {
- if (!dm_strncpy(file_hint.vgname, file_vgname, sizeof(file_hint.vgname)))
- continue;
- }
-
- if (!(alloc_hint = malloc(sizeof(struct hint))))
- continue;
-
- memcpy(alloc_hint, &file_hint, sizeof(struct hint));
-
- log_debug("add hint %s %d:%d %s from pvs_online", file_hint.pvid, file_major, file_minor, file_vgname);
- dm_list_add(&hints_list, &alloc_hint->list);
- found++;
- }
-
- if (closedir(dir))
- stack;
-
- log_debug("accept hints found %d from pvs_online", found);
-
- _get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
-
- /*
- * apply_hints equivalent, move devs from devs_in to devs_out if
- * their devno matches the devno of a hint (and if the hint matches
- * the vgname when a vgname is present.)
- */
- dm_list_iterate_items_safe(devl, devl2, devs_in) {
- dm_list_iterate_items_safe(hint, hint2, &hints_list) {
- if ((MAJOR(devl->dev->dev) == MAJOR(hint->devt)) &&
- (MINOR(devl->dev->dev) == MINOR(hint->devt))) {
-
- if (vgname && hint->vgname[0] && strcmp(vgname, hint->vgname))
- goto next_dev;
-
- snprintf(hint->name, sizeof(hint->name), "%s", dev_name(devl->dev));
- hint->chosen = 1;
-
- dm_list_del(&devl->list);
- dm_list_add(devs_out, &devl->list);
- }
- }
- next_dev:
- ;
- }
-
- log_debug("applied hints using %d other %d vgname %s from pvs_online",
- dm_list_size(devs_out), dm_list_size(devs_in), vgname ?: "");
-
- dm_list_splice(hints_out, &hints_list);
-
- free(vgname);
-
- return 1;
-}
-
/*
* Returns 0: no hints are used.
* . newhints is set if this command should create new hints after scan
@@ -1404,7 +1306,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
*newhints = NEWHINTS_NONE;
/* No commands are using hints. */
- if (!cmd->enable_hints && !cmd->hints_pvs_online)
+ if (!cmd->enable_hints)
return 0;
/*
@@ -1424,19 +1326,6 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
if (!cmd->use_hints)
return 0;
- /*
- * enable_hints is 0 for the special hints=pvs_online
- * and by lvm.conf hints="none" does not disable hints=pvs_online.
- * hints=pvs_online can be disabled with --nohints.
- */
- if (cmd->hints_pvs_online) {
- if (!_get_hints_from_pvs_online(cmd, &hints_list, devs_in, devs_out)) {
- log_debug("get_hints: pvs_online failed");
- return 0;
- }
- return 1;
- }
-
/*
* Check if another command created the nohints file to prevent us from
* using hints.
@@ -1541,7 +1430,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
* us which devs are PVs. We might want to enable this optimization
* separately.)
*/
- _get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
+ get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
_apply_hints(cmd, &hints_list, vgname, devs_in, devs_out);
diff --git a/lib/label/hints.h b/lib/label/hints.h
index e8cfd6a7e..2bf7e7724 100644
--- a/lib/label/hints.h
+++ b/lib/label/hints.h
@@ -41,5 +41,8 @@ void hints_exit(struct cmd_context *cmd);
void pvscan_recreate_hints_begin(struct cmd_context *cmd);
+void get_single_vgname_cmd_arg(struct cmd_context *cmd,
+ struct dm_list *hints, char **vgname);
+
#endif
diff --git a/lib/label/label.c b/lib/label/label.c
index f9ab9a1f1..709ae8fc1 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -26,6 +26,7 @@
#include "lib/metadata/metadata.h"
#include "lib/format_text/layout.h"
#include "lib/device/device_id.h"
+#include "lib/device/online.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -1020,6 +1021,187 @@ int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev
return ret;
}
+/*
+ * Use files under /run/lvm/, created by pvscan --cache autoactivation,
+ * to optimize device setup/scanning for a command that is run for a
+ * specific vg name. autoactivation happens during system startup
+ * when the hints file is not useful, so this uses the online files as
+ * an alternative.
+ */
+
+int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
+{
+ struct dm_list pvs_online;
+ struct dm_list devs;
+ struct pv_online *po;
+ struct device_list *devl, *devl2;
+ int relax_deviceid_filter = 0;
+ int metadata_pv_count;
+
+ dm_list_init(&pvs_online);
+ dm_list_init(&devs);
+
+ /* reads devices file, does not populate dev-cache */
+ if (!setup_devices_for_online_autoactivation(cmd))
+ return 0;
+
+ /*
+ * First attempt to use /run/lvm/pvs_lookup/vgname which should be
+ * used in cases where all PVs in a VG do not contain metadata.
+ * When the pvs_lookup file does not exist, then simply use all
+ * /run/lvm/pvs_online/pvid files that contain a matching vgname.
+ * The list of po structs represents the PVs in the VG, and the
+ * info from the online files tell us which devices those PVs are
+ * located on.
+ */
+ if (!get_pvs_lookup(&pvs_online, vgname)) {
+ if (!get_pvs_online(&pvs_online, vgname))
+ goto bad;
+ }
+
+ /* for each po devno add a struct dev to dev-cache */
+
+ dm_list_iterate_items(po, &pvs_online) {
+ if (!setup_devno_in_dev_cache(cmd, po->devno)) {
+ log_error("No device set up for %d:%d PVID %s",
+ (int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
+ goto bad;
+ }
+
+ if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
+ log_error("No device found for %d:%d PVID %s",
+ (int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
+ goto bad;
+ }
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ goto_bad;
+
+ devl->dev = po->dev;
+ dm_list_add(&devs, &devl->list);
+ }
+
+ /*
+ * factor code common to pvscan_cache_args
+ */
+
+ if (cmd->enable_devices_file) {
+ dm_list_iterate_items(devl, &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;
+ cmd->filter_deviceid_skip = 1;
+ }
+
+ cmd->filter_nodata_only = 1;
+
+ dm_list_iterate_items_safe(devl, devl2, &devs) {
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
+ log_print("%s excluded by filters: %s.",
+ dev_name(devl->dev), dev_filtered_reason(devl->dev));
+ dm_list_del(&devl->list);
+ }
+ }
+
+ cmd->filter_nodata_only = 0;
+
+ /*
+ * Clear the results of nodata filters that were saved by the
+ * persistent filter so that the complete set of filters will
+ * be checked by passes_filter below.
+ */
+ dm_list_iterate_items(devl, &devs)
+ cmd->filter->wipe(cmd, cmd->filter, devl->dev, NULL);
+
+ /*
+ * Read header from each dev.
+ * Eliminate non-lvm devs.
+ * Apply all filters.
+ */
+
+ log_debug("label_scan_vg_online: read and filter devs");
+
+ label_scan_setup_bcache();
+
+ dm_list_iterate_items_safe(devl, devl2, &devs) {
+ int has_pvid;
+
+ if (!label_read_pvid(devl->dev, &has_pvid)) {
+ log_print("%s cannot read label.", dev_name(devl->dev));
+ dm_list_del(&devl->list);
+ continue;
+ }
+
+ if (!has_pvid) {
+ /* Not an lvm device */
+ log_print("%s not an lvm device.", dev_name(devl->dev));
+ dm_list_del(&devl->list);
+ continue;
+ }
+
+ /*
+ * filter-deviceid is not being used because of unstable devnames,
+ * so in place of that check if the pvid is in the devices file.
+ */
+ if (relax_deviceid_filter) {
+ if (!get_du_for_pvid(cmd, devl->dev->pvid)) {
+ log_print("%s excluded by devices file (checking PVID).",
+ dev_name(devl->dev));
+ dm_list_del(&devl->list);
+ continue;
+ }
+ }
+
+ /* Applies all filters, including those that need data from dev. */
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
+ log_print("%s excluded by filters: %s.",
+ dev_name(devl->dev), dev_filtered_reason(devl->dev));
+ dm_list_del(&devl->list);
+ }
+ }
+
+ if (relax_deviceid_filter)
+ cmd->filter_deviceid_skip = 0;
+
+ free_po_list(&pvs_online);
+
+ if (dm_list_empty(&devs))
+ return 1;
+
+ /*
+ * Scan devs to populate lvmcache info, which includes the mda info that's
+ * needed to read vg metadata.
+ * bcache data from label_read_pvid above is not invalidated so it can
+ * be reused (more data may need to be read depending on how much of the
+ * metadata was covered when reading the pvid.)
+ */
+ _scan_list(cmd, NULL, &devs, 0, NULL);
+
+ /*
+ * Check if all PVs from the VG were found after scanning the devs
+ * produced from the online files. The online files are effectively
+ * hints that usually work, but are not definitive, so we need to
+ * be able to fall back to a standard label scan if the online hints
+ * gave fewer PVs than listed in VG metadata.
+ */
+ metadata_pv_count = lvmcache_pvsummary_count(vgname);
+ if (metadata_pv_count != dm_list_size(&devs)) {
+ log_debug("Incorrect PV list from online files %d metadata %d.",
+ dm_list_size(&devs), metadata_pv_count);
+ return 0;
+ }
+
+ return 1;
+bad:
+ free_po_list(&pvs_online);
+ return 0;
+}
+
/*
* Scan devices on the system to discover which are LVM devices.
* Info about the LVM devices (PVs) is saved in lvmcache in a
diff --git a/lib/label/label.h b/lib/label/label.h
index 34563efd0..55ebfde45 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -118,6 +118,7 @@ int label_scan_open_excl(struct device *dev);
int label_scan_open_rw(struct device *dev);
int label_scan_reopen_rw(struct device *dev);
int label_read_pvid(struct device *dev, int *has_pvid);
+int label_scan_vg_online(struct cmd_context *cmd, const char *vgname);
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out);
diff --git a/test/shell/udev-pvscan-vgchange.sh b/test/shell/udev-pvscan-vgchange.sh
index c81acf0ce..f0d637562 100644
--- a/test/shell/udev-pvscan-vgchange.sh
+++ b/test/shell/udev-pvscan-vgchange.sh
@@ -219,6 +219,8 @@ udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg4
+ls "$RUNDIR/lvm/pvs_lookup/"
+cat "$RUNDIR/lvm/pvs_lookup/$vg4" || true
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
@@ -375,6 +377,7 @@ touch $DF
mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
wait_md_create "$mddev"
vgcreate $vg9 "$mddev"
+lvmdevices --adddev "$mddev" || true
PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
BDEVMD=$(basename "$mddev")
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 0f2c832ae..a28d98ecf 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -2542,8 +2542,6 @@ static int _get_current_settings(struct cmd_context *cmd)
if (!strcmp(hint_mode, "none")) {
cmd->enable_hints = 0;
cmd->use_hints = 0;
- } else if (!strcmp(hint_mode, "pvs_online")) {
- cmd->hints_pvs_online = 1;
}
}
diff --git a/tools/pvscan.c b/tools/pvscan.c
index c1f7fbe6d..6fd86e486 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1378,7 +1378,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
* Does not do dev_cache_scan (adds nothing to dev-cache), and
* does not do any device id matching.
*/
- if (!setup_devices_for_pvscan_cache(cmd)) {
+ if (!setup_devices_for_online_autoactivation(cmd)) {
log_error_pvscan(cmd, "Failed to set up devices.");
return 0;
}
diff --git a/tools/vgchange.c b/tools/vgchange.c
index ee06c498c..e20026e4d 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -15,6 +15,7 @@
#include "tools.h"
#include "lib/device/device_id.h"
+#include "lib/label/hints.h"
struct vgchange_params {
int lock_start_count;
@@ -755,10 +756,7 @@ static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params
vp->vg_complete_to_activate = 1;
- if (!arg_is_set(cmd, nohints_ARG))
- cmd->hints_pvs_online = 1;
- else
- cmd->use_hints = 0;
+ cmd->use_hints = 0;
return 1;
}
@@ -767,6 +765,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
{
struct vgchange_params vp = { 0 };
struct processing_handle *handle;
+ char *vgname = NULL;
uint32_t flags = 0;
int ret;
@@ -885,6 +884,20 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
if (skip_command)
return ECMD_PROCESSED;
+
+ /*
+ * Special label scan optimized for autoactivation
+ * that is based on info read from /run/lvm/ files
+ * created by pvscan --cache during autoactivation.
+ * (Add an option to disable this optimization?)
+ */
+ get_single_vgname_cmd_arg(cmd, NULL, &vgname);
+ if (vgname) {
+ if (!label_scan_vg_online(cmd, vgname))
+ log_debug("Standard label_scan required in place of online scan.");
+ else
+ flags |= PROCESS_SKIP_SCAN;
+ }
}
if (update)
2 years, 5 months
main - lvm2-pvscan: include --autoactivation event
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=5f7cb977438891a0732...
Commit: 5f7cb977438891a073227d75029f61970b1710bd
Parent: f40fd88374fe1e911233e5a4fc79223d97decde0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Nov 4 14:14:37 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Nov 4 14:14:37 2021 -0500
lvm2-pvscan: include --autoactivation event
in the pvscan --cache -aay command so that the use
of the command for event activation is explicit.
---
scripts/lvm2-pvscan.service.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/lvm2-pvscan.service.in b/scripts/lvm2-pvscan.service.in
index 09753e8c9..93749f7a7 100644
--- a/scripts/lvm2-pvscan.service.in
+++ b/scripts/lvm2-pvscan.service.in
@@ -10,5 +10,5 @@ Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart=@SBINDIR@/lvm pvscan --cache --activate ay %i
+ExecStart=@SBINDIR@/lvm pvscan --cache --activate ay --autoactivation event %i
ExecStop=@SBINDIR@/lvm pvscan --cache %i
2 years, 5 months
main - move code from pvscan.c to online.c
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f40fd88374fe1e91123...
Commit: f40fd88374fe1e911233e5a4fc79223d97decde0
Parent: d558b3ad7e6086480075b3bf750eba0ee66c78ec
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Nov 3 16:02:38 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Nov 4 11:09:29 2021 -0500
move code from pvscan.c to online.c
related to managing files in /run/lvm/pvs_online
and /run/lvm/vgs_online
---
lib/Makefile.in | 1 +
lib/commands/toolcontext.h | 1 +
lib/device/online.c | 306 ++++++++++++++++++++++++++++++++++++++
lib/device/online.h | 46 ++++++
lib/label/hints.c | 3 +-
tools/lvmcmdline.c | 4 +-
tools/pvscan.c | 360 ++++-----------------------------------------
tools/toollib.c | 1 +
tools/tools.h | 2 -
9 files changed, 384 insertions(+), 340 deletions(-)
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 8b3eac60a..e97f57a4d 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -40,6 +40,7 @@ SOURCES =\
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
+ device/online.c \
display/display.c \
error/errseg.c \
unknown/unknown.c \
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 0ae45ccc0..b3de65702 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -202,6 +202,7 @@ struct cmd_context {
unsigned ignore_device_name_mismatch:1; /* skip updating devices file names */
unsigned backup_disabled:1; /* skip repeated debug message */
unsigned event_activation:1; /* whether event_activation is set */
+ unsigned udevoutput:1;
/*
* Devices and filtering.
diff --git a/lib/device/online.c b/lib/device/online.c
new file mode 100644
index 000000000..28e97d9fe
--- /dev/null
+++ b/lib/device/online.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2021 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "base/memory/zalloc.h"
+#include "lib/misc/lib.h"
+#include "lib/commands/toolcontext.h"
+#include "lib/device/device.h"
+#include "lib/device/device_id.h"
+#include "lib/device/online.h"
+
+#include <dirent.h>
+
+static char *_vgname_in_pvid_file_buf(char *buf)
+{
+ char *p, *n;
+
+ /*
+ * file contains:
+ * <major>:<minor>\n
+ * vg:<vgname>\n\0
+ */
+
+ if (!(p = strchr(buf, '\n')))
+ return NULL;
+
+ p++; /* skip \n */
+
+ if (*p && !strncmp(p, "vg:", 3)) {
+ if ((n = strchr(p, '\n')))
+ *n = '\0';
+ return p + 3;
+ }
+ return NULL;
+}
+
+#define MAX_PVID_FILE_SIZE 512
+
+int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
+{
+ char buf[MAX_PVID_FILE_SIZE] = { 0 };
+ char *name;
+ int fd, rv;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ log_warn("Failed to open %s", path);
+ return 0;
+ }
+
+ rv = read(fd, buf, sizeof(buf) - 1);
+ if (close(fd))
+ log_sys_debug("close", path);
+ if (!rv || rv < 0) {
+ log_warn("No info in %s", path);
+ return 0;
+ }
+ buf[rv] = 0; /* \0 terminated buffer */
+
+ if (sscanf(buf, "%d:%d", major, minor) != 2) {
+ log_warn("No device numbers in %s", path);
+ return 0;
+ }
+
+ /* vgname points to an offset in buf */
+ if ((name = _vgname_in_pvid_file_buf(buf)))
+ strncpy(vgname, name, NAME_LEN);
+ else
+ log_debug("No vgname in %s", path);
+
+ return 1;
+}
+
+/*
+ * When a PV goes offline, remove the vg online file for that VG
+ * (even if other PVs for the VG are still online). This means
+ * that the vg will be activated again when it becomes complete.
+ */
+
+void online_vg_file_remove(const char *vgname)
+{
+ char path[PATH_MAX];
+
+ if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
+ log_error("Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
+ return;
+ }
+
+ log_debug("Unlink vg online: %s", path);
+
+ if (unlink(path) && (errno != ENOENT))
+ log_sys_debug("unlink", path);
+}
+
+int online_vg_file_create(struct cmd_context *cmd, const char *vgname)
+{
+ char path[PATH_MAX];
+ int fd;
+
+ if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
+ log_error_pvscan(cmd, "Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
+ return 0;
+ }
+
+ log_debug("Create vg online: %s", path);
+
+ fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ log_debug("Failed to create %s: %d", path, errno);
+ return 0;
+ }
+
+ /* We don't care about syncing, these files are not even persistent. */
+
+ if (close(fd))
+ log_sys_debug("close", path);
+
+ return 1;
+}
+
+int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
+{
+ char path[PATH_MAX];
+ char buf[MAX_PVID_FILE_SIZE] = { 0 };
+ char file_vgname[NAME_LEN];
+ int file_major = 0, file_minor = 0;
+ int major, minor;
+ int fd;
+ int rv;
+ int len;
+ int len1 = 0;
+ int len2 = 0;
+
+ major = (int)MAJOR(dev->dev);
+ minor = (int)MINOR(dev->dev);
+
+ if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, dev->pvid) < 0) {
+ log_error_pvscan(cmd, "Path %s/%s is too long.", PVS_ONLINE_DIR, dev->pvid);
+ return 0;
+ }
+
+ if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
+ log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
+ return 0;
+ }
+
+ if (vgname) {
+ if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
+ log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
+ /* can still continue without vgname */
+ len2 = 0;
+ }
+ }
+
+ len = len1 + len2;
+
+ log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(dev));
+
+ fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ if (errno == EEXIST)
+ goto check_duplicate;
+ log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
+ return 0;
+ }
+
+ while (len > 0) {
+ rv = write(fd, buf, len);
+ if (rv < 0) {
+ /* file exists so it still works in part */
+ log_warn("Cannot write online file for %s to %s error %d",
+ dev_name(dev), path, errno);
+ if (close(fd))
+ log_sys_debug("close", path);
+ return 1;
+ }
+ len -= rv;
+ }
+
+ /* We don't care about syncing, these files are not even persistent. */
+
+ if (close(fd))
+ log_sys_debug("close", path);
+
+ return 1;
+
+check_duplicate:
+
+ /*
+ * If a PVID online file already exists for this PVID, check if the
+ * file contains a different device number, and if so we may have a
+ * duplicate PV.
+ *
+ * FIXME: disable autoactivation of the VG somehow?
+ * The VG may or may not already be activated when a dupicate appears.
+ * Perhaps write a new field in the pv online or vg online file?
+ */
+
+ memset(file_vgname, 0, sizeof(file_vgname));
+
+ online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
+
+ if ((file_major == major) && (file_minor == minor)) {
+ log_debug("Existing online file for %d:%d", major, minor);
+ return 1;
+ }
+
+ /* Don't know how vgname might not match, but it's not good so fail. */
+
+ if ((file_major != major) || (file_minor != minor))
+ log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
+ dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
+
+ if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
+ log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
+ dev_name(dev), vgname, file_vgname);
+
+ return 0;
+}
+
+int online_pvid_file_exists(const char *pvid)
+{
+ char path[PATH_MAX] = { 0 };
+ struct stat buf;
+ int rv;
+
+ if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid) < 0) {
+ log_debug(INTERNAL_ERROR "Path %s/%s is too long.", PVS_ONLINE_DIR, pvid);
+ return 0;
+ }
+
+ log_debug("Check pv online: %s", path);
+
+ rv = stat(path, &buf);
+ if (!rv) {
+ log_debug("Check pv online %s: yes", pvid);
+ return 1;
+ }
+ log_debug("Check pv online %s: no", pvid);
+ return 0;
+}
+
+void online_dir_setup(struct cmd_context *cmd)
+{
+ struct stat st;
+ int rv;
+
+ if (!stat(DEFAULT_RUN_DIR, &st))
+ goto do_pvs;
+
+ log_debug("Creating run_dir.");
+ dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
+ rv = mkdir(DEFAULT_RUN_DIR, 0755);
+ dm_prepare_selinux_context(NULL, 0);
+
+ if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
+ log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
+
+do_pvs:
+ if (!stat(PVS_ONLINE_DIR, &st))
+ goto do_vgs;
+
+ log_debug("Creating pvs_online_dir.");
+ dm_prepare_selinux_context(PVS_ONLINE_DIR, S_IFDIR);
+ rv = mkdir(PVS_ONLINE_DIR, 0755);
+ dm_prepare_selinux_context(NULL, 0);
+
+ if ((rv < 0) && stat(PVS_ONLINE_DIR, &st))
+ log_error_pvscan(cmd, "Failed to create %s %d", PVS_ONLINE_DIR, errno);
+
+do_vgs:
+ if (!stat(VGS_ONLINE_DIR, &st))
+ goto do_lookup;
+
+ log_debug("Creating vgs_online_dir.");
+ dm_prepare_selinux_context(VGS_ONLINE_DIR, S_IFDIR);
+ rv = mkdir(VGS_ONLINE_DIR, 0755);
+ dm_prepare_selinux_context(NULL, 0);
+
+ if ((rv < 0) && stat(VGS_ONLINE_DIR, &st))
+ log_error_pvscan(cmd, "Failed to create %s %d", VGS_ONLINE_DIR, errno);
+
+do_lookup:
+ if (!stat(PVS_LOOKUP_DIR, &st))
+ return;
+
+ log_debug("Creating pvs_lookup_dir.");
+ dm_prepare_selinux_context(PVS_LOOKUP_DIR, S_IFDIR);
+ rv = mkdir(PVS_LOOKUP_DIR, 0755);
+ dm_prepare_selinux_context(NULL, 0);
+
+ if ((rv < 0) && stat(PVS_LOOKUP_DIR, &st))
+ log_error_pvscan(cmd, "Failed to create %s %d", PVS_LOOKUP_DIR, errno);
+
+
+}
diff --git a/lib/device/online.h b/lib/device/online.h
new file mode 100644
index 000000000..0a5076f7d
--- /dev/null
+++ b/lib/device/online.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ONLINE_H
+#define _ONLINE_H
+
+/*
+ * Avoid a duplicate pvscan[%d] prefix when logging to the journal.
+ * FIXME: this should probably replace if (udevoutput) with
+ * if (log_journal & LOG_JOURNAL_OUTPUT)
+ */
+#define log_print_pvscan(cmd, fmt, args...) \
+do \
+ if (cmd->udevoutput) \
+ log_print(fmt, ##args); \
+ else \
+ log_print("pvscan[%d] " fmt, getpid(), ##args); \
+while (0)
+
+#define log_error_pvscan(cmd, fmt, args...) \
+do \
+ if (cmd->udevoutput) \
+ log_error(fmt, ##args); \
+ else \
+ log_error("pvscan[%d] " fmt, getpid(), ##args); \
+while (0)
+
+int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
+int online_vg_file_create(struct cmd_context *cmd, const char *vgname);
+void online_vg_file_remove(const char *vgname);
+int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname);
+int online_pvid_file_exists(const char *pvid);
+void online_dir_setup(struct cmd_context *cmd);
+
+#endif
diff --git a/lib/label/hints.c b/lib/label/hints.c
index c84bd1f1c..85e5ab1cb 100644
--- a/lib/label/hints.c
+++ b/lib/label/hints.c
@@ -146,6 +146,7 @@
#include "lib/label/hints.h"
#include "lib/device/dev-type.h"
#include "lib/device/device_id.h"
+#include "lib/device/online.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -156,8 +157,6 @@
#include <sys/file.h>
#include <sys/sysmacros.h>
-int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
-
static const char *_hints_file = DEFAULT_RUN_DIR "/hints";
static const char *_nohints_file = DEFAULT_RUN_DIR "/nohints";
static const char *_newhints_file = DEFAULT_RUN_DIR "/newhints";
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 9cbeab91d..0f2c832ae 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -2393,8 +2393,10 @@ static void _reset_current_settings_to_default(struct cmd_context *cmd)
static void _get_current_output_settings_from_args(struct cmd_context *cmd)
{
- if (arg_is_set(cmd, udevoutput_ARG))
+ if (arg_is_set(cmd, udevoutput_ARG)) {
cmd->current_settings.suppress = 1;
+ cmd->udevoutput = 1;
+ }
if (arg_is_set(cmd, debug_ARG))
cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1);
diff --git a/tools/pvscan.c b/tools/pvscan.c
index d9607fdb6..c1f7fbe6d 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -18,11 +18,10 @@
#include "lib/cache/lvmcache.h"
#include "lib/metadata/metadata.h"
#include "lib/label/hints.h"
+#include "lib/device/online.h"
#include <dirent.h>
-int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
-
struct pvscan_params {
int new_pvs_found;
int pvs_found;
@@ -44,10 +43,6 @@ struct pvscan_aa_params {
*/
static struct volume_group *saved_vg;
-static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online";
-static const char *_vgs_online_dir = DEFAULT_RUN_DIR "/vgs_online";
-static const char *_pvs_lookup_dir = DEFAULT_RUN_DIR "/pvs_lookup";
-
static int _pvscan_display_pv(struct cmd_context *cmd,
struct physical_volume *pv,
struct pvscan_params *params)
@@ -181,93 +176,12 @@ out:
return ret;
}
-/*
- * Avoid a duplicate pvscan[%d] prefix when logging to the journal.
- * FIXME: this should probably replace if (udevoutput) with
- * if (log_journal & LOG_JOURNAL_OUTPUT)
- */
-#define log_print_pvscan(cmd, fmt, args...) \
-do \
- if (arg_is_set(cmd, udevoutput_ARG)) \
- log_print(fmt, ##args); \
- else \
- log_print("pvscan[%d] " fmt, getpid(), ##args); \
-while (0)
-
-#define log_error_pvscan(cmd, fmt, args...) \
-do \
- if (arg_is_set(cmd, udevoutput_ARG)) \
- log_error(fmt, ##args); \
- else \
- log_error("pvscan[%d] " fmt, getpid(), ##args); \
-while (0)
-
-static char *_vgname_in_pvid_file_buf(char *buf)
-{
- char *p, *n;
-
- /*
- * file contains:
- * <major>:<minor>\n
- * vg:<vgname>\n\0
- */
-
- if (!(p = strchr(buf, '\n')))
- return NULL;
-
- p++; /* skip \n */
-
- if (*p && !strncmp(p, "vg:", 3)) {
- if ((n = strchr(p, '\n')))
- *n = '\0';
- return p + 3;
- }
- return NULL;
-}
-
-#define MAX_PVID_FILE_SIZE 512
-
-int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
-{
- char buf[MAX_PVID_FILE_SIZE] = { 0 };
- char *name;
- int fd, rv;
-
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- log_warn("Failed to open %s", path);
- return 0;
- }
-
- rv = read(fd, buf, sizeof(buf) - 1);
- if (close(fd))
- log_sys_debug("close", path);
- if (!rv || rv < 0) {
- log_warn("No info in %s", path);
- return 0;
- }
- buf[rv] = 0; /* \0 terminated buffer */
-
- if (sscanf(buf, "%d:%d", major, minor) != 2) {
- log_warn("No device numbers in %s", path);
- return 0;
- }
-
- /* vgname points to an offset in buf */
- if ((name = _vgname_in_pvid_file_buf(buf)))
- strncpy(vgname, name, NAME_LEN);
- else
- log_debug("No vgname in %s", path);
-
- return 1;
-}
-
static void _lookup_file_remove(char *vgname)
{
char path[PATH_MAX];
- if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vgname) < 0) {
- log_error("Path %s/%s is too long.", _pvs_lookup_dir, vgname);
+ if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0) {
+ log_error("Path %s/%s is too long.", PVS_LOOKUP_DIR, vgname);
return;
}
@@ -277,27 +191,6 @@ static void _lookup_file_remove(char *vgname)
log_sys_debug("unlink", path);
}
-/*
- * When a PV goes offline, remove the vg online file for that VG
- * (even if other PVs for the VG are still online). This means
- * that the vg will be activated again when it becomes complete.
- */
-
-void online_vg_file_remove(const char *vgname)
-{
- char path[PATH_MAX];
-
- if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
- log_error("Path %s/%s is too long.", _vgs_online_dir, vgname);
- return;
- }
-
- log_debug("Unlink vg online: %s", path);
-
- if (unlink(path) && (errno != ENOENT))
- log_sys_debug("unlink", path);
-}
-
/*
* When a device goes offline we only know its major:minor, not its PVID.
* Since the dev isn't around, we can't read it to get its PVID, so we have to
@@ -316,7 +209,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
log_debug("Remove pv online devno %d:%d", major, minor);
- if (!(dir = opendir(_pvs_online_dir)))
+ if (!(dir = opendir(PVS_ONLINE_DIR)))
return;
while ((de = readdir(dir))) {
@@ -324,7 +217,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
continue;
memset(path, 0, sizeof(path));
- snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, de->d_name);
+ snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, de->d_name);
file_major = 0;
file_minor = 0;
@@ -344,7 +237,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
}
}
if (closedir(dir))
- log_sys_debug("closedir", _pvs_online_dir);
+ log_sys_debug("closedir", PVS_ONLINE_DIR);
}
static void _online_files_remove(const char *dirpath)
@@ -369,128 +262,6 @@ static void _online_files_remove(const char *dirpath)
log_sys_debug("closedir", dirpath);
}
-static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
-{
- char path[PATH_MAX];
- char buf[MAX_PVID_FILE_SIZE] = { 0 };
- char file_vgname[NAME_LEN];
- int file_major = 0, file_minor = 0;
- int major, minor;
- int fd;
- int rv;
- int len;
- int len1 = 0;
- int len2 = 0;
-
- major = (int)MAJOR(dev->dev);
- minor = (int)MINOR(dev->dev);
-
- if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, dev->pvid) < 0) {
- log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_online_dir, dev->pvid);
- return 0;
- }
-
- if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
- log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
- return 0;
- }
-
- if (vgname) {
- if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
- log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
- /* can still continue without vgname */
- len2 = 0;
- }
- }
-
- len = len1 + len2;
-
- log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(dev));
-
- fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
- if (fd < 0) {
- if (errno == EEXIST)
- goto check_duplicate;
- log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
- return 0;
- }
-
- while (len > 0) {
- rv = write(fd, buf, len);
- if (rv < 0) {
- /* file exists so it still works in part */
- log_warn("Cannot write online file for %s to %s error %d",
- dev_name(dev), path, errno);
- if (close(fd))
- log_sys_debug("close", path);
- return 1;
- }
- len -= rv;
- }
-
- /* We don't care about syncing, these files are not even persistent. */
-
- if (close(fd))
- log_sys_debug("close", path);
-
- return 1;
-
-check_duplicate:
-
- /*
- * If a PVID online file already exists for this PVID, check if the
- * file contains a different device number, and if so we may have a
- * duplicate PV.
- *
- * FIXME: disable autoactivation of the VG somehow?
- * The VG may or may not already be activated when a dupicate appears.
- * Perhaps write a new field in the pv online or vg online file?
- */
-
- memset(file_vgname, 0, sizeof(file_vgname));
-
- online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
-
- if ((file_major == major) && (file_minor == minor)) {
- log_debug("Existing online file for %d:%d", major, minor);
- return 1;
- }
-
- /* Don't know how vgname might not match, but it's not good so fail. */
-
- if ((file_major != major) || (file_minor != minor))
- log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
- dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
-
- if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
- log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
- dev_name(dev), vgname, file_vgname);
-
- return 0;
-}
-
-static int _online_pvid_file_exists(const char *pvid)
-{
- char path[PATH_MAX] = { 0 };
- struct stat buf;
- int rv;
-
- if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid) < 0) {
- log_debug(INTERNAL_ERROR "Path %s/%s is too long.", _pvs_online_dir, pvid);
- return 0;
- }
-
- log_debug("Check pv online: %s", path);
-
- rv = stat(path, &buf);
- if (!rv) {
- log_debug("Check pv online %s: yes", pvid);
- return 1;
- }
- log_debug("Check pv online %s: no", pvid);
- return 0;
-}
-
static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
{
char path[PATH_MAX];
@@ -498,8 +269,8 @@ static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
struct pv_list *pvl;
int fd;
- if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vg->name) < 0) {
- log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
+ if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vg->name) < 0) {
+ log_error_pvscan(cmd, "Path %s/%s is too long.", PVS_LOOKUP_DIR, vg->name);
return 0;
}
@@ -555,7 +326,7 @@ static void _lookup_file_count_pvid_files(FILE *fp, const char *vgname, int *pvs
continue;
}
- if (_online_pvid_file_exists((const char *)pvid))
+ if (online_pvid_file_exists((const char *)pvid))
(*pvs_online)++;
else
(*pvs_offline)++;
@@ -616,8 +387,8 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
*pvs_online = 0;
*pvs_offline = 0;
- if (!(dir = opendir(_pvs_lookup_dir))) {
- log_sys_debug("opendir", _pvs_lookup_dir);
+ if (!(dir = opendir(PVS_LOOKUP_DIR))) {
+ log_sys_debug("opendir", PVS_LOOKUP_DIR);
return 0;
}
@@ -629,8 +400,8 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
if (de->d_name[0] == '.')
continue;
- if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, de->d_name) < 0) {
- log_warn("WARNING: Path %s/%s is too long.", _pvs_lookup_dir, de->d_name);
+ if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, de->d_name) < 0) {
+ log_warn("WARNING: Path %s/%s is too long.", PVS_LOOKUP_DIR, de->d_name);
continue;
}
@@ -655,68 +426,13 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
log_sys_debug("fclose", path);
}
if (closedir(dir))
- log_sys_debug("closedir", _pvs_lookup_dir);
+ log_sys_debug("closedir", PVS_LOOKUP_DIR);
*vgname_out = vgname;
return (vgname) ? 1 : 0;
}
-static void _online_dir_setup(struct cmd_context *cmd)
-{
- struct stat st;
- int rv;
-
- if (!stat(DEFAULT_RUN_DIR, &st))
- goto do_pvs;
-
- log_debug("Creating run_dir.");
- dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
- rv = mkdir(DEFAULT_RUN_DIR, 0755);
- dm_prepare_selinux_context(NULL, 0);
-
- if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
- log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
-
-do_pvs:
- if (!stat(_pvs_online_dir, &st))
- goto do_vgs;
-
- log_debug("Creating pvs_online_dir.");
- dm_prepare_selinux_context(_pvs_online_dir, S_IFDIR);
- rv = mkdir(_pvs_online_dir, 0755);
- dm_prepare_selinux_context(NULL, 0);
-
- if ((rv < 0) && stat(_pvs_online_dir, &st))
- log_error_pvscan(cmd, "Failed to create %s %d", _pvs_online_dir, errno);
-
-do_vgs:
- if (!stat(_vgs_online_dir, &st))
- goto do_lookup;
-
- log_debug("Creating vgs_online_dir.");
- dm_prepare_selinux_context(_vgs_online_dir, S_IFDIR);
- rv = mkdir(_vgs_online_dir, 0755);
- dm_prepare_selinux_context(NULL, 0);
-
- if ((rv < 0) && stat(_vgs_online_dir, &st))
- log_error_pvscan(cmd, "Failed to create %s %d", _vgs_online_dir, errno);
-
-do_lookup:
- if (!stat(_pvs_lookup_dir, &st))
- return;
-
- log_debug("Creating pvs_lookup_dir.");
- dm_prepare_selinux_context(_pvs_lookup_dir, S_IFDIR);
- rv = mkdir(_pvs_lookup_dir, 0755);
- dm_prepare_selinux_context(NULL, 0);
-
- if ((rv < 0) && stat(_pvs_lookup_dir, &st))
- log_error_pvscan(cmd, "Failed to create %s %d", _pvs_lookup_dir, errno);
-
-
-}
-
static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs_offline)
{
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
@@ -727,7 +443,7 @@ static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs
dm_list_iterate_items(pvl, &vg->pvs) {
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
- if (_online_pvid_file_exists(pvid))
+ if (online_pvid_file_exists(pvid))
(*pvs_online)++;
else
(*pvs_offline)++;
@@ -758,32 +474,6 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_PROCESSED;
}
-static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname)
-{
- char path[PATH_MAX];
- int fd;
-
- if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
- log_error_pvscan(cmd, "Path %s/%s is too long.", _vgs_online_dir, vgname);
- return 0;
- }
-
- log_debug("Create vg online: %s", path);
-
- fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
- if (fd < 0) {
- log_debug("Failed to create %s: %d", path, errno);
- return 0;
- }
-
- /* We don't care about syncing, these files are not even persistent. */
-
- if (close(fd))
- log_sys_debug("close", path);
-
- return 1;
-}
-
/*
* This is a very unconventional way of doing things because
* we want to figure out which devices to read the VG from
@@ -843,7 +533,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
memset(path, 0, sizeof(path));
- snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
+ snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
file_major = 0;
file_minor = 0;
@@ -1072,7 +762,7 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
* to run the activation. The first to create the file will do it.
*/
dm_list_iterate_items_safe(sl, sl2, vgnames) {
- if (!_online_vg_file_create(cmd, sl->str)) {
+ if (!online_vg_file_create(cmd, sl->str)) {
log_print_pvscan(cmd, "VG %s skip autoactivation.", sl->str);
str_list_del(vgnames, sl->str);
continue;
@@ -1242,7 +932,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
continue;
}
- if (!_online_pvid_file_exists(pvid)) {
+ if (!online_pvid_file_exists(pvid)) {
log_debug("set_pv_devices_online vg %s pv %s no online file",
vg->name, pvid);
pvl->pv->status |= MISSING_PV;
@@ -1250,7 +940,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
}
memset(path, 0, sizeof(path));
- snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
+ snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
major = 0;
minor = 0;
@@ -1422,7 +1112,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
* Create file named for pvid to record this PV is online.
* The command creates/checks online files only when --cache is used.
*/
- if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
+ if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
release_vg(vg);
ret = 0;
@@ -1507,7 +1197,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
} else if (!do_check_complete) {
log_print("VG %s", vgname);
} else if (vg_complete) {
- if (do_vgonline && !_online_vg_file_create(cmd, vgname)) {
+ if (do_vgonline && !online_vg_file_create(cmd, vgname)) {
log_print("VG %s finished", vgname);
} else {
/*
@@ -1613,9 +1303,9 @@ static int _pvscan_cache_all(struct cmd_context *cmd, int argc, char **argv,
dm_list_init(&pvscan_devs);
- _online_files_remove(_pvs_online_dir);
- _online_files_remove(_vgs_online_dir);
- _online_files_remove(_pvs_lookup_dir);
+ _online_files_remove(PVS_ONLINE_DIR);
+ _online_files_remove(VGS_ONLINE_DIR);
+ _online_files_remove(PVS_LOOKUP_DIR);
unlink_searched_devnames(cmd);
@@ -1958,7 +1648,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
do_all = !argc && !devno_args;
- _online_dir_setup(cmd);
+ online_dir_setup(cmd);
if (do_all) {
if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames))
diff --git a/tools/toollib.c b/tools/toollib.c
index d6f48aad2..33b704134 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -17,6 +17,7 @@
#include "lib/format_text/format-text.h"
#include "lib/label/hints.h"
#include "lib/device/device_id.h"
+#include "lib/device/online.h"
#include <sys/stat.h>
#include <signal.h>
diff --git a/tools/tools.h b/tools/tools.h
index 182ff3af9..cd89e1692 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -295,6 +295,4 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle);
-void online_vg_file_remove(const char *vgname);
-
#endif
2 years, 5 months
main - vgchange -aay: optimize device scan using pvs_online files
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d558b3ad7e608648007...
Commit: d558b3ad7e6086480075b3bf750eba0ee66c78ec
Parent: 594f6ca97024fa23dfa852b6cc9da272877e1ced
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Nov 3 12:03:29 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Nov 4 11:08:38 2021 -0500
vgchange -aay: optimize device scan using pvs_online files
Port the old pvscan -aay scanning optimization to vgchange -aay.
The optimization uses pvs_online files created by pvscan --cache
to derive a list of devices to use when activating a VG. This
allows autoactivation of a VG to avoid scanning all devices, and
only scan the devices used by the VG itself. The optimization is
applied internally using the device hints interface.
The new option "--autoactivation event" is given to pvscan and
vgchange commands that are called by event activation. This
informs the command that it is being used for event activation,
so that it can apply checks and optimizations that are specific
to event activation. Those include:
- skipping the command if lvm.conf event_activation=0
- checking that a VG is complete before activating it
- using pvs_online files to limit device scanning
---
test/shell/vgchange-pvs-online.sh | 98 +++++++++++++++++++++++++++++++++++++++
tools/args.h | 6 +++
tools/command-lines.in | 8 ++--
tools/pvscan.c | 34 +++++++++++++-
tools/tools.h | 2 +-
tools/vgchange.c | 56 +++++++++++++++++++++-
udev/69-dm-lvm-metad.rules.in | 2 +-
udev/69-dm-lvm.rules.in | 4 +-
8 files changed, 199 insertions(+), 11 deletions(-)
diff --git a/test/shell/vgchange-pvs-online.sh b/test/shell/vgchange-pvs-online.sh
new file mode 100644
index 000000000..bdc481ced
--- /dev/null
+++ b/test/shell/vgchange-pvs-online.sh
@@ -0,0 +1,98 @@
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+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"/*
+}
+
+. lib/inittest
+
+aux prepare_devs 4
+
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3"
+pvcreate "$dev4"
+
+lvcreate -l1 -n $lv1 -an $vg1
+lvcreate -l1 -n $lv1 -an $vg2
+
+# With no pv online files, vgchange that uses online files
+# will find no PVs to activate from.
+
+_clear_online_files
+
+not vgchange -aay --autoactivation event $vg1
+not vgchange -aay --autoactivation event $vg2
+vgchange -aay --autoactivation event
+
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg2/$lv1 lv_active ""
+
+# incomplete vg will not be activated
+
+pvscan --cache "$dev1"
+vgchange -aay --autoactivation event $vg1
+# VG foo is incomplete
+check lv_field $vg1/$lv1 lv_active ""
+
+# complete vg is activated
+
+pvscan --cache "$dev3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+pvscan --cache "$dev2"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+
+vgchange -an $vg1
+vgchange -an $vg2
+
+# the same tests but using command options matching udev rule
+
+_clear_online_files
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev1"
+vgchange -aay --autoactivation event $vg1
+# VG foo is incomplete
+check lv_field $vg1/$lv1 lv_active ""
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev2"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+
+vgchange -an $vg1
+vgchange -an $vg2
+
+# with a full pvscan --cache
+
+_clear_online_files
+
+pvscan --cache
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg2/$lv1 lv_active ""
+vgchange -aay --autoactivation event $vg1
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg2/$lv1 lv_active "active"
+
+vgchange -an $vg1
+vgchange -an $vg2
+
+vgremove -f $vg1
+vgremove -f $vg2
+
diff --git a/tools/args.h b/tools/args.h
index 774ce33f4..2aed8afbb 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -87,6 +87,12 @@ arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0,
"which does not contain any newer settings for which LVM would\n"
"issue a warning message when checking the configuration.\n")
+arg(autoactivation_ARG, '\0', "autoactivation", string_VAL, 0, 0,
+ "Specify if autoactivation is being used from an event.\n"
+ "This allows the command to apply settings that are specific\n"
+ "to event activation, such as device scanning optimizations\n"
+ "using pvs_online files created by event-based pvscans.\n")
+
arg(setautoactivation_ARG, '\0', "setautoactivation", bool_VAL, 0, 0,
"Set the autoactivation property on a VG or LV.\n"
"Display the property with vgs or lvs \"-o autoactivation\".\n"
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 10b23e75d..d4691c686 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1642,14 +1642,15 @@ DESC: Record that a PV is online or offline.
pvscan --cache_long --activate ay
OO: --ignorelockingfailure, --reportformat ReportFmt,
---major Number, --minor Number, --noudevsync
+--major Number, --minor Number, --noudevsync, --autoactivation String
OP: PV|String ...
IO: --background
ID: pvscan_cache
DESC: Record that a PV is online and autoactivate the VG if complete.
pvscan --cache_long --listvg PV
-OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput
+OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput,
+--autoactivation String
ID: pvscan_cache
DESC: Record that a PV is online and list the VG using the PV.
@@ -1747,7 +1748,8 @@ DESC: Start or stop processing LV conversions.
vgchange --activate Active
OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit,
---readonly, --ignorelockingfailure, --monitor Bool, --poll Bool, OO_VGCHANGE
+--readonly, --ignorelockingfailure, --monitor Bool, --poll Bool,
+--autoactivation String, OO_VGCHANGE
OP: VG|Tag|Select ...
IO: --ignoreskippedcluster
ID: vgchange_activate
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 4f97e211c..d9607fdb6 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -750,7 +750,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
log_debug("pvscan autoactivating VG %s.", vg_name);
- if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
+ if (!vgchange_activate(cmd, vg, CHANGE_AAY, 1)) {
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++;
}
@@ -1038,7 +1038,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
log_debug("pvscan autoactivating VG %s.", vgname);
- if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
+ if (!vgchange_activate(cmd, vg, CHANGE_AAY, 1)) {
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++;
}
@@ -1869,12 +1869,35 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
return ret;
}
+static int _get_autoactivation(struct cmd_context *cmd, int event_activation, int *skip_command)
+{
+ const char *aa_str;
+
+ if (!(aa_str = arg_str_value(cmd, autoactivation_ARG, NULL)))
+ return 1;
+
+ if (strcmp(aa_str, "event")) {
+ log_print_pvscan(cmd, "Skip pvscan for unknown autoactivation value.");
+ *skip_command = 1;
+ return 1;
+ }
+
+ if (!event_activation) {
+ log_print_pvscan(cmd, "Skip pvscan for event with event_activation=0.");
+ *skip_command = 1;
+ return 1;
+ }
+
+ return 1;
+}
+
int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
{
struct pvscan_aa_params pp = { 0 };
struct dm_list complete_vgnames;
int do_activate = arg_is_set(cmd, activate_ARG);
int event_activation;
+ int skip_command = 0;
int devno_args = 0;
int do_all;
int ret;
@@ -1946,6 +1969,13 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
return ECMD_PROCESSED;
}
+
+ if (!_get_autoactivation(cmd, event_activation, &skip_command))
+ return_ECMD_FAILED;
+
+ if (skip_command)
+ return ECMD_PROCESSED;
+
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;
}
diff --git a/tools/tools.h b/tools/tools.h
index bc98fcb09..182ff3af9 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -228,7 +228,7 @@ int mirror_remove_missing(struct cmd_context *cmd,
int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
- activation_change_t activate);
+ activation_change_t activate, int vg_complete_to_activate);
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
diff --git a/tools/vgchange.c b/tools/vgchange.c
index e4b57dbd2..ee06c498c 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -19,6 +19,7 @@
struct vgchange_params {
int lock_start_count;
unsigned int lock_start_sanlock : 1;
+ unsigned int vg_complete_to_activate : 1;
};
/*
@@ -195,10 +196,11 @@ int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg
}
int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
- activation_change_t activate)
+ activation_change_t activate, int vg_complete_to_activate)
{
int lv_open, active, monitored = 0, r = 1;
const struct lv_list *lvl;
+ struct pv_list *pvl;
int do_activate = is_change_activating(activate);
/*
@@ -219,6 +221,15 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
return 1;
}
+ if (do_activate && vg_complete_to_activate) {
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ if (!pvl->pv->dev) {
+ log_print("VG %s is incomplete.", vg->name);
+ return 1;
+ }
+ }
+ }
+
/*
* Safe, since we never write out new metadata here. Required for
* partial activation to work.
@@ -647,6 +658,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
struct processing_handle *handle)
{
+ struct vgchange_params *vp = (struct vgchange_params *)handle->custom_handle;
int ret = ECMD_PROCESSED;
unsigned i;
activation_change_t activate;
@@ -701,7 +713,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
if (arg_is_set(cmd, activate_ARG)) {
activate = (activation_change_t) arg_uint_value(cmd, activate_ARG, 0);
- if (!vgchange_activate(cmd, vg, activate))
+ if (!vgchange_activate(cmd, vg, activate, vp->vg_complete_to_activate))
return_ECMD_FAILED;
} else if (arg_is_set(cmd, refresh_ARG)) {
/* refreshes the visible LVs (which starts polling) */
@@ -722,8 +734,38 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ret;
}
+static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command)
+{
+ const char *aa;
+
+ if (!(aa = arg_str_value(cmd, autoactivation_ARG, NULL)))
+ return 1;
+
+ if (strcmp(aa, "event")) {
+ log_print("Skip vgchange for unknown autoactivation value.");
+ *skip_command = 1;
+ return 1;
+ }
+
+ if (!find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
+ log_print("Skip vgchange for event and event_activation=0.");
+ *skip_command = 1;
+ return 1;
+ }
+
+ vp->vg_complete_to_activate = 1;
+
+ if (!arg_is_set(cmd, nohints_ARG))
+ cmd->hints_pvs_online = 1;
+ else
+ cmd->use_hints = 0;
+
+ return 1;
+}
+
int vgchange(struct cmd_context *cmd, int argc, char **argv)
{
+ struct vgchange_params vp = { 0 };
struct processing_handle *handle;
uint32_t flags = 0;
int ret;
@@ -837,6 +879,14 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
cmd->lockd_vg_enforce_sh = 1;
}
+ if (arg_is_set(cmd, autoactivation_ARG)) {
+ int skip_command = 0;
+ if (!_check_autoactivation(cmd, &vp, &skip_command))
+ return ECMD_FAILED;
+ if (skip_command)
+ return ECMD_PROCESSED;
+ }
+
if (update)
flags |= READ_FOR_UPDATE;
else if (arg_is_set(cmd, activate_ARG))
@@ -847,6 +897,8 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ handle->custom_handle = &vp;
+
ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_single);
destroy_processing_handle(cmd, handle);
diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in
index 78f506520..a2384f2af 100644
--- a/udev/69-dm-lvm-metad.rules.in
+++ b/udev/69-dm-lvm-metad.rules.in
@@ -121,6 +121,6 @@ LABEL="direct_pvscan"
# MD | | X | X* | |
# loop | | X | X* | |
# other | X | | X | | X
-RUN+="(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major $major --minor $minor", ENV{LVM_SCANNED}="1"
+RUN+="(LVM_EXEC)/lvm pvscan --cache --aay --autoactivation event --major $major --minor $minor", ENV{LVM_SCANNED}="1"
LABEL="lvm_end"
diff --git a/udev/69-dm-lvm.rules.in b/udev/69-dm-lvm.rules.in
index d6bf1e0e9..4f34b2cc2 100644
--- a/udev/69-dm-lvm.rules.in
+++ b/udev/69-dm-lvm.rules.in
@@ -79,8 +79,8 @@ ENV{SYSTEMD_READY}="1"
# 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_EXEC)/lvm vgchange -aay --nohints $env{LVM_VG_NAME_COMPLETE}"
+IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --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_EXEC)/lvm vgchange -aay --autoactivation event $env{LVM_VG_NAME_COMPLETE}"
GOTO="lvm_end"
LABEL="lvm_end"
2 years, 5 months