From 036f9798d8ca856ceb6be0ba970c2d94d8f7c512 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Tue, 10 Feb 2015 11:22:55 -0600
Subject: [PATCH 04/10] Disable uevent sync operations when no block device is
 involved.

Make it possible to disable StorageEventSynchronizer's wait method for
"devices" that do not generate uevents, like regular files, nfs mounts,
and nodev filesystems.
---
 blivet/devices/btrfs.py    |  1 +
 blivet/devices/file.py     |  1 +
 blivet/devices/lvm.py      |  1 +
 blivet/devices/nfs.py      |  1 +
 blivet/devices/nodev.py    |  1 +
 blivet/devices/storage.py  |  3 ++-
 blivet/formats/__init__.py |  2 ++
 blivet/formats/fs.py       |  4 +++-
 blivet/threads.py          | 52 +++++++++++++++++++++++++++++++++-------------
 9 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/blivet/devices/btrfs.py b/blivet/devices/btrfs.py
index 8869d71..09aa207 100644
--- a/blivet/devices/btrfs.py
+++ b/blivet/devices/btrfs.py
@@ -43,6 +43,7 @@ class BTRFSDevice(StorageDevice):
     """ Base class for BTRFS volume and sub-volume devices. """
     _type = "btrfs"
     _packages = ["btrfs-progs"]
+    _udev = False
 
     def __init__(self, *args, **kwargs):
         """ Passing None or no name means auto-generate one like btrfs.%d """
diff --git a/blivet/devices/file.py b/blivet/devices/file.py
index 2db7908..07e27ea 100644
--- a/blivet/devices/file.py
+++ b/blivet/devices/file.py
@@ -39,6 +39,7 @@ class FileDevice(StorageDevice):
     """
     _type = "file"
     _devDir = ""
+    _udev = False
 
     def __init__(self, path, fmt=None, size=None,
                  exists=False, parents=None):
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 562470e..f73cfce 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -52,6 +52,7 @@ class LVMVolumeGroupDevice(ContainerDevice):
     _packages = ["lvm2"]
     _formatClassName = property(lambda s: "lvmpv")
     _formatUUIDAttr = property(lambda s: "vgUuid")
+    _udev = False
 
     def __init__(self, name, parents=None, size=None, free=None,
                  peSize=None, peCount=None, peFree=None, pvCount=None,
diff --git a/blivet/devices/nfs.py b/blivet/devices/nfs.py
index 513a11c..bf88176 100644
--- a/blivet/devices/nfs.py
+++ b/blivet/devices/nfs.py
@@ -31,6 +31,7 @@ class NFSDevice(StorageDevice, NetworkStorageDevice):
     """ An NFS device """
     _type = "nfs"
     _packages = ["dracut-network"]
+    _udev = False
 
     def __init__(self, device, fmt=None, parents=None):
         """
diff --git a/blivet/devices/nodev.py b/blivet/devices/nodev.py
index 618332d..8301f65 100644
--- a/blivet/devices/nodev.py
+++ b/blivet/devices/nodev.py
@@ -30,6 +30,7 @@ from .storage import StorageDevice
 class NoDevice(StorageDevice):
     """ A nodev device for nodev filesystems like tmpfs. """
     _type = "nodev"
