ia64/xen-unstable

changeset 16236:e8905caa47b5

pv-qemu 9/10: XenD device model re-factoring

This patches adapts XenD so that it is capable of starting a qemu-dm
device model for both paravirt and fullyvirt guests. A paravirt guest
will only be given a device model if it has a VFB configured, or the
user explicitly include the device_model option in the config
config. This avoids unnecessary overhead for those wanting a minimal
paravirt guest.

The bulk of this patch involves moving code from the HVMImageHandler
into the base ImageHandler class. The HVMImageHandler and
LinuxImageHandler subclasses now merely containing a couple of
overrides to set some specific command line flags. The most important
is -M xenpv, vs -M xenfv.

The XenConfig class has a minor refactoring to add a has_rfb() method
to avoid duplicating code in a couple of places. Instead of hardcoding
DEFAULT_DM it now uses the xen.util.auxbin APIs to locate it - this
works on platforms where qemu-dm is in /usr/lib64 instead of
/usr/lib. As before paravirt only gets a default qemu-dm if using a
VFB.

The vfbif.py class is trimmed out since it no longer needs to spawn a
daemon. A few other misc fixes deal with qemu-dm interactions when
saving/restoring, and in particular recovering from save failures (or
checkpointing).

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Thu Oct 25 14:45:07 2007 +0100 (2007-10-25)
parents b34ba3bcab0b
children a4df9c0c33fd
files tools/python/xen/xend/XendCheckpoint.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/image.py tools/python/xen/xend/server/vfbif.py
line diff
     1.1 --- a/tools/python/xen/xend/XendCheckpoint.py	Thu Oct 25 14:42:40 2007 +0100
     1.2 +++ b/tools/python/xen/xend/XendCheckpoint.py	Thu Oct 25 14:45:07 2007 +0100
     1.3 @@ -6,6 +6,7 @@
     1.4  # this archive for more details.
     1.5  
     1.6  import os
     1.7 +import os.path
     1.8  import re
     1.9  import string
    1.10  import threading
    1.11 @@ -108,7 +109,7 @@ def save(fd, dominfo, network, live, dst
    1.12          forkHelper(cmd, fd, saveInputHandler, False)
    1.13  
    1.14          # put qemu device model state
    1.15 -        if hvm:
    1.16 +        if os.path.exists("/var/lib/xen/qemu-save.%d" % dominfo.getDomid()):
    1.17              write_exact(fd, QEMU_SIGNATURE, "could not write qemu signature")
    1.18              qemu_fd = os.open("/var/lib/xen/qemu-save.%d" % dominfo.getDomid(),
    1.19                                os.O_RDONLY)
    1.20 @@ -245,6 +246,8 @@ def restore(xd, fd, dominfo = None, paus
    1.21              raise XendError('Could not read console MFN')        
    1.22  
    1.23          # get qemu state and create a tmp file for dm restore
    1.24 +        # Even PV guests may have QEMU stat, but its not currently
    1.25 +        # used so only bother with HVM currently.
    1.26          if is_hvm:
    1.27              qemu_signature = read_exact(fd, len(QEMU_SIGNATURE),
    1.28                                          "invalid device model signature read")
     2.1 --- a/tools/python/xen/xend/XendConfig.py	Thu Oct 25 14:42:40 2007 +0100
     2.2 +++ b/tools/python/xen/xend/XendConfig.py	Thu Oct 25 14:45:07 2007 +0100
     2.3 @@ -32,6 +32,7 @@ from xen.xend.server.BlktapController im
     2.4  from xen.xend.server.netif import randomMAC
     2.5  from xen.util.blkif import blkdev_name_to_number
     2.6  from xen.util import xsconstants
     2.7 +import xen.util.auxbin
     2.8  
     2.9  log = logging.getLogger("xend.XendConfig")
    2.10  log.setLevel(logging.WARN)
    2.11 @@ -234,8 +235,6 @@ LEGACY_XENSTORE_VM_PARAMS = [
    2.12      'on_xend_stop',
    2.13  ]
    2.14  
    2.15 -DEFAULT_DM = '/usr/lib/xen/bin/qemu-dm'
    2.16 -
    2.17  ##
    2.18  ## Config Choices
    2.19  ##
    2.20 @@ -393,13 +392,14 @@ class XendConfig(dict):
    2.21              self['name_label'] = 'Domain-' + self['uuid']
    2.22  
    2.23      def _platform_sanity_check(self):
    2.24 -        if self.is_hvm():
    2.25 -            if 'keymap' not in self['platform'] and XendOptions.instance().get_keymap():
    2.26 -                self['platform']['keymap'] = XendOptions.instance().get_keymap()
    2.27 +        if 'keymap' not in self['platform'] and XendOptions.instance().get_keymap():
    2.28 +            self['platform']['keymap'] = XendOptions.instance().get_keymap()
    2.29  
    2.30 +        if self.is_hvm() or self.has_rfb():
    2.31              if 'device_model' not in self['platform']:
    2.32 -                self['platform']['device_model'] = DEFAULT_DM
    2.33 +                self['platform']['device_model'] = xen.util.auxbin.pathTo("qemu-dm")
    2.34  
    2.35 +        if self.is_hvm():
    2.36              # Compatibility hack, can go away soon.
    2.37              if 'soundhw' not in self['platform'] and \
    2.38                 self['platform'].get('enable_audio'):
    2.39 @@ -744,16 +744,7 @@ class XendConfig(dict):
    2.40          # coalesce hvm vnc frame buffer with vfb config
    2.41          if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
    2.42              # add vfb device if it isn't there already
    2.43 -            has_rfb = False
    2.44 -            for console_uuid in self['console_refs']:
    2.45 -                if self['devices'][console_uuid][1].get('protocol') == 'rfb':
    2.46 -                    has_rfb = True
    2.47 -                    break
    2.48 -                if self['devices'][console_uuid][0] == 'vfb':
    2.49 -                    has_rfb = True
    2.50 -                    break
    2.51 -
    2.52 -            if not has_rfb:
    2.53 +            if not self.has_rfb():
    2.54                  dev_config = ['vfb']
    2.55                  dev_config.append(['type', 'vnc'])
    2.56                  # copy VNC related params from platform config to vfb dev conf
    2.57 @@ -765,6 +756,14 @@ class XendConfig(dict):
    2.58                  self.device_add('vfb', cfg_sxp = dev_config)
    2.59  
    2.60  
    2.61 +    def has_rfb(self):
    2.62 +        for console_uuid in self['console_refs']:
    2.63 +            if self['devices'][console_uuid][1].get('protocol') == 'rfb':
    2.64 +                return True
    2.65 +            if self['devices'][console_uuid][0] == 'vfb':
    2.66 +                return True
    2.67 +        return False
    2.68 +
    2.69      def _sxp_to_xapi_unsupported(self, sxp_cfg):
    2.70          """Read in an SXP configuration object and populate
    2.71          values are that not related directly supported in
     3.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Oct 25 14:42:40 2007 +0100
     3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Oct 25 14:45:07 2007 +0100
     3.3 @@ -1455,10 +1455,16 @@ class XendDomainInfo:
     3.4  
     3.5      def _releaseDevices(self, suspend = False):
     3.6          """Release all domain's devices.  Nothrow guarantee."""
     3.7 -        if suspend and self.image:
     3.8 -            self.image.destroy(suspend)
     3.9 -            return
    3.10 -
    3.11 +        if self.image:
    3.12 +            try:
    3.13 +                log.debug("Destroying device model")
    3.14 +                self.image.destroyDeviceModel()
    3.15 +            except Exception, e:
    3.16 +                log.exception("Device model destroy failed %s" % str(e))
    3.17 +        else:
    3.18 +            log.debug("No device model")
    3.19 +
    3.20 +        log.debug("Releasing devices")
    3.21          t = xstransact("%s/device" % self.dompath)
    3.22          for devclass in XendDevices.valid_devices():
    3.23              for dev in t.list(devclass):
    3.24 @@ -1709,11 +1715,6 @@ class XendDomainInfo:
    3.25              bootloader_tidy(self)
    3.26  
    3.27              if self.image:
    3.28 -                try:
    3.29 -                    self.image.destroy()
    3.30 -                except:
    3.31 -                    log.exception(
    3.32 -                        "XendDomainInfo.cleanup: image.destroy() failed.")
    3.33                  self.image = None
    3.34  
    3.35              try:
    3.36 @@ -1881,8 +1882,8 @@ class XendDomainInfo:
    3.37              ResumeDomain(self.domid)
    3.38          except:
    3.39              log.exception("XendDomainInfo.resume: xc.domain_resume failed on domain %s." % (str(self.domid)))
    3.40 -        if self.is_hvm():
    3.41 -            self.image.resumeDeviceModel()
    3.42 +        self.image.resumeDeviceModel()
    3.43 +        log.debug("XendDomainInfo.resumeDomain: completed")
    3.44  
    3.45  
    3.46      #
     4.1 --- a/tools/python/xen/xend/image.py	Thu Oct 25 14:42:40 2007 +0100
     4.2 +++ b/tools/python/xen/xend/image.py	Thu Oct 25 14:45:07 2007 +0100
     4.3 @@ -56,10 +56,9 @@ class ImageHandler:
     4.4      defining in a subclass.
     4.5  
     4.6      The method createDeviceModel() is called to create the domain device
     4.7 -    model if it needs one.  The default is to do nothing.
     4.8 +    model.
     4.9  
    4.10 -    The method destroy() is called when the domain is destroyed.
    4.11 -    The default is to do nothing.
    4.12 +    The method destroyDeviceModel() is called to reap the device model
    4.13      """
    4.14  
    4.15      ostype = None
    4.16 @@ -91,6 +90,15 @@ class ImageHandler:
    4.17                          ("image/cmdline", self.cmdline),
    4.18                          ("image/ramdisk", self.ramdisk))
    4.19  
    4.20 +        self.dmargs = self.parseDeviceModelArgs(vmConfig)
    4.21 +        self.device_model = vmConfig['platform'].get('device_model')
    4.22 +
    4.23 +        self.display = vmConfig['platform'].get('display')
    4.24 +        self.xauthority = vmConfig['platform'].get('xauthority')
    4.25 +        self.vncconsole = vmConfig['platform'].get('vncconsole')
    4.26 +        self.pid = None
    4.27 +
    4.28 +
    4.29  
    4.30      def cleanupBootloading(self):
    4.31          if self.bootloader:
    4.32 @@ -173,216 +181,13 @@ class ImageHandler:
    4.33          """Build the domain. Define in subclass."""
    4.34          raise NotImplementedError()
    4.35  
    4.36 -    def createDeviceModel(self, restore = False):
    4.37 -        """Create device model for the domain (define in subclass if needed)."""
    4.38 -        pass
    4.39 -    
    4.40 -    def saveDeviceModel(self):
    4.41 -        """Save device model for the domain (define in subclass if needed)."""
    4.42 -        pass
    4.43 -
    4.44 -    def resumeDeviceModel(self):
    4.45 -        """Unpause device model for the domain (define in subclass if needed)."""
    4.46 -        pass
    4.47 -
    4.48 -    def destroy(self):
    4.49 -        """Extra cleanup on domain destroy (define in subclass if needed)."""
    4.50 -        pass
    4.51 -
    4.52 -
    4.53 -    def recreate(self):
    4.54 -        pass
    4.55 -
    4.56 -
    4.57 -class LinuxImageHandler(ImageHandler):
    4.58 -
    4.59 -    ostype = "linux"
    4.60 -    flags = 0
    4.61 -    vhpt = 0
    4.62 -
    4.63 -    def buildDomain(self):
    4.64 -        store_evtchn = self.vm.getStorePort()
    4.65 -        console_evtchn = self.vm.getConsolePort()
    4.66 -
    4.67 -        mem_mb = self.getRequiredInitialReservation() / 1024
    4.68 -
    4.69 -        log.debug("domid          = %d", self.vm.getDomid())
    4.70 -        log.debug("memsize        = %d", mem_mb)
    4.71 -        log.debug("image          = %s", self.kernel)
    4.72 -        log.debug("store_evtchn   = %d", store_evtchn)
    4.73 -        log.debug("console_evtchn = %d", console_evtchn)
    4.74 -        log.debug("cmdline        = %s", self.cmdline)
    4.75 -        log.debug("ramdisk        = %s", self.ramdisk)
    4.76 -        log.debug("vcpus          = %d", self.vm.getVCpuCount())
    4.77 -        log.debug("features       = %s", self.vm.getFeatures())
    4.78 -        if arch.type == "ia64":
    4.79 -            log.debug("vhpt          = %d", self.flags)
    4.80 -
    4.81 -        return xc.linux_build(domid          = self.vm.getDomid(),
    4.82 -                              memsize        = mem_mb,
    4.83 -                              image          = self.kernel,
    4.84 -                              store_evtchn   = store_evtchn,
    4.85 -                              console_evtchn = console_evtchn,
    4.86 -                              cmdline        = self.cmdline,
    4.87 -                              ramdisk        = self.ramdisk,
    4.88 -                              features       = self.vm.getFeatures(),
    4.89 -                              flags          = self.flags,
    4.90 -                              vhpt           = self.vhpt)
    4.91 -
    4.92 -class PPC_LinuxImageHandler(LinuxImageHandler):
    4.93 -
    4.94 -    ostype = "linux"
    4.95 -    
    4.96 -    def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
    4.97 -        """@param shadow_mem_kb The configured shadow memory, in KiB.
    4.98 -        @param maxmem_kb The configured maxmem, in KiB.
    4.99 -        @return The corresponding required amount of shadow memory, also in
   4.100 -        KiB.
   4.101 -        PowerPC currently uses "shadow memory" to refer to the hash table."""
   4.102 -        return max(maxmem_kb / 64, shadow_mem_kb)
   4.103 -
   4.104 -
   4.105 -
   4.106 -class HVMImageHandler(ImageHandler):
   4.107 -
   4.108 -    ostype = "hvm"
   4.109 -
   4.110 -    def __init__(self, vm, vmConfig):
   4.111 -        ImageHandler.__init__(self, vm, vmConfig)
   4.112 -        self.shutdownWatch = None
   4.113 -        self.rebootFeatureWatch = None
   4.114 -
   4.115 -    def configure(self, vmConfig):
   4.116 -        ImageHandler.configure(self, vmConfig)
   4.117 -
   4.118 -        if not self.kernel:
   4.119 -            self.kernel = '/usr/lib/xen/boot/hvmloader'
   4.120 -
   4.121 -        info = xc.xeninfo()
   4.122 -        if 'hvm' not in info['xen_caps']:
   4.123 -            raise HVMRequired()
   4.124 -
   4.125 -        self.dmargs = self.parseDeviceModelArgs(vmConfig)
   4.126 -        self.device_model = vmConfig['platform'].get('device_model')
   4.127 -        if not self.device_model:
   4.128 -            raise VmError("hvm: missing device model")
   4.129 -        
   4.130 -        self.display = vmConfig['platform'].get('display')
   4.131 -        self.xauthority = vmConfig['platform'].get('xauthority')
   4.132 -        self.vncconsole = vmConfig['platform'].get('vncconsole')
   4.133 -
   4.134 -        rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset')
   4.135 -
   4.136 -        self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
   4.137 -                        ("image/device-model", self.device_model),
   4.138 -                        ("image/display", self.display))
   4.139 -        self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset))
   4.140 -
   4.141 -        self.pid = None
   4.142 -
   4.143 -        self.apic = int(vmConfig['platform'].get('apic', 0))
   4.144 -        self.acpi = int(vmConfig['platform'].get('acpi', 0))
   4.145 -        
   4.146 -
   4.147 -    def buildDomain(self):
   4.148 -        store_evtchn = self.vm.getStorePort()
   4.149 -
   4.150 -        mem_mb = self.getRequiredInitialReservation() / 1024
   4.151 -
   4.152 -        log.debug("domid          = %d", self.vm.getDomid())
   4.153 -        log.debug("image          = %s", self.kernel)
   4.154 -        log.debug("store_evtchn   = %d", store_evtchn)
   4.155 -        log.debug("memsize        = %d", mem_mb)
   4.156 -        log.debug("vcpus          = %d", self.vm.getVCpuCount())
   4.157 -        log.debug("acpi           = %d", self.acpi)
   4.158 -        log.debug("apic           = %d", self.apic)
   4.159 -
   4.160 -        rc = xc.hvm_build(domid          = self.vm.getDomid(),
   4.161 -                          image          = self.kernel,
   4.162 -                          memsize        = mem_mb,
   4.163 -                          vcpus          = self.vm.getVCpuCount(),
   4.164 -                          acpi           = self.acpi,
   4.165 -                          apic           = self.apic)
   4.166 -
   4.167 -        rc['notes'] = { 'SUSPEND_CANCEL': 1 }
   4.168 -
   4.169 -        rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(),
   4.170 -                                           HVM_PARAM_STORE_PFN)
   4.171 -        xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_STORE_EVTCHN,
   4.172 -                         store_evtchn)
   4.173 -
   4.174 -        return rc
   4.175 -
   4.176      # Return a list of cmd line args to the device models based on the
   4.177      # xm config file
   4.178      def parseDeviceModelArgs(self, vmConfig):
   4.179 -        dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
   4.180 -                   'localtime', 'serial', 'stdvga', 'isa',
   4.181 -                   'acpi', 'usb', 'usbdevice', 'keymap', 'pci' ]
   4.182 -        
   4.183 -        ret = ['-vcpus', str(self.vm.getVCpuCount())]
   4.184 -
   4.185 -        for a in dmargs:
   4.186 -            v = vmConfig['platform'].get(a)
   4.187 -
   4.188 -            # python doesn't allow '-' in variable names
   4.189 -            if a == 'stdvga': a = 'std-vga'
   4.190 -            if a == 'keymap': a = 'k'
   4.191 -
   4.192 -            # Handle booleans gracefully
   4.193 -            if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']:
   4.194 -                try:
   4.195 -                    if v != None: v = int(v)
   4.196 -                    if v: ret.append("-%s" % a)
   4.197 -                except (ValueError, TypeError):
   4.198 -                    pass # if we can't convert it to a sane type, ignore it
   4.199 -            else:
   4.200 -                if v:
   4.201 -                    ret.append("-%s" % a)
   4.202 -                    ret.append("%s" % v)
   4.203 -
   4.204 -            if a in ['fda', 'fdb']:
   4.205 -                if v:
   4.206 -                    if not os.path.isabs(v):
   4.207 -                        raise VmError("Floppy file %s does not exist." % v)
   4.208 -            log.debug("args: %s, val: %s" % (a,v))
   4.209 +        ret = ["-domain-name", str(self.vm.info['name_label'])]
   4.210  
   4.211 -        # Handle disk/network related options
   4.212 -        mac = None
   4.213 -        ret = ret + ["-domain-name", str(self.vm.info['name_label'])]
   4.214 -        nics = 0
   4.215 -        
   4.216 -        for devuuid in vmConfig['vbd_refs']:
   4.217 -            devinfo = vmConfig['devices'][devuuid][1]
   4.218 -            uname = devinfo.get('uname')
   4.219 -            if uname is not None and 'file:' in uname:
   4.220 -                (_, vbdparam) = string.split(uname, ':', 1)
   4.221 -                if not os.path.isfile(vbdparam):
   4.222 -                    raise VmError('Disk image does not exist: %s' %
   4.223 -                                  vbdparam)
   4.224 -
   4.225 -        for devuuid in vmConfig['vif_refs']:
   4.226 -            devinfo = vmConfig['devices'][devuuid][1]
   4.227 -            dtype = devinfo.get('type', 'ioemu')
   4.228 -            if dtype != 'ioemu':
   4.229 -                continue
   4.230 -            nics += 1
   4.231 -            mac = devinfo.get('mac')
   4.232 -            if mac is None:
   4.233 -                raise VmError("MAC address not specified or generated.")
   4.234 -            bridge = devinfo.get('bridge', 'xenbr0')
   4.235 -            model = devinfo.get('model', 'rtl8139')
   4.236 -            ret.append("-net")
   4.237 -            ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
   4.238 -                       (nics, mac, model))
   4.239 -            ret.append("-net")
   4.240 -            ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
   4.241 -
   4.242 -
   4.243 -        #
   4.244          # Find RFB console device, and if it exists, make QEMU enable
   4.245          # the VNC console.
   4.246 -        #
   4.247          if int(vmConfig['platform'].get('nographic', 0)) != 0:
   4.248              # skip vnc init if nographic is set
   4.249              ret.append('-nographic')
   4.250 @@ -398,6 +203,11 @@ class HVMImageHandler(ImageHandler):
   4.251                  has_vnc = True
   4.252                  break
   4.253  
   4.254 +        keymap = vmConfig['platform'].get("keymap")
   4.255 +        if keymap:
   4.256 +            ret.append("-k")
   4.257 +            ret.append(keymap)
   4.258 +
   4.259          if has_vnc:
   4.260              if not vnc_config:
   4.261                  for key in ('vncunused', 'vnclisten', 'vncdisplay',
   4.262 @@ -435,20 +245,20 @@ class HVMImageHandler(ImageHandler):
   4.263              ret = ret + ['-monitor', 'vc']
   4.264          return ret
   4.265  
   4.266 +    def getDeviceModelArgs(self, restore = False):
   4.267 +        args = [self.device_model]
   4.268 +        args = args + ([ "-d",  "%d" % self.vm.getDomid() ])
   4.269 +        args = args + self.dmargs
   4.270 +        return args
   4.271 +
   4.272      def createDeviceModel(self, restore = False):
   4.273 +        if self.device_model is None:
   4.274 +            return
   4.275          if self.pid:
   4.276              return
   4.277          # Execute device model.
   4.278          #todo: Error handling
   4.279 -        args = [self.device_model]
   4.280 -        args = args + ([ "-d",  "%d" % self.vm.getDomid() ])
   4.281 -        if arch.type == "ia64":
   4.282 -            args = args + ([ "-m", "%s" %
   4.283 -                             (self.getRequiredInitialReservation() / 1024) ])
   4.284 -        args = args + self.dmargs
   4.285 -        if restore:
   4.286 -            args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" %
   4.287 -                             self.vm.getDomid() ])
   4.288 +        args = self.getDeviceModelArgs(restore)
   4.289          env = dict(os.environ)
   4.290          if self.display:
   4.291              env['DISPLAY'] = self.display
   4.292 @@ -463,6 +273,8 @@ class HVMImageHandler(ImageHandler):
   4.293          log.info("device model pid: %d", self.pid)
   4.294  
   4.295      def saveDeviceModel(self):
   4.296 +        if self.device_model is None:
   4.297 +            return
   4.298          # Signal the device model to pause itself and save its state
   4.299          xstransact.Store("/local/domain/0/device-model/%i"
   4.300                           % self.vm.getDomid(), ('command', 'save'))
   4.301 @@ -479,15 +291,21 @@ class HVMImageHandler(ImageHandler):
   4.302                  raise VmError('Timed out waiting for device model to save')
   4.303  
   4.304      def resumeDeviceModel(self):
   4.305 +        if self.device_model is None:
   4.306 +            return
   4.307          # Signal the device model to resume activity after pausing to save.
   4.308          xstransact.Store("/local/domain/0/device-model/%i"
   4.309                           % self.vm.getDomid(), ('command', 'continue'))
   4.310  
   4.311      def recreate(self):
   4.312 +        if self.device_model is None:
   4.313 +            return
   4.314          self.pid = self.vm.gatherDom(('image/device-model-pid', int))
   4.315  
   4.316 -    def destroy(self, suspend = False):
   4.317 -        if self.pid and not suspend:
   4.318 +    def destroyDeviceModel(self):
   4.319 +        if self.device_model is None:
   4.320 +            return
   4.321 +        if self.pid:
   4.322              try:
   4.323                  os.kill(self.pid, signal.SIGKILL)
   4.324              except OSError, exn:
   4.325 @@ -504,6 +322,201 @@ class HVMImageHandler(ImageHandler):
   4.326                                        % self.vm.getDomid())
   4.327  
   4.328  
   4.329 +class LinuxImageHandler(ImageHandler):
   4.330 +
   4.331 +    ostype = "linux"
   4.332 +    flags = 0
   4.333 +    vhpt = 0
   4.334 +
   4.335 +    def buildDomain(self):
   4.336 +        store_evtchn = self.vm.getStorePort()
   4.337 +        console_evtchn = self.vm.getConsolePort()
   4.338 +
   4.339 +        mem_mb = self.getRequiredInitialReservation() / 1024
   4.340 +
   4.341 +        log.debug("domid          = %d", self.vm.getDomid())
   4.342 +        log.debug("memsize        = %d", mem_mb)
   4.343 +        log.debug("image          = %s", self.kernel)
   4.344 +        log.debug("store_evtchn   = %d", store_evtchn)
   4.345 +        log.debug("console_evtchn = %d", console_evtchn)
   4.346 +        log.debug("cmdline        = %s", self.cmdline)
   4.347 +        log.debug("ramdisk        = %s", self.ramdisk)
   4.348 +        log.debug("vcpus          = %d", self.vm.getVCpuCount())
   4.349 +        log.debug("features       = %s", self.vm.getFeatures())
   4.350 +        if arch.type == "ia64":
   4.351 +            log.debug("vhpt          = %d", self.flags)
   4.352 +
   4.353 +        return xc.linux_build(domid          = self.vm.getDomid(),
   4.354 +                              memsize        = mem_mb,
   4.355 +                              image          = self.kernel,
   4.356 +                              store_evtchn   = store_evtchn,
   4.357 +                              console_evtchn = console_evtchn,
   4.358 +                              cmdline        = self.cmdline,
   4.359 +                              ramdisk        = self.ramdisk,
   4.360 +                              features       = self.vm.getFeatures(),
   4.361 +                              flags          = self.flags,
   4.362 +                              vhpt           = self.vhpt)
   4.363 +
   4.364 +    def parseDeviceModelArgs(self, vmConfig):
   4.365 +        ret = ImageHandler.parseDeviceModelArgs(self, vmConfig)
   4.366 +        # Equivalent to old xenconsoled behaviour. Should make
   4.367 +        # it configurable in future
   4.368 +        ret = ret + ["-serial", "pty"]
   4.369 +        return ret
   4.370 +
   4.371 +    def getDeviceModelArgs(self, restore = False):
   4.372 +        args = ImageHandler.getDeviceModelArgs(self, restore)
   4.373 +        args = args + ([ "-M", "xenpv"])
   4.374 +        return args
   4.375 +
   4.376 +
   4.377 +class PPC_LinuxImageHandler(LinuxImageHandler):
   4.378 +
   4.379 +    ostype = "linux"
   4.380 +    
   4.381 +    def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
   4.382 +        """@param shadow_mem_kb The configured shadow memory, in KiB.
   4.383 +        @param maxmem_kb The configured maxmem, in KiB.
   4.384 +        @return The corresponding required amount of shadow memory, also in
   4.385 +        KiB.
   4.386 +        PowerPC currently uses "shadow memory" to refer to the hash table."""
   4.387 +        return max(maxmem_kb / 64, shadow_mem_kb)
   4.388 +
   4.389 +
   4.390 +
   4.391 +class HVMImageHandler(ImageHandler):
   4.392 +
   4.393 +    ostype = "hvm"
   4.394 +
   4.395 +    def __init__(self, vm, vmConfig):
   4.396 +        ImageHandler.__init__(self, vm, vmConfig)
   4.397 +        self.shutdownWatch = None
   4.398 +        self.rebootFeatureWatch = None
   4.399 +
   4.400 +    def configure(self, vmConfig):
   4.401 +        ImageHandler.configure(self, vmConfig)
   4.402 +
   4.403 +        if not self.kernel:
   4.404 +            self.kernel = '/usr/lib/xen/boot/hvmloader'
   4.405 +
   4.406 +        info = xc.xeninfo()
   4.407 +        if 'hvm' not in info['xen_caps']:
   4.408 +            raise HVMRequired()
   4.409 +
   4.410 +        rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset')
   4.411 +
   4.412 +        self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
   4.413 +                        ("image/device-model", self.device_model),
   4.414 +                        ("image/display", self.display))
   4.415 +        self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset))
   4.416 +
   4.417 +        self.apic = int(vmConfig['platform'].get('apic', 0))
   4.418 +        self.acpi = int(vmConfig['platform'].get('acpi', 0))
   4.419 +
   4.420 +    # Return a list of cmd line args to the device models based on the
   4.421 +    # xm config file
   4.422 +    def parseDeviceModelArgs(self, vmConfig):
   4.423 +        ret = ImageHandler.parseDeviceModelArgs(self, vmConfig)
   4.424 +        ret = ret + ['-vcpus', str(self.vm.getVCpuCount())]
   4.425 +
   4.426 +        dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
   4.427 +                   'localtime', 'serial', 'stdvga', 'isa',
   4.428 +                   'acpi', 'usb', 'usbdevice', 'pci' ]
   4.429 +
   4.430 +        for a in dmargs:
   4.431 +            v = vmConfig['platform'].get(a)
   4.432 +
   4.433 +            # python doesn't allow '-' in variable names
   4.434 +            if a == 'stdvga': a = 'std-vga'
   4.435 +            if a == 'keymap': a = 'k'
   4.436 +
   4.437 +            # Handle booleans gracefully
   4.438 +            if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']:
   4.439 +                try:
   4.440 +                    if v != None: v = int(v)
   4.441 +                    if v: ret.append("-%s" % a)
   4.442 +                except (ValueError, TypeError):
   4.443 +                    pass # if we can't convert it to a sane type, ignore it
   4.444 +            else:
   4.445 +                if v:
   4.446 +                    ret.append("-%s" % a)
   4.447 +                    ret.append("%s" % v)
   4.448 +
   4.449 +            if a in ['fda', 'fdb']:
   4.450 +                if v:
   4.451 +                    if not os.path.isabs(v):
   4.452 +                        raise VmError("Floppy file %s does not exist." % v)
   4.453 +            log.debug("args: %s, val: %s" % (a,v))
   4.454 +
   4.455 +        # Handle disk/network related options
   4.456 +        mac = None
   4.457 +        nics = 0
   4.458 +        
   4.459 +        for devuuid in vmConfig['vbd_refs']:
   4.460 +            devinfo = vmConfig['devices'][devuuid][1]
   4.461 +            uname = devinfo.get('uname')
   4.462 +            if uname is not None and 'file:' in uname:
   4.463 +                (_, vbdparam) = string.split(uname, ':', 1)
   4.464 +                if not os.path.isfile(vbdparam):
   4.465 +                    raise VmError('Disk image does not exist: %s' %
   4.466 +                                  vbdparam)
   4.467 +
   4.468 +        for devuuid in vmConfig['vif_refs']:
   4.469 +            devinfo = vmConfig['devices'][devuuid][1]
   4.470 +            dtype = devinfo.get('type', 'ioemu')
   4.471 +            if dtype != 'ioemu':
   4.472 +                continue
   4.473 +            nics += 1
   4.474 +            mac = devinfo.get('mac')
   4.475 +            if mac is None:
   4.476 +                raise VmError("MAC address not specified or generated.")
   4.477 +            bridge = devinfo.get('bridge', 'xenbr0')
   4.478 +            model = devinfo.get('model', 'rtl8139')
   4.479 +            ret.append("-net")
   4.480 +            ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
   4.481 +                       (nics, mac, model))
   4.482 +            ret.append("-net")
   4.483 +            ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
   4.484 +
   4.485 +        return ret
   4.486 +
   4.487 +    def getDeviceModelArgs(self, restore = False):
   4.488 +        args = ImageHandler.getDeviceModelArgs(self, restore)
   4.489 +        args = args + ([ "-M", "xenfv"])
   4.490 +        if restore:
   4.491 +            args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" %
   4.492 +                             self.vm.getDomid() ])
   4.493 +        return args
   4.494 +
   4.495 +    def buildDomain(self):
   4.496 +        store_evtchn = self.vm.getStorePort()
   4.497 +
   4.498 +        mem_mb = self.getRequiredInitialReservation() / 1024
   4.499 +
   4.500 +        log.debug("domid          = %d", self.vm.getDomid())
   4.501 +        log.debug("image          = %s", self.kernel)
   4.502 +        log.debug("store_evtchn   = %d", store_evtchn)
   4.503 +        log.debug("memsize        = %d", mem_mb)
   4.504 +        log.debug("vcpus          = %d", self.vm.getVCpuCount())
   4.505 +        log.debug("acpi           = %d", self.acpi)
   4.506 +        log.debug("apic           = %d", self.apic)
   4.507 +
   4.508 +        rc = xc.hvm_build(domid          = self.vm.getDomid(),
   4.509 +                          image          = self.kernel,
   4.510 +                          memsize        = mem_mb,
   4.511 +                          vcpus          = self.vm.getVCpuCount(),
   4.512 +                          acpi           = self.acpi,
   4.513 +                          apic           = self.apic)
   4.514 +        rc['notes'] = { 'SUSPEND_CANCEL': 1 }
   4.515 +
   4.516 +        rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(),
   4.517 +                                           HVM_PARAM_STORE_PFN)
   4.518 +        xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_STORE_EVTCHN,
   4.519 +                         store_evtchn)
   4.520 +
   4.521 +        return rc
   4.522 +
   4.523 +
   4.524  class IA64_HVM_ImageHandler(HVMImageHandler):
   4.525  
   4.526      def configure(self, vmConfig):
   4.527 @@ -529,6 +542,13 @@ class IA64_HVM_ImageHandler(HVMImageHand
   4.528          # Explicit shadow memory is not a concept 
   4.529          return 0
   4.530  
   4.531 +    def getDeviceModelArgs(self, restore = False):
   4.532 +        args = HVMImageHandler.getDeviceModelArgs(self, restore)
   4.533 +        args = args + ([ "-m", "%s" %
   4.534 +                         (self.getRequiredInitialReservation() / 1024) ])
   4.535 +        return args
   4.536 +
   4.537 +
   4.538  class IA64_Linux_ImageHandler(LinuxImageHandler):
   4.539  
   4.540      def configure(self, vmConfig):
     5.1 --- a/tools/python/xen/xend/server/vfbif.py	Thu Oct 25 14:42:40 2007 +0100
     5.2 +++ b/tools/python/xen/xend/server/vfbif.py	Thu Oct 25 14:45:07 2007 +0100
     5.3 @@ -5,14 +5,6 @@ from xen.xend.XendError import VmError
     5.4  import xen.xend
     5.5  import os
     5.6  
     5.7 -def spawn_detached(path, args, env):
     5.8 -    p = os.fork()
     5.9 -    if p == 0:
    5.10 -        os.spawnve(os.P_NOWAIT, path, args, env)
    5.11 -        os._exit(0)
    5.12 -    else:
    5.13 -        os.waitpid(p, 0)
    5.14 -        
    5.15  CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused',
    5.16                    'display', 'xauthority', 'keymap',
    5.17                    'uuid', 'location', 'protocol']
    5.18 @@ -43,65 +35,9 @@ class VfbifController(DevController):
    5.19                       for i in range(len(CONFIG_ENTRIES))
    5.20                       if devinfo[i] is not None])
    5.21  
    5.22 -
    5.23 -    def createDevice(self, config):
    5.24 -        DevController.createDevice(self, config)
    5.25 -        if self.vm.info.is_hvm():
    5.26 -            # is HVM, so qemu-dm will handle the vfb.
    5.27 -            return
    5.28 -        
    5.29 -        args = [ xen.util.auxbin.pathTo("qemu-dm"),
    5.30 -                 "-M", "xenpv",
    5.31 -                 "-d", "%d" % self.vm.getDomid(),
    5.32 -                 "-domain-name", self.vm.getName() ]
    5.33 -        t = config.get("type", None)
    5.34 -        if t == "vnc":
    5.35 -            passwd = None
    5.36 -            if config.has_key("vncpasswd"):
    5.37 -                passwd = config["vncpasswd"]
    5.38 -            else:
    5.39 -                passwd = xen.xend.XendOptions.instance().get_vncpasswd_default()
    5.40 -            if passwd:
    5.41 -                self.vm.storeVm("vncpasswd", passwd)
    5.42 -                log.debug("Stored a VNC password for vfb access")
    5.43 -            else:
    5.44 -                log.debug("No VNC passwd configured for vfb access")
    5.45 -
    5.46 -            vnclisten = config.get('vnclisten',
    5.47 -                                   xen.xend.XendOptions.instance().get_vnclisten_address())
    5.48 -            vncdisplay = config.get('vncdisplay', 0)
    5.49 -            args += ['-vnc', "%s:%d" % (vnclisten, vncdisplay)]
    5.50 -
    5.51 -            if config.get('vncunused', 0):
    5.52 -                args += ['-vncunused']
    5.53 -
    5.54 -            if config.has_key("keymap"):
    5.55 -                args += ["-k", "%s" % config["keymap"]]
    5.56 -            else:
    5.57 -                xoptions = xen.xend.XendOptions.instance()
    5.58 -                if xoptions.get_keymap():
    5.59 -                    args += ["-k", "%s" % xoptions.get_keymap()]
    5.60 -
    5.61 -            spawn_detached(args[0], args, os.environ)
    5.62 -        elif t == "sdl":
    5.63 -            env = dict(os.environ)
    5.64 -            if config.has_key("display"):
    5.65 -                env['DISPLAY'] = config["display"]
    5.66 -            if config.has_key("xauthority"):
    5.67 -                env['XAUTHORITY'] = config["xauthority"]
    5.68 -            spawn_detached(args[0], args, env)
    5.69 -        else:
    5.70 -            raise VmError('Unknown vfb type %s (%s)' % (t, repr(config)))
    5.71 -
    5.72 -
    5.73      def waitForDevice(self, devid):
    5.74 -        if self.vm.info.get('HVM_boot_policy'):
    5.75 -            log.debug('skip waiting for HVM vfb')
    5.76 -            # is a qemu-dm managed device, don't wait for hotplug for these.
    5.77 -            return
    5.78 -
    5.79 -        DevController.waitForDevice(self, devid)
    5.80 -
    5.81 +        # is a qemu-dm managed device, don't wait for hotplug for these.
    5.82 +        return
    5.83  
    5.84      def reconfigureDevice(self, _, config):
    5.85          """ Only allow appending location information of vnc port into
    5.86 @@ -115,19 +51,16 @@ class VfbifController(DevController):
    5.87          raise VmError('Refusing to reconfigure device vfb:%d' % devid)
    5.88  
    5.89      def destroyDevice(self, devid, force):
    5.90 -        if self.vm.info.get('HVM_boot_policy'):
    5.91 -            # remove the backend xenstore entries for HVM guests no matter
    5.92 -            # what
    5.93 -            DevController.destroyDevice(self, devid, True)
    5.94 -        else:
    5.95 -            DevController.destroyDevice(self, devid, force)
    5.96 +        # remove the backend xenstore entries no matter what
    5.97 +        # because we kill qemu-dm with extreme prejudice
    5.98 +        # not giving it a chance to remove them itself
    5.99 +        DevController.destroyDevice(self, devid, True)
   5.100  
   5.101  
   5.102      def migrate(self, deviceConfig, network, dst, step, domName):
   5.103 -        if self.vm.info.get('HVM_boot_policy'):        
   5.104 -            return 0
   5.105 -        return DevController.migrate(self, deviceConfig, network, dst, step,
   5.106 -                                     domName)
   5.107 +        # Handled by qemu-dm so no action needed
   5.108 +        return 0
   5.109 +
   5.110      
   5.111  class VkbdifController(DevController):
   5.112      """Virtual keyboard controller. Handles all vkbd devices for a domain.
   5.113 @@ -141,22 +74,15 @@ class VkbdifController(DevController):
   5.114          return (devid, back, front)
   5.115  
   5.116      def waitForDevice(self, config):
   5.117 -        if self.vm.info.get('HVM_boot_policy'):
   5.118 -            # is a qemu-dm managed device, don't wait for hotplug for these.
   5.119 -            return
   5.120 -
   5.121 -        DevController.waitForDevice(self, config)
   5.122 +        # is a qemu-dm managed device, don't wait for hotplug for these.
   5.123 +        return
   5.124  
   5.125      def destroyDevice(self, devid, force):
   5.126 -        if self.vm.info.get('HVM_boot_policy'):
   5.127 -            # remove the backend xenstore entries for HVM guests no matter
   5.128 -            # what
   5.129 -            DevController.destroyDevice(self, devid, True)
   5.130 -        else:
   5.131 -            DevController.destroyDevice(self, devid, force)
   5.132 +        # remove the backend xenstore entries no matter what
   5.133 +        # because we kill qemu-dm with extreme prejudice
   5.134 +        # not giving it a chance to remove them itself
   5.135 +        DevController.destroyDevice(self, devid, True)
   5.136  
   5.137      def migrate(self, deviceConfig, network, dst, step, domName):
   5.138 -        if self.vm.info.get('HVM_boot_policy'):        
   5.139 -            return 0
   5.140 -        return DevController.migrate(self, deviceConfig, network, dst, step,
   5.141 -                                     domName)        
   5.142 +        # Handled by qemu-dm so no action needed
   5.143 +        return 0