ia64/xen-unstable

changeset 2699:7b0448e9f11d

bitkeeper revision 1.1159.116.3 (4177deb5O2BSukkVC4mhGVTFnJJiwA)

Fix problem with block device recreation after xend restart.
Save device state info in the domain record and use when
the domain info and devices are recreated.
author mjw@wray-m-3.hpl.hp.com
date Thu Oct 21 16:07:17 2004 +0000 (2004-10-21)
parents ffc49e9c4837
children cc42f35f9597
files tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/controller.py tools/python/xen/xend/server/netif.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Tue Oct 19 11:18:09 2004 +0000
     1.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Oct 21 16:07:17 2004 +0000
     1.3 @@ -33,8 +33,6 @@ xend = server.SrvDaemon.instance()
     1.4  
     1.5  from XendError import VmError
     1.6  
     1.7 -from server.blkif import blkdev_name_to_number
     1.8 -
     1.9  """The length of domain names that Xen can handle.
    1.10  The names stored in Xen itself are not used for much, and
    1.11  xend can handle domain names of any length.
    1.12 @@ -92,24 +90,6 @@ def shutdown_reason(code):
    1.13      """
    1.14      return shutdown_reasons.get(code, "?")
    1.15  
    1.16 -def make_disk(vm, config, uname, dev, mode, recreate=0):
    1.17 -    """Create a virtual disk device for a domain.
    1.18 -
    1.19 -    @param vm:       vm
    1.20 -    @param uname:    device to export
    1.21 -    @param dev:      device name in domain
    1.22 -    @param mode:     read/write mode
    1.23 -    @param recreate: recreate flag (after xend restart)
    1.24 -    @return: deferred
    1.25 -    """
    1.26 -    idx = vm.next_device_index('vbd')
    1.27 -    # todo: The 'dev' should be looked up in the context of the domain.
    1.28 -    vdev = blkdev_name_to_number(dev)
    1.29 -    if not vdev:
    1.30 -        raise VmError("vbd: Device not found: uname=%s dev=%s" % (uname, dev))
    1.31 -    ctrl = xend.blkif_create(vm.dom, recreate=recreate)
    1.32 -    return ctrl.attachDevice(idx, config, uname, vdev, mode, recreate=recreate)
    1.33 -        
    1.34  def vif_up(iplist):
    1.35      """send an unsolicited ARP reply for all non link-local IP addresses.
    1.36  
    1.37 @@ -222,6 +202,7 @@ def vm_recreate(savedinfo, info):
    1.38      """
    1.39      vm = XendDomainInfo()
    1.40      vm.recreate = 1
    1.41 +    vm.savedinfo = savedinfo
    1.42      vm.setdom(info['dom'])
    1.43      #vm.name = info['name']
    1.44      vm.memory = info['mem_kb']/1024
    1.45 @@ -239,6 +220,7 @@ def vm_recreate(savedinfo, info):
    1.46          vm.name = info['name']
    1.47          d = defer.succeed(vm)
    1.48      vm.recreate = 0
    1.49 +    vm.savedinfo = None
    1.50      return d
    1.51  
    1.52  def vm_restore(src, progress=0):
    1.53 @@ -336,6 +318,7 @@ class XendDomainInfo:
    1.54          self.restart_state = None
    1.55          self.restart_time = None
    1.56          self.console_port = None
    1.57 +        self.savedinfo = None
    1.58  
    1.59      def setdom(self, dom):
    1.60          """Set the domain id.
    1.61 @@ -397,10 +380,21 @@ class XendDomainInfo:
    1.62              sxpr.append(['restart_state', self.restart_state])
    1.63          if self.restart_time:
    1.64              sxpr.append(['restart_time', str(self.restart_time)])
    1.65 +        devs = self.sxpr_devices()
    1.66 +        if devs:
    1.67 +            sxpr.append(devs)
    1.68          if self.config:
    1.69              sxpr.append(['config', self.config])
    1.70          return sxpr
    1.71  
    1.72 +    def sxpr_devices(self):
    1.73 +        sxpr = ['devices']
    1.74 +        for devs in self.devices.values():
    1.75 +            for dev in devs:
    1.76 +                if hasattr(dev, 'sxpr'):
    1.77 +                    sxpr.append(dev.sxpr())
    1.78 +        return sxpr
    1.79 +
    1.80      def check_name(self, name):
    1.81          """Check if a vm name is valid. Valid names start with a non-digit
    1.82          and contain alphabetic characters, digits, or characters in '_-.:/+'.
    1.83 @@ -586,6 +580,25 @@ class XendDomainInfo:
    1.84                  return d
    1.85          return None
    1.86  
    1.87 +    def get_device_savedinfo(self, type, index):
    1.88 +        val = None
    1.89 +        if self.savedinfo is None:
    1.90 +            return val
    1.91 +        index = str(index)
    1.92 +        devinfo = sxp.child(self.savedinfo, 'devices')
    1.93 +        if devinfo is None:
    1.94 +            return val
    1.95 +        for d in sxp.children(devinfo, type):
    1.96 +            dindex = sxp.child_value(d, 'index')
    1.97 +            if dindex is None: continue
    1.98 +            if str(dindex) == index:
    1.99 +                val = d
   1.100 +                break
   1.101 +        return val
   1.102 +
   1.103 +    def get_device_recreate(self, type, index):
   1.104 +        return self.get_device_savedinfo(type, index) or self.recreate
   1.105 +
   1.106      def add_config(self, val):
   1.107          """Add configuration data to a virtual machine.
   1.108  
   1.109 @@ -840,7 +853,7 @@ class XendDomainInfo:
   1.110      def configure_memory(self):
   1.111          """Configure vm memory limit.
   1.112          """
   1.113 -        maxmem = sxp.get_child_value(self.config, "maxmem")
   1.114 +        maxmem = sxp.child_value(self.config, "maxmem")
   1.115          if maxmem is None:
   1.116              maxmem = self.memory
   1.117          xc.domain_setmaxmem(self.dom, maxmem_kb = maxmem * 1024)
   1.118 @@ -1070,9 +1083,11 @@ def vm_dev_vif(vm, val, index, change=0)
   1.119      vmac = sxp.child_value(val, "mac")
   1.120      ctrl = xend.netif_create(vm.dom, recreate=vm.recreate)
   1.121      log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac))
   1.122 -    defer = ctrl.attachDevice(vif, val, recreate=vm.recreate)
   1.123 +    recreate = vm.get_device_recreate('vif', index)
   1.124 +    defer = ctrl.attachDevice(vif, val, recreate=recreate)
   1.125      def cbok(dev):
   1.126          dev.vifctl('up', vmname=vm.name)
   1.127 +        dev.setIndex(index)
   1.128          vm.add_device('vif', dev)
   1.129          if change:
   1.130              dev.interfaceChanged()
   1.131 @@ -1088,23 +1103,19 @@ def vm_dev_vbd(vm, val, index, change=0)
   1.132      @param index:     vbd index
   1.133      @return: deferred
   1.134      """
   1.135 +    idx = vm.next_device_index('vbd')
   1.136      uname = sxp.child_value(val, 'uname')
   1.137 -    if not uname:
   1.138 -        raise VmError('vbd: Missing uname')
   1.139 -    dev = sxp.child_value(val, 'dev')
   1.140 -    if not dev:
   1.141 -        raise VmError('vbd: Missing dev')
   1.142 -    mode = sxp.child_value(val, 'mode', 'r')
   1.143 -    log.debug("Creating vbd dom=%d uname=%s dev=%s", vm.dom, uname, dev)
   1.144 -    defer = make_disk(vm, val, uname, dev, mode, vm.recreate)
   1.145 -    def fn(vbd):
   1.146 -        vbd.dev = dev
   1.147 -        vbd.uname = uname
   1.148 -        vm.add_device('vbd', vbd)
   1.149 +    log.debug("Creating vbd dom=%d uname=%s", vm.dom, uname)
   1.150 +    ctrl = xend.blkif_create(vm.dom, recreate=vm.recreate)
   1.151 +    recreate = vm.get_device_recreate('vbd', index)
   1.152 +    defer = ctrl.attachDevice(idx, val, recreate=recreate)
   1.153 +    def cbok(dev):
   1.154 +        dev.setIndex(index)
   1.155 +        vm.add_device('vbd', dev)
   1.156          if change:
   1.157 -            vbd.interfaceChanged()
   1.158 -        return vbd
   1.159 -    defer.addCallback(fn)
   1.160 +            dev.interfaceChanged()
   1.161 +        return dev
   1.162 +    defer.addCallback(cbok)
   1.163      return defer
   1.164  
   1.165  def parse_pci(val):
     2.1 --- a/tools/python/xen/xend/server/blkif.py	Tue Oct 19 11:18:09 2004 +0000
     2.2 +++ b/tools/python/xen/xend/server/blkif.py	Thu Oct 21 16:07:17 2004 +0000
     2.3 @@ -16,6 +16,46 @@ import channel
     2.4  import controller
     2.5  from messages import *
     2.6  
     2.7 +
     2.8 +def blkdev_name_to_number(name):
     2.9 +    """Take the given textual block-device name (e.g., '/dev/sda1',
    2.10 +    'hda') and return the device number used by the OS. """
    2.11 +
    2.12 +    if re.match( '^/dev/', name ):
    2.13 +	n = name
    2.14 +    else:
    2.15 +	n = '/dev/' + name
    2.16 +    
    2.17 +    try:
    2.18 +	return os.stat(n).st_rdev
    2.19 +    except Exception, ex:
    2.20 +        log.debug("exception looking up device number for %s: %s", name, ex)
    2.21 +	pass
    2.22 +
    2.23 +    # see if this is a hex device number
    2.24 +    if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
    2.25 +	return string.atoi(name,16)
    2.26 +	
    2.27 +    return None
    2.28 +
    2.29 +def blkdev_segment(name):
    2.30 +    """Take the given block-device name (e.g. '/dev/sda1', 'hda')
    2.31 +    and return a dictionary { device, start_sector,
    2.32 +    nr_sectors, type }
    2.33 +        device:       Device number of the given partition
    2.34 +        start_sector: Index of first sector of the partition
    2.35 +        nr_sectors:   Number of sectors comprising this partition
    2.36 +        type:         'Disk' or identifying name for partition type
    2.37 +    """
    2.38 +    val = None
    2.39 +    n = blkdev_name_to_number(name)
    2.40 +    if n:
    2.41 +	val = { 'device' : n,
    2.42 +                'start_sector' : long(0),
    2.43 +                'nr_sectors' : long(1L<<63),
    2.44 +                'type' : 'Disk' }
    2.45 +    return val
    2.46 +
    2.47  class BlkifBackendController(controller.BackendController):
    2.48      """ Handler for the 'back-end' channel to a block device driver domain.
    2.49      """
    2.50 @@ -231,26 +271,70 @@ class BlkDev(controller.SplitDev):
    2.51      """Info record for a block device.
    2.52      """
    2.53  
    2.54 -    def __init__(self, idx, ctrl, config, vdev, mode, segment):
    2.55 +    def __init__(self, idx, ctrl, config):
    2.56          controller.SplitDev.__init__(self, idx, ctrl)
    2.57 -        self.config = config
    2.58          self.dev = None
    2.59          self.uname = None
    2.60 -        self.vdev = vdev
    2.61 -        self.mode = mode
    2.62 -        self.device = segment['device']
    2.63 -        self.start_sector = segment['start_sector']
    2.64 -        self.nr_sectors = segment['nr_sectors']
    2.65 +        self.vdev = None
    2.66 +        self.mode = None
    2.67 +        self.type = None
    2.68 +        self.params = None
    2.69 +        self.node = None
    2.70 +        self.device = None
    2.71 +        self.start_sector = None
    2.72 +        self.nr_sectors = None
    2.73 +        self.configure(config)
    2.74 +
    2.75 +    def configure(self, config):
    2.76 +        self.config = config
    2.77 +        self.uname = sxp.child_value(config, 'uname')
    2.78 +        if not self.uname:
    2.79 +            raise VmError('vbd: Missing uname')
    2.80 +        # Split into type and type-specific params (which are passed to the
    2.81 +        # type-specific control script).
    2.82 +        (self.type, self.params) = string.split(self.uname, ':', 1)
    2.83 +        self.dev = sxp.child_value(config, 'dev')
    2.84 +        if not self.dev:
    2.85 +            raise VmError('vbd: Missing dev')
    2.86 +        self.mode = sxp.child_value(config, 'mode', 'r')
    2.87 +        # todo: The 'dev' should be looked up in the context of the domain.
    2.88 +        self.vdev = blkdev_name_to_number(self.dev)
    2.89 +        if not self.vdev:
    2.90 +            raise VmError('vbd: Device not found: %s' % self.dev)
    2.91          try:
    2.92              self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
    2.93          except:
    2.94              raise XendError('invalid backend domain')
    2.95  
    2.96 +    def recreate(self, savedinfo):
    2.97 +        node = sxp.child_value(savedinfo, 'node')
    2.98 +        self.setNode(node)
    2.99 +
   2.100 +    def attach(self):
   2.101 +        node = Blkctl.block('bind', self.type, self.params)
   2.102 +        self.setNode(node)
   2.103 +        return self.attachBackend()
   2.104 +
   2.105 +    def unbind(self):
   2.106 +        if self.node is None: return
   2.107 +        log.debug("Unbinding vbd (type %s) from %s"
   2.108 +                  % (self.type, self.node))
   2.109 +        Blkctl.block('unbind', self.type, self.node)
   2.110 +
   2.111 +    def setNode(self, node):
   2.112 +        segment = blkdev_segment(node)
   2.113 +        if not segment:
   2.114 +            raise VmError("vbd: Segment not found: uname=%s" % self.uname)
   2.115 +        self.node = node
   2.116 +        self.device = segment['device']
   2.117 +        self.start_sector = segment['start_sector']
   2.118 +        self.nr_sectors = segment['nr_sectors']
   2.119 +
   2.120      def readonly(self):
   2.121          return 'w' not in self.mode
   2.122  
   2.123      def sxpr(self):
   2.124 -        val = ['blkdev',
   2.125 +        val = ['vbd',
   2.126                 ['idx', self.idx],
   2.127                 ['vdev', self.vdev],
   2.128                 ['device', self.device],
   2.129 @@ -259,13 +343,12 @@ class BlkDev(controller.SplitDev):
   2.130              val.append(['dev', self.dev])
   2.131          if self.uname:
   2.132              val.append(['uname', self.uname])
   2.133 +        if self.node:
   2.134 +            val.append(['node', self.node])
   2.135 +        if self.index is not None:
   2.136 +            val.append(['index', self.index])
   2.137          return val
   2.138  
   2.139 -    def unbind(self):
   2.140 -        log.debug("Unbinding block dev (type %s) from %s"
   2.141 -                  % (self.type, self.node))
   2.142 -        Blkctl.block('unbind', self.type, self.node)
   2.143 -
   2.144      def destroy(self, change=0):
   2.145          """Destroy the device. If 'change' is true notify the front-end interface.
   2.146  
   2.147 @@ -283,7 +366,7 @@ class BlkDev(controller.SplitDev):
   2.148          """
   2.149          self.getBackendInterface().interfaceChanged()
   2.150  
   2.151 -    def attach(self):
   2.152 +    def attachBackend(self):
   2.153          """Attach the device to its controller.
   2.154  
   2.155          """
   2.156 @@ -356,46 +439,6 @@ class BlkDev(controller.SplitDev):
   2.157          return d
   2.158          
   2.159  
   2.160 -def blkdev_name_to_number(name):
   2.161 -    """Take the given textual block-device name (e.g., '/dev/sda1',
   2.162 -    'hda') and return the device number used by the OS. """
   2.163 -
   2.164 -    if not re.match( '^/dev/', name ):
   2.165 -	n = '/dev/' + name
   2.166 -    else:
   2.167 -	n = name
   2.168 -    
   2.169 -    try:
   2.170 -	return os.stat(n).st_rdev
   2.171 -    except Exception, e:
   2.172 -        print "blkdev_name_to_number> exception looking up device number for %s: %s" % (name, e)
   2.173 -	pass
   2.174 -
   2.175 -    # see if this is a hex device number
   2.176 -    if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
   2.177 -	return string.atoi(name,16)
   2.178 -	
   2.179 -    return None
   2.180 -
   2.181 -def lookup_raw_partn(name):
   2.182 -    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
   2.183 -    and return a dictionary { device, start_sector,
   2.184 -    nr_sectors, type }
   2.185 -        device:       Device number of the given partition
   2.186 -        start_sector: Index of first sector of the partition
   2.187 -        nr_sectors:   Number of sectors comprising this partition
   2.188 -        type:         'Disk' or identifying name for partition type
   2.189 -    """
   2.190 -
   2.191 -    n = blkdev_name_to_number(name)
   2.192 -    if n:
   2.193 -	return [ { 'device' : n,
   2.194 -		   'start_sector' : long(0),
   2.195 -		   'nr_sectors' : long(1L<<63),
   2.196 -		   'type' : 'Disk' } ]
   2.197 -    else:
   2.198 -	return None
   2.199 -
   2.200  class BlkifController(controller.SplitController):
   2.201      """Block device interface controller. Handles all block devices
   2.202      for a domain.
   2.203 @@ -418,65 +461,37 @@ class BlkifController(controller.SplitCo
   2.204          val = ['blkif', ['dom', self.dom]]
   2.205          return val
   2.206  
   2.207 -    def addDevice(self, idx, config, vdev, mode, segment):
   2.208 +    def addDevice(self, idx, config):
   2.209          """Add a device to the device table.
   2.210  
   2.211          @param vdev:     device index
   2.212          @type  vdev:     int
   2.213 -        @param mode:     read/write mode
   2.214 -        @type  mode:     string
   2.215 -        @param segment:  segment
   2.216 -        @type  segment:  int
   2.217 +        @param config: device configuration
   2.218          @return: device
   2.219          @rtype:  BlkDev
   2.220          """
   2.221          if idx in self.devices:
   2.222              raise XendError('device exists: ' + str(idx))
   2.223 -        dev = BlkDev(idx, self, config, vdev, mode, segment)
   2.224 +        dev = BlkDev(idx, self, config )
   2.225          self.devices[idx] = dev
   2.226          return dev
   2.227  
   2.228 -    def attachDevice(self, idx, config, uname, vdev, mode, recreate=0):
   2.229 +    def attachDevice(self, idx, config, recreate=0):
   2.230          """Attach a device to the specified interface.
   2.231          On success the returned deferred will be called with the device.
   2.232  
   2.233          @param idx:      device id
   2.234          @param config:   device configuration
   2.235 -        @param vdev:     device index
   2.236 -        @type  vdev:     int
   2.237 -        @param mode:     read/write mode
   2.238 -        @type  mode:     string
   2.239 -        @param segment:  segment
   2.240 -        @type  segment:  int
   2.241          @param recreate: if true it's being recreated (after xend restart)
   2.242          @type  recreate: bool
   2.243          @return: deferred
   2.244          @rtype:  Deferred
   2.245          """
   2.246 -        if not recreate:
   2.247 -            # Split into type and type-specific details (which are passed to the
   2.248 -            # type-specific control script).
   2.249 -            type, dets = string.split(uname, ':', 1)
   2.250 -            # Special case: don't bother calling a script for phy.  Could
   2.251 -            # alternatively provide a "do nothing" script for phy devices...
   2.252 -            node = Blkctl.block('bind', type, dets)
   2.253 -
   2.254 -        segments = lookup_raw_partn(node)
   2.255 -
   2.256 -        if not segments:
   2.257 -            raise VmError("vbd: Segments not found: uname=%s" % uname)
   2.258 -        if len(segments) > 1:
   2.259 -            raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
   2.260 -
   2.261 -        segment = segments[0]            
   2.262 -
   2.263 -        dev = self.addDevice(idx, config, vdev, mode, segment)
   2.264 -            
   2.265 +        dev = self.addDevice(idx, config)
   2.266          if recreate:
   2.267 +            dev.recreate(recreate)
   2.268              d = defer.succeed(dev)
   2.269          else:
   2.270 -            dev.node = node
   2.271 -            dev.type = type
   2.272              d = dev.attach()
   2.273          return d
   2.274  
     3.1 --- a/tools/python/xen/xend/server/controller.py	Tue Oct 19 11:18:09 2004 +0000
     3.2 +++ b/tools/python/xen/xend/server/controller.py	Thu Oct 21 16:07:17 2004 +0000
     3.3 @@ -682,10 +682,17 @@ class SplitDev(Dev):
     3.4      def __init__(self, idx, controller):
     3.5          Dev.__init__(self, idx, controller)
     3.6          self.backendDomain = 0
     3.7 +        self.index = None
     3.8  
     3.9      def getBackendInterface(self):
    3.10          return self.controller.getBackendInterface(self.backendDomain)
    3.11  
    3.12 +    def getIndex(self):
    3.13 +        return self.index
    3.14 +
    3.15 +    def setIndex(self, index):
    3.16 +        self.index = index
    3.17 +
    3.18  
    3.19  
    3.20      
     4.1 --- a/tools/python/xen/xend/server/netif.py	Tue Oct 19 11:18:09 2004 +0000
     4.2 +++ b/tools/python/xen/xend/server/netif.py	Thu Oct 21 16:07:17 2004 +0000
     4.3 @@ -198,6 +198,8 @@ class NetDev(controller.SplitDev):
     4.4              val.append(['evtchn',
     4.5                          self.evtchn['port1'],
     4.6                          self.evtchn['port2']])
     4.7 +        if self.index is not None:
     4.8 +            val.append(['index', self.index])
     4.9          return val
    4.10  
    4.11      def get_vifname(self):