Skip to content

Commit a56b9a8

Browse files
committed
Skip memory balance for preloaded until pause
Balloon is allowed before paused and can be canceled by touching the file. For: QubesOS/qubes-issues#1512
1 parent b2d305f commit a56b9a8

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

qubes/qmemman/systemstate.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ def init(self) -> None:
7373
def get_xs_path(self, domid, key) -> str:
7474
return "/local/domain/" + str(domid) + "/memory/" + key
7575

76+
def can_membalance(self, domid) -> bool:
77+
stop_file = "/var/run/qubes/do-not-membalance-domid-" + str(domid)
78+
curr_stop_file = (
79+
"/var/run/qubes/do-not-membalance-cancel-current-domid-"
80+
+ str(domid)
81+
)
82+
for file in [stop_file, curr_stop_file]:
83+
if os.path.isfile(file):
84+
self.log.debug("File present: %r" % file)
85+
return False
86+
return True
87+
7688
def add_domain(self, domid) -> None:
7789
self.log.debug("add_domain(domid={!r})".format(domid))
7890
self.dom_dict[domid] = DomainState(domid)
@@ -208,6 +220,7 @@ def inhibit_balloon_up(self) -> None:
208220
if (
209221
dom.mem_actual is not None
210222
and dom.mem_actual + 200 * 1024 < dom.last_target
223+
and self.can_membalance(domid)
211224
):
212225
self.log.info(
213226
"Preventing balloon up to {}".format(dom.last_target)
@@ -247,7 +260,7 @@ def do_balloon(self, mem_size) -> bool:
247260
xenfree_ring[ring_slot] = xenfree
248261
for domid, prev_mem in prev_mem_actual.items():
249262
dom = self.dom_dict[domid]
250-
if prev_mem == dom.mem_actual:
263+
if prev_mem == dom.mem_actual or not self.can_membalance(domid):
251264
# domain not responding to memset requests, remove it
252265
# from donors
253266
dom.no_progress = True
@@ -289,6 +302,9 @@ def do_balloon_dom(self, dom_memset: dict) -> bool:
289302
memset_reqs = {}
290303
for domid, memset in dom_memset.items():
291304
dom = dom_dict[domid]
305+
if not self.can_membalance(domid):
306+
succeeded.append(domid)
307+
continue
292308
if memset == 0:
293309
# Domain hasn't sent meminfo back to the server, it is still at
294310
# the initial amount. pref_mem can't be calculated yet.
@@ -327,6 +343,8 @@ def do_balloon_dom(self, dom_memset: dict) -> bool:
327343
while True:
328344
self.refresh_mem_actual(domid_list)
329345
for domid, dom in dom_dict.items():
346+
if not self.can_membalance(domid):
347+
succeeded.append(domid)
330348
if domid in succeeded:
331349
continue
332350
assert isinstance(dom.mem_actual, int)
@@ -346,6 +364,12 @@ def do_balloon_dom(self, dom_memset: dict) -> bool:
346364
diff,
347365
)
348366
if all(dom in succeeded for dom in domid_list):
367+
for domid in dom_dict.keys():
368+
curr_stop_file = (
369+
"/var/run/qubes/do-not-membalance-cancel-current-domid-"
370+
+ str(domid)
371+
)
372+
Path(curr_stop_file).unlink(missing_ok=True)
349373
return True
350374
slow = []
351375
for domid, dom in dom_dict.items():
@@ -365,6 +389,12 @@ def do_balloon_dom(self, dom_memset: dict) -> bool:
365389
)
366390
slow.append(domid)
367391
if any(dom in slow for dom in domid_list):
392+
for domid in dom_dict.keys():
393+
curr_stop_file = (
394+
"/var/run/qubes/do-not-membalance-cancel-current-domid-"
395+
+ str(domid)
396+
)
397+
Path(curr_stop_file).unlink(missing_ok=True)
368398
return False
369399
for domid, memset in memset_reqs.items():
370400
if domid in succeeded:

qubes/vm/dispvm.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import copy
2727
import subprocess
2828
from typing import Optional, Any
29+
from pathlib import Path
2930

3031
import qubes.config
3132
import qubes.vm.appvm
@@ -622,16 +623,24 @@ async def on_domain_pre_paused(self, event, **kwargs) -> None:
622623
result = None
623624
cancelled = False
624625
self.log.info("Setting qube memory to pref mem")
626+
do_not_membalance_file = Path(
627+
"/var/run/qubes/do-not-membalance-domid-" + str(self.xid)
628+
)
625629
try:
626630
# CI uses Python 3.12 and asynchronous iterator requires >=3.13
627631
# pylint: disable=not-an-iterable
628632
async for earliest_task in asyncio.as_completed(tasks):
629633
await earliest_task
634+
do_not_membalance_file.touch(exist_ok=True)
630635
if earliest_task == break_task:
631636
self.log.info(
632637
"Canceling ballooning task, server might continue"
633638
)
634639
cancelled = True
640+
Path(
641+
"/var/run/qubes/do-not-membalance-cancel-current-domid-"
642+
+ str(self.xid)
643+
).touch(exist_ok=True)
635644
qmemman_task.cancel()
636645
else:
637646
result = qmemman_task.result()
@@ -898,6 +907,9 @@ async def use_preload(self) -> None:
898907
"""
899908
if not self.is_preload:
900909
raise qubes.exc.QubesException("Disposable is not preloaded")
910+
Path("/var/run/qubes/do-not-membalance-domid-" + str(self.xid)).unlink(
911+
missing_ok=True
912+
)
901913
appvm = self.template
902914
if self.preload_requested:
903915
self.log.info("Using preloaded qube")

0 commit comments

Comments
 (0)