Blob Blame History Raw
From 959a8703937f01161988221940d189acc4f7a796 Mon Sep 17 00:00:00 2001
From: Federico Simoncelli <fsimonce@redhat.com>
Date: Sun, 13 Jan 2013 16:21:55 +0200
Subject: [PATCH 17/22] udev: Race fix- load and trigger dev rule

The rule file is generated, yet not synch-loaded in memory, so a VM with
a direct lun fails to start.
This patch reloads the rules before triggering using the new private
udev functions - udevReloadRules() in supervdsmServer.py .
Also added a check in appropriateDevice() (hsm.py) to make sure the
mapping is indeed there.

Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=891300
Change-Id: If3b2008a3d9df2dcaf54190721c2dd9764338627
Signed-off-by: Lee Yarwood <lyarwood@redhat.com>
Signed-off-by: Vered Volansky <vvolansk@redhat.com>
Signed-off-by: Federico Simoncelli <fsimonce@redhat.com>
Reviewed-on: http://gerrit.ovirt.org/11410
Reviewed-by: Allon Mureinik <amureini@redhat.com>
---
 vdsm/storage/hsm.py     |  7 +++++++
 vdsm/supervdsmServer.py | 31 +++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index efb2749..62e9f74 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -67,6 +67,7 @@ import mount
 import dispatcher
 import supervdsm
 import storageServer
+from vdsm import utils
 
 GUID = "guid"
 NAME = "name"
@@ -87,6 +88,8 @@ SECTOR_SIZE = 512
 
 STORAGE_CONNECTION_DIR = os.path.join(constants.P_VDSM_RUN, "connections/")
 
+QEMU_READABLE_TIMEOUT = 30
+
 
 def public(f=None, **kwargs):
     if f is None:
@@ -2925,6 +2928,10 @@ class HSM:
         """
         supervdsm.getProxy().appropriateDevice(guid, thiefId)
         supervdsm.getProxy().udevTrigger(guid)
+        devPath = devicemapper.DMPATH_FORMAT % guid
+        utils.retry(partial(fileUtils.validateQemuReadable, devPath),
+                    expectedException=OSError,
+                    timeout=QEMU_READABLE_TIMEOUT)
 
     @public
     def inappropriateDevices(self, thiefId):
diff --git a/vdsm/supervdsmServer.py b/vdsm/supervdsmServer.py
index dc89218..833e91f 100755
--- a/vdsm/supervdsmServer.py
+++ b/vdsm/supervdsmServer.py
@@ -89,6 +89,10 @@ LOG_CONF_PATH = "/etc/vdsm/logger.conf"
 
 class _SuperVdsm(object):
 
+    UDEV_WITH_RELOAD_VERSION = 181
+
+    log = logging.getLogger("SuperVdsm.ServerCallback")
+
     @logDecorator
     def ping(self, *args, **kwargs):
         # This method exists for testing purposes
@@ -226,6 +230,7 @@ class _SuperVdsm(object):
 
     @logDecorator
     def udevTrigger(self, guid):
+        self.__udevReloadRules(guid)
         cmd = [EXT_UDEVADM, 'trigger', '--verbose', '--action', 'change',
                '--property-match=DM_NAME=%s' % guid]
         rc, out, err = misc.execCmd(cmd, sudo=False)
@@ -304,6 +309,32 @@ class _SuperVdsm(object):
     def removeFs(self, path):
         return mkimage.removeFs(path)
 
+    def __udevReloadRules(self, guid):
+        if self.__udevOperationReload():
+            reload = "--reload"
+        else:
+            reload = "--reload-rules"
+        cmd = [EXT_UDEVADM, 'control', reload]
+        rc, out, err = misc.execCmd(cmd, sudo=False)
+        if rc:
+            self.log.error("Udevadm reload-rules command failed rc=%s, "
+                           "out=\"%s\", err=\"%s\"", rc, out, err)
+            raise OSError(errno.EINVAL, "Could not reload-rules for device "
+                          "%s" % guid)
+
+    @utils.memoized
+    def __udevVersion(self):
+        cmd = [EXT_UDEVADM, '--version']
+        rc, out, err = misc.execCmd(cmd, sudo=False)
+        if rc:
+            self.log.error("Udevadm version command failed rc=%s, "
+                           " out=\"%s\", err=\"%s\"", rc, out, err)
+            raise RuntimeError("Could not get udev version number")
+        return int(out[0])
+
+    def __udevOperationReload(self):
+        return self.__udevVersion() > self.UDEV_WITH_RELOAD_VERSION
+
 
 def __pokeParent(parentPid, address, log):
     try:
-- 
1.8.1