Skip to content

Commit a5d4bf1

Browse files
committed
Merge remote-tracking branch 'origin/pr/742'
* origin/pr/742: Clean preloaded disposable remnants on next boot
2 parents 13b1111 + 3e842d7 commit a5d4bf1

3 files changed

Lines changed: 43 additions & 18 deletions

File tree

qubes/vm/dispvm.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,17 @@ async def on_domain_shutdown(self, _event, **_kwargs):
433433
"""Do auto cleanup if enabled"""
434434
await self._auto_cleanup()
435435

436+
@qubes.events.handler("domain-remove-from-disk")
437+
async def on_domain_delete(self, _event, **_kwargs) -> None:
438+
"""
439+
On volume removal, remove preloaded disposable from ``preload-dispvm``
440+
feature in disposable template. If the feature is still here, it means
441+
the ``domain-shutdown`` cleanup was bypassed, possibly by improper
442+
shutdown, which can happen when a disposable is running, qubesd stops
443+
and system reboots.
444+
"""
445+
self._preload_cleanup()
446+
436447
@qubes.events.handler("property-pre-reset:template")
437448
def on_property_pre_reset_template(self, event, name, oldvalue=None):
438449
"""Forbid deleting template of VM""" # pylint: disable=unused-argument
@@ -612,18 +623,26 @@ def use_preload(self):
612623
appvm.fire_event_async("domain-preload-dispvm-used", dispvm=self)
613624
)
614625

626+
def _preload_cleanup(self):
627+
"""Cleanup preload from list"""
628+
if self.name in self.template.get_feat_preload():
629+
self.log.info("Automatic cleanup removes qube from preload list")
630+
self.template.remove_preload_from_list([self.name])
631+
615632
async def _bare_cleanup(self):
616633
"""Cleanup bare DispVM objects."""
617634
if self in self.app.domains:
618635
del self.app.domains[self]
619636
await self.remove_from_disk()
620637
self.app.save()
621638

622-
def _preload_cleanup(self):
623-
"""Cleanup preload from list"""
624-
if self.name in self.template.get_feat_preload():
625-
self.log.info("Automatic cleanup removes qube from preload list")
626-
self.template.remove_preload_from_list([self.name])
639+
async def _auto_cleanup(self):
640+
"""Do auto cleanup if enabled"""
641+
if not self.auto_cleanup:
642+
return
643+
self._preload_cleanup()
644+
if self in self.app.domains:
645+
await self._bare_cleanup()
627646

628647
async def cleanup(self):
629648
"""Clean up after the DispVM
@@ -633,20 +652,14 @@ async def cleanup(self):
633652
"""
634653
if self not in self.app.domains:
635654
return
655+
running = True
636656
try:
637657
await self.kill()
638658
except qubes.exc.QubesVMNotStartedError:
639-
pass
640-
# This will be done automatically if event 'domain-shutdown' is
641-
# triggered and 'auto_cleanup' evaluates to 'True'.
642-
if not self.auto_cleanup:
643-
self._preload_cleanup()
644-
if self in self.app.domains:
645-
await self._bare_cleanup()
646-
647-
async def _auto_cleanup(self):
648-
"""Do auto cleanup if enabled"""
649-
if self.auto_cleanup:
659+
running = False
660+
# Full cleanup will be done automatically if event 'domain-shutdown' is
661+
# triggered and "auto_cleanup=True".
662+
if not running or not self.auto_cleanup:
650663
self._preload_cleanup()
651664
if self in self.app.domains:
652665
await self._bare_cleanup()

qubes/vm/mix/dvmtemplate.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,21 @@ def on_domain_loaded(self, event): # pylint: disable=unused-argument
6868

6969
# Preloading was in progress (either preloading but not completed or
7070
# requested but not delivered) and qubesd stopped.
71+
#
72+
# Or qubesd stopped and the qube was destroyed/killed in the meantime,
73+
# shutdown was not called by qubesd so the qube is still present. The
74+
# "preload-dispvm-completed" is used to check if this was a preloaded
75+
# qube instead of "is_preload()" because it might not be in the
76+
# "preload-dispvm" list anymore if the following happened: "removed
77+
# from list -> scheduled cleanup -> stopped qubesd".
7178
preload_in_progress = [
7279
qube
7380
for qube in self.dispvms
74-
if qube.features.get("preload-dispvm-in-progress", False)
81+
if (
82+
not qube.is_running()
83+
and qube.features.get("preload-dispvm-completed", False)
84+
)
85+
or qube.features.get("preload-dispvm-in-progress", False)
7586
]
7687
if preload_in_progress:
7788
changes = True
@@ -84,6 +95,7 @@ def on_domain_loaded(self, event): # pylint: disable=unused-argument
8495
)
8596
for dispvm in preload_in_progress:
8697
asyncio.ensure_future(dispvm.cleanup())
98+
8799
if changes:
88100
self.app.save()
89101

qubes/vm/qubesvm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.LocalVM):
348348
Fired after the qube was loaded from :file:`qubes.xml`
349349
350350
:param subject: Event emitter (the qube object)
351-
:param event: Event name (``'domain-loaded'``)
351+
:param event: Event name (``'domain-load'``)
352352
353353
.. event:: domain-pre-start \
354354
(subject, event, start_guid, mem_required)

0 commit comments

Comments
 (0)