ia64/xen-unstable

changeset 1041:7c3b17193b4b

bitkeeper revision 1.680 (40083bb4Kb4q4cb9z5eySYtCRnVh3A)

maw_vd.patch
author kaf24@scramble.cl.cam.ac.uk[kaf24]
date Fri Jan 16 19:29:56 2004 +0000 (2004-01-16)
parents d75b1dfddb4b
children 3a01e5ddf625
files .rootkeys docs/VBD-HOWTO.txt tools/examples/add_vbd_to_dom.py tools/examples/createlinuxdom.py tools/examples/list_vbds.py tools/examples/remove_vbd_from_dom.py tools/examples/vd_create.py tools/examples/vd_delete.py tools/examples/vd_format.py tools/examples/vd_refresh.py tools/xc/py/XenoUtil.py
line diff
     1.1 --- a/.rootkeys	Fri Jan 16 17:32:17 2004 +0000
     1.2 +++ b/.rootkeys	Fri Jan 16 19:29:56 2004 +0000
     1.3 @@ -7,6 +7,7 @@ 3f5ef5a24IaQasQE2tyMxrfxskMmvw README
     1.4  3f5ef5a2l4kfBYSQTUaOyyD76WROZQ README.CD
     1.5  3f69d8abYB1vMyD_QVDvzxy5Zscf1A TODO
     1.6  3f9e7d53iC47UnlfORp9iC1vai6kWw docs/Makefile
     1.7 +40083bb4LVQzRqA3ABz0__pPhGNwtA docs/VBD-HOWTO.txt
     1.8  3fafbf11blCNItRsHe0UHwyu5CCDkw docs/Xeno-HOWTO
     1.9  3f9e7d60PWZJeVh5xdnk0nLUdxlqEA docs/eps/xenlogo.eps
    1.10  3f9e7d63lTwQbp2fnx7yY93epWS-eQ docs/figs/dummy
    1.11 @@ -39,13 +40,20 @@ 3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Mak
    1.12  3e6377b24eQqYMsDi9XrFkIgTzZ47A tools/balloon/Makefile
    1.13  3e6377d6eiFjF1hHIS6JEIOFk62xSA tools/balloon/README
    1.14  3e6377dbGcgnisKw16DPCaND7oGO3Q tools/balloon/balloon.c
    1.15 +40083bb4_j61quzxosgZ19LUgLlgYw tools/examples/add_vbd_to_dom.py
    1.16  3fbe2f12OPAkzIUtumU3wRAihnhocQ tools/examples/createlinuxdom.py
    1.17  3fbe2f12dZbmXLlgQdMgkmnSUj23AQ tools/examples/destroydom.py
    1.18 +40083bb4lxCIf5HRu6fwWUyHCYOHKA tools/examples/list_vbds.py
    1.19  3fbe2f12ltvweb13kBSsxqzZDAq4sg tools/examples/listdoms.py
    1.20  3fca7700PVj36cZObaFZlQicRiw1pQ tools/examples/pincpu.py
    1.21  3fd8bc48ww3aOqPhYjCr8KGulG0NQQ tools/examples/readxenconsolering.py
    1.22 +40083bb4zWkCUTHJKd1ApEOoPAuihg tools/examples/remove_vbd_from_dom.py
    1.23  3fccbe068ov0YCxnk-2m4law19QMmA tools/examples/startdom.py
    1.24  3fbe2f12Bnt8mwmr1ZCP6HWGS6yvYw tools/examples/stopdom.py
    1.25 +40083bb4LeyQyL-0riaV3UYDfHkl5g tools/examples/vd_create.py
    1.26 +40083bb4TmKs8pcFkOcJj1bKn3zcmg tools/examples/vd_delete.py
    1.27 +40083bb4u9Od6ujgect6mrxWfkk1pQ tools/examples/vd_format.py
    1.28 +40083bb4NhDpKiYTrebI3ZjX__oI_w tools/examples/vd_refresh.py
    1.29  3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
    1.30  3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
    1.31  3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/docs/VBD-HOWTO.txt	Fri Jan 16 19:29:56 2004 +0000
     2.3 @@ -0,0 +1,273 @@
     2.4 +Virtual Block Devices / Virtual Disks in Xen - HOWTO
     2.5 +====================================================
     2.6 +
     2.7 +HOWTO for Xen 1.2
     2.8 +
     2.9 +Mark A. Williamson (mark.a.williamson@intel.com)
    2.10 +(C) Intel Research Cambridge 2004
    2.11 +
    2.12 +Introduction
    2.13 +------------
    2.14 +
    2.15 +This document describes the new Virtual Block Device (VBD) and Virtual Disk
    2.16 +features available in Xen release 1.2.  First, a brief introduction to some
    2.17 +basic disk concepts on a Xen system:
    2.18 +
    2.19 +Virtual Block Devices (VBDs):
    2.20 +	VBDs are the disk abstraction provided by Xen.  All XenoLinux disk accesses
    2.21 +	go through the VBD driver.  Using the VBD functionality, it is possible
    2.22 +	to selectively grant domains access to portions of the physical disks
    2.23 +	in the system.
    2.24 +
    2.25 +	A virtual block device can also consist of multiple extents from the
    2.26 +	physical disks in the system, allowing them to be accessed as a single
    2.27 +	uniform device from the domain with access to that VBD.
    2.28 +
    2.29 +	Everyone who uses Xen / XenoLinux uses VBDs but for less advanced uses
    2.30 +	they can almost be ignored.
    2.31 +
    2.32 +Virtual Disks (VDs):
    2.33 +	VDs are an abstraction built on top of the functionality provided by
    2.34 +	VBDs.  The VD management code maintains a "free pool" of disk space on
    2.35 +	the system that has been reserved for use with VDs.  The tools can
    2.36 +	automatically allocate collections of extents from this free pool to
    2.37 +	create "virtual disks" on demand.
    2.38 +
    2.39 +	VDs can then be used just like normal disks by domains.  VDs appear
    2.40 +	just like any other disk to guest domains, since they use the same VBD
    2.41 +	abstraction, as provided by Xen.
    2.42 +
    2.43 +	Using VDs is optional, since it's always possible to dedicate
    2.44 +	partitions, or entire disks to your virtual machines.  VDs are handy
    2.45 +	when you have a dynamically changing set of virtual machines and you
    2.46 +	don't want to have to keep repartitioning in order to provide them with
    2.47 +	disk space.
    2.48 +
    2.49 +If that didn't all make sense, it doesn't matter too much ;-)  Using the
    2.50 +functionality is fairly straightforward and some examples will clarify things.
    2.51 +The text below expands a bit on the concepts involved, finishing up with a
    2.52 +walkthrough of some simple virtual disk management tasks.
    2.53 +
    2.54 +
    2.55 +Virtual Block Devices
    2.56 +---------------------
    2.57 +
    2.58 +Before covering VD management, it's worth discussing some aspects of the VBD
    2.59 +functionality that will be useful to know.
    2.60 +
    2.61 +A VBD is made up of a number of extents from physical disk devices.  The
    2.62 +extents for a VBD don't have to be contiguous, or even on the same device.  Xen
    2.63 +performs address translation so that they appear as a single contiguous
    2.64 +device.
    2.65 +
    2.66 +When the VBD layer is used to give access to entire drives or entire
    2.67 +partitions, the VBDs simply consist of a single extent, corresponding to the
    2.68 +drive or partition used.  When used with Virtual Disks, the extent list
    2.69 +functionality will be used (discussed later).
    2.70 +
    2.71 +Xen 1.2 and its associated XenoLinux release support automatic registration /
    2.72 +removal of VBDs.  It has always been possible to add a VBD to a running
    2.73 +XenoLinux domain but it was then necessary to run "xen_vbd_refresh" in order
    2.74 +for the new device to be detected.  Nowadays, when a VBD is added, the domain
    2.75 +it's added to automatically registers the disk.
    2.76 +
    2.77 +Note that it is possible to use the VBD functionality to allow multiple domains
    2.78 +write access to the same areas of disk.  This is almost always a bad thing!
    2.79 +
    2.80 +The provided example script createlinuxdom.py does its best to check that disk
    2.81 +areas are not shared unsafely and will catch many cases of this.  Setting the
    2.82 +vbd_expert variable in that script controls how unsafe it allows VBD mappings
    2.83 +to be - 0 should be right for most people ;-)
    2.84 +
    2.85 +
    2.86 +Virtual Disk Management
    2.87 +-----------------------
    2.88 +
    2.89 +The VD management code runs entirely in userspace.  The code is written in
    2.90 +Python and can therefore be accessed from custom scripts, as well as from the
    2.91 +convenience scripts provided.  The underlying VD database is a SQLite database
    2.92 +in /var/spool/xen_vdisks.sqlite.
    2.93 +
    2.94 +The scripts provided are as follows:
    2.95 +
    2.96 +vd_format.py -	     "Formats" a partition or disk device for use storing
    2.97 +		     virtual disks.  This does not actually write data to the
    2.98 +		     specified device.  Rather, it adds the device to the VD
    2.99 +		     free-space pool, for later allocation.
   2.100 +
   2.101 +		     You should only add devices that correspond directly to
   2.102 +		     physical disks / partitions - trying to use a VBD that you
   2.103 +		     have created yourself as part of the free space pool has
   2.104 +		     undefined (possibly nasty) results.
   2.105 +
   2.106 +vd_create.py -	     Creates a virtual disk of specified size by allocating space
   2.107 +		     from the free space pool.  The virtual disk is identified
   2.108 +		     in future by the unique ID returned by this script.
   2.109 +
   2.110 +		     The disk can be given an expiry time, if desired.  For
   2.111 +		     most users, the best idea is to specify a time of 0 (which
   2.112 +		     has the special meaning "never expire") and then
   2.113 +		     explicitly delete the VD when finished with it -
   2.114 +		     otherwise, VDs could disappear unexpectedly...
   2.115 +
   2.116 +vd_refresh.py -	     Allows the expiry time of a (not yet expired) virtual disk to
   2.117 +		     be modified.  Be aware the VD will disappear when the time has
   2.118 +		     expired.
   2.119 +
   2.120 +vd_delete.py -	     Explicitly delete a VD.  Makes it disappear immediately.
   2.121 +
   2.122 +
   2.123 +The functionality provided by these scripts is also available directly from
   2.124 +Python functions in the XenoUtil module - you can use this functionality in
   2.125 +your own scripts.
   2.126 +
   2.127 +Populating VDs:
   2.128 +
   2.129 +Once you've created a VD, you might want to populate it from DOM0 (for
   2.130 +instance, to put a root filesystem onto it for a guest domain).  This can be
   2.131 +done by dynamically creating a VBD - this is discussed below.
   2.132 +
   2.133 +More detail:
   2.134 +
   2.135 +When you use vd_format.py to add a device to the free space pool, the device is
   2.136 +logically split up into extents.  These extents are recorded in the Virtual
   2.137 +Disk Management database in /var/spool/xen_vdisks.sqlite.
   2.138 +
   2.139 +When you use vd_create.py to add create a virtual disk, some of the extents in
   2.140 +the free space pool are reallocated for that virtual disk and a record for that
   2.141 +VD is added to the database.  When VDs are mapped into domains as VBDs, the
   2.142 +system looks up the allocated extents for the virtual disk in order to set up
   2.143 +the underlying VBD.
   2.144 +
   2.145 +Free space is identified by the fact that it belongs to an "expired" disk.
   2.146 +When vd_format.py adds a real device to the free pool, it actually divides it
   2.147 +into extents and adds them to an already-expired virtual disk.
   2.148 +
   2.149 +If you set an expiry time on a VD, its extents will be liable to be reallocated
   2.150 +to new VDs as soon as that expiry time runs out.  Therefore, be careful when
   2.151 +setting expiry times.
   2.152 +
   2.153 +Finally, vd_delete.py can be used to delete virtual disks when they are no
   2.154 +longer needed.  It works by causing them to expire immediately.
   2.155 +
   2.156 +Security note:
   2.157 +
   2.158 +The disk space for VDs is not zeroed when it is initially added to the free
   2.159 +space pool OR when a VD expires OR when a VD is created.  Therefore, if this is
   2.160 +not done manually it is possible for a domain to read a VD to determine what
   2.161 +was written by previous owners of its constituent extents.  If this is a
   2.162 +problem, users should manually clean the VD in some way before allocating
   2.163 +
   2.164 +
   2.165 +Dynamically Registering VBDs
   2.166 +----------------------------
   2.167 +
   2.168 +Two scripts are included to make it easy to add VDs to domains.
   2.169 +
   2.170 +add_vbd_to_dom.py -	 Creates a VBD corresponding to either a physical
   2.171 +			 device or a virtual disk and adds it as a specified
   2.172 +			 device under the target domain, with either read or
   2.173 +			 write access.
   2.174 +
   2.175 +remove_vbd_from_dom.py - Removes the VBD associated with a specified device
   2.176 +			 node from the target domain.
   2.177 +
   2.178 +These scripts are most useful when populating VDs.  VDs can't be populated
   2.179 +directly, since they don't correspond to real devices.  Using:
   2.180 +
   2.181 +  add_vbd_to_dom.py vd:your_vd_id /dev/wherever 0 rw
   2.182 +
   2.183 +You can make a virtual disk available to DOM0.  Sensible devices to map VDs to
   2.184 +in DOM0 are the /dev/xvd* nodes, since that makes it obvious that they are Xen
   2.185 +virtual devices that don't correspond to real physical devices.
   2.186 +
   2.187 +You can then format, mount and populate the VD through the nominated device
   2.188 +node.  When you've finished, use:
   2.189 +
   2.190 +  remove_vbd_from_dom.py /dev/whatever 0
   2.191 +
   2.192 +To revoke DOM0's access to it.  It's then ready for use in a guest domain.
   2.193 +
   2.194 +
   2.195 +
   2.196 +You can also use add_vbd_to_dom.py to grant access to a physical device to a
   2.197 +guest - you might use this to temporarily share a partition, or to add access
   2.198 +to a partition that wasn't granted at boot time.  Again, remove_vbd_from_dom.py
   2.199 +allows you to revoke access.
   2.200 +
   2.201 +When playing with VBDs, remember that in general, it is only safe for two
   2.202 +domains to have access to a filesystem if they both have read-only access.  You
   2.203 +shouldn't be trying to share anything which is writeable, even if only by one
   2.204 +domain, unless you're really sure you know what you're doing!
   2.205 +
   2.206 +
   2.207 +
   2.208 +Walkthrough: Booting a domain from a VD
   2.209 +---------------------------------------
   2.210 +
   2.211 +As an example, here is a sequence of commands you might use to create a virtual
   2.212 +disk, populate it with a root filesystem and boot a domain from it.  These
   2.213 +steps assume that you've installed the example scripts somewhere on your PATH -
   2.214 +if you haven't done that, you'll need to specify a fully qualified pathname in
   2.215 +the examples below.  The steps also assume that you know how to use the
   2.216 +createlinuxdom.py script provided and have already set it up for your local
   2.217 +configuration, apart from the virtual disks info.
   2.218 +
   2.219 +First, if you haven't done so already, you'll initialise the free space pool by
   2.220 +adding a real partition to it.  The details are stored in the database, so
   2.221 +you'll only need to do it once.  You can also use this command to add further
   2.222 +partitions to the existing free space pool.
   2.223 +
   2.224 +> vd_format.py /dev/<real partition>
   2.225 +
   2.226 +Now you'll want to allocate the space for your virtual disk.  Do so using the
   2.227 +following, specifying the size in megabytes.
   2.228 +
   2.229 +> vd_create.py <chosen size>
   2.230 +
   2.231 +At this point, the vd_create.py program will tell you the virtual disk ID.
   2.232 +Note it down, as it is how you will identify the virtual device in future.
   2.233 +
   2.234 +If you don't want the VD to be bootable (i.e. you're booting a domain from some
   2.235 +other medium and just want it to be able to access this VD), you can simply add
   2.236 +it to the vbds list in your custom createlinuxdom.py (step 5) and then run that
   2.237 +script.  Any formatting / populating of the VD can be done from that domain.
   2.238 +
   2.239 +If you want to boot off your new VD as well then you need to populate it with a
   2.240 +standard Linux root filesystem.  You'll need to temporarily add the VD to DOM0
   2.241 +in order to do this.  To give DOM0 r/w access to the VD, use the following
   2.242 +command line, substituting the ID you got earlier.
   2.243 +
   2.244 +> add_vbd_to_dom.py vd:<id> /dev/xvda 0 rw
   2.245 +
   2.246 +This attaches the VD to the device /dev/xvda - you can use other devices if you
   2.247 +choose too but with the xvd* devices it's obvious you're using a virtual device.
   2.248 +
   2.249 +Now make a filesystem on this device, mount it and populate it with a root
   2.250 +filesystem.  These steps are exactly the same as under normal Linux.  When
   2.251 +you've finished, unmount the filesystem again.
   2.252 +
   2.253 +You should now remove the VD from DOM0.  This will prevent you accidentally
   2.254 +changing it in DOM0, whilst the guest domain is using it.
   2.255 +
   2.256 +> remove_vbd_from_dom.py /dev/xvda 0
   2.257 +
   2.258 +It should now be possible to boot a guest domain from the VD.  To do this, you
   2.259 +should add the VD's details to the vbds list in step 5 of createlinuxdom.py and
   2.260 +set the value of rootbit in step 6.  For instance, you might add:
   2.261 +
   2.262 +('vd:<id>', '/dev/xvda', 'w')
   2.263 +
   2.264 +To the vbds list in step 5 - this gives the domain writeable access to the VD
   2.265 +as if it were the domain's /dev/xvda.
   2.266 +
   2.267 +Then you would set:
   2.268 +
   2.269 +rootbit = "root=/dev/xvda ro"
   2.270 +
   2.271 +In step 6 to tell the kernel where the root filesystem is.
   2.272 +
   2.273 +
   2.274 +
   2.275 +Once these variables are set, you can run createlinuxdom.py to start your new
   2.276 +domain.
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/examples/add_vbd_to_dom.py	Fri Jan 16 19:29:56 2004 +0000
     3.3 @@ -0,0 +1,51 @@
     3.4 +#!/usr/bin/env python
     3.5 +
     3.6 +# Used to map a VBD into a domain's device space.  Useful for populating a new
     3.7 +# VBD with data from DOM0 before starting a new domain using it, for instance.
     3.8 +
     3.9 +import Xc, XenoUtil, sys
    3.10 +
    3.11 +XenoUtil.VBD_EXPERT_LEVEL = 0 # sets the allowed level of potentially unsafe mappings
    3.12 +
    3.13 +def usage():
    3.14 +    print >>sys.stderr,"""Usage: add_vdisk_to_dom.py uname target-dev target-dom [perms]
    3.15 +        uname        - the uname of the source device, e.g. vd:2341 or phy:hda3
    3.16 +        target-dev   - the device node to map the VBD to
    3.17 +        target-dom   - domain to add the new VBD to
    3.18 +        perms        - optionally specify 'r', or 'rw' (default is 'r')
    3.19 +        """
    3.20 +    sys.exit(1)    
    3.21 +
    3.22 +xc = Xc.new()
    3.23 +
    3.24 +if not 4 <= len(sys.argv) <= 5:
    3.25 +    print len(sys.argv)
    3.26 +    usage()
    3.27 +    
    3.28 +writeable = 0
    3.29 +
    3.30 +if len(sys.argv) == 5:
    3.31 +    if sys.argv[4] == 'rw':
    3.32 +        writeable = 1;
    3.33 +    else:
    3.34 +        if sys.argv[4] != 'r':
    3.35 +            usage()
    3.36 +
    3.37 +segments = XenoUtil.lookup_disk_uname(sys.argv[1])
    3.38 +
    3.39 +if XenoUtil.vd_extents_validate(segments,writeable) < 0:
    3.40 +    print "That mapping is too unsafe for the current VBD expertise level"
    3.41 +    sys.exit(1)
    3.42 +
    3.43 +virt_dev = XenoUtil.blkdev_name_to_number(sys.argv[2])
    3.44 +
    3.45 +target_dom = int(sys.argv[3])
    3.46 +
    3.47 +xc.vbd_create(target_dom,virt_dev,writeable)
    3.48 +
    3.49 +if xc.vbd_setextents( target_dom, virt_dev, segments ):
    3.50 +    print "Error populating VBD vbd=%d\n" % virt_dev
    3.51 +    sys.exit(1)
    3.52 +
    3.53 +
    3.54 +print "Added " + sys.argv[1] + " to domain " + sys.argv[3] + " as device " + sys.argv[2]
     4.1 --- a/tools/examples/createlinuxdom.py	Fri Jan 16 17:32:17 2004 +0000
     4.2 +++ b/tools/examples/createlinuxdom.py	Fri Jan 16 19:29:56 2004 +0000
     4.3 @@ -51,6 +51,12 @@ vbds = [ ('phy:sda%d'%(7+guestid),'sda1'
     4.4  	 ('phy:sda6','sda6','r'),
     4.5  	 ('phy:cdrom','hdd','r') ]
     4.6  
     4.7 +# STEP 5b. Set the VBD expertise level.  Most people should leave this
     4.8 +# on 0, at least to begin with - this script can detect most dangerous
     4.9 +# disk sharing between domains and with this set to zero it will only
    4.10 +# allow read only sharing.
    4.11 +vbd_expert = 0
    4.12 +
    4.13  # STEP 6. Build the command line for the new domain. Edit as req'd.
    4.14  # You only need the ip= line if you're NFS booting or the root file system
    4.15  # doesn't set it later e.g. in ifcfg-eth0 or via DHCP
    4.16 @@ -96,7 +102,7 @@ def make_domain():
    4.17  
    4.18      # set up access to the global variables declared above
    4.19      global image, memory_megabytes, domain_name, ipaddr, netmask
    4.20 -    global vbds, cmdline, xc
    4.21 +    global vbds, cmdline, xc, vbd_expert
    4.22      	
    4.23      if not os.path.isfile( image ):
    4.24          print "Image file '" + image + "' does not exist"
    4.25 @@ -116,6 +122,10 @@ def make_domain():
    4.26          sys.exit()
    4.27  
    4.28      # setup the virtual block devices
    4.29 +
    4.30 +    # set the expertise level appropriately
    4.31 +    XenoUtil.VBD_EXPERT_MODE = vbd_expert
    4.32 +    
    4.33      for ( uname, virt_name, rw ) in vbds:
    4.34  	virt_dev = XenoUtil.blkdev_name_to_number( virt_name )
    4.35  
    4.36 @@ -125,20 +135,23 @@ def make_domain():
    4.37  	    xc.domain_destroy ( dom=id )
    4.38  	    sys.exit()
    4.39  
    4.40 +        # check that setting up this VBD won't violate the sharing
    4.41 +        # allowed by the current VBD expertise level
    4.42 +        if XenoUtil.vd_extents_validate(segments, rw=='w') < 0:
    4.43 +            xc.domain_destroy( dom = id )
    4.44 +            sys.exit()
    4.45 +            
    4.46  	if xc.vbd_create( dom=id, vbd=virt_dev, writeable= rw=='w' ):
    4.47  	    print "Error creating VBD vbd=%d writeable=%d\n" % (virt_dev,rw)
    4.48  	    xc.domain_destroy ( dom=id )
    4.49  	    sys.exit()
    4.50  
    4.51 -	for (s_dev,s_start,s_len,s_type) in segments:
    4.52 -	    if xc.vbd_grow( dom=id,
    4.53 -			    vbd=virt_dev,
    4.54 -			    device=s_dev,
    4.55 -			    start_sector=s_start,
    4.56 -			    nr_sectors=s_len ):
    4.57 -		print "Error populating VBD vbd=%d\n" % virt_dev
    4.58 -		xc.domain_destroy ( dom=id )
    4.59 -		sys.exit()
    4.60 +        if xc.vbd_setextents( dom=id,
    4.61 +                              vbd=virt_dev,
    4.62 +                              extents=segments):
    4.63 +            print "Error populating VBD vbd=%d\n" % virt_dev
    4.64 +            xc.domain_destroy ( dom=id )
    4.65 +            sys.exit()
    4.66  
    4.67      # setup virtual firewall rules for all aliases
    4.68      for ip in ipaddr:
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/examples/list_vbds.py	Fri Jan 16 19:29:56 2004 +0000
     5.3 @@ -0,0 +1,8 @@
     5.4 +#!/usr/bin/env python
     5.5 +
     5.6 +
     5.7 +import Xc, sys
     5.8 +
     5.9 +xc = Xc.new()
    5.10 +
    5.11 +print xc.vbd_probe()
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/examples/remove_vbd_from_dom.py	Fri Jan 16 19:29:56 2004 +0000
     6.3 @@ -0,0 +1,29 @@
     6.4 +#!/usr/bin/env python
     6.5 +
     6.6 +# Used to map a VBD into a domain's device space.  Useful for populating a new
     6.7 +# VBD with data from DOM0 before starting a new domain using it, for instance.
     6.8 +
     6.9 +# Usage: add_vdisk_to_dom.py uname target-dev-name target-dom-number
    6.10 +#        uname             - the uname of the device, e.g. vd:2341 or phy:hda3
    6.11 +#        target-dev-name   - the device node to map the VBD to
    6.12 +#        target-dom-number - domain to add the new VBD to
    6.13 +
    6.14 +import Xc, XenoUtil, sys
    6.15 +
    6.16 +xc = Xc.new()
    6.17 +
    6.18 +if len(sys.argv) != 3:
    6.19 +    print >>sys.stderr,"""Usage: add_vdisk_to_dom.py target-dev target-dom
    6.20 +        target-dev   - the device node the VBD is mapped to
    6.21 +        target-dom   - domain to remove the VBD from"""
    6.22 +    sys.exit(1)
    6.23 +
    6.24 +virt_dev = XenoUtil.blkdev_name_to_number(sys.argv[1])
    6.25 +
    6.26 +target_dom = int(sys.argv[2])
    6.27 +
    6.28 +if not xc.vbd_destroy(target_dom,virt_dev):
    6.29 +    print "Removed " + sys.argv[1] + " from domain " + sys.argv[2]
    6.30 +else:
    6.31 +    print "Failed"
    6.32 +    sys.exit(1)
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/examples/vd_create.py	Fri Jan 16 19:29:56 2004 +0000
     7.3 @@ -0,0 +1,36 @@
     7.4 +#!/usr/bin/env python
     7.5 +
     7.6 +#
     7.7 +# Wrapper script for creating a virtual disk.
     7.8 +#
     7.9 +# Usage: vd_create.py size [expiry]
    7.10 +#
    7.11 +
    7.12 +import XenoUtil, sys
    7.13 +
    7.14 +if len(sys.argv) > 1:
    7.15 +    size = int(sys.argv[1])
    7.16 +else:
    7.17 +    print "Usage: " + sys.argv[0] + """ size [expiry]
    7.18 +    Allocates a Virtual Disk out of the free space pool.  An expiry time
    7.19 +    can be specified in seconds from now (0 means never expire) - the default
    7.20 +    is for disks to never expire."""
    7.21 +    sys.exit(1)
    7.22 +
    7.23 +if len(sys.argv) > 2:
    7.24 +    expiry_time = int(sys.argv[2])
    7.25 +else:
    7.26 +    print "No expiry time specified - using default\n"
    7.27 +    expiry_time = 0
    7.28 +
    7.29 +print "Creating a virtual disk"
    7.30 +print "Size: %d" % size
    7.31 +print "Expiry time (seconds from now): %d" % expiry_time
    7.32 +
    7.33 +ret = XenoUtil.vd_create(size, expiry_time)
    7.34 +
    7.35 +if ret < 0:
    7.36 +    print >> sys.stderr, "An error occurred creating the the disk"
    7.37 +    sys.exit(ret)
    7.38 +else:
    7.39 +    print "Virtual disk allocated, with ID: " + ret
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/examples/vd_delete.py	Fri Jan 16 19:29:56 2004 +0000
     8.3 @@ -0,0 +1,20 @@
     8.4 +#!/usr/bin/env python
     8.5 +
     8.6 +#
     8.7 +# Wrapper script for deleting a virtual disk.
     8.8 +#
     8.9 +# Usage: vd_create.py id
    8.10 +#
    8.11 +
    8.12 +import sys, XenoUtil
    8.13 +
    8.14 +if len(sys.argv) > 1:
    8.15 +        id = sys.argv[1]
    8.16 +else:
    8.17 +    print "Usage: " + sys.argv[0] + """ id
    8.18 +    Deletes a virtual disk."""
    8.19 +    sys.exit(1)
    8.20 +
    8.21 +print "Deleting a virtual disk with ID: " + id
    8.22 +
    8.23 +ret = XenoUtil.vd_delete(id)
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/examples/vd_format.py	Fri Jan 16 19:29:56 2004 +0000
     9.3 @@ -0,0 +1,34 @@
     9.4 +#!/usr/bin/env python
     9.5 +
     9.6 +#
     9.7 +# Wrapper script for formatting a device to host Xen virtual disk extents
     9.8 +#
     9.9 +# Usage: vd_format.py device [extent_size]
    9.10 +#
    9.11 +
    9.12 +import sys, XenoUtil
    9.13 +
    9.14 +if len(sys.argv) > 1:
    9.15 +    device = sys.argv[1]
    9.16 +else:
    9.17 +    print "Usage: " + sys.argv[0] + """ device [extent_size]
    9.18 +     Formats a device to host Xen virtual disk extents.  The extent size can
    9.19 +     optionally be specified in megabytes (default 64MB)."""
    9.20 +    sys.exit(1)
    9.21 +
    9.22 +if len(sys.argv) > 2:
    9.23 +    extent_size = int(sys.argv[2])
    9.24 +else:
    9.25 +    print """No extent size specified - using default size
    9.26 +    (for really small devices, the default size of 64MB might not work)"""
    9.27 +    extent_size = 64
    9.28 +
    9.29 +print "Formatting for virtual disks"
    9.30 +print "Device: " + sys.argv[1]
    9.31 +print "Extent size: " + str(extent_size) + "MB"
    9.32 +
    9.33 +ret = XenoUtil.vd_format(device, extent_size)
    9.34 +
    9.35 +if ret:
    9.36 +    print >> sys.stderr, "An error occurred formatting the device"
    9.37 +    sys.exit(ret)
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/examples/vd_refresh.py	Fri Jan 16 19:29:56 2004 +0000
    10.3 @@ -0,0 +1,31 @@
    10.4 +#!/usr/bin/env python
    10.5 +
    10.6 +#
    10.7 +# Wrapper script for creating a virtual disk.
    10.8 +#
    10.9 +# Usage: vd_refresh.py id [new-expiry]
   10.10 +#
   10.11 +
   10.12 +import sys, XenoUtil
   10.13 +
   10.14 +if len(sys.argv) > 1:
   10.15 +        id = sys.argv[1]
   10.16 +else:
   10.17 +    print "Usage: " + sys.argv[0] + """ ID [expiry-new]
   10.18 +    Refreshes a Virtual Disk expiry time.  An expiry time
   10.19 +    can be specified in seconds from now (0 means never expire) - the default
   10.20 +    is for disks to never expire."""
   10.21 +    sys.exit(1)
   10.22 +
   10.23 +if len(sys.argv) > 2:
   10.24 +    expiry_time = int(sys.argv[2])
   10.25 +else:
   10.26 +    print "No expiry time specified - using default\n"
   10.27 +    expiry_time = 0
   10.28 +
   10.29 +print "Refreshing a virtual disk"
   10.30 +print "Id: " + sys.argv[1]
   10.31 +print "Expiry time (seconds from now): " + sys.argv[2]
   10.32 +
   10.33 +ret = XenoUtil.vd_refresh(id, expiry_time)
   10.34 +
    11.1 --- a/tools/xc/py/XenoUtil.py	Fri Jan 16 17:32:17 2004 +0000
    11.2 +++ b/tools/xc/py/XenoUtil.py	Fri Jan 16 19:29:56 2004 +0000
    11.3 @@ -1,67 +1,22 @@
    11.4 -
    11.5 -import string, re, os
    11.6 +import string, re, os, sqlite, Xc, sys
    11.7  
    11.8 -def blkdev_name_to_number(name):
    11.9 -    """Take the given textual block-device name (e.g., '/dev/sda1',
   11.10 -    'hda') and return the device number used by the OS. """
   11.11 -
   11.12 -    if not re.match( '/dev/', name ):
   11.13 -        name = '/dev/' + name
   11.14 -        
   11.15 -    return os.stat(name).st_rdev
   11.16 -
   11.17 +##### Module variables
   11.18  
   11.19 -# lookup_blkdev_partn_info( '/dev/sda3' )
   11.20 -def lookup_raw_partn(partition):
   11.21 -    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
   11.22 -    and return a information tuple ( partn-dev, disc-dev, start-sect,
   11.23 -    nr-sects, type )
   11.24 -        partn-dev:  Device number of the given partition
   11.25 -        disc-dev:   Device number of the disc containing the partition
   11.26 -        start-sect: Index of first sector of the partition
   11.27 -        nr-sects:   Number of sectors comprising this partition
   11.28 -        type:       'Disk' or identifying name for partition type
   11.29 -    """
   11.30 -
   11.31 -    if not re.match( '/dev/', partition ):
   11.32 -        partition = '/dev/' + partition
   11.33 -
   11.34 -    drive = re.split( '[0-9]', partition )[0]
   11.35 +"""Location of the Virtual Disk management database.
   11.36 +   defaults to /var/spool/xen_vdisks.sqlite
   11.37 +"""
   11.38 +VD_DB_FILE = "/var/spool/xen_vdisks.sqlite"
   11.39  
   11.40 -    if drive == partition:
   11.41 -        fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
   11.42 -        line = fd.readline()
   11.43 -        if line:
   11.44 -            return [( blkdev_name_to_number(drive),
   11.45 -                     0,
   11.46 -                     string.atol(line) * 2,
   11.47 -                     'Disk' )]
   11.48 -        return None
   11.49 -
   11.50 -    # determine position on disk
   11.51 -    fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
   11.52 +"""VBD expertise level - determines the strictness of the sanity checking.
   11.53 +  This mode determines the level of complaints when disk sharing occurs
   11.54 +  through the current VBD mappings.
   11.55 +   0 - only allow shared mappings if both domains have r/o access (always OK)
   11.56 +   1 - also allow sharing with one dom r/w and the other r/o
   11.57 +   2 - allow sharing with both doms r/w
   11.58 +"""
   11.59 +VBD_EXPERT_MODE = 0
   11.60  
   11.61 -    #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
   11.62 -    lines = fd.readlines()
   11.63 -    for line in lines:
   11.64 -        m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
   11.65 -                       'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
   11.66 -        if m:
   11.67 -            return [( blkdev_name_to_number(drive),
   11.68 -                     string.atol(m.group(1)),
   11.69 -                     string.atol(m.group(2)),
   11.70 -                     m.group(3) )]
   11.71 -    return None
   11.72 -
   11.73 -def lookup_disk_uname( uname ):
   11.74 -    ( type, d_name ) = string.split( uname, ':' )
   11.75 -
   11.76 -    if type == "phy":
   11.77 -	segments = lookup_raw_partn( d_name )
   11.78 -    elif type == "vd":
   11.79 -	segments = lookup_vd( d_name )
   11.80 -
   11.81 -    return segments
   11.82 +##### Networking-related functions
   11.83  
   11.84  def get_current_ipaddr(dev='eth0'):
   11.85      """Return a string containing the primary IP address for the given
   11.86 @@ -134,3 +89,463 @@ def add_offset_to_ip( ip, off ):
   11.87      return '%d.%d.%d.%d' % ( ((a>>24)&0xff), ((a>>16)&0xff),
   11.88  			     ((a>>8)&0xff), (a&0xff) )
   11.89  
   11.90 +##### VBD-related Functions
   11.91 +
   11.92 +def blkdev_name_to_number(name):
   11.93 +    """Take the given textual block-device name (e.g., '/dev/sda1',
   11.94 +    'hda') and return the device number used by the OS. """
   11.95 +
   11.96 +    if not re.match( '/dev/', name ):
   11.97 +        name = '/dev/' + name
   11.98 +        
   11.99 +    return os.stat(name).st_rdev
  11.100 +
  11.101 +# lookup_blkdev_partn_info( '/dev/sda3' )
  11.102 +def lookup_raw_partn(partition):
  11.103 +    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
  11.104 +    and return a dictionary { partn-dev, start-sect,
  11.105 +    nr-sects, type }
  11.106 +        device:       Device number of the given partition
  11.107 +        start_sector: Index of first sector of the partition
  11.108 +        nr_sectsors:  Number of sectors comprising this partition
  11.109 +        type:       'Disk' or identifying name for partition type
  11.110 +    """
  11.111 +
  11.112 +    if not re.match( '/dev/', partition ):
  11.113 +        partition = '/dev/' + partition
  11.114 +
  11.115 +    drive = re.split( '[0-9]', partition )[0]
  11.116 +
  11.117 +    if drive == partition:
  11.118 +        fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
  11.119 +        line = fd.readline()
  11.120 +        if line:
  11.121 +            return [ { 'device' : blkdev_name_to_number(drive),
  11.122 +                       'start_sector' : 0,
  11.123 +                       'nr_sectors' : string.atol(line) * 2,
  11.124 +                       'type' : 'Disk' } ]
  11.125 +        return None
  11.126 +
  11.127 +    # determine position on disk
  11.128 +    fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
  11.129 +
  11.130 +    #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
  11.131 +    lines = fd.readlines()
  11.132 +    for line in lines:
  11.133 +        m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
  11.134 +                       'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
  11.135 +        if m:
  11.136 +            return [ { 'device' : blkdev_name_to_number(drive),
  11.137 +                       'start_sector' : string.atol(m.group(1)),
  11.138 +                       'nr_sectors' : string.atol(m.group(2)),
  11.139 +                       'type' : m.group(3) } ]
  11.140 +    
  11.141 +    return None
  11.142 +
  11.143 +def lookup_disk_uname( uname ):
  11.144 +    """Lookup a list of segments for either a physical or a virtual device.
  11.145 +    uname [string]:  name of the device in the format \'vd:id\' for a virtual
  11.146 +                     disk, or \'phy:dev\' for a physical device
  11.147 +    returns [list of dicts]: list of extents that make up the named device
  11.148 +    """
  11.149 +    ( type, d_name ) = string.split( uname, ':' )
  11.150 +
  11.151 +    if type == "phy":
  11.152 +        segments = lookup_raw_partn( d_name )
  11.153 +    elif type == "vd":
  11.154 +	segments = vd_lookup( d_name )
  11.155 +
  11.156 +    return segments
  11.157 +
  11.158 +
  11.159 +
  11.160 +##### VD Management-related functions
  11.161 +
  11.162 +
  11.163 +
  11.164 +def __vd_no_database():
  11.165 +    """Called when no database found - exits with an error
  11.166 +    """
  11.167 +    print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE
  11.168 +    sys.exit(1)
  11.169 +
  11.170 +def vd_format(partition, extent_size_mb):
  11.171 +    """Format a partition or drive for use a virtual disk storage.
  11.172 +    partition [string]: device file representing the partition
  11.173 +    extent_size_mb [string]: extent size in megabytes to use on this disk
  11.174 +    """
  11.175 +
  11.176 +    if not os.path.isfile(VD_DB_FILE):
  11.177 +        vd_init_db(VD_DB_FILE)
  11.178 +    
  11.179 +    if not re.match( '/dev/', partition ):
  11.180 +        partition = '/dev/' + partition
  11.181 +
  11.182 +    cx = sqlite.connect(VD_DB_FILE)
  11.183 +    cu = cx.cursor()
  11.184 +
  11.185 +    cu.execute("select * from vdisk_part where partition = \'"
  11.186 +               + partition + "\'")
  11.187 +    row = cu.fetchone()
  11.188 +
  11.189 +    extent_size = extent_size_mb * 2048 # convert megabytes to sectors
  11.190 +    
  11.191 +    if not row:
  11.192 +        part_info = lookup_raw_partn(partition)[0]
  11.193 +        
  11.194 +        cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " +
  11.195 +                   "VALUES ( \'" + partition + "\', " + str(part_info['device'])
  11.196 +                   + ", " + str(extent_size) + ")")
  11.197 +
  11.198 +
  11.199 +        cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents "
  11.200 +                   + "WHERE vdisk_id = 0")
  11.201 +        
  11.202 +        max_id, = cu.fetchone()
  11.203 +
  11.204 +        if max_id != None:
  11.205 +            new_id = max_id + 1
  11.206 +        else:
  11.207 +            new_id = 0
  11.208 +
  11.209 +        for i in range(part_info['nr_sectors'] / extent_size):
  11.210 +            sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id,
  11.211 +                                              part_id, part_extent_no)
  11.212 +                    VALUES ("""+ str(new_id + i) + ", 0, "\
  11.213 +                               + str(part_info['device']) + ", " + str(i) + ")"
  11.214 +            cu.execute(sql)
  11.215 +
  11.216 +    cx.commit()
  11.217 +    cx.close()
  11.218 +    return 0
  11.219 +
  11.220 +def vd_create(size_mb, expiry):
  11.221 +    """Create a new virtual disk.
  11.222 +    size_mb [int]: size in megabytes for the new virtual disk
  11.223 +    expiry [int]: expiry time in seconds from now
  11.224 +    """
  11.225 +
  11.226 +    if not os.path.isfile(VD_DB_FILE):
  11.227 +        __vd_no_database()
  11.228 +
  11.229 +    cx = sqlite.connect(VD_DB_FILE)
  11.230 +    cu = cx.cursor()
  11.231 +
  11.232 +    size = size_mb * 2048
  11.233 +
  11.234 +    cu.execute("SELECT max(vdisk_id) FROM vdisks")
  11.235 +    max_id, = cu.fetchone()
  11.236 +    new_id = int(max_id) + 1
  11.237 +
  11.238 +    # fetch a list of extents from the expired disks, along with information
  11.239 +    # about their size
  11.240 +    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  11.241 +                         vdisk_extents.part_id, extent_size
  11.242 +                  FROM vdisk_extents NATURAL JOIN vdisks
  11.243 +                                                  NATURAL JOIN vdisk_part
  11.244 +                  WHERE expires AND expiry_time < datetime('now')
  11.245 +                  ORDER BY expiry_time asc, vdisk_extent_no desc
  11.246 +               """)  # aims to reuse the last extents
  11.247 +                     # from the longest-expired disks first
  11.248 +
  11.249 +    allocated = 0
  11.250 +
  11.251 +    if expiry:
  11.252 +        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  11.253 +        expires = 1;
  11.254 +    else:
  11.255 +        expiry_ts = "NULL"
  11.256 +        expires = 0;
  11.257 +
  11.258 +    # we'll use this to build the SQL statement we want
  11.259 +    building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \
  11.260 +                   +" VALUES ("+str(new_id)+", "+str(size)+ ", "              \
  11.261 +                   + str(expires) + ", " + expiry_ts + "); "
  11.262 +
  11.263 +    counter = 0
  11.264 +
  11.265 +    while allocated < size:
  11.266 +        row = cu.fetchone()
  11.267 +        if not row:
  11.268 +            cx.close()
  11.269 +            return -1
  11.270 +
  11.271 +        (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  11.272 +        allocated += extent_size
  11.273 +        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \
  11.274 +                        + ", " + "vdisk_extent_no = " + str(counter)         \
  11.275 +                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  11.276 +                        + " AND vdisk_id = " + str(vdisk_id) + "; "
  11.277 +
  11.278 +        counter += 1
  11.279 +        
  11.280 +
  11.281 +    # this will execute the SQL query we build to store details of the new
  11.282 +    # virtual disk and allocate space to it print building_sql
  11.283 +    cu.execute(building_sql)
  11.284 +    
  11.285 +    cx.commit()
  11.286 +    cx.close()
  11.287 +    return str(new_id)
  11.288 +
  11.289 +
  11.290 +# Future work: Disk sizes aren't modified when vd_create scavenges extents from
  11.291 +# expired disks.  As a result it is possible to check if a disk is expired but
  11.292 +# intact (assuming VD IDs are not reused) - could allow recovery when people
  11.293 +# mess up.
  11.294 +
  11.295 +def vd_lookup(id):
  11.296 +    """Lookup a Virtual Disk by ID.
  11.297 +    id [string]: a virtual disk identifier
  11.298 +    Returns [list of dicts]: a list of extents as dicts, contain fields:
  11.299 +                             device : Linux device number
  11.300 +                             start_sector : within the device
  11.301 +                             nr_sectors : size of this extent
  11.302 +                             type : set to \'VD Extent\'
  11.303 +    """
  11.304 +
  11.305 +    if not os.path.isfile(VD_DB_FILE):
  11.306 +        __vd_no_database()
  11.307 +
  11.308 +    cx = sqlite.connect(VD_DB_FILE)
  11.309 +    cu = cx.cursor()
  11.310 +
  11.311 +  
  11.312 +    # This query tells PySQLite how to convert the data returned from the
  11.313 +    # following query - the use of the multiplication confuses it otherwise ;-)
  11.314 +    # This row is significant to PySQLite but is syntactically an SQL comment.
  11.315 +
  11.316 +    cu.execute("-- types int, int, int")
  11.317 +
  11.318 +    # This SQL statement is designed so that when the results are fetched they
  11.319 +    # will be in the right format to return immediately.
  11.320 +    cu.execute("""SELECT vdisk_extents.part_id,
  11.321 +                         round(part_extent_no * extent_size) as start,
  11.322 +                         extent_size
  11.323 +                         
  11.324 +                  FROM vdisk_extents NATURAL JOIN vdisks
  11.325 +                                                NATURAL JOIN vdisk_part
  11.326 +                                                
  11.327 +                  WHERE (expiry_time > datetime('now') OR not expires)
  11.328 +                                    AND vdisk_extents.vdisk_id = """ + id
  11.329 +               )
  11.330 +
  11.331 +    ret = cu.fetchall()
  11.332 +
  11.333 +    # use this function to map the results from the database into a dict
  11.334 +    # list of extents, for consistency with the rest of the code
  11.335 +    def transform ((device, start_sector, nr_sectors)):
  11.336 +        return {'device' : device, 'start_sector' : int(start_sector),
  11.337 +                'nr_sectors' : nr_sectors, 'type' : 'VD Extent' }
  11.338 +
  11.339 +    cx.commit()
  11.340 +    cx.close()
  11.341 +
  11.342 +    return map(transform, ret) # transforms the tuples into dicts to return
  11.343 +
  11.344 +
  11.345 +def vd_refresh(id, expiry):
  11.346 +    """Change the expiry time of a virtual disk.
  11.347 +    id [string]: a virtual disk identifier
  11.348 +    expiry [int]: expiry time in seconds from now (0 = never expire)
  11.349 +    """
  11.350 +
  11.351 +    if not os.path.isfile(VD_DB_FILE):
  11.352 +        __vd_no_database()
  11.353 +    
  11.354 +    cx = sqlite.connect(VD_DB_FILE)
  11.355 +    cu = cx.cursor()
  11.356 +
  11.357 +    if expiry:
  11.358 +        expires = 1
  11.359 +        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  11.360 +    else:
  11.361 +        expires = 0
  11.362 +        expiry_ts = "NULL"
  11.363 +
  11.364 +    cu.execute("UPDATE vdisks SET expires = " + str(expires)
  11.365 +               + ", expiry_time = " + expiry_ts
  11.366 +               + " WHERE vdisk_id = " + id)
  11.367 +
  11.368 +    cx.commit()
  11.369 +    cx.close()
  11.370 +    
  11.371 +    return
  11.372 +
  11.373 +def vd_delete(id):
  11.374 +    """Deletes a Virtual Disk, making its extents available for future
  11.375 +    virtual disks.
  11.376 +       [id] identifier for the virtual disk to delete
  11.377 +    """
  11.378 +
  11.379 +    if not os.path.isfile(VD_DB_FILE):
  11.380 +        __vd_no_database()
  11.381 +    
  11.382 +    cx = sqlite.connect(VD_DB_FILE)
  11.383 +    cu = cx.cursor()
  11.384 +
  11.385 +    cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')"
  11.386 +               + " WHERE vdisk_id = " + id)
  11.387 +
  11.388 +    cx.commit()
  11.389 +    cx.close()
  11.390 +    
  11.391 +    return
  11.392 +
  11.393 +def vd_init_db(path):
  11.394 +    """Initialise the VD SQLite database
  11.395 +    path [string]: path to the SQLite database file
  11.396 +    """
  11.397 +
  11.398 +    cx = sqlite.connect(path)
  11.399 +    cu = cx.cursor()
  11.400 +
  11.401 +    cu.execute(
  11.402 +        """CREATE TABLE vdisk_extents
  11.403 +                           ( vdisk_extent_no INT,
  11.404 +                             vdisk_id INT,
  11.405 +                             part_id INT,
  11.406 +                             part_extent_no INT )
  11.407 +        """)
  11.408 +
  11.409 +    cu.execute(
  11.410 +        """CREATE TABLE vdisk_part
  11.411 +                           ( part_id INT,
  11.412 +                             partition VARCHAR,
  11.413 +                             extent_size INT )
  11.414 +        """)
  11.415 +
  11.416 +    cu.execute(
  11.417 +        """CREATE TABLE vdisks
  11.418 +                           ( vdisk_id INT,
  11.419 +                             size INT,
  11.420 +                             expires BOOLEAN,
  11.421 +                             expiry_time TIMESTAMP )
  11.422 +        """)
  11.423 +
  11.424 +
  11.425 +    cu.execute(
  11.426 +        """INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time )
  11.427 +                       VALUES ( 0,        0,    1,       datetime('now') )
  11.428 +        """)
  11.429 +
  11.430 +    cx.commit()
  11.431 +    cx.close()
  11.432 +
  11.433 +    VD_DB_FILE = path
  11.434 +
  11.435 +
  11.436 +
  11.437 +def vd_extents_validate(new_extents,new_writeable):
  11.438 +    """Validate the extents against the existing extents.
  11.439 +    Complains if the list supplied clashes against the extents that
  11.440 +    are already in use in the system.
  11.441 +    new_extents [list of dicts]: list of new extents, as dicts
  11.442 +    new_writeable [int]: 1 if they are to be writeable, 0 otherwise
  11.443 +    returns [int]: either the expertise level of the mapping if it doesn't
  11.444 +                   exceed VBD_EXPERT_MODE or -1 if it does (error)
  11.445 +    """
  11.446 +
  11.447 +    xc = Xc.new()
  11.448 +
  11.449 +    ##### Probe for explicitly created virtual disks and build a list
  11.450 +    ##### of extents for comparison with the ones that are being added
  11.451 +
  11.452 +    probe = xc.vbd_probe()
  11.453 +
  11.454 +    old_extents = [] # this will hold a list of all existing extents and
  11.455 +                     # their writeable status, as a list of (device,
  11.456 +                     # start, size, writeable?) tuples
  11.457 +
  11.458 +    for vbd in probe:
  11.459 +        this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd'])
  11.460 +        for vbd_ext in this_vbd_extents:
  11.461 +            vbd_ext['writeable'] = vbd['writeable']
  11.462 +            old_extents.append(vbd_ext);
  11.463 +
  11.464 +    ##### Now scan /proc/mounts for compile a list of extents corresponding to
  11.465 +    ##### any devices mounted in DOM0.  This list is added on to old_extents
  11.466 +
  11.467 +    regexp = re.compile("/dev/(\S*) \S* \S* (..).*");
  11.468 +    fd = open('/proc/mounts', "r")
  11.469 +
  11.470 +    while True:
  11.471 +        line = fd.readline()
  11.472 +        if not line: # if we've run out of lines then stop reading
  11.473 +            break
  11.474 +        
  11.475 +        m = regexp.match(line)
  11.476 +
  11.477 +        # if the regexp didn't match then it's probably a line we don't
  11.478 +        # care about - skip to next line
  11.479 +        if not m:
  11.480 +            continue
  11.481 +
  11.482 +        # lookup the device
  11.483 +        ext_list = lookup_raw_partn(m.group(1))
  11.484 +
  11.485 +        # if lookup failed, skip to next mounted device
  11.486 +        if not ext_list:
  11.487 +            continue
  11.488 +
  11.489 +        # set a writeable flag as appropriate
  11.490 +        for ext in ext_list:
  11.491 +            ext['writeable'] = m.group(2) == 'rw'
  11.492 +
  11.493 +        # now we've got here, the contents of ext_list are in a
  11.494 +        # suitable format to be added onto the old_extents list, ready
  11.495 +        # for checking against the new extents
  11.496 +
  11.497 +        old_extents.extend(ext_list)
  11.498 +
  11.499 +    fd.close() # close /proc/mounts
  11.500 +
  11.501 +    ##### By this point, old_extents contains a list of extents, in
  11.502 +    ##### dictionary format corresponding to every extent of physical
  11.503 +    ##### disk that's either part of an explicitly created VBD, or is
  11.504 +    ##### mounted under DOM0.  We now check these extents against the
  11.505 +    ##### proposed additions in new_extents, to see if a conflict will
  11.506 +    ##### happen if they are added with write status new_writeable
  11.507 +
  11.508 +    level = 0 # this'll accumulate the max warning level
  11.509 +
  11.510 +    # Search for clashes between the new extents and the old ones
  11.511 +    # Takes time O(len(new_extents) * len(old_extents))
  11.512 +    for new_ext in new_extents:
  11.513 +        for old_ext in old_extents:
  11.514 +            if(new_ext['device'] == old_ext['device']):
  11.515 +
  11.516 +                new_ext_start = new_ext['start_sector']
  11.517 +                new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1
  11.518 +                
  11.519 +                old_ext_start = old_ext['start_sector']
  11.520 +                old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1
  11.521 +                
  11.522 +                if((old_ext_start <= new_ext_start <= old_ext_end) or
  11.523 +                   (old_ext_start <= new_ext_end <= old_ext_end)):
  11.524 +                    if (not old_ext['writeable']) and new_writeable:
  11.525 +                        level = max(1,level)
  11.526 +                    elif old_ext['writeable'] and (not new_writeable):
  11.527 +                        level = max(1,level)
  11.528 +                    elif old_ext['writeable'] and new_writeable:
  11.529 +                        level = max(2,level)
  11.530 +
  11.531 +
  11.532 +    ##### level now holds the warning level incurred by the current
  11.533 +    ##### VBD setup and we complain appropriately to the user
  11.534 +
  11.535 +
  11.536 +    if level == 1:
  11.537 +        print >> sys.stderr, """Warning: one or more hard disk extents
  11.538 +         writeable by one domain are also readable by another."""
  11.539 +    elif level == 2:
  11.540 +        print >> sys.stderr, """Warning: one or more hard disk extents are
  11.541 +         writeable by two or more domains simultaneously."""
  11.542 +
  11.543 +    if level > VBD_EXPERT_MODE:
  11.544 +        print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed
  11.545 +        at the current safety level (%d).""" % VBD_EXPERT_MODE
  11.546 +        level = -1
  11.547 +
  11.548 +    return level
  11.549 +