+    _udev = False
 
     def __init__(self, fmt=None):
         """
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py
index abe86f4..a2727b9 100644
--- a/blivet/devices/storage.py
+++ b/blivet/devices/storage.py
@@ -57,6 +57,7 @@ class StorageDevice(Device):
     _partitionable = False
     _isDisk = False
     _encrypted = False
+    _udev = True
 
     def __init__(self, name, fmt=None, uuid=None,
                  size=None, major=None, minor=None,
@@ -130,7 +131,7 @@ class StorageDevice(Device):
         self.deviceLinks = []
 
         """ Condition used to synchronize access with uevent handlers. """
-        self.cv = StorageSynchronizer()
+        self.cv = StorageSynchronizer(passthrough=not self.__class__._udev)
 
     def __str__(self):
         exist = "existing"
diff --git a/blivet/formats/__init__.py b/blivet/formats/__init__.py
index 06b59e2..6641b48 100644
--- a/blivet/formats/__init__.py
+++ b/blivet/formats/__init__.py
@@ -21,6 +21,7 @@
 #
 
 import os
+import stat
 from six import add_metaclass
 
 from ..util import notify_kernel
@@ -309,6 +310,7 @@ class DeviceFormat(ObjectID):
         if devspec and not devspec.startswith("/"):
             raise ValueError("device must be a fully qualified path")
         self._device = devspec
+        self.cv.passthrough = not stat.S_ISBLK(os.stat(self._device).st_mode)
 
     def _getDevice(self):
         return self._device
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 3e0d7b4..8b4107b 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -1521,6 +1521,7 @@ class NFS(FS):
     def _setDevice(self, devspec):
         self._deviceCheck(devspec)
         self._device = devspec
+        self.cv.passthrough = True
 
     def _getDevice(self):
         return self._device
@@ -1560,6 +1561,7 @@ class NoDevFS(FS):
 
     def _setDevice(self, devspec):
         self._device = devspec
+        self.cv.passthrough = True
 
     @property
     def type(self):
@@ -1702,7 +1704,7 @@ class TmpFS(NoDevFS):
         # assignment, so we need a setter for the
         # device property, but as the device is always the
         # same, nothing actually needs to be set
-        pass
+        self.cv.passthrough = True
 
     device = property(_getDevice, _setDevice)
 
diff --git a/blivet/threads.py b/blivet/threads.py
index d426166..3be0fd9 100644
--- a/blivet/threads.py
+++ b/blivet/threads.py
@@ -45,7 +45,39 @@ class NoisyRLock(_RLock):
 #blivet_lock = NoisyRLock()
 blivet_lock = _RLock(verbose=flags.debug_threads)
 
-class StorageSynchronizer(object):
+class StorageSynchronizerFlags(object):
+    _flag_names = ["starting", "stopping", "creating", "destroying", "resizing",
+                   "changing"]
+
+    def __init__(self):
+        self._flags = {flag_name: False for flag_name in self._flag_names}
+
+    def _get_flag(self, flag):
+        return self._flags[flag]
+
+    def _set_flag(self, flag, val):
+        print "setting %s=%s" % (flag, val)
+        if val and any(self._flags.values()):
+            for fl, v in self._flags.items():
+                print "%s=%s" % (fl,v)
+            raise RuntimeError("only one flag can be active at a time")
+
+        self._flags[flag] = val
+
+    starting = property(lambda s: s._get_flag("starting"),
+                        lambda s,v: s._set_flag("starting", v))
+    stopping = property(lambda s: s._get_flag("stopping"),
+                        lambda s,v: s._set_flag("stopping", v))
+    creating = property(lambda s: s._get_flag("creating"),
+                        lambda s,v: s._set_flag("creating", v))
+    destroying = property(lambda s: s._get_flag("destroying"),
+                        lambda s,v: s._set_flag("destroying", v))
+    resizing = property(lambda s: s._get_flag("resizing"),
+                        lambda s,v: s._set_flag("resizing", v))
+    changing = property(lambda s: s._get_flag("changing"),
+                        lambda s,v: s._set_flag("changing", v))
+
+class StorageSynchronizer(StorageSynchronizerFlags):
     """ Manager for shared state related to storage operations.
 
         Each :class:`~.devices.StorageDevice` and
@@ -60,18 +92,10 @@ class StorageSynchronizer(object):
         It only provides wait and notify methods, both of which are merely
         wrappers around the internal threading.Condition instance.
     """
-    def __init__(self):
+    def __init__(self, passthrough=False):
+        super(StorageSynchronizer, self).__init__()
         self._cv = Condition(blivet_lock, verbose=flags.debug_threads)
-
-        # FIXME: make it so that only one of the flags can be set at a time
-        self.starting = False
-        self.stopping = False
-        self.creating = False
-        self.destroying = False
-        self.resizing = False
-
-        # for general purposes
-        self.changing = False
+        self.passthrough = passthrough
 
     def __deepcopy__(self, memo):
         new = self.__class__.__new__(self.__class__)
@@ -86,14 +110,14 @@ class StorageSynchronizer(object):
         return new
 
     def wait(self, timeout=None):
-        if not flags.uevents:
+        if self.passthrough or not flags.uevents:
             return
 
         args = [] if timeout is None else [timeout]
         self._cv.wait(*args)
 
     def notify(self, n=None):
-        if not flags.uevents:
+        if self.passthrough or not flags.uevents:
             return
 
         args = [] if n is None else [n]
-- 
1.9.3

