master - lvmdbusd: Change print statements to log_error
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=16b127259761da...
Commit: 16b127259761da212bc7ba6ab3c95b42fe0fe276
Parent: ca28ea88bedbc0ecb64e5579c1b3076b9a7cd533
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Mon Mar 21 17:24:04 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Mar 21 17:28:51 2016 -0500
lvmdbusd: Change print statements to log_error
Should not be using print() in the service code.
Signed-off-by: Tony Asleson <tasleson(a)redhat.com>
---
daemons/lvmdbusd/lvmdb.py | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/daemons/lvmdbusd/lvmdb.py b/daemons/lvmdbusd/lvmdb.py
index be37868..d14ae3b 100755
--- a/daemons/lvmdbusd/lvmdb.py
+++ b/daemons/lvmdbusd/lvmdb.py
@@ -16,7 +16,7 @@ import os
try:
from . import cmdhandler
- from .utils import log_debug
+ from .utils import log_debug, log_error
except SystemError:
import cmdhandler
from utils import log_debug
@@ -337,13 +337,13 @@ class DataStore(object):
rc.append(self.lvs[self.lv_full_name_to_uuid[s]])
return rc
except KeyError as ke:
- print("Key %s not found!" % (str(lv_names)))
- print("lv name to uuid lookup")
+ log_error("Key %s not found!" % (str(lv_names)))
+ log_error("lv name to uuid lookup")
for keys in sorted(self.lv_full_name_to_uuid.keys()):
- print("%s" % (keys))
- print("lvs entries by uuid")
+ log_error("%s" % (keys))
+ log_error("lvs entries by uuid")
for keys in sorted(self.lvs.keys()):
- print("%s" % (keys))
+ log_error("%s" % (keys))
raise ke
def pv_pe_segments(self, pv_uuid):
8 years, 1 month
master - lvmdbusd: Add lvm flight recorder
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ca28ea88bedbc0...
Commit: ca28ea88bedbc0ecb64e5579c1b3076b9a7cd533
Parent: a0c7875c547fb8a420d789271f5e6660210e749f
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Mon Mar 21 17:22:56 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Mar 21 17:28:51 2016 -0500
lvmdbusd: Add lvm flight recorder
To help out with debug, when an exception is thrown in the dbus service we
will dump all the information we have on the last 16 commands that were
executed along with the stack strace.
Signed-off-by: Tony Asleson <tasleson(a)redhat.com>
---
daemons/lvmdbusd/cfg.py | 3 ++
daemons/lvmdbusd/cmdhandler.py | 46 +++++++++++++++++++++++++++++++++++++--
daemons/lvmdbusd/request.py | 1 +
3 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/daemons/lvmdbusd/cfg.py b/daemons/lvmdbusd/cfg.py
index bde6a64..8aec8ae 100644
--- a/daemons/lvmdbusd/cfg.py
+++ b/daemons/lvmdbusd/cfg.py
@@ -78,3 +78,6 @@ load = None
# Global cached state
db = None
+
+# lvm flight recorder
+blackbox = None
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 370fb61..1522ebf 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -11,6 +11,7 @@ from subprocess import Popen, PIPE
import time
import threading
from itertools import chain
+import collections
try:
from . import cfg
@@ -28,13 +29,51 @@ total_count = 0
# We need to prevent different threads from using the same lvm shell
# at the same time.
-cmd_lock = threading.Lock()
+cmd_lock = threading.RLock()
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = None
+class LvmExecutionMeta(object):
+
+ def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
+ self.start = start
+ self.ended = ended
+ self.cmd = cmd
+ self.ec = ec
+ self.stdout_txt = stdout_txt
+ self.stderr_txt = stderr_txt
+
+ def __str__(self):
+ return "EC= %d for %s\n" \
+ "STARTED: %f, ENDED: %f\n" \
+ "STDOUT=%s\n" \
+ "STDERR=%s\n" % \
+ (self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
+ self.stderr_txt)
+
+
+class LvmFlightRecorder(object):
+
+ def __init__(self):
+ self.queue = collections.deque(maxlen=16)
+
+ def add(self, lvm_exec_meta):
+ self.queue.append(lvm_exec_meta)
+
+ def dump(self):
+ with cmd_lock:
+ log_error("LVM dbus flight recorder START")
+ for c in self.queue:
+ log_error(str(c))
+ log_error("LVM dbus flight recorder END")
+
+
+cfg.blackbox = LvmFlightRecorder()
+
+
def _debug_c(cmd, exit_code, out):
log_error('CMD= %s' % ' '.join(cmd))
log_error(("EC= %d" % exit_code))
@@ -105,9 +144,10 @@ def time_wrapper(command, debug=False):
with cmd_lock:
start = time.time()
results = _t_call(command, debug)
- total_time += (time.time() - start)
+ ended = time.time()
+ total_time += (ended - start)
total_count += 1
-
+ cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index cf258f1..02f8c88 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -69,6 +69,7 @@ class RequestEntry(object):
# have gotten a job by the time we hit an error
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
+ cfg.blackbox.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)
8 years, 1 month
master - lvmdbusd: Allow PV devices to be referenced by symlink(s)
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a0c7875c547fb8...
Commit: a0c7875c547fb8a420d789271f5e6660210e749f
Parent: 86e9d12b6f06c741ada66cd417f3fa82ea0364b6
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Mon Mar 21 17:19:38 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Mar 21 17:28:51 2016 -0500
lvmdbusd: Allow PV devices to be referenced by symlink(s)
See: https://bugzilla.redhat.com/show_bug.cgi?id=1318754
Signed-off-by: Tony Asleson <tasleson(a)redhat.com>
---
daemons/lvmdbusd/lvmdb.py | 6 ++++++
daemons/lvmdbusd/objectmanager.py | 31 +++++++++++++++++++++++--------
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/daemons/lvmdbusd/lvmdb.py b/daemons/lvmdbusd/lvmdb.py
index 132bee7..be37868 100755
--- a/daemons/lvmdbusd/lvmdb.py
+++ b/daemons/lvmdbusd/lvmdb.py
@@ -12,6 +12,7 @@
from collections import OrderedDict
import pprint as prettyprint
+import os
try:
from . import cmdhandler
@@ -309,6 +310,11 @@ class DataStore(object):
else:
rc = []
for s in pv_name:
+ # Ths user could be using a symlink instead of the actual
+ # block device, make sure we are using actual block device file
+ # if the pv name isn't in the lookup
+ if s not in self.pv_path_to_uuid:
+ s = os.path.realpath(s)
rc.append(self.pvs[self.pv_path_to_uuid[s]])
return rc
diff --git a/daemons/lvmdbusd/objectmanager.py b/daemons/lvmdbusd/objectmanager.py
index e2f1e0a..f28c5c8 100644
--- a/daemons/lvmdbusd/objectmanager.py
+++ b/daemons/lvmdbusd/objectmanager.py
@@ -11,6 +11,7 @@ import sys
import threading
import traceback
import dbus
+import os
from . import cfg
from .utils import log_debug
from .automatedproperties import AutomatedProperties
@@ -184,13 +185,13 @@ class ObjectManager(AutomatedProperties):
return self.get_object_by_path(self._id_to_object_path[lvm_id])
return None
- def _uuid_verify(self, path, lvm_id, uuid):
+ def _uuid_verify(self, path, uuid, lvm_id):
"""
Ensure uuid is present for a successful lvm_id lookup
NOTE: Internal call, assumes under object manager lock
:param path: Path to object we looked up
- :param lvm_id: lvm_id used to find object
:param uuid: lvm uuid to verify
+ :param lvm_id: lvm_id used to find object
:return: None
"""
# This gets called when we found an object based on lvm_id, ensure
@@ -200,6 +201,17 @@ class ObjectManager(AutomatedProperties):
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
+ def _return_lookup(self, uuid, lvm_identifier):
+ """
+ We found an identifier, so lets return the path to the found object
+ :param uuid: The lvm uuid
+ :param lvm_identifier: The lvm_id used to find object
+ :return:
+ """
+ path = self._id_to_object_path[lvm_identifier]
+ self._uuid_verify(path, uuid, lvm_identifier)
+ return path
+
def get_object_path_by_lvm_id(self, uuid, lvm_id, path_create=None,
gen_new=True):
"""
@@ -221,16 +233,19 @@ class ObjectManager(AutomatedProperties):
path = None
if lvm_id in self._id_to_object_path:
- path = self._id_to_object_path[lvm_id]
- self._uuid_verify(path, lvm_id, uuid)
- return path
+ self._return_lookup(uuid, lvm_id)
+
if "/" in lvm_id:
vg, lv = lvm_id.split("/", 1)
int_lvm_id = vg + "/" + ("[%s]" % lv)
if int_lvm_id in self._id_to_object_path:
- path = self._id_to_object_path[int_lvm_id]
- self._uuid_verify(path, int_lvm_id, uuid)
- return path
+ self._return_lookup(uuid, int_lvm_id)
+ elif lvm_id.startswith('/'):
+ # We could have a pv device path lookup that failed,
+ # lets try canonical form and try again.
+ canonical = os.path.realpath(lvm_id)
+ if canonical in self._id_to_object_path:
+ self._return_lookup(uuid, canonical)
if uuid and uuid in self._id_to_object_path:
# If we get here it indicates that we found the object, but
8 years, 1 month
master - lvmdbusd: Remove --udev in service file
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=86e9d12b6f06c7...
Commit: 86e9d12b6f06c741ada66cd417f3fa82ea0364b6
Parent: cc57cd39ab0e47a3e0fc6fc81c378c4d4d292093
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Mon Mar 21 10:18:18 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Mar 21 17:28:51 2016 -0500
lvmdbusd: Remove --udev in service file
With commit 2d5dc6512e10924ab68e6a139081d7121bc3f7d6 the dbus server
no longer needs to utilize udev to know when to update its internal
state.
Signed-off-by: Tony Asleson <tasleson(a)redhat.com>
---
scripts/lvm2_lvmdbusd_systemd_red_hat.service.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/scripts/lvm2_lvmdbusd_systemd_red_hat.service.in b/scripts/lvm2_lvmdbusd_systemd_red_hat.service.in
index d3ad870..64cec4e 100644
--- a/scripts/lvm2_lvmdbusd_systemd_red_hat.service.in
+++ b/scripts/lvm2_lvmdbusd_systemd_red_hat.service.in
@@ -5,7 +5,7 @@ Documentation=man:lvmdbusd(8)
[Service]
Type=dbus
BusName=com.redhat.lvmdbus1
-ExecStart=@sbindir@/lvmdbusd --udev
+ExecStart=@sbindir@/lvmdbusd
[Install]
WantedBy=multi-user.target
8 years, 1 month
master - tests: add vg-check-devs-used.sh
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=cc57cd39ab0e47...
Commit: cc57cd39ab0e47a3e0fc6fc81c378c4d4d292093
Parent: 8fad9b9e5d219861fc1f758216fb446cffe3817f
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Mon Mar 21 16:21:30 2016 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Mar 21 16:21:30 2016 +0100
tests: add vg-check-devs-used.sh
---
test/shell/vg-check-devs-used.sh | 24 ++++++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/test/shell/vg-check-devs-used.sh b/test/shell/vg-check-devs-used.sh
new file mode 100644
index 0000000..b368227
--- /dev/null
+++ b/test/shell/vg-check-devs-used.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 3 8
+
+vgcreate $vg $dev1 $dev2
+lvcreate -l100%FREE -n $lv $vg
+dd if="$dev1" of="$dev3" bs=1M
+pvs --config "devices/global_filter = [ \"a|$dev2|\", \"a|$dev3|\", \"r|.*|\" ]" 2>err
+grep "WARNING: Device mismatch detected for $vg/$lv which is accessing $dev1 instead of $dev3" err
+
+vgremove -ff $vg
8 years, 1 month
master - dev: be safer when reading sysfs properties
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8fad9b9e5d2198...
Commit: 8fad9b9e5d219861fc1f758216fb446cffe3817f
Parent: ca7bac53cf0b3b64bdfa375085fc1535589ab1eb
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Mon Mar 21 15:48:36 2016 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Mar 21 15:50:32 2016 +0100
dev: be safer when reading sysfs properties
Check if the value we read from sysfs is not blank and replace the '\n'
at the end only when needed ('\n' should usually be there for sysfs values,
but better check this).
---
lib/device/dev-cache.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 490cec3..d912dea 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -365,6 +365,7 @@ static int _add_alias(struct device *dev, const char *path)
static int _get_sysfs_value(const char *path, char *buf, size_t buf_size)
{
FILE *fp;
+ size_t len;
if (!(fp = fopen(path, "r"))) {
log_sys_error("fopen", path);
@@ -378,7 +379,13 @@ static int _get_sysfs_value(const char *path, char *buf, size_t buf_size)
return 0;
}
- buf[strlen(buf) - 1] = '\0';
+ if (!(len = strlen(buf))) {
+ log_error("_get_sysfs_value: %s: no value", path);
+ return 0;
+ }
+
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
if (fclose(fp))
log_sys_error("fclose", path);
8 years, 1 month
master - test: Turn on dbus test
by Marian Csontos
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ca7bac53cf0b3b...
Commit: ca7bac53cf0b3b64bdfa375085fc1535589ab1eb
Parent: f231bdb20bdc885460dfc49db744147bb1bc90da
Author: Marian Csontos <mcsontos(a)redhat.com>
AuthorDate: Tue Feb 23 09:00:35 2016 +0100
Committer: Marian Csontos <mcsontos(a)redhat.com>
CommitterDate: Mon Mar 21 15:22:58 2016 +0100
test: Turn on dbus test
(cherry picked from commit f1ea96c6c1dc6414169bda1a18cf14cd9ebb1493)
---
test/api/dbustest.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/test/api/dbustest.sh b/test/api/dbustest.sh
index 039689d..dd9b23d 100644
--- a/test/api/dbustest.sh
+++ b/test/api/dbustest.sh
@@ -17,7 +17,7 @@ SKIP_WITH_CLVMD=1
. lib/inittest
# Will default to skip until we can get this reviewed
-skip
+#skip
aux prepare_pvs 6
8 years, 1 month
master - metadata: use own mem pool to report PV device mismatch in VG
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f231bdb20bdc88...
Commit: f231bdb20bdc885460dfc49db744147bb1bc90da
Parent: 03b0a786403ad1762bfbbe354756a9b83ee6629c
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Mon Mar 21 14:38:49 2016 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Mar 21 14:39:11 2016 +0100
metadata: use own mem pool to report PV device mismatch in VG
---
lib/metadata/metadata.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 86fb7cd..2c5ede5 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4582,9 +4582,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
#define DEV_LIST_DELIM ", "
-static int _check_devs_used_correspond_with_lv(struct dm_list *list, struct logical_volume *lv)
+static int _check_devs_used_correspond_with_lv(struct dm_pool *mem, struct dm_list *list, struct logical_volume *lv)
{
- struct dm_pool *mem = lv->vg->vgmem;
struct device_list *dl;
int found_inconsistent = 0;
struct device *dev;
@@ -4657,6 +4656,7 @@ bad:
static int _check_devs_used_correspond_with_vg(struct volume_group *vg)
{
+ struct dm_pool *mem;
char vgid[ID_LEN + 1];
struct pv_list *pvl;
struct lv_list *lvl;
@@ -4689,10 +4689,17 @@ static int _check_devs_used_correspond_with_vg(struct volume_group *vg)
}
if (found_inconsistent) {
+ if (!(mem = dm_pool_create("vg_devs_check", 1024)))
+ return_0;
+
dm_list_iterate_items(lvl, &vg->lvs) {
- if (!_check_devs_used_correspond_with_lv(list, lvl->lv))
+ if (!_check_devs_used_correspond_with_lv(mem, list, lvl->lv)) {
+ dm_pool_destroy(mem);
return_0;
+ }
}
+
+ dm_pool_destroy(mem);
}
return 1;
8 years, 1 month
master - dev: detect mismatch between devices used and devices assumed for an LV
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=03b0a786403ad1...
Commit: 03b0a786403ad1762bfbbe354756a9b83ee6629c
Parent: 65d9f742f8e45caaa530e1eaf9f18bfd689af6f3
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Wed Mar 16 14:01:26 2016 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Mar 21 11:40:40 2016 +0100
dev: detect mismatch between devices used and devices assumed for an LV
It's possible for an LVM LV to use a device during activation which
then differs from device which LVM assumes based on metadata later on.
For example, such device mismatch can occur if LVM doesn't have
complete view of devices during activation or if filters are
misbehaving or they're incorrectly set during activation.
This patch adds code that can detect this mismatch by creating
VG UUID and LV UUID index while scanning devices for device cache.
The VG UUID index maps VG UUID to a device list. Each device in the
list has a device layered above as a holder which is an LVM LV device
and for which we know the VG UUID (and similarly for LV UUID index).
We can acquire VG and LV UUID by reading /sys/block/<dm_dev_name>/dm/uuid.
So these indices represent the actual state of PV device use in
the system by LVs and then we compare that to what LVM assumes
based on metadata.
For example:
[0] fedora/~ # lsblk /dev/sdq /dev/sdr /dev/sds /dev/sdt
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdq 65:0 0 104M 0 disk
|-vg-lvol0 253:2 0 200M 0 lvm
`-mpath_dev1 253:3 0 104M 0 mpath
sdr 65:16 0 104M 0 disk
`-mpath_dev1 253:3 0 104M 0 mpath
sds 65:32 0 104M 0 disk
|-vg-lvol0 253:2 0 200M 0 lvm
`-mpath_dev2 253:4 0 104M 0 mpath
sdt 65:48 0 104M 0 disk
`-mpath_dev2 253:4 0 104M 0 mpath
In this case the vg-lvol0 is mapped onto sdq and sds becauset this is
what was available and seen during activation. Then later on, sdr and
sdt appeared and mpath devices were created out of sdq+sdr (mpath_dev1)
and sds+sdt (mpath_dev2). Now, LVM assumes (correctly) that mpath_dev1
and mpath_dev2 are the PVs that should be used, not the mpath
components (sdq/sdr, sds/sdt).
[0] fedora/~ # pvs
Found duplicate PV xSUix1GJ2SK82ACFuKzFLAQi8xMfFxnO: using /dev/mapper/mpath_dev1 not /dev/sdq
Using duplicate PV /dev/mapper/mpath_dev1 from subsystem DM, replacing /dev/sdq
Found duplicate PV MvHyMVabtSqr33AbkUrobq1LjP8oiTRm: using /dev/mapper/mpath_dev2 not /dev/sds
Using duplicate PV /dev/mapper/mpath_dev2 from subsystem DM, ignoring /dev/sds
WARNING: Device mismatch detected for vg/lvol0 which is accessing /dev/sdq, /dev/sds instead of /dev/mapper/mpath_dev1, /dev/mapper/mpath_dev2.
PV VG Fmt Attr PSize PFree
/dev/mapper/mpath_dev1 vg lvm2 a-- 100.00m 0
/dev/mapper/mpath_dev2 vg lvm2 a-- 100.00m 0
---
WHATS_NEW | 1 +
lib/device/dev-cache.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++-
lib/device/dev-cache.h | 3 +
lib/device/device.h | 7 +-
lib/metadata/metadata.c | 119 ++++++++++++++++++++++
5 files changed, 385 insertions(+), 2 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index d096a52..0f81021 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.148 -
==================================
+ Detect and warn about mismatch between devices used and assumed for an LV.
Version 2.02.147 - 19th March 2016
==================================
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 47ae140..490cec3 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -17,6 +17,8 @@
#include "btree.h"
#include "config.h"
#include "toolcontext.h"
+#include "dm-ioctl.h" /* for DM_UUID_LEN */
+#include "lvm-string.h" /* for LVM's UUID_PREFIX */
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
@@ -38,6 +40,8 @@ struct dir_list {
static struct {
struct dm_pool *mem;
struct dm_hash_table *names;
+ struct dm_hash_table *vgid_index;
+ struct dm_hash_table *lvid_index;
struct btree *devices;
struct dm_regex *preferred_names_matcher;
const char *dev_dir;
@@ -358,6 +362,229 @@ static int _add_alias(struct device *dev, const char *path)
return 1;
}
+static int _get_sysfs_value(const char *path, char *buf, size_t buf_size)
+{
+ FILE *fp;
+
+ if (!(fp = fopen(path, "r"))) {
+ log_sys_error("fopen", path);
+ return 0;
+ }
+
+ if (!fgets(buf, buf_size, fp)) {
+ log_sys_error("fgets", path);
+ if (fclose(fp))
+ log_sys_error("fclose", path);
+ return 0;
+ }
+
+ buf[strlen(buf) - 1] = '\0';
+
+ if (fclose(fp))
+ log_sys_error("fclose", path);
+
+ return 1;
+}
+
+static int _get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
+{
+ char path[PATH_MAX];
+
+ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/uuid", dm_sysfs_dir(), major, minor) < 0) {
+ log_error("%d:%d: dm_snprintf failed for path to sysfs dm directory.", major, minor);
+ return 0;
+ }
+
+ return _get_sysfs_value(path, buf, buf_size);
+}
+
+static struct dm_list *_get_or_add_list_by_index_key(struct dm_hash_table *idx, const char *key)
+{
+ struct dm_list *list;
+
+ if ((list = dm_hash_lookup(idx, key)))
+ return list;
+
+ if (!(list = _zalloc(sizeof(*list)))) {
+ log_error("%s: failed to allocate device list for device cache index.", key);
+ return NULL;
+ }
+
+ dm_list_init(list);
+
+ if (!dm_hash_insert(idx, key, list)) {
+ log_error("%s: failed to insert device list to device cache index.", key);
+ return NULL;
+ }
+
+ return list;
+}
+
+static struct device *_get_device_for_sysfs_dev_name_using_devno(const char *dev_name)
+{
+ char path[PATH_MAX];
+ char buf[PATH_MAX];
+ int major, minor;
+
+ if (dm_snprintf(path, sizeof(path), "%sblock/%s/dev", dm_sysfs_dir(), dev_name) < 0) {
+ log_error("_get_device_for_non_dm_dev: %s: dm_snprintf failed", dev_name);
+ return NULL;
+ }
+
+ if (!_get_sysfs_value(path, buf, sizeof(buf)))
+ return_NULL;
+
+ if (sscanf(buf, "%d:%d", &major, &minor) != 2) {
+ log_error("_get_device_for_non_dm_dev: %s: failed to get major and minor number", dev_name);
+ return NULL;
+ }
+
+ return (struct device *) btree_lookup(_cache.devices, (uint32_t) MKDEV(major, minor));
+}
+
+#define NOT_LVM_UUID "-"
+
+static int _get_vgid_and_lvid_for_dev(struct device *dev)
+{
+ size_t lvm_prefix_len = strlen(UUID_PREFIX);
+ char uuid[DM_UUID_LEN];
+
+ if (!_get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
+ return_0;
+
+ if (strlen(uuid) == (2 * ID_LEN + 4) &&
+ !strncmp(uuid, UUID_PREFIX, lvm_prefix_len)) {
+ /* Separate VGID and LVID part from DM UUID. */
+ if (!(dev->vgid = dm_pool_strndup(_cache.mem, uuid + lvm_prefix_len, ID_LEN)) ||
+ !(dev->lvid = dm_pool_strndup(_cache.mem, uuid + lvm_prefix_len + ID_LEN, ID_LEN)))
+ return_0;
+ } else
+ dev->vgid = dev->lvid = NOT_LVM_UUID;
+
+ return 1;
+}
+
+static int _index_dev_by_vgid_and_lvid(struct device *dev)
+{
+ const char *devname = dev_name(dev);
+ char devpath[PATH_MAX];
+ char path[PATH_MAX];
+ DIR *d;
+ struct dirent *dirent;
+ struct device *holder_dev;
+ struct dm_list *vgid_list, *lvid_list;
+ struct device_list *dl_vgid, *dl_lvid;
+ int r = 0;
+
+ /* Get holders for device. */
+ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/holders/", dm_sysfs_dir(), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)) < 0) {
+ log_error("%s: dm_snprintf failed for path to holders directory.", devname);
+ return 0;
+ }
+
+ if (!(d = opendir(path))) {
+ if (errno == ENOENT) {
+ log_debug("%s: path does not exist, skipping", path);
+ return 1;
+ }
+ log_sys_error("opendir", path);
+ return 0;
+ }
+
+ /* Iterate over device's holders and look for LVs. */
+ while ((dirent = readdir(d))) {
+ if (!strcmp(".", dirent->d_name) ||
+ !strcmp("..", dirent->d_name))
+ continue;
+
+ if (dm_snprintf(devpath, sizeof(devpath), "%s%s", _cache.dev_dir, dirent->d_name) == -1) {
+ log_error("%s: dm_snprintf failed for holder %s device path.", devname, dirent->d_name);
+ goto out;
+ }
+
+ if (!(holder_dev = (struct device *) dm_hash_lookup(_cache.names, devpath))) {
+ /*
+ * Cope with situation where canonical /<dev_dir>/<dirent->d_name>
+ * does not exist, but some other node name or symlink exists in
+ * non-standard environments - someone renaming the nodes or using
+ * mknod with different dev names than actual kernel names.
+ * This looks up struct device by major:minor pair which we get
+ * by looking at /sys/block/<dirent->d_name>/dev sysfs attribute.
+ */
+ if (!(holder_dev = _get_device_for_sysfs_dev_name_using_devno(dirent->d_name))) {
+ log_error("%s: failed to find associated device structure for holder %s.", devname, devpath);
+ goto out;
+ }
+ }
+
+ /* We're only interested in a holder which is a DM device. */
+ if (!dm_is_dm_major(MAJOR(holder_dev->dev)))
+ continue;
+
+ /*
+ * And if it's a DM device, we're only interested in a holder which is an LVM device.
+ * Get the VG UUID and LV UUID if we don't have that already.
+ */
+ if (!holder_dev->vgid && !_get_vgid_and_lvid_for_dev(holder_dev))
+ goto_out;
+
+ if (*holder_dev->vgid == *NOT_LVM_UUID)
+ continue;
+
+ /*
+ * Do not add internal LV devices to index.
+ * If a device is internal, the holder has the same VG UUID as the device.
+ */
+ if (dm_is_dm_major(MAJOR(dev->dev))) {
+ if (!dev->vgid && !_get_vgid_and_lvid_for_dev(dev))
+ goto_out;
+
+ if (*dev->vgid != *NOT_LVM_UUID && !strcmp(holder_dev->vgid, dev->vgid))
+ continue;
+ }
+
+ if (!(vgid_list = _get_or_add_list_by_index_key(_cache.vgid_index, holder_dev->vgid)) ||
+ !(lvid_list = _get_or_add_list_by_index_key(_cache.lvid_index, holder_dev->lvid)))
+ goto_out;
+
+ /* Create dev list items for the holder device. */
+ if (!(dl_vgid = _zalloc(sizeof(*dl_vgid))) ||
+ !(dl_lvid = _zalloc(sizeof(*dl_lvid)))) {
+ log_error("%s: failed to allocate dev list item.", devname);
+ goto out;
+ }
+
+ dl_vgid->dev = dl_lvid->dev = dev;
+
+ /* Add dev list item to VGID device list if it's not there already. */
+ if (!(dev->flags & DEV_USED_FOR_LV))
+ dm_list_add(vgid_list, &dl_vgid->list);
+
+ /* Add dev list item to LVID device list. */
+ dm_list_add(lvid_list, &dl_lvid->list);
+
+ /* Mark device as used == also indexed in dev cache by VGID and LVID. */
+ dev->flags |= DEV_USED_FOR_LV;
+ }
+
+ r = 1;
+out:
+ if (closedir(d))
+ log_sys_error("closedir", path);
+
+ return r;
+}
+
+struct dm_list *dev_cache_get_dev_list_for_vgid(const char *vgid)
+{
+ return dm_hash_lookup(_cache.vgid_index, vgid);
+}
+
+struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid)
+{
+ return dm_hash_lookup(_cache.lvid_index, lvid);
+}
+
/*
* Either creates a new dev, or adds an alias to
* an existing dev.
@@ -570,6 +797,24 @@ bad:
return 0;
}
+static int _add_devs_to_index(void)
+{
+ struct btree_iter *iter = btree_first(_cache.devices);
+ struct device *dev;
+ int r = 1;
+
+ while (iter) {
+ dev = btree_get_data(iter);
+
+ if (!_index_dev_by_vgid_and_lvid(dev))
+ r = 0;
+
+ iter = btree_next(iter);
+ }
+
+ return r;
+}
+
static void _insert_dirs(struct dm_list *dirs)
{
struct dir_list *dl;
@@ -590,6 +835,8 @@ static void _insert_dirs(struct dm_list *dirs)
log_debug_devs("%s: Failed to insert devices to "
"device cache fully", dl->dir);
}
+
+ (void) _add_devs_to_index();
}
#else /* UDEV_SYNC_SUPPORT */
@@ -751,7 +998,9 @@ int dev_cache_init(struct cmd_context *cmd)
if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
return_0;
- if (!(_cache.names = dm_hash_create(128))) {
+ if (!(_cache.names = dm_hash_create(128)) ||
+ !(_cache.vgid_index = dm_hash_create(32)) ||
+ !(_cache.lvid_index = dm_hash_create(32))) {
dm_pool_destroy(_cache.mem);
_cache.mem = 0;
return_0;
@@ -825,6 +1074,12 @@ int dev_cache_exit(void)
if (_cache.names)
dm_hash_destroy(_cache.names);
+ if (_cache.vgid_index)
+ dm_hash_destroy(_cache.vgid_index);
+
+ if (_cache.lvid_index)
+ dm_hash_destroy(_cache.lvid_index);
+
memset(&_cache, 0, sizeof(_cache));
return (!num_open);
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 05911d4..d21f521 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -31,6 +31,9 @@ struct dev_filter {
unsigned use_count;
};
+struct dm_list *dev_cache_get_dev_list_for_vgid(const char *vgid);
+struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid);
+
/*
* The global device cache.
*/
diff --git a/lib/device/device.h b/lib/device/device.h
index fc5a5b9..aaa009f 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -28,6 +28,8 @@
#define DEV_O_DIRECT 0x00000020 /* Use O_DIRECT */
#define DEV_O_DIRECT_TESTED 0x00000040 /* DEV_O_DIRECT is reliable */
#define DEV_OPEN_FAILURE 0x00000080 /* Has last open failed? */
+#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
+#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
/*
* Support for external device info.
@@ -69,7 +71,10 @@ struct device {
struct dm_list open_list;
struct dev_ext ext;
- char pvid[ID_LEN + 1];
+ const char *vgid; /* if device is an LV */
+ const char *lvid; /* if device is an LV */
+
+ char pvid[ID_LEN + 1]; /* if device is a PV */
char _padding[7];
};
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index d04adb6..86fb7cd 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4580,6 +4580,124 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return correct_vg;
}
+#define DEV_LIST_DELIM ", "
+
+static int _check_devs_used_correspond_with_lv(struct dm_list *list, struct logical_volume *lv)
+{
+ struct dm_pool *mem = lv->vg->vgmem;
+ struct device_list *dl;
+ int found_inconsistent = 0;
+ struct device *dev;
+ struct lv_segment *seg;
+ uint32_t s;
+ char *used_devnames = NULL, *assumed_devnames = NULL;
+
+ if (!(list = dev_cache_get_dev_list_for_lvid(lv->lvid.s + ID_LEN)))
+ return 1;
+
+ dm_list_iterate_items(dl, list) {
+ dev = dl->dev;
+ if (!(dev->flags & DEV_ASSUMED_FOR_LV)) {
+ if (!found_inconsistent) {
+ dm_pool_begin_object(mem, 32);
+ found_inconsistent = 1;
+ } else
+ dm_pool_grow_object(mem, DEV_LIST_DELIM, sizeof(DEV_LIST_DELIM) - 1);
+ if (!dm_pool_grow_object(mem, dev_name(dev), 0))
+ goto_bad;
+ }
+ }
+
+ if (!found_inconsistent)
+ return 1;
+
+ dm_pool_grow_object(mem, "\0", 1);
+ used_devnames = dm_pool_end_object(mem);
+
+ found_inconsistent = 0;
+ dm_list_iterate_items(seg, &lv->segments) {
+ for (s = 0; s < seg->area_count; s++) {
+ if (seg_type(seg, s) == AREA_PV) {
+ if (!(dev = seg_dev(seg, s))) {
+ log_error("Couldn't find device for segment belonging to "
+ "%s/%s while checking used and assumed devices.",
+ lv->vg->name, lv->name);
+ goto bad;
+ }
+ if (!(dev->flags & DEV_USED_FOR_LV)) {
+ if (!found_inconsistent) {
+ dm_pool_begin_object(mem, 32);
+ found_inconsistent = 1;
+ } else {
+ dm_pool_grow_object(mem, DEV_LIST_DELIM, sizeof(DEV_LIST_DELIM) - 1);
+ }
+ if (!dm_pool_grow_object(mem, dev_name(dev), 0))
+ goto bad;
+ }
+ }
+ }
+ }
+
+ if (found_inconsistent) {
+ dm_pool_grow_object(mem, "\0", 1);
+ assumed_devnames = dm_pool_end_object(mem);
+ }
+
+ log_warn("WARNING: Device mismatch detected for %s/%s which is accessing %s instead of %s.",
+ lv->vg->name, lv->name, used_devnames, assumed_devnames);
+
+ /* This also frees assumed_devnames. */
+ dm_pool_free(mem, (void *) used_devnames);
+ return 1;
+bad:
+ if (found_inconsistent)
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+static int _check_devs_used_correspond_with_vg(struct volume_group *vg)
+{
+ char vgid[ID_LEN + 1];
+ struct pv_list *pvl;
+ struct lv_list *lvl;
+ struct dm_list *list;
+ struct device_list *dl;
+ int found_inconsistent = 0;
+
+ if (is_orphan_vg(vg->name))
+ return 1;
+
+ strncpy(vgid, (const char *) vg->id.uuid, sizeof(vgid));
+ vgid[ID_LEN] = '\0';
+
+ /* Mark all PVs in VG as used. */
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ if (is_missing_pv(pvl->pv))
+ continue;
+ pvl->pv->dev->flags |= DEV_ASSUMED_FOR_LV;
+ }
+
+ if (!(list = dev_cache_get_dev_list_for_vgid(vgid)))
+ return 1;
+
+ dm_list_iterate_items(dl, list) {
+ if (!(dl->dev->flags & DEV_OPEN_FAILURE) &&
+ !(dl->dev->flags & DEV_ASSUMED_FOR_LV)) {
+ found_inconsistent = 1;
+ break;
+ }
+ }
+
+ if (found_inconsistent) {
+ dm_list_iterate_items(lvl, &vg->lvs) {
+ if (!_check_devs_used_correspond_with_lv(list, lvl->lv))
+ return_0;
+ }
+ }
+
+ return 1;
+}
+
struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgname,
const char *vgid, uint32_t warn_flags, int *consistent)
{
@@ -4624,6 +4742,7 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
}
}
+ (void) _check_devs_used_correspond_with_vg(vg);
out:
if (!*consistent && (warn_flags & WARN_INCONSISTENT)) {
if (is_orphan_vg(vgname))
8 years, 1 month
master - device: add DEV_OPEN_FAILURE flag
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=65d9f742f8e45c...
Commit: 65d9f742f8e45caaa530e1eaf9f18bfd689af6f3
Parent: e58d24293f10b6e29825113cadab8aa70099a128
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu Mar 17 13:45:14 2016 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Mar 21 11:06:05 2016 +0100
device: add DEV_OPEN_FAILURE flag
DEV_OPEN_FAILURE flag is set if the most recent "open" for a device
failed and it's unset if any subsequent "open" succeeds.
---
lib/device/dev-io.c | 3 +++
lib/device/device.h | 1 +
2 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c
index f8b24bf..9bf6d2e 100644
--- a/lib/device/dev-io.c
+++ b/lib/device/dev-io.c
@@ -513,6 +513,8 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
log_sys_debug("open", name);
else
log_sys_error("open", name);
+
+ dev->flags |= DEV_OPEN_FAILURE;
return 0;
}
@@ -556,6 +558,7 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
+ dev->flags &= ~DEV_OPEN_FAILURE;
return 1;
}
diff --git a/lib/device/device.h b/lib/device/device.h
index 6b01fb6..fc5a5b9 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -27,6 +27,7 @@
#define DEV_OPENED_EXCL 0x00000010 /* Opened EXCL */
#define DEV_O_DIRECT 0x00000020 /* Use O_DIRECT */
#define DEV_O_DIRECT_TESTED 0x00000040 /* DEV_O_DIRECT is reliable */
+#define DEV_OPEN_FAILURE 0x00000080 /* Has last open failed? */
/*
* Support for external device info.
8 years, 1 month