[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Fix the handling of VCPUs, specifically wrt the broken VCPU hotplugging, bug



# HG changeset patch
# User emellor@ewan
# Node ID 6f71824a45c19e860a3655dd8e76a83e047c84d2
# Parent  6e5463aec499333e9d4f91f612981aeb1f576445
Fix the handling of VCPUs, specifically wrt the broken VCPU hotplugging, bug
#280.  The cpu/<id>/availability paths had moved into /vm, but that is not
easily accessible by the hotplugging driver, so I have created a /vm entry
called vcpu_avail, so that the setting migrates along with the domain, and
moved the cpu/<id> ones back to /local/domain.

Don't try and destroy the domain twice if it fails within construct.  This
wasn't harming anything, but there's no need.

Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx>

diff -r 6e5463aec499 -r 6f71824a45c1 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Wed Oct  5 16:48:36 2005
+++ b/tools/python/xen/xend/XendDomainInfo.py   Wed Oct  5 17:06:42 2005
@@ -111,6 +111,8 @@
 ROUNDTRIPPING_CONFIG_ENTRIES = [
         ('name',         str),
         ('ssidref',      int),
+        ('vcpus',        int),
+        ('vcpu_avail',   int),
         ('cpu_weight',   float),
         ('bootloader',   str),
         ('on_poweroff',  str),
@@ -119,6 +121,27 @@
     ]
 
 
+#
+# There are a number of CPU-related fields:
+#
+#   vcpus:       the number of virtual CPUs this domain is configured to use.
+#   vcpu_avail:  a bitmap telling the guest domain whether it may use each of
+#                its VCPUs.  This is translated to
+#                <dompath>/cpu/<id>/availability = {online,offline} for use
+#                by the guest domain.
+#   vcpu_to_cpu: the current mapping between virtual CPUs and the physical
+#                CPU it is using.
+#   cpumap:      a list of bitmaps, one for each VCPU, giving the physical
+#                CPUs that that VCPU may use.
+#   cpu:         a configuration setting requesting that VCPU 0 is pinned to
+#                the specified physical CPU.
+#
+# vcpus and vcpu_avail settings persist with the VM (i.e. they are persistent
+# across save, restore, migrate, and restart).  The other settings are only
+# specific to the domain, so are lost when the VM moves.
+#
+
+
 def create(config):
     """Create a VM from a configuration.
 
@@ -134,6 +157,7 @@
         vm.refreshShutdown()
         return vm
     except:
+        log.exception('Domain construction failed')
         vm.destroy()
         raise
 
@@ -200,7 +224,7 @@
         raise VmError('Invalid ssidref in config: %s' % exn)
 
     domid = xc.domain_create(ssidref = ssidref)
-    if domid <= 0:
+    if domid < 0:
         raise VmError('Creating domain failed for restore')
     try:
         vm = XendDomainInfo(uuid, parseConfig(config), domid)
@@ -240,12 +264,12 @@
     for e in ROUNDTRIPPING_CONFIG_ENTRIES:
         result[e[0]] = get_cfg(e[0], e[1])
 
-    result['memory']       = get_cfg('memory',     int)
-    result['mem_kb']       = get_cfg('mem_kb',     int)
-    result['maxmem']       = get_cfg('maxmem',     int)
-    result['maxmem_kb']    = get_cfg('maxmem_kb',  int)
-    result['cpu']          = get_cfg('cpu',        int)
-    result['image']        = get_cfg('image')
+    result['memory']    = get_cfg('memory',    int)
+    result['mem_kb']    = get_cfg('mem_kb',    int)
+    result['maxmem']    = get_cfg('maxmem',    int)
+    result['maxmem_kb'] = get_cfg('maxmem_kb', int)
+    result['cpu']       = get_cfg('cpu',       int)
+    result['image']     = get_cfg('image')
 
     try:
         if result['image']:
@@ -338,7 +362,7 @@
         self.uuid = uuid
         self.info = info
 
-        if domid:
+        if domid is not None:
             self.domid = domid
         elif 'dom' in info:
             self.domid = int(info['dom'])
@@ -382,6 +406,8 @@
                   ("on_reboot",    str),
                   ("on_crash",     str),
                   ("image",        str),
+                  ("vcpus",        int),
+                  ("vcpu_avail",   int),
                   ("start_time", float))
 
         from_store = self.gatherVm(*params)
@@ -393,13 +419,13 @@
             devconfig = self.getDeviceConfigurations(c)
             if devconfig:
                 device.extend(map(lambda x: (c, x), devconfig))
-
         useIfNeeded('device', device)
 
 
     def validateInfo(self):
         """Validate and normalise the info block.  This has either been parsed
-        by parseConfig, or received from xc through recreate.
+        by parseConfig, or received from xc through recreate and augmented by
+        the current store contents.
         """
         def defaultInfo(name, val):
             if not self.infoIsSet(name):
@@ -413,6 +439,8 @@
             defaultInfo('on_crash',     lambda: "restart")
             defaultInfo('cpu',          lambda: None)
             defaultInfo('cpu_weight',   lambda: 1.0)
+            defaultInfo('vcpus',        lambda: 1)
+            defaultInfo('vcpu_avail',   lambda: (1 << self.info['vcpus']) - 1)
             defaultInfo('bootloader',   lambda: None)
             defaultInfo('backend',      lambda: [])
             defaultInfo('device',       lambda: [])
@@ -499,12 +527,6 @@
                     raise VmError('invalid restart event: %s = %s' %
                                   (event, str(self.info[event])))
 
-            if 'cpumap' not in self.info:
-                if [self.info['vcpus'] == 1]:
-                    self.info['cpumap'] = [1];
-                else:
-                    raise VmError('Cannot create CPU map')
-
         except KeyError, exn:
             log.exception(exn)
             raise VmError('Unspecified domain detail: %s' % str(exn))
@@ -552,7 +574,8 @@
         if self.infoIsSet('image'):
             to_store['image'] = sxp.to_string(self.info['image'])
 
-        for k in ['name', 'ssidref', 'on_poweroff', 'on_reboot', 'on_crash']:
+        for k in ['name', 'ssidref', 'on_poweroff', 'on_reboot', 'on_crash',
+                  'vcpus', 'vcpu_avail']:
             if self.infoIsSet(k):
                 to_store[k] = str(self.info[k])
 
@@ -572,6 +595,15 @@
         for (k, v) in self.info.items():
             if v:
                 to_store[k] = str(v)
+
+        def availability(n):
+            if self.info['vcpu_avail'] & (1 << n):
+                return 'online'
+            else:
+                return 'offline'
+
+        for v in range(0, self.info['vcpus']):
+            to_store["cpu/%d/availability" % v] = availability(v)
 
         log.debug("Storing domain details: %s" % str(to_store))
 
@@ -916,7 +948,8 @@
         if self.infoIsSet('cpu_time'):
             sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
         sxpr.append(['vcpus', self.info['vcpus']])
-        sxpr.append(['cpumap', self.info['cpumap']])
+        if self.infoIsSet('cpumap'):
+            sxpr.append(['cpumap', self.info['cpumap']])
         if self.infoIsSet('vcpu_to_cpu'):
             sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
             sxpr.append(['vcpu_to_cpu', self.prettyVCpuMap()])
@@ -986,27 +1019,21 @@
 
         self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'])
 
-        if self.domid <= 0:
+        if self.domid < 0:
             raise VmError('Creating domain failed: name=%s' %
                           self.info['name'])
 
-        try:
-            self.dompath = DOMROOT + str(self.domid)
-
-            # Ensure that the domain entry is clean.  This prevents a stale
-            # shutdown_start_time from killing the domain, for example.
-            self.removeDom()
-
-            self.initDomain()
-            self.construct_image()
-            self.configure()
-            self.storeVmDetails()
-            self.storeDomDetails()
-        except:
-            log.exception('Domain construction failed')
-            self.destroy()
-            raise VmError('Creating domain failed: name=%s' %
-                          self.info['name'])
+        self.dompath = DOMROOT + str(self.domid)
+
+        # Ensure that the domain entry is clean.  This prevents a stale
+        # shutdown_start_time from killing the domain, for example.
+        self.removeDom()
+
+        self.initDomain()
+        self.construct_image()
+        self.configure()
+        self.storeVmDetails()
+        self.storeDomDetails()
 
 
     def initDomain(self):
@@ -1041,13 +1068,6 @@
                   self.domid, self.info['name'], self.info['memory_KiB'])
 
 
-    def configure_vcpus(self):
-        d = {}
-        for v in range(0, self.info['vcpus']):
-            d["cpu/%d/availability" % v] = "online"
-        self.writeVm(d)
-
-
     def construct_image(self):
         """Construct the boot image for the domain.
         """
@@ -1055,7 +1075,6 @@
         self.image.createImage()
         IntroduceDomain(self.domid, self.store_mfn,
                         self.store_channel.port1, self.dompath)
-        self.configure_vcpus()
 
 
     ## public:
@@ -1376,10 +1395,13 @@
             log.error("Invalid VCPU %d" % vcpu)
             return
         if int(state) == 0:
+            self.info['vcpu_avail'] &= ~(1 << vcpu)
             availability = "offline"
         else:
+            self.info['vcpu_avail'] &= (1 << vcpu)
             availability = "online"
-        self.storeVm("cpu/%d/availability" % vcpu, availability)
+        self.storeVm('vcpu_avail', self.info['vcpu_avail'])
+        self.storeDom("cpu/%d/availability" % vcpu, availability)
 
     def send_sysrq(self, key=0):
         self.storeDom("control/sysrq", '%c' % key)
@@ -1397,7 +1419,6 @@
                     pass
                 else:
                     raise
-        self.configure_vcpus()
 
 
     def dom0_enforce_vcpus(self):

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.