Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 28 additions & 10 deletions qubes/storage/lvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ def list_volumes(self):
continue
if vol_info['pool_lv'] != self.thin_pool:
continue
if vid.endswith('-snap') or vid.endswith('-import'):
if vid.endswith('-snap') or vid.endswith('-import') or \
vid.endswith('+export'):
# implementation detail volume
continue
if vid.endswith('-back'):
Expand Down Expand Up @@ -292,6 +293,7 @@ def __init__(self, volume_group, **kwargs):
self._vid_snap = self.vid + '-snap'
if self.save_on_stop:
self._vid_import = self.vid + '-import'
self._is_exporting = False

@property
def path(self):
Expand Down Expand Up @@ -409,7 +411,6 @@ async def _commit(self, vid_to_commit=None, keep=False):
cmd = ['rename', self.vid,
'{}-{}-back'.format(self.vid, int(time.time()))]
await qubes_lvm_coro(cmd, self.log)
await reset_cache_coro()

cmd = ['clone' if keep else 'rename',
vid_to_commit,
Expand Down Expand Up @@ -470,13 +471,31 @@ async def remove(self):
# pylint: disable=protected-access
self.pool._volume_objects_cache.pop(self.vid, None)

async def export(self):
@property
def _vid_export(self) -> str:
return self.vid + '+export'

@property
def _path_export(self) -> str:
return '/dev/' + self._vid_export

async def export(self) -> str:
''' Returns an object that can be `open()`. '''
# make sure the device node is available
cmd = ['activate', self.path]
await qubes_lvm_coro(cmd, self.log)
devpath = self.path
return devpath
vid_export = self._vid_export
export_path = self._path_export
if not os.path.exists(export_path):
cmd = ['clone', self._vid_current, vid_export]
await qubes_lvm_coro(cmd, self.log)
self._is_exporting = True
return export_path

async def export_end(self, path: str) -> None:
assert path == self._path_export, \
f'Refusing to remove incorrect path {path!r} ' \
f'(expected {self._path_export!r})'
await self._remove_if_exists(self._vid_export)
self._is_exporting = False

@qubes.storage.Volume.locked
async def import_volume(self, src_volume):
Expand Down Expand Up @@ -681,6 +700,8 @@ async def stop(self):
changed = await self._remove_if_exists(self._vid_snap)
else:
changed = await self._remove_if_exists(self.vid)
if not self._is_exporting:
await self._remove_if_exists(self._vid_export)
finally:
if changed:
await reset_cache_coro()
Expand Down Expand Up @@ -767,9 +788,6 @@ def _get_lvm_cmdline(cmd):
elif action == 'extend':
assert len(cmd) == 3, 'wrong number of arguments for extend'
lvm_cmd = ["lvextend", "--size=" + cmd[2] + 'B', '--', cmd[1]]
elif action == 'activate':
assert len(cmd) == 2, 'wrong number of arguments for activate'
lvm_cmd = ['lvchange', '--activate=y', '--', cmd[1]]
elif action == 'rename':
assert len(cmd) == 3, 'wrong number of arguments for rename'
lvm_cmd = ['lvrename', '--', cmd[1], cmd[2]]
Expand Down