Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions qubes/tests/integ/dispvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ async def wait_preload(
preload_unfinished = preload_dispvm
for _ in range(timeout):
for qube in preload_unfinished.copy():
if qube not in self.app.domains:
break
if self.app.domains[qube].preload_complete.is_set():
logger.info("preload completed for '%s'", qube)
preload_unfinished.remove(qube)
Expand Down Expand Up @@ -1104,6 +1106,53 @@ def mock_open_mem_threshold(file, *args, **kwargs):
)
self.assertEqual(1, len(self.disp_base.get_feat_preload()))

def test_012_preload_low_mem_early_startup(self):
"""Test preloading with low memory on early startup"""
self.loop.run_until_complete(
self._test_012_preload_low_mem_early_startup()
)

async def _test_012_preload_low_mem_early_startup(self):
# pylint: disable=unspecified-encoding
logger.info("start")
unpatched_open = open

def mock_open_mem_raise(file, *args, **kwargs):
if file == qubes.config.qmemman_avail_mem_file:
raise FileNotFoundError(2, "No such file or directory", file)
return unpatched_open(file, *args, **kwargs)

preload_max = 2
with patch("builtins.open", side_effect=mock_open_mem_raise):
logger.info("insufficient memory reserve (early startup failure)")
old_memory = self.disp_base.memory
old_dispvms = [
qube.name
for qube in self.app.domains
if getattr(qube, "is_preload", False)
]
self.disp_base.memory = 999999999999999999999
self.disp_base.features["preload-dispvm-max"] = str(preload_max)
await self.wait_preload(
preload_max, fail_on_timeout=False, timeout=15
)
self.assertEqual(0, len(self.disp_base.get_feat_preload()))
new_dispvms = [
qube.name
for qube in self.app.domains
if getattr(qube, "is_preload", False)
]
self.assertEqual(new_dispvms, old_dispvms)

# Nothing will be done here, just to prepare to the next test.
self.disp_base.features["preload-dispvm-max"] = "0"
with patch("builtins.open", side_effect=mock_open_mem_raise):
logger.info("enough memory reserve but no avail-mem file")
self.disp_base.memory = old_memory
self.disp_base.features["preload-dispvm-max"] = str(preload_max)
await self.wait_preload(preload_max)
self.assertEqual(2, len(self.disp_base.get_feat_preload()))

logger.info("end")

def test_015_preload_race_more(self):
Expand Down
2 changes: 1 addition & 1 deletion qubes/vm/dispvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ async def start(self, **kwargs):
await super().start(**kwargs)
except:
# Cleanup also on failed startup
await self.cleanup()
await self.cleanup(force=True)
raise

def create_qdb_entries(self) -> None:
Expand Down
3 changes: 1 addition & 2 deletions qubes/vm/mix/dvmtemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,6 @@ async def on_domain_preload_dispvm_used(
return

avail_mem_file = qubes.config.qmemman_avail_mem_file
available_memory = None
try:
with open(avail_mem_file, "r", encoding="ascii") as file:
available_memory = max(
Expand All @@ -525,7 +524,7 @@ async def on_domain_preload_dispvm_used(
except FileNotFoundError:
can_preload = want_preload
self.log.warning("File containing available memory was not found")
if available_memory is not None:
else:
memory = getattr(self, "memory", 0) * 1024**2
unrestricted_preload = int(available_memory / memory)
can_preload = min(unrestricted_preload, want_preload)
Expand Down