ia64/xen-unstable

changeset 7231:6f71824a45c1

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@xensource.com>
author emellor@ewan
date Wed Oct 05 18:06:42 2005 +0100 (2005-10-05)
parents 6e5463aec499
children c3d9b7013b14 971e7c7411b3
files tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Wed Oct 05 17:48:36 2005 +0100
     1.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Oct 05 18:06:42 2005 +0100
     1.3 @@ -111,6 +111,8 @@ xroot = XendRoot.instance()
     1.4  ROUNDTRIPPING_CONFIG_ENTRIES = [
     1.5          ('name',         str),
     1.6          ('ssidref',      int),
     1.7 +        ('vcpus',        int),
     1.8 +        ('vcpu_avail',   int),
     1.9          ('cpu_weight',   float),
    1.10          ('bootloader',   str),
    1.11          ('on_poweroff',  str),
    1.12 @@ -119,6 +121,27 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [
    1.13      ]
    1.14  
    1.15  
    1.16 +#
    1.17 +# There are a number of CPU-related fields:
    1.18 +#
    1.19 +#   vcpus:       the number of virtual CPUs this domain is configured to use.
    1.20 +#   vcpu_avail:  a bitmap telling the guest domain whether it may use each of
    1.21 +#                its VCPUs.  This is translated to
    1.22 +#                <dompath>/cpu/<id>/availability = {online,offline} for use
    1.23 +#                by the guest domain.
    1.24 +#   vcpu_to_cpu: the current mapping between virtual CPUs and the physical
    1.25 +#                CPU it is using.
    1.26 +#   cpumap:      a list of bitmaps, one for each VCPU, giving the physical
    1.27 +#                CPUs that that VCPU may use.
    1.28 +#   cpu:         a configuration setting requesting that VCPU 0 is pinned to
    1.29 +#                the specified physical CPU.
    1.30 +#
    1.31 +# vcpus and vcpu_avail settings persist with the VM (i.e. they are persistent
    1.32 +# across save, restore, migrate, and restart).  The other settings are only
    1.33 +# specific to the domain, so are lost when the VM moves.
    1.34 +#
    1.35 +
    1.36 +
    1.37  def create(config):
    1.38      """Create a VM from a configuration.
    1.39  
    1.40 @@ -134,6 +157,7 @@ def create(config):
    1.41          vm.refreshShutdown()
    1.42          return vm
    1.43      except:
    1.44 +        log.exception('Domain construction failed')
    1.45          vm.destroy()
    1.46          raise
    1.47  
    1.48 @@ -200,7 +224,7 @@ def restore(config):
    1.49          raise VmError('Invalid ssidref in config: %s' % exn)
    1.50  
    1.51      domid = xc.domain_create(ssidref = ssidref)
    1.52 -    if domid <= 0:
    1.53 +    if domid < 0:
    1.54          raise VmError('Creating domain failed for restore')
    1.55      try:
    1.56          vm = XendDomainInfo(uuid, parseConfig(config), domid)
    1.57 @@ -240,12 +264,12 @@ def parseConfig(config):
    1.58      for e in ROUNDTRIPPING_CONFIG_ENTRIES:
    1.59          result[e[0]] = get_cfg(e[0], e[1])
    1.60  
    1.61 -    result['memory']       = get_cfg('memory',     int)
    1.62 -    result['mem_kb']       = get_cfg('mem_kb',     int)
    1.63 -    result['maxmem']       = get_cfg('maxmem',     int)
    1.64 -    result['maxmem_kb']    = get_cfg('maxmem_kb',  int)
    1.65 -    result['cpu']          = get_cfg('cpu',        int)
    1.66 -    result['image']        = get_cfg('image')
    1.67 +    result['memory']    = get_cfg('memory',    int)
    1.68 +    result['mem_kb']    = get_cfg('mem_kb',    int)
    1.69 +    result['maxmem']    = get_cfg('maxmem',    int)
    1.70 +    result['maxmem_kb'] = get_cfg('maxmem_kb', int)
    1.71 +    result['cpu']       = get_cfg('cpu',       int)
    1.72 +    result['image']     = get_cfg('image')
    1.73  
    1.74      try:
    1.75          if result['image']:
    1.76 @@ -338,7 +362,7 @@ class XendDomainInfo:
    1.77          self.uuid = uuid
    1.78          self.info = info
    1.79  
    1.80 -        if domid:
    1.81 +        if domid is not None:
    1.82              self.domid = domid
    1.83          elif 'dom' in info:
    1.84              self.domid = int(info['dom'])
    1.85 @@ -382,6 +406,8 @@ class XendDomainInfo:
    1.86                    ("on_reboot",    str),
    1.87                    ("on_crash",     str),
    1.88                    ("image",        str),
    1.89 +                  ("vcpus",        int),
    1.90 +                  ("vcpu_avail",   int),
    1.91                    ("start_time", float))
    1.92  
    1.93          from_store = self.gatherVm(*params)
    1.94 @@ -393,13 +419,13 @@ class XendDomainInfo:
    1.95              devconfig = self.getDeviceConfigurations(c)
    1.96              if devconfig:
    1.97                  device.extend(map(lambda x: (c, x), devconfig))
    1.98 -
    1.99          useIfNeeded('device', device)
   1.100  
   1.101  
   1.102      def validateInfo(self):
   1.103          """Validate and normalise the info block.  This has either been parsed
   1.104 -        by parseConfig, or received from xc through recreate.
   1.105 +        by parseConfig, or received from xc through recreate and augmented by
   1.106 +        the current store contents.
   1.107          """
   1.108          def defaultInfo(name, val):
   1.109              if not self.infoIsSet(name):
   1.110 @@ -413,6 +439,8 @@ class XendDomainInfo:
   1.111              defaultInfo('on_crash',     lambda: "restart")
   1.112              defaultInfo('cpu',          lambda: None)
   1.113              defaultInfo('cpu_weight',   lambda: 1.0)
   1.114 +            defaultInfo('vcpus',        lambda: 1)
   1.115 +            defaultInfo('vcpu_avail',   lambda: (1 << self.info['vcpus']) - 1)
   1.116              defaultInfo('bootloader',   lambda: None)
   1.117              defaultInfo('backend',      lambda: [])
   1.118              defaultInfo('device',       lambda: [])
   1.119 @@ -499,12 +527,6 @@ class XendDomainInfo:
   1.120                      raise VmError('invalid restart event: %s = %s' %
   1.121                                    (event, str(self.info[event])))
   1.122  
   1.123 -            if 'cpumap' not in self.info:
   1.124 -                if [self.info['vcpus'] == 1]:
   1.125 -                    self.info['cpumap'] = [1];
   1.126 -                else:
   1.127 -                    raise VmError('Cannot create CPU map')
   1.128 -
   1.129          except KeyError, exn:
   1.130              log.exception(exn)
   1.131              raise VmError('Unspecified domain detail: %s' % str(exn))
   1.132 @@ -552,7 +574,8 @@ class XendDomainInfo:
   1.133          if self.infoIsSet('image'):
   1.134              to_store['image'] = sxp.to_string(self.info['image'])
   1.135  
   1.136 -        for k in ['name', 'ssidref', 'on_poweroff', 'on_reboot', 'on_crash']:
   1.137 +        for k in ['name', 'ssidref', 'on_poweroff', 'on_reboot', 'on_crash',
   1.138 +                  'vcpus', 'vcpu_avail']:
   1.139              if self.infoIsSet(k):
   1.140                  to_store[k] = str(self.info[k])
   1.141  
   1.142 @@ -573,6 +596,15 @@ class XendDomainInfo:
   1.143              if v:
   1.144                  to_store[k] = str(v)
   1.145  
   1.146 +        def availability(n):
   1.147 +            if self.info['vcpu_avail'] & (1 << n):
   1.148 +                return 'online'
   1.149 +            else:
   1.150 +                return 'offline'
   1.151 +
   1.152 +        for v in range(0, self.info['vcpus']):
   1.153 +            to_store["cpu/%d/availability" % v] = availability(v)
   1.154 +
   1.155          log.debug("Storing domain details: %s" % str(to_store))
   1.156  
   1.157          self.writeDom(to_store)
   1.158 @@ -916,7 +948,8 @@ class XendDomainInfo:
   1.159          if self.infoIsSet('cpu_time'):
   1.160              sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
   1.161          sxpr.append(['vcpus', self.info['vcpus']])
   1.162 -        sxpr.append(['cpumap', self.info['cpumap']])
   1.163 +        if self.infoIsSet('cpumap'):
   1.164 +            sxpr.append(['cpumap', self.info['cpumap']])
   1.165          if self.infoIsSet('vcpu_to_cpu'):
   1.166              sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
   1.167              sxpr.append(['vcpu_to_cpu', self.prettyVCpuMap()])
   1.168 @@ -986,27 +1019,21 @@ class XendDomainInfo:
   1.169  
   1.170          self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'])
   1.171  
   1.172 -        if self.domid <= 0:
   1.173 +        if self.domid < 0:
   1.174              raise VmError('Creating domain failed: name=%s' %
   1.175                            self.info['name'])
   1.176  
   1.177 -        try:
   1.178 -            self.dompath = DOMROOT + str(self.domid)
   1.179 +        self.dompath = DOMROOT + str(self.domid)
   1.180  
   1.181 -            # Ensure that the domain entry is clean.  This prevents a stale
   1.182 -            # shutdown_start_time from killing the domain, for example.
   1.183 -            self.removeDom()
   1.184 +        # Ensure that the domain entry is clean.  This prevents a stale
   1.185 +        # shutdown_start_time from killing the domain, for example.
   1.186 +        self.removeDom()
   1.187  
   1.188 -            self.initDomain()
   1.189 -            self.construct_image()
   1.190 -            self.configure()
   1.191 -            self.storeVmDetails()
   1.192 -            self.storeDomDetails()
   1.193 -        except:
   1.194 -            log.exception('Domain construction failed')
   1.195 -            self.destroy()
   1.196 -            raise VmError('Creating domain failed: name=%s' %
   1.197 -                          self.info['name'])
   1.198 +        self.initDomain()
   1.199 +        self.construct_image()
   1.200 +        self.configure()
   1.201 +        self.storeVmDetails()
   1.202 +        self.storeDomDetails()
   1.203  
   1.204  
   1.205      def initDomain(self):
   1.206 @@ -1041,13 +1068,6 @@ class XendDomainInfo:
   1.207                    self.domid, self.info['name'], self.info['memory_KiB'])
   1.208  
   1.209  
   1.210 -    def configure_vcpus(self):
   1.211 -        d = {}
   1.212 -        for v in range(0, self.info['vcpus']):
   1.213 -            d["cpu/%d/availability" % v] = "online"
   1.214 -        self.writeVm(d)
   1.215 -
   1.216 -
   1.217      def construct_image(self):
   1.218          """Construct the boot image for the domain.
   1.219          """
   1.220 @@ -1055,7 +1075,6 @@ class XendDomainInfo:
   1.221          self.image.createImage()
   1.222          IntroduceDomain(self.domid, self.store_mfn,
   1.223                          self.store_channel.port1, self.dompath)
   1.224 -        self.configure_vcpus()
   1.225  
   1.226  
   1.227      ## public:
   1.228 @@ -1376,10 +1395,13 @@ class XendDomainInfo:
   1.229              log.error("Invalid VCPU %d" % vcpu)
   1.230              return
   1.231          if int(state) == 0:
   1.232 +            self.info['vcpu_avail'] &= ~(1 << vcpu)
   1.233              availability = "offline"
   1.234          else:
   1.235 +            self.info['vcpu_avail'] &= (1 << vcpu)
   1.236              availability = "online"
   1.237 -        self.storeVm("cpu/%d/availability" % vcpu, availability)
   1.238 +        self.storeVm('vcpu_avail', self.info['vcpu_avail'])
   1.239 +        self.storeDom("cpu/%d/availability" % vcpu, availability)
   1.240  
   1.241      def send_sysrq(self, key=0):
   1.242          self.storeDom("control/sysrq", '%c' % key)
   1.243 @@ -1397,7 +1419,6 @@ class XendDomainInfo:
   1.244                      pass
   1.245                  else:
   1.246                      raise
   1.247 -        self.configure_vcpus()
   1.248  
   1.249  
   1.250      def dom0_enforce_vcpus(self):