Skip to content

Commit

Permalink
storage/callback: async Volume.export() & added Volume.export_end()
Browse files Browse the repository at this point in the history
  • Loading branch information
3hhh committed Jul 16, 2020
1 parent 42d62bb commit 56c8d9d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 16 deletions.
2 changes: 2 additions & 0 deletions qubes/storage/callback.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"pre_volume_import": "Called before importing a volume from elsewhere. Same as above otherwise.",
"pre_volume_import_data": "Called before importing a volume from elsewhere. Same as above otherwise.",
"post_volume_import_data_end": "Called after finishing an `import_data` action. Same as above otherwise.",
"pre_volume_export": "Called before exporting a volume. Same as above otherwise.",
"post_volume_export_end": "Called after a volume export completed. Same as above otherwise.",
"description": "Optional description for your personal reference."
},
"testing-fail-missing-all":
Expand Down
29 changes: 13 additions & 16 deletions qubes/storage/callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import subprocess
import json
import asyncio
import threading
from shlex import quote
from qubes.utils import coro_maybe

Expand Down Expand Up @@ -234,7 +233,7 @@ def __init__(self, *, name, conf_id):
raise qubes.storage.StoragePoolException('The class %s must be a subclass of qubes.storage.Pool.' % cls)

self._cb_requires_init = self._check_init() #: Boolean indicating whether late storage initialization yet has to be done or not.
self._cb_init_lock = threading.Lock() #: Lock ensuring that late storage initialization is only run exactly once. Currently a `threading.Lock()` to make it accessible from synchronous code as well.
self._cb_init_lock = asyncio.Lock() #: Lock ensuring that late storage initialization is only run exactly once.
bdriver_args = self._cb_conf.get('bdriver_args', {})
self._cb_impl = cls(name=name, **bdriver_args) #: Instance of the backend pool driver.

Expand All @@ -254,20 +253,12 @@ def _init(self, callback=True):
''' Late storage initialization on first use for e.g. decryption on first usage request.
:param callback: Whether to trigger the `pre_sinit` callback or not.
'''
with self._cb_init_lock:
with (yield from self._cb_init_lock):
if self._cb_requires_init:
if callback:
yield from self._callback('pre_sinit')
self._cb_requires_init = False

def _init_nocoro(self, callback=True):
''' `_init()` in synchronous code. '''
with self._cb_init_lock:
if self._cb_requires_init:
if callback:
self._callback_nocoro('pre_sinit')
self._cb_requires_init = False

@asyncio.coroutine
def _assert_initialized(self, **kwargs):
if self._cb_requires_init:
Expand Down Expand Up @@ -571,12 +562,18 @@ def block_device(self):
return None
return self._cb_impl.block_device()

@asyncio.coroutine
def export(self):
# pylint: disable=protected-access
#TODO: once this becomes a coroutine in the Volume class, avoid the below blocking & potentially exception-throwing code; maybe also add a callback
if self._cb_pool._cb_requires_init:
self._cb_pool._init_nocoro()
return self._cb_impl.export()
yield from self._assert_initialized()
yield from self._callback('pre_volume_export')
return (yield from coro_maybe(self._cb_impl.export()))

@asyncio.coroutine
def export_end(self, path):
yield from self._assert_initialized()
ret = yield from coro_maybe(self._cb_impl.export_end(path))
yield from self._callback('post_volume_export_end', cb_args=[path])
return ret

@asyncio.coroutine
def verify(self):
Expand Down

0 comments on commit 56c8d9d

Please sign in to comment.