Skip to content

Commit

Permalink
qmemman: fix race condition on starting new VM
Browse files Browse the repository at this point in the history
Force refreshing domain list after starting new VM, even if the
triggering watch wasn't about domain list change. Otherwise (with
outdated domain list) memory allocated to a new VM, but not yet used may
be redistributed (leaving to little to the Xen itself).

Fixes QubesOS/qubes-issues#1389
  • Loading branch information
marmarek committed Jan 14, 2016
1 parent 411e8b5 commit 5d36923
Showing 1 changed file with 38 additions and 18 deletions.
56 changes: 38 additions & 18 deletions qmemman/qmemman_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@

system_state = SystemState()
global_lock = thread.allocate_lock()
# If XS_Watcher will
# handle meminfo event before @introduceDomain, it will use
# incomplete domain list for that and may redistribute memory
# allocated to some VM, but not yet used (see #1389).
# To fix that, system_state should be updated (refresh domain
# list) before processing other changes, every time some process requested
# memory for a new VM, before releasing the lock. Then XS_Watcher will check
# this flag before processing other event.
force_refresh_domain_list = False

def only_in_first_list(l1, l2):
ret=[]
Expand All @@ -65,17 +74,30 @@ def __init__(self):
self.log.debug('XS_Watcher()')

self.handle = xen.lowlevel.xs.xs()
self.handle.watch('@introduceDomain', WatchType(XS_Watcher.domain_list_changed, None))
self.handle.watch('@releaseDomain', WatchType(XS_Watcher.domain_list_changed, None))
self.handle.watch('@introduceDomain', WatchType(
XS_Watcher.domain_list_changed, False))
self.handle.watch('@releaseDomain', WatchType(
XS_Watcher.domain_list_changed, False))
self.watch_token_dict = {}

def domain_list_changed(self, refresh_only=False):
"""
Check if any domain was created/destroyed. If it was, update
appropriate list. Then redistribute memory.
def domain_list_changed(self, param):
self.log.debug('domain_list_changed(param={!r})'.format(param))
:param refresh_only If True, only refresh domain list, do not
redistribute memory. In this mode, caller must already hold
global_lock.
"""
self.log.debug('domain_list_changed(only_refresh={!r})'.format(
refresh_only))

self.log.debug('acquiring global_lock')
global_lock.acquire()
self.log.debug('global_lock acquired')
got_lock = False
if not refresh_only:
self.log.debug('acquiring global_lock')
global_lock.acquire()
got_lock = True
self.log.debug('global_lock acquired')
try:
curr = self.handle.ls('', '/local/domain')
if curr is None:
Expand Down Expand Up @@ -105,10 +127,12 @@ def domain_list_changed(self, param):
self.watch_token_dict.pop(i)
system_state.del_domain(i)
finally:
global_lock.release()
self.log.debug('global_lock released')
if got_lock:
global_lock.release()
self.log.debug('global_lock released')

system_state.do_balance()
if not refresh_only:
system_state.do_balance()


def meminfo_changed(self, domain_id):
Expand All @@ -120,6 +144,8 @@ def meminfo_changed(self, domain_id):
self.log.debug('acquiring global_lock')
global_lock.acquire()
self.log.debug('global_lock acquired')
if force_refresh_domain_list:
self.domain_list_changed(refresh_only=True)

system_state.refresh_meminfo(domain_id, untrusted_meminfo_key)

Expand Down Expand Up @@ -155,15 +181,9 @@ def handle(self):
self.log.debug('data={!r}'.format(self.data))
if len(self.data) == 0:
self.log.info('EOF')
# FIXME: there is a race condition here: if XS_Watcher will
# handle meminfo event before @introduceDomain, it will use
# incomplete domain list for that and may redistribute memory
# allocated to some VM, but not yet used (see #1389).
# To fix that, system_state should be updated (refresh domain
# list) before releasing the lock, but in the current code
# layout XS_Watcher instance isn't available here,
# so xenstore watches would not be registered
if got_lock:
global force_refresh_domain_list
force_refresh_domain_list = True
global_lock.release()
self.log.debug('global_lock released')
return
Expand Down

0 comments on commit 5d36923

Please sign in to comment.