storage: fix handling snap_on_start=True file volumes
Use the right cow image and apply the second layer to provide read-write access. The correct setup is: - base image + base cow -> read-only snapshot (base changes "cached" until committed) - read-only snapshot + VM cow -> read-write snapshot (changes discarded after VM shutdown) This way, even VM without Qubes-specific startup scripts will can benefit from Template VMs, while VMs with Qubes-specific startup scripts may still see original root.img content (for possible signature verification, when storage domain got implemented). QubesOS/qubes-issues#2256
This commit is contained in:
parent
b89689e278
commit
01aedb7f18
@ -235,21 +235,34 @@ class FilePool(qubes.storage.Pool):
|
||||
create_dir_if_not_exists(vm_templates_path)
|
||||
|
||||
def start(self, volume):
|
||||
if volume._is_snapshot or volume._is_origin:
|
||||
_check_path(volume.path)
|
||||
try:
|
||||
_check_path(volume.path_cow)
|
||||
except qubes.storage.StoragePoolException:
|
||||
create_sparse_file(volume.path_cow, volume.size)
|
||||
_check_path(volume.path_cow)
|
||||
elif volume._is_volatile:
|
||||
if volume._is_volatile:
|
||||
self.reset(volume)
|
||||
else:
|
||||
_check_path(volume.path)
|
||||
if volume.snap_on_start:
|
||||
if not volume.save_on_stop:
|
||||
# make sure previous snapshot is removed - even if VM
|
||||
# shutdown routing wasn't called (power interrupt or so)
|
||||
_remove_if_exists(volume.path_cow)
|
||||
try:
|
||||
_check_path(volume.path_cow)
|
||||
except qubes.storage.StoragePoolException:
|
||||
create_sparse_file(volume.path_cow, volume.size)
|
||||
_check_path(volume.path_cow)
|
||||
if hasattr(volume, 'path_source_cow'):
|
||||
try:
|
||||
_check_path(volume.path_source_cow)
|
||||
except qubes.storage.StoragePoolException:
|
||||
create_sparse_file(volume.path_source_cow, volume.size)
|
||||
_check_path(volume.path_source_cow)
|
||||
return volume
|
||||
|
||||
def stop(self, volume):
|
||||
if volume.save_on_stop:
|
||||
self.commit(volume)
|
||||
elif volume._is_volatile:
|
||||
elif volume.snap_on_start:
|
||||
_remove_if_exists(volume.path_cow)
|
||||
else:
|
||||
_remove_if_exists(volume.path)
|
||||
return volume
|
||||
|
||||
@ -316,6 +329,8 @@ class FileVolume(qubes.storage.Volume):
|
||||
if self._is_snapshot:
|
||||
self.path = os.path.join(self.dir_path, self.source + '.img')
|
||||
img_name = self.source + '-cow.img'
|
||||
self.path_source_cow = os.path.join(self.dir_path, img_name)
|
||||
img_name = self.vid + '-cow.img'
|
||||
self.path_cow = os.path.join(self.dir_path, img_name)
|
||||
elif self._is_volume or self._is_volatile:
|
||||
self.path = os.path.join(self.dir_path, self.vid + '.img')
|
||||
@ -347,6 +362,8 @@ class FileVolume(qubes.storage.Volume):
|
||||
the libvirt XML template as <disk>.
|
||||
'''
|
||||
path = self.path
|
||||
if self._is_snapshot:
|
||||
path += ":" + self.path_source_cow
|
||||
if self._is_origin or self._is_snapshot:
|
||||
path += ":" + self.path_cow
|
||||
return qubes.devices.BlockDevice(path, self.name, self.script, self.rw,
|
||||
@ -380,7 +397,7 @@ class FileVolume(qubes.storage.Volume):
|
||||
def _is_origin(self):
|
||||
''' Internal helper. Useful for differentiating volume handling '''
|
||||
# pylint: disable=line-too-long
|
||||
return not self.snap_on_start and self.save_on_stop and self.revisions_to_keep > 0 # NOQA
|
||||
return self.save_on_stop and self.revisions_to_keep > 0 # NOQA
|
||||
|
||||
@property
|
||||
def _is_snapshot(self):
|
||||
|
@ -216,7 +216,7 @@ class TC_01_FileVolumes(qubes.tests.QubesTestCase):
|
||||
label='red')
|
||||
|
||||
expected = vm.template.dir_path + '/root.img:' + vm.template.dir_path \
|
||||
+ '/root-cow.img'
|
||||
+ '/root-cow.img:' + vm.dir_path + '/root-cow.img'
|
||||
self.assertVolumePath(vm, 'root', expected, rw=False)
|
||||
expected = vm.dir_path + '/private.img:' + \
|
||||
vm.dir_path + '/private-cow.img'
|
||||
|
Loading…
Reference in New Issue
Block a user