|
|
146ac4 |
From e403c3953fe8664525ca85e2ecabbe13dc7a0ae7 Mon Sep 17 00:00:00 2001
|
|
|
146ac4 |
From: David Teigland <teigland@redhat.com>
|
|
|
146ac4 |
Date: Thu, 21 Feb 2019 15:53:36 -0600
|
|
|
146ac4 |
Subject: [PATCH 3/5] pvscan: autoactivate a VG once
|
|
|
146ac4 |
|
|
|
146ac4 |
When a VG has multiple PVs, and all those PVs come online
|
|
|
146ac4 |
at the same time, concurrent pvscans for each PV will all
|
|
|
146ac4 |
create the individual pvid files, and all will often see
|
|
|
146ac4 |
the VG is now complete. This causes each of the pvscan
|
|
|
146ac4 |
commands to think it should activate the VG, so there
|
|
|
146ac4 |
are multiple activations of the same VG. The vg lock
|
|
|
146ac4 |
serializes them, and only the first pvscan actually does
|
|
|
146ac4 |
the activation, but there is still a lot of extra overhead
|
|
|
146ac4 |
and time used by the other pvscans that attempt to
|
|
|
146ac4 |
activate the already active VG. This can lead to a backlog
|
|
|
146ac4 |
of pvscans and timeouts.
|
|
|
146ac4 |
|
|
|
146ac4 |
To fix this, this adds a new /run/lvm/vgs_online/ dir that
|
|
|
146ac4 |
works like the existing /run/lvm/pvs_online/ dir. Each pvscan
|
|
|
146ac4 |
that wants to activate a VG will first try to exlusively create
|
|
|
146ac4 |
the file vgs_online/<vgname>. Only the first pvscan will
|
|
|
146ac4 |
succeed, and that one will do the VG activation. The other
|
|
|
146ac4 |
pvscans will find the vgname file exists and will not do the
|
|
|
146ac4 |
activation step.
|
|
|
146ac4 |
|
|
|
146ac4 |
When a PV goes offline, the vgs_online file for the corresponding
|
|
|
146ac4 |
VG is removed. This allows the VG to be autoactivated again
|
|
|
146ac4 |
when the PV comes online again. This requires that the vgname be
|
|
|
146ac4 |
stored in the pvid files.
|
|
|
146ac4 |
---
|
|
|
146ac4 |
test/shell/pvscan-autoactivate.sh | 39 ++++---
|
|
|
146ac4 |
test/shell/pvscan-cache.sh | 20 +++-
|
|
|
146ac4 |
tools/pvscan.c | 214 ++++++++++++++++++++++++++++++++------
|
|
|
146ac4 |
3 files changed, 226 insertions(+), 47 deletions(-)
|
|
|
146ac4 |
|
|
|
146ac4 |
diff --git a/test/shell/pvscan-autoactivate.sh b/test/shell/pvscan-autoactivate.sh
|
|
|
146ac4 |
index cd360e9..419fb9b 100644
|
|
|
146ac4 |
--- a/test/shell/pvscan-autoactivate.sh
|
|
|
146ac4 |
+++ b/test/shell/pvscan-autoactivate.sh
|
|
|
146ac4 |
@@ -14,14 +14,15 @@ SKIP_WITH_LVMPOLLD=1
|
|
|
146ac4 |
|
|
|
146ac4 |
RUNDIR="/run"
|
|
|
146ac4 |
test -d "$RUNDIR" || RUNDIR="/var/run"
|
|
|
146ac4 |
-ONLINEDIR="$RUNDIR/lvm/pvs_online"
|
|
|
146ac4 |
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
|
|
|
146ac4 |
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
|
|
|
146ac4 |
|
|
|
146ac4 |
# FIXME: kills logic for running system
|
|
|
146ac4 |
-_clear_online() {
|
|
|
146ac4 |
+_clear_online_files() {
|
|
|
146ac4 |
# wait till udev is finished
|
|
|
146ac4 |
aux udev_wait
|
|
|
146ac4 |
- rm -f "$ONLINEDIR"/*
|
|
|
146ac4 |
- test -n "${1+varset}" || touch "$ONLINEDIR/foo"
|
|
|
146ac4 |
+ rm -f "$PVS_ONLINE_DIR"/*
|
|
|
146ac4 |
+ rm -f "$VGS_ONLINE_DIR"/*
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
. lib/inittest
|
|
|
146ac4 |
@@ -32,8 +33,9 @@ vgcreate $vg1 "$dev1" "$dev2"
|
|
|
146ac4 |
lvcreate -n $lv1 -l 4 -a n $vg1
|
|
|
146ac4 |
|
|
|
146ac4 |
# the first pvscan scans all devs
|
|
|
146ac4 |
-test -d "$ONLINEDIR" || mkdir -p "$ONLINEDIR"
|
|
|
146ac4 |
-_clear_online nofoo
|
|
|
146ac4 |
+test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
|
|
|
146ac4 |
+test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active "active"
|
|
|
146ac4 |
@@ -42,7 +44,7 @@ lvchange -an $vg1
|
|
|
146ac4 |
# the first pvscan scans all devs even when
|
|
|
146ac4 |
# only one device is specified
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online nofoo
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay "$dev1"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active "active"
|
|
|
146ac4 |
@@ -50,7 +52,8 @@ lvchange -an $vg1
|
|
|
146ac4 |
|
|
|
146ac4 |
# touch foo to disable first-pvscan case,
|
|
|
146ac4 |
# then check pvscan with no args scans all
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active "active"
|
|
|
146ac4 |
@@ -60,7 +63,8 @@ lvchange -an $vg1
|
|
|
146ac4 |
# then check that vg is activated only after
|
|
|
146ac4 |
# both devs appear separately
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay "$dev1"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active ""
|
|
|
146ac4 |
@@ -72,7 +76,8 @@ lvchange -an $vg1
|
|
|
146ac4 |
# then check that vg is activated when both
|
|
|
146ac4 |
# devs appear together
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay "$dev1" "$dev2"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active "active"
|
|
|
146ac4 |
@@ -92,7 +97,8 @@ lvcreate -n $lv1 -l 4 -a n $vg1
|
|
|
146ac4 |
# touch foo to disable first-pvscan case,
|
|
|
146ac4 |
# test case where dev with metadata appears first
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay "$dev2"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active ""
|
|
|
146ac4 |
@@ -104,7 +110,8 @@ lvchange -an $vg1
|
|
|
146ac4 |
# test case where dev without metadata
|
|
|
146ac4 |
# appears first which triggers scanning all
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay "$dev1"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active "active"
|
|
|
146ac4 |
@@ -115,7 +122,7 @@ lvchange -an $vg1
|
|
|
146ac4 |
# dev without metadata is scanned, but
|
|
|
146ac4 |
# first-pvscan case scans all devs
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online nofoo
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache -aay "$dev1"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active "active"
|
|
|
146ac4 |
@@ -125,7 +132,8 @@ lvchange -an $vg1
|
|
|
146ac4 |
# is online without the -aay option to
|
|
|
146ac4 |
# activate until after they are online
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache "$dev1"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active ""
|
|
|
146ac4 |
@@ -137,7 +145,8 @@ lvchange -an $vg1
|
|
|
146ac4 |
|
|
|
146ac4 |
# like previous
|
|
|
146ac4 |
|
|
|
146ac4 |
-_clear_online
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
+touch "$RUNDIR/lvm/pvs_online/foo"
|
|
|
146ac4 |
|
|
|
146ac4 |
pvscan --cache "$dev1"
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active ""
|
|
|
146ac4 |
diff --git a/test/shell/pvscan-cache.sh b/test/shell/pvscan-cache.sh
|
|
|
146ac4 |
index c272c6c..e0576f9 100644
|
|
|
146ac4 |
--- a/test/shell/pvscan-cache.sh
|
|
|
146ac4 |
+++ b/test/shell/pvscan-cache.sh
|
|
|
146ac4 |
@@ -13,6 +13,18 @@
|
|
|
146ac4 |
SKIP_WITH_LVMLOCKD=1
|
|
|
146ac4 |
SKIP_WITH_LVMPOLLD=1
|
|
|
146ac4 |
|
|
|
146ac4 |
+RUNDIR="/run"
|
|
|
146ac4 |
+test -d "$RUNDIR" || RUNDIR="/var/run"
|
|
|
146ac4 |
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
|
|
|
146ac4 |
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+_clear_online_files() {
|
|
|
146ac4 |
+ # wait till udev is finished
|
|
|
146ac4 |
+ aux udev_wait
|
|
|
146ac4 |
+ rm -f "$PVS_ONLINE_DIR"/*
|
|
|
146ac4 |
+ rm -f "$VGS_ONLINE_DIR"/*
|
|
|
146ac4 |
+}
|
|
|
146ac4 |
+
|
|
|
146ac4 |
. lib/inittest
|
|
|
146ac4 |
|
|
|
146ac4 |
aux prepare_pvs 2
|
|
|
146ac4 |
@@ -35,9 +47,12 @@ check lv_exists $vg1
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active ""
|
|
|
146ac4 |
|
|
|
146ac4 |
# Check that an LV cannot be activated by pvscan while VG is exported
|
|
|
146ac4 |
+vgchange -an $vg1
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
vgexport $vg1
|
|
|
146ac4 |
-not pvscan --cache -aay "$dev1"
|
|
|
146ac4 |
-not pvscan --cache -aay "$dev2"
|
|
|
146ac4 |
+pvscan --cache -aay "$dev1" || true
|
|
|
146ac4 |
+pvscan --cache -aay "$dev2" || true
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
vgimport $vg1
|
|
|
146ac4 |
check lv_exists $vg1
|
|
|
146ac4 |
check lv_field $vg1/$lv1 lv_active ""
|
|
|
146ac4 |
@@ -51,6 +66,7 @@ lvchange -an $vg1/$lv1
|
|
|
146ac4 |
# metadata which hasn't been updated for some
|
|
|
146ac4 |
# time and also since the MDA is marked as ignored,
|
|
|
146ac4 |
# it should really be *ignored*!
|
|
|
146ac4 |
+_clear_online_files
|
|
|
146ac4 |
pvchange --metadataignore y "$dev1"
|
|
|
146ac4 |
aux disable_dev "$dev2"
|
|
|
146ac4 |
pvscan --cache
|
|
|
146ac4 |
diff --git a/tools/pvscan.c b/tools/pvscan.c
|
|
|
146ac4 |
index df46e04..465b3e6 100644
|
|
|
146ac4 |
--- a/tools/pvscan.c
|
|
|
146ac4 |
+++ b/tools/pvscan.c
|
|
|
146ac4 |
@@ -36,6 +36,9 @@ struct pvscan_aa_params {
|
|
|
146ac4 |
unsigned int activate_errors;
|
|
|
146ac4 |
};
|
|
|
146ac4 |
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online";
|
|
|
146ac4 |
+static const char *_vgs_online_dir = DEFAULT_RUN_DIR "/vgs_online";
|
|
|
146ac4 |
static const char *_online_file = DEFAULT_RUN_DIR "/pvs_online_lock";
|
|
|
146ac4 |
static int _online_fd = -1;
|
|
|
146ac4 |
|
|
|
146ac4 |
@@ -227,7 +230,51 @@ out:
|
|
|
146ac4 |
return ret;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
-static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online";
|
|
|
146ac4 |
+static char *_vgname_in_pvid_file_buf(char *buf)
|
|
|
146ac4 |
+{
|
|
|
146ac4 |
+ char *p, *n;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ /*
|
|
|
146ac4 |
+ * file contains:
|
|
|
146ac4 |
+ * <major>:<minor>\n
|
|
|
146ac4 |
+ * vg:<vgname>\n\0
|
|
|
146ac4 |
+ */
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (!(p = strchr(buf, '\n')))
|
|
|
146ac4 |
+ return NULL;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ p++; /* skip \n */
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (*p && !strncmp(p, "vg:", 3)) {
|
|
|
146ac4 |
+ if ((n = strchr(p, '\n')))
|
|
|
146ac4 |
+ *n = '\0';
|
|
|
146ac4 |
+ return p + 3;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+ return NULL;
|
|
|
146ac4 |
+}
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+#define MAX_PVID_FILE_SIZE 512
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+/*
|
|
|
146ac4 |
+ * When a PV goes offline, remove the vg online file for that VG
|
|
|
146ac4 |
+ * (even if other PVs for the VG are still online). This means
|
|
|
146ac4 |
+ * that the vg will be activated again when it becomes complete.
|
|
|
146ac4 |
+ */
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+static void _online_vg_file_remove(const char *vgname)
|
|
|
146ac4 |
+{
|
|
|
146ac4 |
+ char path[PATH_MAX];
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
|
|
|
146ac4 |
+ log_error("Path %s/%s is too long.", _vgs_online_dir, vgname);
|
|
|
146ac4 |
+ return;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ log_debug("Unlink vg online: %s", path);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (unlink(path))
|
|
|
146ac4 |
+ log_sys_debug("unlink", path);
|
|
|
146ac4 |
+}
|
|
|
146ac4 |
|
|
|
146ac4 |
/*
|
|
|
146ac4 |
* When a device goes offline we only know its major:minor, not its PVID.
|
|
|
146ac4 |
@@ -240,8 +287,9 @@ static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online";
|
|
|
146ac4 |
static void _online_pvid_file_remove_devno(int major, int minor)
|
|
|
146ac4 |
{
|
|
|
146ac4 |
char path[PATH_MAX];
|
|
|
146ac4 |
- char buf[32];
|
|
|
146ac4 |
- char buf_in[32];
|
|
|
146ac4 |
+ char buf[MAX_PVID_FILE_SIZE];
|
|
|
146ac4 |
+ char buf_in[MAX_PVID_FILE_SIZE];
|
|
|
146ac4 |
+ char *vgname = NULL;
|
|
|
146ac4 |
DIR *dir;
|
|
|
146ac4 |
struct dirent *de;
|
|
|
146ac4 |
int fd, rv;
|
|
|
146ac4 |
@@ -267,6 +315,8 @@ static void _online_pvid_file_remove_devno(int major, int minor)
|
|
|
146ac4 |
continue;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
+ memset(buf_in, 0, sizeof(buf_in));
|
|
|
146ac4 |
+
|
|
|
146ac4 |
rv = read(fd, buf_in, sizeof(buf_in));
|
|
|
146ac4 |
if (close(fd))
|
|
|
146ac4 |
log_sys_debug("close", path);
|
|
|
146ac4 |
@@ -276,9 +326,16 @@ static void _online_pvid_file_remove_devno(int major, int minor)
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
if (!strncmp(buf, buf_in, strlen(buf))) {
|
|
|
146ac4 |
- log_debug("Unlink pv online %s %s", buf, path);
|
|
|
146ac4 |
+ log_debug("Unlink pv online %s", path);
|
|
|
146ac4 |
if (unlink(path))
|
|
|
146ac4 |
log_sys_debug("unlink", path);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ /* vgname points to an offset in buf_in */
|
|
|
146ac4 |
+ if ((vgname = _vgname_in_pvid_file_buf(buf_in)))
|
|
|
146ac4 |
+ _online_vg_file_remove(vgname);
|
|
|
146ac4 |
+ else
|
|
|
146ac4 |
+ log_debug("No vgname in pvid file");
|
|
|
146ac4 |
+
|
|
|
146ac4 |
break;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
}
|
|
|
146ac4 |
@@ -286,13 +343,13 @@ static void _online_pvid_file_remove_devno(int major, int minor)
|
|
|
146ac4 |
log_sys_debug("closedir", _pvs_online_dir);
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
-static void _online_pvid_files_remove(void)
|
|
|
146ac4 |
+static void _online_files_remove(const char *dirpath)
|
|
|
146ac4 |
{
|
|
|
146ac4 |
char path[PATH_MAX];
|
|
|
146ac4 |
DIR *dir;
|
|
|
146ac4 |
struct dirent *de;
|
|
|
146ac4 |
|
|
|
146ac4 |
- if (!(dir = opendir(_pvs_online_dir)))
|
|
|
146ac4 |
+ if (!(dir = opendir(dirpath)))
|
|
|
146ac4 |
return;
|
|
|
146ac4 |
|
|
|
146ac4 |
while ((de = readdir(dir))) {
|
|
|
146ac4 |
@@ -300,22 +357,26 @@ static void _online_pvid_files_remove(void)
|
|
|
146ac4 |
continue;
|
|
|
146ac4 |
|
|
|
146ac4 |
memset(path, 0, sizeof(path));
|
|
|
146ac4 |
- snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, de->d_name);
|
|
|
146ac4 |
+ snprintf(path, sizeof(path), "%s/%s", dirpath, de->d_name);
|
|
|
146ac4 |
if (unlink(path))
|
|
|
146ac4 |
log_sys_debug("unlink", path);
|
|
|
146ac4 |
}
|
|
|
146ac4 |
if (closedir(dir))
|
|
|
146ac4 |
- log_sys_debug("closedir", _pvs_online_dir);
|
|
|
146ac4 |
+ log_sys_debug("closedir", dirpath);
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
-static int _online_pvid_file_create(struct device *dev)
|
|
|
146ac4 |
+static int _online_pvid_file_create(struct device *dev, const char *vgname)
|
|
|
146ac4 |
{
|
|
|
146ac4 |
char path[PATH_MAX];
|
|
|
146ac4 |
- char buf[32];
|
|
|
146ac4 |
+ char buf[MAX_PVID_FILE_SIZE];
|
|
|
146ac4 |
int major, minor;
|
|
|
146ac4 |
int fd;
|
|
|
146ac4 |
int rv;
|
|
|
146ac4 |
int len;
|
|
|
146ac4 |
+ int len1 = 0;
|
|
|
146ac4 |
+ int len2 = 0;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ memset(buf, 0, sizeof(buf));
|
|
|
146ac4 |
|
|
|
146ac4 |
major = (int)MAJOR(dev->dev);
|
|
|
146ac4 |
minor = (int)MINOR(dev->dev);
|
|
|
146ac4 |
@@ -325,16 +386,26 @@ static int _online_pvid_file_create(struct device *dev)
|
|
|
146ac4 |
return 0;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
- if ((len = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
|
|
|
146ac4 |
- log_error("Device %d:%d is too long.", major, minor);
|
|
|
146ac4 |
+ if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
|
|
|
146ac4 |
+ log_error("Cannot create online pv file for %d:%d.", major, minor);
|
|
|
146ac4 |
return 0;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
+ if (vgname) {
|
|
|
146ac4 |
+ if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
|
|
|
146ac4 |
+ log_warn("Incomplete online pv file for %d:%d vg %s.", major, minor, vgname);
|
|
|
146ac4 |
+ /* can still continue without vgname */
|
|
|
146ac4 |
+ len2 = 0;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ len = len1 + len2;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(dev));
|
|
|
146ac4 |
|
|
|
146ac4 |
fd = open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
|
|
|
146ac4 |
if (fd < 0) {
|
|
|
146ac4 |
- log_error("Failed to open %s: %d", path, errno);
|
|
|
146ac4 |
+ log_error("Failed to open create %s: %d", path, errno);
|
|
|
146ac4 |
return 0;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
@@ -377,20 +448,45 @@ static int _online_pvid_file_exists(const char *pvid)
|
|
|
146ac4 |
return 0;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
-static void _online_pvid_dir_setup(void)
|
|
|
146ac4 |
+static void _online_dir_setup(void)
|
|
|
146ac4 |
{
|
|
|
146ac4 |
struct stat st;
|
|
|
146ac4 |
int rv;
|
|
|
146ac4 |
|
|
|
146ac4 |
+ if (!stat(DEFAULT_RUN_DIR, &st))
|
|
|
146ac4 |
+ goto do_pvs;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ log_debug("Creating run_dir.");
|
|
|
146ac4 |
+ dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
|
|
|
146ac4 |
+ rv = mkdir(DEFAULT_RUN_DIR, 0755);
|
|
|
146ac4 |
+ dm_prepare_selinux_context(NULL, 0);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
|
|
|
146ac4 |
+ log_error("Failed to create %s %d", DEFAULT_RUN_DIR, errno);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+do_pvs:
|
|
|
146ac4 |
if (!stat(_pvs_online_dir, &st))
|
|
|
146ac4 |
- return;
|
|
|
146ac4 |
+ goto do_vgs;
|
|
|
146ac4 |
|
|
|
146ac4 |
+ log_debug("Creating pvs_online_dir.");
|
|
|
146ac4 |
dm_prepare_selinux_context(_pvs_online_dir, S_IFDIR);
|
|
|
146ac4 |
- rv = mkdir(_pvs_online_dir, 0777);
|
|
|
146ac4 |
+ rv = mkdir(_pvs_online_dir, 0755);
|
|
|
146ac4 |
+ dm_prepare_selinux_context(NULL, 0);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if ((rv < 0) && stat(_pvs_online_dir, &st))
|
|
|
146ac4 |
+ log_error("Failed to create %s %d", _pvs_online_dir, errno);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+do_vgs:
|
|
|
146ac4 |
+ if (!stat(_vgs_online_dir, &st))
|
|
|
146ac4 |
+ return;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ log_debug("Creating vgs_online_dir.");
|
|
|
146ac4 |
+ dm_prepare_selinux_context(_vgs_online_dir, S_IFDIR);
|
|
|
146ac4 |
+ rv = mkdir(_vgs_online_dir, 0755);
|
|
|
146ac4 |
dm_prepare_selinux_context(NULL, 0);
|
|
|
146ac4 |
|
|
|
146ac4 |
- if (rv < 0)
|
|
|
146ac4 |
- log_debug("Failed to create %s", _pvs_online_dir);
|
|
|
146ac4 |
+ if ((rv < 0) && stat(_vgs_online_dir, &st))
|
|
|
146ac4 |
+ log_error("Failed to create %s %d", _vgs_online_dir, errno);
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
static void _online_file_setup(void)
|
|
|
146ac4 |
@@ -401,8 +497,10 @@ static void _online_file_setup(void)
|
|
|
146ac4 |
if (!stat(_online_file, &st))
|
|
|
146ac4 |
return;
|
|
|
146ac4 |
|
|
|
146ac4 |
- if (!(fp = fopen(_online_file, "w")))
|
|
|
146ac4 |
+ if (!(fp = fopen(_online_file, "w"))) {
|
|
|
146ac4 |
+ log_error("Failed to create %s %d", _online_file, errno);
|
|
|
146ac4 |
return;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
if (fclose(fp))
|
|
|
146ac4 |
stack;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
@@ -442,11 +540,13 @@ static int _online_pv_found(struct cmd_context *cmd,
|
|
|
146ac4 |
* Create file named for pvid to record this PV is online.
|
|
|
146ac4 |
*/
|
|
|
146ac4 |
|
|
|
146ac4 |
- if (!_online_pvid_file_create(dev))
|
|
|
146ac4 |
+ if (!_online_pvid_file_create(dev, vg ? vg->name : NULL))
|
|
|
146ac4 |
return_0;
|
|
|
146ac4 |
|
|
|
146ac4 |
- if (!vg || !found_vgnames)
|
|
|
146ac4 |
+ if (!vg || !found_vgnames) {
|
|
|
146ac4 |
+ log_print("pvscan[%d] PV %s online.", getpid(), dev_name(dev));
|
|
|
146ac4 |
return 1;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
|
|
|
146ac4 |
/*
|
|
|
146ac4 |
* Check if all the PVs for this VG are online. This is only
|
|
|
146ac4 |
@@ -469,8 +569,13 @@ static int _online_pv_found(struct cmd_context *cmd,
|
|
|
146ac4 |
* in the VG, which means the VG is not yet complete.
|
|
|
146ac4 |
*/
|
|
|
146ac4 |
|
|
|
146ac4 |
- if (pvids_not_online)
|
|
|
146ac4 |
+ if (pvids_not_online) {
|
|
|
146ac4 |
+ log_print("pvscan[%d] PV %s online, VG %s incomplete (need %d).",
|
|
|
146ac4 |
+ getpid(), dev_name(dev), vg->name, pvids_not_online);
|
|
|
146ac4 |
return 1;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ log_print("pvscan[%d] PV %s online, VG %s is complete.", getpid(), dev_name(dev), vg->name);
|
|
|
146ac4 |
|
|
|
146ac4 |
/*
|
|
|
146ac4 |
* When all PVIDs from the VG are online, then add vgname to
|
|
|
146ac4 |
@@ -541,7 +646,7 @@ static int _online_pvscan_one(struct cmd_context *cmd, struct device *dev,
|
|
|
146ac4 |
log_debug("pvscan metadata from dev %s", dev_name(dev));
|
|
|
146ac4 |
|
|
|
146ac4 |
if (udev_dev_is_mpath_component(dev)) {
|
|
|
146ac4 |
- log_debug("Ignore multipath component for pvscan.");
|
|
|
146ac4 |
+ log_print("pvscan[%d] ignore multipath component %s.", getpid(), dev_name(dev));
|
|
|
146ac4 |
return 1;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
@@ -649,10 +754,37 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
|
|
|
146ac4 |
return ECMD_PROCESSED;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
+static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname)
|
|
|
146ac4 |
+{
|
|
|
146ac4 |
+ char path[PATH_MAX];
|
|
|
146ac4 |
+ int fd;
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
|
|
|
146ac4 |
+ log_error("Path %s/%s is too long.", _vgs_online_dir, vgname);
|
|
|
146ac4 |
+ return 0;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ log_debug("Create vg online: %s", path);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
|
|
|
146ac4 |
+ if (fd < 0) {
|
|
|
146ac4 |
+ log_debug("Failed to create %s: %d", path, errno);
|
|
|
146ac4 |
+ return 0;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ /* We don't care about syncing, these files are not even persistent. */
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (close(fd))
|
|
|
146ac4 |
+ log_sys_debug("close", path);
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ return 1;
|
|
|
146ac4 |
+}
|
|
|
146ac4 |
+
|
|
|
146ac4 |
static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
|
|
|
146ac4 |
struct dm_list *vgnames)
|
|
|
146ac4 |
{
|
|
|
146ac4 |
struct processing_handle *handle = NULL;
|
|
|
146ac4 |
+ struct dm_str_list *sl, *sl2;
|
|
|
146ac4 |
int ret;
|
|
|
146ac4 |
|
|
|
146ac4 |
if (dm_list_empty(vgnames)) {
|
|
|
146ac4 |
@@ -667,6 +799,27 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
|
|
|
146ac4 |
|
|
|
146ac4 |
handle->custom_handle = pp;
|
|
|
146ac4 |
|
|
|
146ac4 |
+ /*
|
|
|
146ac4 |
+ * For each complete vg that can be autoactivated, see if this
|
|
|
146ac4 |
+ * particular pvscan command should activate the vg. There can be
|
|
|
146ac4 |
+ * multiple concurrent pvscans for the same completed vg (when all the
|
|
|
146ac4 |
+ * PVs for the VG appear at once), and we want only one of the pvscans
|
|
|
146ac4 |
+ * to run the activation. The first to create the file will do it.
|
|
|
146ac4 |
+ */
|
|
|
146ac4 |
+ dm_list_iterate_items_safe(sl, sl2, vgnames) {
|
|
|
146ac4 |
+ if (!_online_vg_file_create(cmd, sl->str)) {
|
|
|
146ac4 |
+ log_print("pvscan[%d] VG %s skip autoactivation.", getpid(), sl->str);
|
|
|
146ac4 |
+ str_list_del(vgnames, sl->str);
|
|
|
146ac4 |
+ continue;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+ log_print("pvscan[%d] VG %s run autoactivation.", getpid(), sl->str);
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
+ if (dm_list_empty(vgnames)) {
|
|
|
146ac4 |
+ destroy_processing_handle(cmd, handle);
|
|
|
146ac4 |
+ return ECMD_PROCESSED;
|
|
|
146ac4 |
+ }
|
|
|
146ac4 |
+
|
|
|
146ac4 |
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, READ_FOR_UPDATE, 0, handle, _pvscan_aa_single);
|
|
|
146ac4 |
|
|
|
146ac4 |
destroy_processing_handle(cmd, handle);
|
|
|
146ac4 |
@@ -707,7 +860,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
|
|
146ac4 |
return EINVALID_CMD_LINE;
|
|
|
146ac4 |
}
|
|
|
146ac4 |
|
|
|
146ac4 |
- _online_pvid_dir_setup();
|
|
|
146ac4 |
+ _online_dir_setup();
|
|
|
146ac4 |
_online_file_setup();
|
|
|
146ac4 |
|
|
|
146ac4 |
if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_READ, NULL)) {
|
|
|
146ac4 |
@@ -721,8 +874,8 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
|
|
146ac4 |
if (!argc && !devno_args) {
|
|
|
146ac4 |
_lock_online(LOCK_EX, 0);
|
|
|
146ac4 |
log_verbose("pvscan all devices for requested refresh.");
|
|
|
146ac4 |
- _online_pvid_files_remove();
|
|
|
146ac4 |
- /* identify complete vgs, and only activate those vgs */
|
|
|
146ac4 |
+ _online_files_remove(_pvs_online_dir);
|
|
|
146ac4 |
+ _online_files_remove(_vgs_online_dir);
|
|
|
146ac4 |
_online_pvscan_all_devs(cmd, complete_vgnames, NULL);
|
|
|
146ac4 |
_unlock_online();
|
|
|
146ac4 |
goto activate;
|
|
|
146ac4 |
@@ -750,16 +903,17 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
|
|
146ac4 |
* In the non-init case, a VG with two PVs, where both PVs appear at once
|
|
|
146ac4 |
* two parallel pvscans for each PV create the pvid files for each PV in
|
|
|
146ac4 |
* parallel, then both pvscans see the vg has completed, and both pvscans
|
|
|
146ac4 |
- * activate the VG in parallel. The activations should be serialized by
|
|
|
146ac4 |
- * the VG lock.
|
|
|
146ac4 |
+ * activate the VG in parallel. The first pvscan to create the vgname
|
|
|
146ac4 |
+ * file in vgs_online will do the activation, any others will skip it.
|
|
|
146ac4 |
*/
|
|
|
146ac4 |
|
|
|
146ac4 |
_lock_online(LOCK_EX, 0);
|
|
|
146ac4 |
|
|
|
146ac4 |
if (_online_pvid_files_missing()) {
|
|
|
146ac4 |
log_verbose("pvscan all devices to initialize available PVs.");
|
|
|
146ac4 |
- _online_pvid_files_remove();
|
|
|
146ac4 |
- /* identify complete vgs, and only activate those vgs */
|
|
|
146ac4 |
+ _online_files_remove(_pvs_online_dir);
|
|
|
146ac4 |
+ _online_files_remove(_vgs_online_dir);
|
|
|
146ac4 |
+ cmd->pvscan_cache_single = 1;
|
|
|
146ac4 |
_online_pvscan_all_devs(cmd, complete_vgnames, NULL);
|
|
|
146ac4 |
_unlock_online();
|
|
|
146ac4 |
goto activate;
|
|
|
146ac4 |
--
|
|
|
146ac4 |
1.8.3.1
|
|
|
146ac4 |
|