From fcdc7f0d00deebc72f9d83fc1706f391663b2c96 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Tue, 12 May 2015 15:51:33 -0500
Subject: [PATCH 43/51] Improve initial sync-up of action with event handler.

This obviates the extra notify/wait cycle for device create and destroy
actions, which was a crude attempt to solve the same problem.
---
 blivet/devices/partition.py |  3 +++
 blivet/devices/storage.py   | 31 ++++++++-----------------------
 blivet/formats/__init__.py  |  4 ++++
 blivet/formats/disklabel.py |  2 ++
 blivet/formats/fs.py        |  7 ++++---
 blivet/handler.py           | 10 ++--------
 6 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py
index 0713d16..f255a0b 100644
--- a/blivet/devices/partition.py
+++ b/blivet/devices/partition.py
@@ -561,6 +561,7 @@ class PartitionDevice(StorageDevice):
             log.error(str(e))
             err = True
         finally:
+            event_sync.set_ready()
             timeout = 2 if err else None
             event_sync.wait(timeout=timeout)
             event_sync.reset()
@@ -607,6 +608,7 @@ class PartitionDevice(StorageDevice):
             try:
                 self.format.wipe()
             finally:
+                self.format.eventSync.set_ready()
                 self.format.eventSync.wait()
                 self.format.eventSync.reset()
                 self.format.eventSync.notify()
@@ -671,6 +673,7 @@ class PartitionDevice(StorageDevice):
         except Exception:
             raise
         else:
+            event_sync.set_ready()
             event_sync.wait()
         finally:
             event_sync.reset()
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py
index a7fee09..40fd8de 100644
--- a/blivet/devices/storage.py
+++ b/blivet/devices/storage.py
@@ -371,6 +371,7 @@ class StorageDevice(Device):
             self._setup(orig=orig)
         except Exception:
             # don't cause a deadlock if the failure generated an event
+            self.controlSync.set_ready()
             self.controlSync.wait(timeout=1)
             self.controlSync.notify()
             self.controlSync.reset()
@@ -381,6 +382,7 @@ class StorageDevice(Device):
         """ Perform post-setup operations. """
         event_sync = self.controlSync
         if self.__class__._setup != StorageDevice._setup:
+            event_sync.set_ready()
             event_sync.wait()
 
         event_sync.reset()
@@ -433,6 +435,7 @@ class StorageDevice(Device):
             self._teardown(recursive=recursive)
         except Exception:
             # don't cause a deadlock if the failure generated an event
+            self.controlSync.set_ready()
             self.controlSync.wait(timeout=1)
             self.controlSync.notify()
             self.controlSync.reset()
@@ -444,6 +447,7 @@ class StorageDevice(Device):
         """ Perform post-teardown operations. """
         event_sync = self.controlSync
         if self.__class__._teardown != StorageDevice._teardown:
+            event_sync.set_ready()
             event_sync.wait(timeout=self._postTeardownWaitTimeout)
 
         event_sync.reset()
@@ -476,7 +480,7 @@ class StorageDevice(Device):
             self._create()
         except Exception:
             # don't cause a deadlock if the failure generated an event
-            self.modifySync.notify()
+            self.modifySync.set_ready()
             self.modifySync.wait(timeout=1)
             self.modifySync.notify()
             self.modifySync.reset()
@@ -489,24 +493,7 @@ class StorageDevice(Device):
         #     they are created
         event_sync = self.modifySync
         if self.__class__._create != StorageDevice._create:
-            # There is an extra notify/wait cycle for device creation. This is
-            # because some device types (partition) have so much pre/post code
-            # that it becomes likely that the event handler will notify the
-            # event sync before the device is waiting for that notification,
-            # which leads to a deadlock when the device waits for notification.
-            #
-            # It seemed better to add an extra wait with a short (~1s) timeout
-            # in the event handler than to use a timeout here and potentially
-            # run along before any event is received.
-            #
-            # If the timeout is here, we're assuming that reaching this point
-            # means an event has been generated and is being handled -- the
-            # second part there is the tricky one.
-            # If the timeout is there, we're assuming that reaching that point
-            # means that the device will be ready for post-processing within the
-            # timeout.
-            # The latter seems like a safer assumption to me.
-            event_sync.notify() # notify the handler we're ready to post-process
+            event_sync.set_ready()
             event_sync.wait() # wait for notification the event was received
 
         event_sync.reset()
@@ -549,7 +536,7 @@ class StorageDevice(Device):
             self._destroy()
         except Exception:
             # don't cause a deadlock if the failure generated an event
-            self.modifySync.notify()
+            self.modifySync.set_ready()
             self.modifySync.wait(timeout=1)
             self.modifySync.notify()
             self.modifySync.reset()
@@ -560,9 +547,7 @@ class StorageDevice(Device):
         """ Perform post-destruction operations. """
         event_sync = self.modifySync
         if self.__class__._destroy != StorageDevice._destroy:
