diff --git a/qubes/storage/__init__.py b/qubes/storage/__init__.py index c081fcb4..f373740a 100644 --- a/qubes/storage/__init__.py +++ b/qubes/storage/__init__.py @@ -815,6 +815,17 @@ class Pool(object): ''' raise self._not_implemented("get_volume") + def included_in(self, app): + ''' Check if this pool is physically included in another one + + This works on best-effort basis, because one pool driver may not know + all the other drivers. + + :param app: Qubes() object to lookup other pools in + :returns pool or None + ''' + pass + @property def size(self): ''' Storage pool size in bytes ''' @@ -865,6 +876,27 @@ def isodate(seconds=time.time()): ''' Helper method which returns an iso date ''' return datetime.utcfromtimestamp(seconds).isoformat("T") +def search_pool_containing_dir(pools, dir_path): + ''' Helper function looking for a pool containing given directory. + + This is useful for implementing Pool.included_in method + ''' + + # prefer filesystem pools + for pool in pools: + if hasattr(pool, 'dir_path'): + if dir_path.startswith(pool.dir_path): + return pool + + # then look for lvm + for pool in pools: + if hasattr(pool, 'thin_pool') and hasattr(pool, 'volume_group'): + if (pool.volume_group, pool.thin_pool) == \ + DirectoryThinPool.thin_pool(dir_path): + return pool + + return None + class VmCreationManager(object): ''' A `ContextManager` which cleans up if volume creation fails. diff --git a/qubes/storage/file.py b/qubes/storage/file.py index 10c1b304..f598f406 100644 --- a/qubes/storage/file.py +++ b/qubes/storage/file.py @@ -163,6 +163,12 @@ class FilePool(qubes.storage.Pool): statvfs = os.statvfs(self.dir_path) return statvfs.f_frsize * (statvfs.f_blocks - statvfs.f_bfree) + def included_in(self, app): + ''' Check if there is pool containing this one - either as a + filesystem or its LVM volume''' + return qubes.storage.search_pool_containing_dir( + [pool for pool in app.pools.values() if pool is not self], + self.dir_path) class FileVolume(qubes.storage.Volume): ''' Parent class for the xen volumes implementation which expects a diff --git a/qubes/storage/kernels.py b/qubes/storage/kernels.py index e60ac70e..448057b1 100644 --- a/qubes/storage/kernels.py +++ b/qubes/storage/kernels.py @@ -24,6 +24,7 @@ import os import qubes.exc +import qubes.storage from qubes.storage import Pool, StoragePoolException, Volume @@ -202,6 +203,12 @@ class LinuxKernel(Pool): raise qubes.exc.QubesValueError( 'LinuxModules supports only revisions_to_keep=0') + def included_in(self, app): + ''' Check if there is pool containing /var/lib/qubes/vm-kernels ''' + return qubes.storage.search_pool_containing_dir( + [pool for pool in app.pools.values() if pool is not self], + self.dir_path) + @property def volumes(self): ''' Return all known kernel volumes ''' diff --git a/qubes/storage/reflink.py b/qubes/storage/reflink.py index 7cb9ca10..a11e6d3a 100644 --- a/qubes/storage/reflink.py +++ b/qubes/storage/reflink.py @@ -108,6 +108,12 @@ class ReflinkPool(qubes.storage.Pool): statvfs = os.statvfs(self.dir_path) return statvfs.f_frsize * (statvfs.f_blocks - statvfs.f_bfree) + def included_in(self, app): + ''' Check if there is pool containing this one - either as a + filesystem or its LVM volume''' + return qubes.storage.search_pool_containing_dir( + [pool for pool in app.pools.values() if pool is not self], + self.dir_path) class ReflinkVolume(qubes.storage.Volume): def create(self):