Skip to content

Commit f296a88

Browse files
committed
Test early startup error of insufficient reserve
The "request_mem" is done very early on "QubesVM.start", the error handling doesn't have "self.kill" as the domain is not running yet, and therefore it was skipping "_auto_cleanup". Make sure that early startup failures are property handled, not remaining disposable in the domains collection nor in the preload-dispvm list.
1 parent a82f4f2 commit f296a88

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

qubes/tests/integ/dispvm.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ async def wait_preload(
410410
preload_unfinished = preload_dispvm
411411
for _ in range(timeout):
412412
for qube in preload_unfinished.copy():
413+
if qube not in self.app.domains:
414+
break
413415
if self.app.domains[qube].preload_complete.is_set():
414416
logger.info("preload completed for '%s'", qube)
415417
preload_unfinished.remove(qube)
@@ -1104,6 +1106,53 @@ def mock_open_mem_threshold(file, *args, **kwargs):
11041106
)
11051107
self.assertEqual(1, len(self.disp_base.get_feat_preload()))
11061108

1109+
def test_012_preload_low_mem_early_startup(self):
1110+
"""Test preloading with low memory on early startup"""
1111+
self.loop.run_until_complete(
1112+
self._test_012_preload_low_mem_early_startup()
1113+
)
1114+
1115+
async def _test_012_preload_low_mem_early_startup(self):
1116+
# pylint: disable=unspecified-encoding
1117+
logger.info("start")
1118+
unpatched_open = open
1119+
1120+
def mock_open_mem_raise(file, *args, **kwargs):
1121+
if file == qubes.config.qmemman_avail_mem_file:
1122+
raise FileNotFoundError(2, "No such file or directory", file)
1123+
return unpatched_open(file, *args, **kwargs)
1124+
1125+
preload_max = 2
1126+
with patch("builtins.open", side_effect=mock_open_mem_raise):
1127+
logger.info("insufficient memory reserve (early startup failure)")
1128+
old_memory = self.disp_base.memory
1129+
old_dispvms = [
1130+
qube.name
1131+
for qube in self.app.domains
1132+
if getattr(qube, "is_preload", False)
1133+
]
1134+
self.disp_base.memory = 999999999999999999999
1135+
self.disp_base.features["preload-dispvm-max"] = str(preload_max)
1136+
await self.wait_preload(
1137+
preload_max, fail_on_timeout=False, timeout=15
1138+
)
1139+
self.assertEqual(0, len(self.disp_base.get_feat_preload()))
1140+
new_dispvms = [
1141+
qube.name
1142+
for qube in self.app.domains
1143+
if getattr(qube, "is_preload", False)
1144+
]
1145+
self.assertEqual(new_dispvms, old_dispvms)
1146+
1147+
# Nothing will be done here, just to prepare to the next test.
1148+
self.disp_base.features["preload-dispvm-max"] = "0"
1149+
with patch("builtins.open", side_effect=mock_open_mem_raise):
1150+
logger.info("enough memory reserve but no avail-mem file")
1151+
self.disp_base.memory = old_memory
1152+
self.disp_base.features["preload-dispvm-max"] = str(preload_max)
1153+
await self.wait_preload(preload_max)
1154+
self.assertEqual(2, len(self.disp_base.get_feat_preload()))
1155+
11071156
logger.info("end")
11081157

11091158
def test_015_preload_race_more(self):

qubes/vm/mix/dvmtemplate.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,6 @@ async def on_domain_preload_dispvm_used(
516516
return
517517

518518
avail_mem_file = qubes.config.qmemman_avail_mem_file
519-
available_memory = None
520519
try:
521520
with open(avail_mem_file, "r", encoding="ascii") as file:
522521
available_memory = max(
@@ -525,7 +524,7 @@ async def on_domain_preload_dispvm_used(
525524
except FileNotFoundError:
526525
can_preload = want_preload
527526
self.log.warning("File containing available memory was not found")
528-
if available_memory is not None:
527+
else:
529528
memory = getattr(self, "memory", 0) * 1024**2
530529
unrestricted_preload = int(available_memory / memory)
531530
can_preload = min(unrestricted_preload, want_preload)

0 commit comments

Comments
 (0)