-            # See comment in _postCreate, above for explanation of the extra
-            # notify here as compared to setup and teardown.
-            event_sync.notify() # notify the handler we're ready to post-process
+            event_sync.set_ready()
             event_sync.wait() # wait for notification that event was received
 
         event_sync.reset()
diff --git a/blivet/formats/__init__.py b/blivet/formats/__init__.py
index 74d66e2..eebc963 100644
--- a/blivet/formats/__init__.py
+++ b/blivet/formats/__init__.py
@@ -364,6 +364,7 @@ class DeviceFormat(ObjectID):
             self._create(**kwargs)
         except Exception:
             if self.createGeneratesEvent:
+                self.eventSync.set_ready()
                 self.eventSync.wait(timeout=2)
                 self.eventSync.reset()
                 self.eventSync.notify()
@@ -407,6 +408,7 @@ class DeviceFormat(ObjectID):
     # pylint: disable=unused-argument
     def _postCreate(self, **kwargs):
         if self.createGeneratesEvent:
+            self.eventSync.set_ready()
             self.eventSync.wait()
             self.eventSync.reset()
             self.eventSync.notify()
@@ -432,6 +434,7 @@ class DeviceFormat(ObjectID):
             self._destroy()
         except Exception:
             if self.destroyGeneratesEvent:
+                self.eventSync.set_ready()
                 self.eventSync.wait(timeout=2)
                 self.eventSync.reset()
                 self.eventSync.notify()
@@ -482,6 +485,7 @@ class DeviceFormat(ObjectID):
     def _postDestroy(self, **kwargs):
         notify = kwargs.pop("notify", True)
         if notify and self.destroyGeneratesEvent:
+            self.eventSync.set_ready()
             self.eventSync.wait()
         self.exists = False
         self.eventSync.reset()
diff --git a/blivet/formats/disklabel.py b/blivet/formats/disklabel.py
index 3b2c89f..b9b5a31 100644
--- a/blivet/formats/disklabel.py
+++ b/blivet/formats/disklabel.py
@@ -321,6 +321,7 @@ class DiskLabel(DeviceFormat):
             if not flags.uevents:
                 udev.settle()
             if notify:
+                self.eventSync.set_ready()
                 timeout = 2 if err else None
                 self.eventSync.wait(timeout=timeout)
                 self.eventSync.reset()
@@ -339,6 +340,7 @@ class DiskLabel(DeviceFormat):
             self.updateOrigPartedDisk()
             if not flags.uevents:
                 udev.settle()
+            self.eventSync.set_ready()
             self.eventSync.wait()
         finally:
             self.eventSync.reset()
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 3d9c463..c5c61bc 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -513,6 +513,7 @@ class FS(DeviceFormat):
         except OSError as e:
             raise FSResizeError(e, self.device)
         else:
+            self.eventSync.set_ready()
             self.eventSync.wait()
         finally:
             self.eventSync.reset()
@@ -554,15 +555,14 @@ class FS(DeviceFormat):
             raise FSError("device does not exist")
 
         self.eventSync.changing = True
-
         try:
             ret = util.run_program([self.fsckProg] + self._getCheckArgs())
         except OSError as e:
             raise FSError("filesystem check failed: %s" % e)
-        else:
+        finally:
+            self.eventSync.set_ready()
             # it may not have been opened r/w, so just wait briefly
             self.eventSync.wait(timeout=2)
-        finally:
             self.eventSync.reset()
             self.eventSync.notify()
 
@@ -821,6 +821,7 @@ class FS(DeviceFormat):
         except Exception:
             raise
         else:
+            self.eventSync.set_ready()
             timeout = 2 if rc else None
             self.eventSync.wait(timeout=timeout)
         finally:
diff --git a/blivet/handler.py b/blivet/handler.py
index 73ae2b3..083f65a 100644
--- a/blivet/handler.py
+++ b/blivet/handler.py
@@ -492,9 +492,6 @@ class EventHandler(object):
             log.debug("* create %s", device.name)
             ## device create without event delegation (eg: partition)
             event_sync = device.modifySync
-            # Only wait briefly since there is a possibility the device already
-            # notified the cv from _postCreate.
-            event_sync.wait(1) # wait until the device says it's ready
         elif action in ("add", "change"):
             # could be any number of operations on a device that may no longer
             # be in the tree
@@ -527,11 +524,6 @@ class EventHandler(object):
                 ## device change (eg: event on pv for vg or lv creation)
                 log.debug("* change %s", device.name)
                 event_sync = device.controlSync
-                # There's an extra notify/wait pair in device create/destroy
-                # that the other branches in this block will not do.
-                # Only wait briefly since it's possible the device has already
-                # notified the CV from _postCreate/_postDestroy.
-                event_sync.wait(1)
             elif action == "change" and device and \
                  device.format.eventSync.active and \
                  device.format.eventSync.validate(info):
@@ -624,6 +616,8 @@ class EventHandler(object):
 
         if event_sync is not None:
             event_sync.reset()
+            print "waiting for ready " + name
+            event_sync.wait_for_ready()
             print "notify " + name
             event_sync.notify()
             print "wait " + name
-- 
2.1.0

