ia64/xen-unstable

changeset 2567:82cab392896d

bitkeeper revision 1.1159.1.191 (41597997cc5ZJzvh6XLLSIhJ9hLEnA)

Initial support for automatic management of non-phy block devices.
author mwilli2@equilibrium.research
date Tue Sep 28 14:47:51 2004 +0000 (2004-09-28)
parents 3f0a9708178b
children 4ecd18756ef8
files .rootkeys tools/examples/block-enbd tools/examples/block-file tools/examples/xend-config.sxp tools/python/xen/xend/Blkctl.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendRoot.py tools/python/xen/xend/server/blkif.py
line diff
     1.1 --- a/.rootkeys	Mon Sep 27 17:35:52 2004 +0000
     1.2 +++ b/.rootkeys	Tue Sep 28 14:47:51 2004 +0000
     1.3 @@ -314,6 +314,8 @@ 4124b308ly20ptMKQoiztPyP_X68Mw tools/che
     1.4  4124b308O8yPHMKbj4YPR_grPGZmdA tools/check/chk
     1.5  401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile
     1.6  401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README
     1.7 +41597996VhTbNuHbuscYSfRb-WR6fA tools/examples/block-enbd
     1.8 +41597996GHP2_yVih2UspXh328fgMQ tools/examples/block-file
     1.9  405ff55dawQyCHFEnJ067ChPRoXBBA tools/examples/init.d/xend
    1.10  40278d94cIUWl2eRgnwZtr4hTyWT1Q tools/examples/init.d/xendomains
    1.11  40ee75a9xFz6S05sDKu-JCLqyVTkDA tools/examples/network
    1.12 @@ -453,6 +455,7 @@ 4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/pyt
    1.13  40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py
    1.14  4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py
    1.15  40c9c468SNuObE_YWARyS0hzTPSzKg tools/python/xen/xend/Args.py
    1.16 +41597996WNvJA-DVCBmc0xU9w_XmoA tools/python/xen/xend/Blkctl.py
    1.17  40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py
    1.18  40c9c468U8EVl0d3G--8YXVg6VJD3g tools/python/xen/xend/EventTypes.py
    1.19  40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/examples/block-enbd	Tue Sep 28 14:47:51 2004 +0000
     2.3 @@ -0,0 +1,33 @@
     2.4 +#!/bin/sh
     2.5 +
     2.6 +# Usage: block-enbd [bind server ctl_port |unbind node]
     2.7 +#
     2.8 +# The file argument to the bind command is the file we are to bind to a
     2.9 +# loop device.  We print the path to the loop device node to stdout.
    2.10 +#
    2.11 +# The node argument to unbind is the name of the device node we are to
    2.12 +# unbind.
    2.13 +#
    2.14 +# This assumes you're running a correctly configured server at the other end!
    2.15 +
    2.16 +case $1 in
    2.17 +	bind)
    2.18 +		for dev in /dev/nd*; do
    2.19 +			if nbd-client $2:$3 $dev; then
    2.20 +				echo $dev
    2.21 +				exit 0
    2.22 +			fi
    2.23 +		done
    2.24 +		exit 1
    2.25 +	;;
    2.26 +
    2.27 +	unbind)
    2.28 +		nbd-client -d $2
    2.29 +		exit 0
    2.30 +	;;
    2.31 +
    2.32 +	*)
    2.33 +		echo 'Unknown command: ' $1
    2.34 +		echo 'Valid commands are: bind, unbind'
    2.35 +		exit 1
    2.36 +esac
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/examples/block-file	Tue Sep 28 14:47:51 2004 +0000
     3.3 @@ -0,0 +1,31 @@
     3.4 +#!/bin/sh
     3.5 +
     3.6 +# Usage: block_loop [bind file|unbind node]
     3.7 +#
     3.8 +# The file argument to the bind command is the file we are to bind to a
     3.9 +# loop device.  We print the path to the loop device node to stdout.
    3.10 +#
    3.11 +# The node argument to unbind is the name of the device node we are to
    3.12 +# unbind.
    3.13 +
    3.14 +case $1 in
    3.15 +	bind)
    3.16 +		for dev in /dev/loop*; do
    3.17 +			if losetup $dev $2; then
    3.18 +				echo $dev
    3.19 +				exit 0
    3.20 +			fi
    3.21 +		done
    3.22 +		exit 1
    3.23 +	;;
    3.24 +
    3.25 +	unbind)
    3.26 +		losetup -d $2
    3.27 +		exit 0
    3.28 +	;;
    3.29 +
    3.30 +	*)
    3.31 +		echo 'Unknown command: ' $1
    3.32 +		echo 'Valid commands are: bind, unbind'
    3.33 +		exit 1
    3.34 +esac
     4.1 --- a/tools/examples/xend-config.sxp	Mon Sep 27 17:35:52 2004 +0000
     4.2 +++ b/tools/examples/xend-config.sxp	Tue Sep 28 14:47:51 2004 +0000
     4.3 @@ -21,3 +21,9 @@
     4.4  # virtual interfaces. Specify 'yes' or 'no'.
     4.5  (vif-antispoof     no)
     4.6  
     4.7 +# Setup script for file-backed block devices
     4.8 +(block-file block-file)
     4.9 +
    4.10 +# Setup script for enbd-backed block devices
    4.11 +(block-enbd block-enbd)
    4.12 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/python/xen/xend/Blkctl.py	Tue Sep 28 14:47:51 2004 +0000
     5.3 @@ -0,0 +1,42 @@
     5.4 +"""Xend interface to block control scripts.
     5.5 +"""
     5.6 +import os
     5.7 +import os.path
     5.8 +import sys
     5.9 +import string
    5.10 +
    5.11 +from xen.xend import XendRoot
    5.12 +xroot = XendRoot.instance()
    5.13 +
    5.14 +"""Where network control scripts live."""
    5.15 +SCRIPT_DIR = xroot.block_script_dir
    5.16 +
    5.17 +def block(op, type, dets, script=None):
    5.18 +    """Call a block control script.
    5.19 +    Xend calls this with op 'bind' when it is about to export a block device
    5.20 +    (other than a raw partition).  The script is called with unbind when a
    5.21 +    device is no longer in use and should be removed.
    5.22 +
    5.23 +    @param op:        operation (start, stop, status)
    5.24 +    @param type:      type of block device (determines the script used)
    5.25 +    @param dets:      arguments to the control script
    5.26 +    @param script:    block script name
    5.27 +    """
    5.28 +    
    5.29 +    if op not in ['bind', 'unbind']:
    5.30 +        raise ValueError('Invalid operation:' + op)
    5.31 +
    5.32 +    # Special case phy devices - they don't require any (un)binding
    5.33 +    if type == 'phy':
    5.34 +        return dets
    5.35 +    
    5.36 +    if script is None:
    5.37 +        script = xroot.get_block_script(type)
    5.38 +    script = os.path.join(SCRIPT_DIR, script)
    5.39 +    args = [op] + string.split(dets, ':')
    5.40 +    args = ' '.join(args)
    5.41 +    out = os.popen(script + ' ' + args)
    5.42 +
    5.43 +    output = out.readline()
    5.44 +    out.close()
    5.45 +    return string.rstrip(output)
     6.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Mon Sep 27 17:35:52 2004 +0000
     6.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Tue Sep 28 14:47:51 2004 +0000
     6.3 @@ -33,6 +33,8 @@ xend = server.SrvDaemon.instance()
     6.4  
     6.5  from XendError import VmError
     6.6  
     6.7 +from server.blkif import blkdev_name_to_number
     6.8 +
     6.9  """The length of domain names that Xen can handle.
    6.10  The names stored in Xen itself are not used for much, and
    6.11  xend can handle domain names of any length.
    6.12 @@ -90,61 +92,6 @@ def shutdown_reason(code):
    6.13      """
    6.14      return shutdown_reasons.get(code, "?")
    6.15  
    6.16 -def blkdev_name_to_number(name):
    6.17 -    """Take the given textual block-device name (e.g., '/dev/sda1',
    6.18 -    'hda') and return the device number used by the OS. """
    6.19 -
    6.20 -    if not re.match( '^/dev/', name ):
    6.21 -	n = '/dev/' + name
    6.22 -    else:
    6.23 -	n = name
    6.24 -        
    6.25 -    try:
    6.26 -	return os.stat(n).st_rdev
    6.27 -    except:
    6.28 -	pass
    6.29 -
    6.30 -    # see if this is a hex device number
    6.31 -    if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
    6.32 -	return string.atoi(name,16)
    6.33 -	
    6.34 -    return None
    6.35 -
    6.36 -def lookup_raw_partn(name):
    6.37 -    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
    6.38 -    and return a dictionary { device, start_sector,
    6.39 -    nr_sectors, type }
    6.40 -        device:       Device number of the given partition
    6.41 -        start_sector: Index of first sector of the partition
    6.42 -        nr_sectors:   Number of sectors comprising this partition
    6.43 -        type:         'Disk' or identifying name for partition type
    6.44 -    """
    6.45 -
    6.46 -    n = blkdev_name_to_number(name)
    6.47 -    if n:
    6.48 -	return [ { 'device' : n,
    6.49 -		   'start_sector' : long(0),
    6.50 -		   'nr_sectors' : long(1L<<63),
    6.51 -		   'type' : 'Disk' } ]
    6.52 -    else:
    6.53 -	return None
    6.54 -
    6.55 -def lookup_disk_uname(uname):
    6.56 -    """Lookup a list of segments for a physical device.
    6.57 -    
    6.58 -    @param uname: name of the device in the format \'phy:dev\' for a physical device
    6.59 -    @type  uname: string
    6.60 -    @return: list of extents that make up the named device
    6.61 -    @rtype: [dict]
    6.62 -    """
    6.63 -    ( type, d_name ) = string.split( uname, ':' )
    6.64 -
    6.65 -    if type == "phy":
    6.66 -        segments = lookup_raw_partn( d_name )
    6.67 -    else:
    6.68 -        segments = None
    6.69 -    return segments
    6.70 -
    6.71  def make_disk(vm, config, uname, dev, mode, recreate=0):
    6.72      """Create a virtual disk device for a domain.
    6.73  
    6.74 @@ -156,18 +103,12 @@ def make_disk(vm, config, uname, dev, mo
    6.75      @return: deferred
    6.76      """
    6.77      idx = vm.next_device_index('vbd')
    6.78 -    segments = lookup_disk_uname(uname)
    6.79 -    if not segments:
    6.80 -        raise VmError("vbd: Segments not found: uname=%s" % uname)
    6.81 -    if len(segments) > 1:
    6.82 -        raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
    6.83 -    segment = segments[0]
    6.84      # todo: The 'dev' should be looked up in the context of the domain.
    6.85      vdev = blkdev_name_to_number(dev)
    6.86      if not vdev:
    6.87          raise VmError("vbd: Device not found: uname=%s dev=%s" % (uname, dev))
    6.88      ctrl = xend.blkif_create(vm.dom, recreate=recreate)
    6.89 -    return ctrl.attachDevice(idx, config, vdev, mode, segment, recreate=recreate)
    6.90 +    return ctrl.attachDevice(idx, config, uname, vdev, mode, recreate=recreate)
    6.91          
    6.92  def vif_up(iplist):
    6.93      """send an unsolicited ARP reply for all non link-local IP addresses.
     7.1 --- a/tools/python/xen/xend/XendRoot.py	Mon Sep 27 17:35:52 2004 +0000
     7.2 +++ b/tools/python/xen/xend/XendRoot.py	Tue Sep 28 14:47:51 2004 +0000
     7.3 @@ -46,6 +46,9 @@ class XendRoot:
     7.4      """Where network control scripts live."""
     7.5      network_script_dir = "/etc/xen/scripts"
     7.6  
     7.7 +    """Where block control scripts live."""
     7.8 +    block_script_dir = "/etc/xen/scripts"
     7.9 +
    7.10      logfile_default = "/var/log/xend.log"
    7.11  
    7.12      loglevel_default = 'DEBUG'
    7.13 @@ -260,6 +263,9 @@ class XendRoot:
    7.14      def get_xend_address(self):
    7.15          return self.get_config_value('xend-address', '')
    7.16  
    7.17 +    def get_block_script(self, type):
    7.18 +        return self.get_config_value('block-%s' % type, '')
    7.19 +
    7.20      def get_network_script(self):
    7.21          return self.get_config_value('network-script', 'network')
    7.22  
     8.1 --- a/tools/python/xen/xend/server/blkif.py	Mon Sep 27 17:35:52 2004 +0000
     8.2 +++ b/tools/python/xen/xend/server/blkif.py	Tue Sep 28 14:47:51 2004 +0000
     8.3 @@ -5,9 +5,13 @@
     8.4  from twisted.internet import defer
     8.5  
     8.6  from xen.xend import sxp
     8.7 +from xen.xend import Blkctl
     8.8  from xen.xend.XendLogging import log
     8.9 -from xen.xend.XendError import XendError
    8.10 +from xen.xend.XendError import XendError, VmError
    8.11  
    8.12 +import os
    8.13 +import re
    8.14 +import string
    8.15  import channel
    8.16  import controller
    8.17  from messages import *
    8.18 @@ -257,6 +261,11 @@ class BlkDev(controller.SplitDev):
    8.19              val.append(['uname', self.uname])
    8.20          return val
    8.21  
    8.22 +    def unbind(self):
    8.23 +        log.debug("Unbinding block dev (type %s) from %s"
    8.24 +                  % (self.type, self.node))
    8.25 +        Blkctl.block('unbind', self.type, self.node)
    8.26 +
    8.27      def destroy(self, change=0):
    8.28          """Destroy the device. If 'change' is true notify the front-end interface.
    8.29  
    8.30 @@ -266,6 +275,7 @@ class BlkDev(controller.SplitDev):
    8.31          d = self.send_be_vbd_destroy()
    8.32          if change:
    8.33              d.addCallback(lambda val: self.interfaceChanged())
    8.34 +        d.addCallback(lambda val: self.unbind())
    8.35  
    8.36      def interfaceChanged(self):
    8.37          """Tell the back-end to notify the front-end that a device has been
    8.38 @@ -345,7 +355,47 @@ class BlkDev(controller.SplitDev):
    8.39          backend.writeRequest(msg, response=d)
    8.40          return d
    8.41          
    8.42 -        
    8.43 +
    8.44 +def blkdev_name_to_number(name):
    8.45 +    """Take the given textual block-device name (e.g., '/dev/sda1',
    8.46 +    'hda') and return the device number used by the OS. """
    8.47 +
    8.48 +    if not re.match( '^/dev/', name ):
    8.49 +	n = '/dev/' + name
    8.50 +    else:
    8.51 +	n = name
    8.52 +    
    8.53 +    try:
    8.54 +	return os.stat(n).st_rdev
    8.55 +    except Exception, e:
    8.56 +        print "blkdev_name_to_number> exception looking up device number for %s: %s" % (name, e)
    8.57 +	pass
    8.58 +
    8.59 +    # see if this is a hex device number
    8.60 +    if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
    8.61 +	return string.atoi(name,16)
    8.62 +	
    8.63 +    return None
    8.64 +
    8.65 +def lookup_raw_partn(name):
    8.66 +    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
    8.67 +    and return a dictionary { device, start_sector,
    8.68 +    nr_sectors, type }
    8.69 +        device:       Device number of the given partition
    8.70 +        start_sector: Index of first sector of the partition
    8.71 +        nr_sectors:   Number of sectors comprising this partition
    8.72 +        type:         'Disk' or identifying name for partition type
    8.73 +    """
    8.74 +
    8.75 +    n = blkdev_name_to_number(name)
    8.76 +    if n:
    8.77 +	return [ { 'device' : n,
    8.78 +		   'start_sector' : long(0),
    8.79 +		   'nr_sectors' : long(1L<<63),
    8.80 +		   'type' : 'Disk' } ]
    8.81 +    else:
    8.82 +	return None
    8.83 +
    8.84  class BlkifController(controller.SplitController):
    8.85      """Block device interface controller. Handles all block devices
    8.86      for a domain.
    8.87 @@ -386,7 +436,7 @@ class BlkifController(controller.SplitCo
    8.88          self.devices[idx] = dev
    8.89          return dev
    8.90  
    8.91 -    def attachDevice(self, idx, config, vdev, mode, segment, recreate=0):
    8.92 +    def attachDevice(self, idx, config, uname, vdev, mode, recreate=0):
    8.93          """Attach a device to the specified interface.
    8.94          On success the returned deferred will be called with the device.
    8.95  
    8.96 @@ -403,10 +453,30 @@ class BlkifController(controller.SplitCo
    8.97          @return: deferred
    8.98          @rtype:  Deferred
    8.99          """
   8.100 +        if not recreate:
   8.101 +            # Split into type and type-specific details (which are passed to the
   8.102 +            # type-specific control script).
   8.103 +            type, dets = string.split(uname, ':', 1)
   8.104 +            # Special case: don't bother calling a script for phy.  Could
   8.105 +            # alternatively provide a "do nothing" script for phy devices...
   8.106 +            node = Blkctl.block('bind', type, dets)
   8.107 +
   8.108 +        segments = lookup_raw_partn(node)
   8.109 +
   8.110 +        if not segments:
   8.111 +            raise VmError("vbd: Segments not found: uname=%s" % uname)
   8.112 +        if len(segments) > 1:
   8.113 +            raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
   8.114 +
   8.115 +        segment = segments[0]            
   8.116 +
   8.117          dev = self.addDevice(idx, config, vdev, mode, segment)
   8.118 +            
   8.119          if recreate:
   8.120              d = defer.succeed(dev)
   8.121          else:
   8.122 +            dev.node = node
   8.123 +            dev.type = type
   8.124              d = dev.attach()
   8.125          return d
   8.126