Explorar o código

storage/reflink: preferably get volume size from image size

There were (at least) five ways for the volume's nominal size and the
volume image file's actual size to desynchronize:

- loading a stale qubes.xml if a crash happened right after resizing the
  image but before saving the updated qubes.xml (-> previously fixed)
- restarting a snap_on_start volume after resizing the volume or its
  source volume (-> previously fixed)
- reverting to a differently sized revision
- importing a volume
- user tinkering with image files

Rather than trying to fix these one by one and hoping that there aren't
any others, override the volume size getter itself to always update from
the image file size. (If the getter is called though the storage API, it
takes the volume lock to avoid clobbering the nominal size when resize()
is running concurrently.)
Rusty Bird %!s(int64=4) %!d(string=hai) anos
pai
achega
2b4b45ead8
Modificáronse 1 ficheiros con 13 adicións e 4 borrados
  1. 13 4
      qubes/storage/reflink.py

+ 13 - 4
qubes/storage/reflink.py

@@ -154,7 +154,7 @@ class ReflinkVolume(qubes.storage.Volume):
     @_locked
     def create(self):
         if self.save_on_stop and not self.snap_on_start:
-            _create_sparse_file(self._path_clean, self.size)
+            _create_sparse_file(self._path_clean, self._get_size())
         return self
 
     @_coroutinized
@@ -213,7 +213,7 @@ class ReflinkVolume(qubes.storage.Volume):
         if self.snap_on_start or self.save_on_stop:
             _copy_file(self._path_clean, self._path_dirty)
         else:
-            _create_sparse_file(self._path_dirty, self.size)
+            _create_sparse_file(self._path_dirty, self._get_size())
         return self
 
     @_coroutinized
@@ -276,7 +276,7 @@ class ReflinkVolume(qubes.storage.Volume):
                 _resize_file(path, size)
                 break
 
-        self.size = size
+        self._size = size
         if path == self._path_dirty:
             _update_loopdev_sizes(self._path_dirty)
         return self
@@ -293,7 +293,7 @@ class ReflinkVolume(qubes.storage.Volume):
         if not self.save_on_stop:
             raise NotImplementedError(
                 'Cannot import_data: {} is not save_on_stop'.format(self.vid))
-        _create_sparse_file(self._path_import, self.size)
+        _create_sparse_file(self._path_import, self._get_size())
         return self._path_import
 
     def _import_data_end(self, success):
@@ -338,6 +338,15 @@ class ReflinkVolume(qubes.storage.Volume):
         return collections.OrderedDict(sorted(items,
                                               key=lambda item: int(item[0])))
 
+    def _get_size(self):
+        for path in (self._path_dirty, self._path_clean):
+            with suppress(FileNotFoundError):
+                self._size = os.path.getsize(path)
+                break
+        return self._size
+
+    size = property(_locked(_get_size))
+
     @property
     def usage(self):
         ''' Return volume disk usage from the VM's perspective. It is