Skip to content

Commit aa4e10d

Browse files
committed
EXPERIMENTAL Report maxmem and fix get_mem variants
Add "maxmem" property to "Qubes" (app) and "AdminVM", so clients can now system/host memory and dom0 memory. Fix "get_mem" and "get_mem_static_max" mess: - AdminVM: - "get_mem": supposedly, should report usage in KiB, but it's reading /proc/meminfo and returning kB - "get_mem_static_max": returning total host memory - QubesVM: - "get_mem": supposedly, should report usage, but it's reporting initial memory - "get_mem_static_max": same as above Now all of these methods returns memory in KiB. "get_mem" returns allocated/assigned memory, while "get_mem_static_max" returns maxmem in KiB.
1 parent d3360ee commit aa4e10d

3 files changed

Lines changed: 70 additions & 52 deletions

File tree

qubes/app.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,11 @@ def get_qube_prop_deps(
899899
return system_deps, qube_deps
900900

901901

902+
def _default_maxmem(self) -> int:
903+
"""Get maximum memory available to the whole system."""
904+
return self.host.memory_total
905+
906+
902907
class Qubes(qubes.PropertyHolder):
903908
"""Main Qubes application
904909
@@ -1145,6 +1150,15 @@ class Qubes(qubes.PropertyHolder):
11451150
doc="Check for updates inside qubes",
11461151
)
11471152

1153+
maxmem = qubes.property(
1154+
"maxmem",
1155+
type=int,
1156+
setter=qubes.property.forbidden,
1157+
load_stage=3,
1158+
default=_default_maxmem,
1159+
doc="Maximum system memory",
1160+
)
1161+
11481162
def __init__(
11491163
self, store=None, load=True, offline_mode=None, lock=False, **kwargs
11501164
):

qubes/vm/adminvm.py

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import grp
2626
import subprocess
2727
import libvirt
28+
import lxml
29+
import lxml.etree
2830
import uuid
2931

3032
import qubes
@@ -33,6 +35,30 @@
3335
from qubes.vm.qubesvm import _setter_denied_list, _setter_kbd_layout
3436
from qubes.vm import LocalVM, BaseVM
3537

38+
def _default_maxmem(self):
39+
if self.app.vmm.offline_mode:
40+
# default value passed on xen cmdline
41+
return 4096
42+
try:
43+
# Faster to use Xen than to query the fetch the full XML. If one could
44+
# find a libvirt method instead of XMLDesc to get the same value as
45+
# static-max, that would help.
46+
if self.app.vmm.is_xen:
47+
val = self.app.vmm.xs.read("", "/local/domain/0/memory/static-max")
48+
if not isinstance(val, bytes):
49+
raise TypeError("xenstore key static-max is not set")
50+
val = val.decode()
51+
else:
52+
xml = lxml.etree.fromstring(self.libvirt_domain.XMLDesc())
53+
val = xml.findtext("currentMemory")
54+
if val is None:
55+
raise TypeError("not set")
56+
if not val.isdigit():
57+
raise ValueError("not a digit")
58+
return int(val // 1024)
59+
except (TypeError, ValueError, libvirt.libvirtError) as e:
60+
self.log.warning("Failed to get maxmem for dom0: %s", e)
61+
return 4096
3662

3763
class AdminVM(LocalVM):
3864
"""Dom0"""
@@ -95,6 +121,14 @@ class AdminVM(LocalVM):
95121
doc="Keyboard layout for this VM",
96122
)
97123

124+
maxmem = qubes.property(
125+
"maxmem",
126+
type=int,
127+
setter=qubes.property.forbidden,
128+
default=_default_maxmem,
129+
doc="""Maximum amount of memory available for this VM""",
130+
)
131+
98132
def __init__(self, *args, **kwargs):
99133
super().__init__(*args, **kwargs)
100134

@@ -176,37 +210,30 @@ def get_power_state():
176210
"""
177211
return "Running"
178212

179-
@staticmethod
180-
def get_mem():
181-
"""Get current memory usage of Dom0.
182-
183-
Unit is KiB.
213+
def get_mem(self):
214+
"""Get memory assigned to VM.
184215
185-
.. seealso:
186-
:py:meth:`qubes.vm.qubesvm.QubesVM.get_mem`
216+
:returns: Memory assigned in KiB.
187217
"""
188-
189-
# return psutil.virtual_memory().total/1024
190-
with open("/proc/meminfo", encoding="ascii") as file:
191-
for line in file:
192-
if line.startswith("MemTotal:"):
193-
return int(line.split(":")[1].strip().split()[0])
194-
raise NotImplementedError()
218+
if self.libvirt_domain is None:
219+
return 0
220+
try:
221+
if not self.libvirt_domain.isActive():
222+
return 0
223+
return self.libvirt_domain.memoryStats()["actual"]
224+
except libvirt.libvirtError as e:
225+
self.log.exception(
226+
"libvirt error code: {!r}".format(e.get_error_code())
227+
)
228+
raise
195229

196230
def get_mem_static_max(self):
197231
"""Get maximum memory available to Dom0.
198232
199233
.. seealso:
200234
:py:meth:`qubes.vm.qubesvm.QubesVM.get_mem_static_max`
201235
"""
202-
if self.app.vmm.offline_mode:
203-
# default value passed on xen cmdline
204-
return 4096
205-
try:
206-
return self.app.vmm.libvirt_conn.getInfo()[1]
207-
except libvirt.libvirtError as e:
208-
self.log.warning("Failed to get memory limit for dom0: %s", e)
209-
return 4096
236+
return self.maxmem * 1024
210237

211238
def get_cputime(self):
212239
"""Get total CPU time burned by Dom0 since start.

qubes/vm/qubesvm.py

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,20 +2595,17 @@ def on_domain_is_fully_usable(self, event):
25952595
# memory and disk
25962596

25972597
def get_mem(self):
2598-
"""Get current memory usage from VM.
2598+
"""Get memory assigned to VM.
25992599
2600-
:returns: Memory usage [FIXME unit].
2601-
:rtype: FIXME
2600+
:returns: Memory assigned in KiB.
2601+
:rtype: int
26022602
"""
2603-
26042603
if self.libvirt_domain is None:
26052604
return 0
2606-
26072605
try:
26082606
if not self.libvirt_domain.isActive():
26092607
return 0
2610-
return self.libvirt_domain.info()[1]
2611-
2608+
return self.libvirt_domain.memoryStats()["actual"]
26122609
except libvirt.libvirtError as e:
26132610
if e.get_error_code() in (
26142611
# qube no longer exists
@@ -2617,7 +2614,6 @@ def get_mem(self):
26172614
libvirt.VIR_ERR_INTERNAL_ERROR,
26182615
):
26192616
return 0
2620-
26212617
self.log.exception(
26222618
"libvirt error code: {!r}".format(e.get_error_code())
26232619
)
@@ -2626,29 +2622,10 @@ def get_mem(self):
26262622
def get_mem_static_max(self):
26272623
"""Get maximum memory available to VM.
26282624
2629-
:returns: Memory limit [FIXME unit].
2630-
:rtype: FIXME
2625+
:returns: Memory limit in KiB.
2626+
:rtype: int
26312627
"""
2632-
2633-
if self.libvirt_domain is None:
2634-
return 0
2635-
2636-
try:
2637-
return self.libvirt_domain.maxMemory()
2638-
2639-
except libvirt.libvirtError as e:
2640-
if e.get_error_code() in (
2641-
# qube no longer exists
2642-
libvirt.VIR_ERR_NO_DOMAIN,
2643-
# libxl_domain_info failed (race condition from isActive)
2644-
libvirt.VIR_ERR_INTERNAL_ERROR,
2645-
):
2646-
return 0
2647-
2648-
self.log.exception(
2649-
"libvirt error code: {!r}".format(e.get_error_code())
2650-
)
2651-
raise
2628+
return self.maxmem * 1024
26522629

26532630
def get_cputime(self):
26542631
"""Get total CPU time burned by this domain since start.

0 commit comments

Comments
 (0)