From d96480719fc878780e352dd36cff6a9a7450d227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Mon, 6 Jul 2020 00:34:10 +0200 Subject: [PATCH] storage: add Volume.export_end() function This is a counterpart to Volume.export(). Up until now, no driver needed any cleanup after exporting data, but it doesn't mean there won't be any. This is especially relevant because Volume.export() is supposed to return a path of a snapshot from before VM start - which may be a different one than currently active one. QubesOS/qubes-issues#5935 --- doc/qubes-storage.rst | 4 ++++ qubes/backup.py | 3 ++- qubes/storage/__init__.py | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/doc/qubes-storage.rst b/doc/qubes-storage.rst index 3d9fafa6..d2abdeab 100644 --- a/doc/qubes-storage.rst +++ b/doc/qubes-storage.rst @@ -99,6 +99,10 @@ Methods and properties required to be implemented by the volume class: - :py:meth:`~qubes.storage.Volume.export` - return a path to be read to extract volume data; for complex formats, this can be a pipe (connected to some data-extracting process) + - :py:meth:`~qubes.storage.Volume.export_end` - cleanup after exporting the + data; this function is called when the path returned by + :py:meth:`~qubes.storage.Volume.export` is not used anymore. This method + optional - some storage drivers may not implement it if not needed. - :py:meth:`~qubes.storage.Volume.import_data` - return a path the data should be written to, to import volume data; for complex formats, this can be pipe (connected to some data-importing process) diff --git a/qubes/backup.py b/qubes/backup.py index 661af44a..5b81b2d0 100644 --- a/qubes/backup.py +++ b/qubes/backup.py @@ -394,7 +394,8 @@ class Backup: volume.export, subdir, name + '.img', - volume.usage)) + volume.usage, + cleanup_func=volume.export_end)) vm_files.extend(self.FileToBackup(i, subdir) for i in vm.fire_event('backup-get-files')) diff --git a/qubes/storage/__init__.py b/qubes/storage/__init__.py index 519c8bf3..f778c41b 100644 --- a/qubes/storage/__init__.py +++ b/qubes/storage/__init__.py @@ -206,6 +206,18 @@ class Volume: ''' raise self._not_implemented("export") + def export_end(self, path): + """ Cleanup after exporting data. + + This method is called after exporting the volume data (using + :py:meth:`export`), when the *path* is not needed anymore. + + This can be implemented as a coroutine. + + :param path: path to cleanup, returned by :py:meth:`export` + """ + # do nothing by default (optional method) + def import_data(self, size): ''' Returns a path to overwrite volume data. @@ -643,6 +655,19 @@ class Storage: return self.vm.volumes[volume].export() + @asyncio.coroutine + def export_end(self, volume, export_path): + """ Cleanup after exporting data from the volume + + :param volume: volume that was exported + :param export_path: path returned by the export() call + """ + assert isinstance(volume, (Volume, str)), \ + "You need to pass a Volume or pool name as str" + if not isinstance(volume, Volume): + volume = self.vm.volumes[volume] + yield from qubes.utils.coro_maybe(volume.export_end(export_path)) + @asyncio.coroutine def import_data(self, volume, size): '''