ia64/xen-unstable

changeset 1045:0e414c9b0f17

bitkeeper revision 1.684 (400c774fo827ucpAwphsDx-HwAJs0Q)

maw-vd-3.patch
author iap10@labyrinth.cl.cam.ac.uk[iap10]
date Tue Jan 20 00:33:19 2004 +0000 (2004-01-20)
parents b51f4782dd4d
children c58d699fc01b
files .rootkeys tools/examples/vd_read_from_file.py tools/examples/vd_to_file.py tools/xc/py/XenoUtil.py
line diff
     1.1 --- a/.rootkeys	Mon Jan 19 19:45:06 2004 +0000
     1.2 +++ b/.rootkeys	Tue Jan 20 00:33:19 2004 +0000
     1.3 @@ -55,7 +55,9 @@ 40083bb4TmKs8pcFkOcJj1bKn3zcmg tools/exa
     1.4  40083bb4u9Od6ujgect6mrxWfkk1pQ tools/examples/vd_format.py
     1.5  400c33000SvWkdG92u4Bvdu6BPjGPw tools/examples/vd_freespace.py
     1.6  400c3300jb_Ufz2kWsovGKNoDPEf-A tools/examples/vd_list.py
     1.7 +400c774eVfeVCkLn34s-Lh4-6jBXWw tools/examples/vd_read_from_file.py
     1.8  40083bb4NhDpKiYTrebI3ZjX__oI_w tools/examples/vd_refresh.py
     1.9 +400c774eXs8hWKK70ZYzi1ScKiSjPQ tools/examples/vd_to_file.py
    1.10  400c33001-uDKTfHBchTKUwuMFcqTA tools/examples/vd_undelete.py
    1.11  3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
    1.12  3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/examples/vd_read_from_file.py	Tue Jan 20 00:33:19 2004 +0000
     2.3 @@ -0,0 +1,29 @@
     2.4 +#!/usr/bin/env python
     2.5 +
     2.6 +#
     2.7 +# vd_read_from_file.py filename
     2.8 +#
     2.9 +# Reads a virtual disk in from a file and allocates a VD (prints out its ID)
    2.10 +#
    2.11 +
    2.12 +import XenoUtil, sys
    2.13 +
    2.14 +if len(sys.argv) < 2:
    2.15 +    print "Usage: " + sys.argv[0] + """ filename [expiry]
    2.16 +    Reads in a virtual disk form a file and allocates a VD.
    2.17 +    Can optionally set the expiry time in seconds from now
    2.18 +    (default - don't expire)
    2.19 +    """
    2.20 +    sys.exit()
    2.21 +
    2.22 +if len(sys.argv) > 2:
    2.23 +    expiry = int(sys.argv[2])
    2.24 +else:
    2.25 +    expiry = 0
    2.26 +
    2.27 +ret = XenoUtil.vd_read_from_file(sys.argv[1], expiry)
    2.28 +
    2.29 +if ret < 0:
    2.30 +    print "Operation failed"
    2.31 +else:
    2.32 +    print "File " + sys.argv[1] + " read into virtual disk ID " + ret
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/examples/vd_to_file.py	Tue Jan 20 00:33:19 2004 +0000
     3.3 @@ -0,0 +1,34 @@
     3.4 +#!/usr/bin/env python
     3.5 +
     3.6 +#
     3.7 +# vd_to_file.py filename [-m]
     3.8 +#
     3.9 +# Writes a virtual disk out to a file.  Optionally, the "-m" (move)
    3.10 +# flag causes the virtual disk to be deallocated once its data is
    3.11 +# read out.
    3.12 +
    3.13 +import XenoUtil, sys
    3.14 +
    3.15 +def usage():
    3.16 +    print "Usage: " + sys.argv[0] + """ vdisk_id filename [-m]
    3.17 +    Writes a virtual disk out to a file.  Optionally, the "-m" (move)
    3.18 +    flag causes the virtual disk to be deallocated once its data is
    3.19 +    read out.
    3.20 +    """
    3.21 +    sys.exit()
    3.22 +
    3.23 +if not 3 <= len(sys.argv) <= 4:
    3.24 +    usage()
    3.25 +
    3.26 +if len(sys.argv) == 4:
    3.27 +    if sys.argv[3] != "-m":
    3.28 +        usage()
    3.29 +    else:
    3.30 +        print "Doing move to file..."
    3.31 +        if XenoUtil.vd_mv_to_file(sys.argv[1],sys.argv[2]):
    3.32 +            print "Failed"    
    3.33 +else:
    3.34 +    print "Doing copy to file..."
    3.35 +    if XenoUtil.vd_cp_to_file(sys.argv[1], sys.argv[2]):
    3.36 +        print "Failed"
    3.37 +    
     4.1 --- a/tools/xc/py/XenoUtil.py	Mon Jan 19 19:45:06 2004 +0000
     4.2 +++ b/tools/xc/py/XenoUtil.py	Tue Jan 20 00:33:19 2004 +0000
     4.3 @@ -103,8 +103,8 @@ def blkdev_name_to_number(name):
     4.4  # lookup_blkdev_partn_info( '/dev/sda3' )
     4.5  def lookup_raw_partn(partition):
     4.6      """Take the given block-device name (e.g., '/dev/sda1', 'hda')
     4.7 -    and return a dictionary { partn-dev, start-sect,
     4.8 -    nr-sects, type }
     4.9 +    and return a dictionary { device, start_sector,
    4.10 +    nr_sectors, type }
    4.11          device:       Device number of the given partition
    4.12          start_sector: Index of first sector of the partition
    4.13          nr_sectsors:  Number of sectors comprising this partition
    4.14 @@ -194,7 +194,8 @@ def vd_format(partition, extent_size_mb)
    4.15          part_info = lookup_raw_partn(partition)[0]
    4.16          
    4.17          cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " +
    4.18 -                   "VALUES ( \'" + partition + "\', " + str(part_info['device'])
    4.19 +                   "VALUES ( \'" + partition + "\', "
    4.20 +                   + str(blkdev_name_to_number(partition))
    4.21                     + ", " + str(extent_size) + ")")
    4.22  
    4.23  
    4.24 @@ -212,7 +213,8 @@ def vd_format(partition, extent_size_mb)
    4.25              sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id,
    4.26                                                part_id, part_extent_no)
    4.27                      VALUES ("""+ str(new_id + i) + ", 0, "\
    4.28 -                               + str(part_info['device']) + ", " + str(i) + ")"
    4.29 +                               + str(blkdev_name_to_number(partition))\
    4.30 +                               + ", " + str(i) + ")"
    4.31              cu.execute(sql)
    4.32  
    4.33      cx.commit()
    4.34 @@ -242,9 +244,9 @@ def vd_create(size_mb, expiry):
    4.35      # about their size
    4.36      cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
    4.37                           vdisk_extents.part_id, extent_size
    4.38 -                  FROM vdisk_extents NATURAL JOIN vdisks
    4.39 +                  FROM vdisks NATURAL JOIN vdisk_extents
    4.40                                                    NATURAL JOIN vdisk_part
    4.41 -                  WHERE expires AND expiry_time < datetime('now')
    4.42 +                  WHERE expires AND expiry_time <= datetime('now')
    4.43                    ORDER BY expiry_time asc, vdisk_extent_no desc
    4.44                 """)  # aims to reuse the last extents
    4.45                       # from the longest-expired disks first
    4.46 @@ -268,6 +270,7 @@ def vd_create(size_mb, expiry):
    4.47      while allocated < size:
    4.48          row = cu.fetchone()
    4.49          if not row:
    4.50 +            print "ran out of space, having allocated %d meg of %d" % (allocated, size)
    4.51              cx.close()
    4.52              return -1
    4.53          
    4.54 @@ -291,19 +294,17 @@ def vd_create(size_mb, expiry):
    4.55      return str(new_id)
    4.56  
    4.57  
    4.58 -# Future work: Disk sizes aren't modified when vd_create scavenges extents from
    4.59 -# expired disks.  As a result it is possible to check if a disk is expired but
    4.60 -# intact (assuming VD IDs are not reused) - could allow recovery when people
    4.61 -# mess up.
    4.62 -
    4.63  def vd_lookup(id):
    4.64      """Lookup a Virtual Disk by ID.
    4.65      id [string]: a virtual disk identifier
    4.66 -    Returns [list of dicts]: a list of extents as dicts, contain fields:
    4.67 -                             device : Linux device number
    4.68 +    Returns [list of dicts]: a list of extents as dicts, containing fields:
    4.69 +                             device : Linux device number of host disk
    4.70                               start_sector : within the device
    4.71                               nr_sectors : size of this extent
    4.72                               type : set to \'VD Extent\'
    4.73 +                             
    4.74 +                             part_device : Linux device no of host partition
    4.75 +                             part_start_sector : within the partition
    4.76      """
    4.77  
    4.78      if not os.path.isfile(VD_DB_FILE):
    4.79 @@ -330,16 +331,16 @@ def vd_lookup(id):
    4.80      # following query - the use of the multiplication confuses it otherwise ;-)
    4.81      # This row is significant to PySQLite but is syntactically an SQL comment.
    4.82  
    4.83 -    cu.execute("-- types int, int, int")
    4.84 +    cu.execute("-- types str, int, int, int")
    4.85  
    4.86      # This SQL statement is designed so that when the results are fetched they
    4.87      # will be in the right format to return immediately.
    4.88 -    cu.execute("""SELECT vdisk_extents.part_id,
    4.89 +    cu.execute("""SELECT partition, vdisk_part.part_id,
    4.90                           round(part_extent_no * extent_size) as start,
    4.91                           extent_size
    4.92                           
    4.93 -                  FROM vdisk_extents NATURAL JOIN vdisks
    4.94 -                                                NATURAL JOIN vdisk_part
    4.95 +                  FROM vdisks NATURAL JOIN vdisk_extents
    4.96 +                                             NATURAL JOIN vdisk_part
    4.97                                                  
    4.98                    WHERE vdisk_extents.vdisk_id = """ + id
    4.99                 )
   4.100 @@ -348,9 +349,20 @@ def vd_lookup(id):
   4.101  
   4.102      # use this function to map the results from the database into a dict
   4.103      # list of extents, for consistency with the rest of the code
   4.104 -    def transform ((device, start_sector, nr_sectors)):
   4.105 -        return {'device' : device, 'start_sector' : int(start_sector),
   4.106 -                'nr_sectors' : nr_sectors, 'type' : 'VD Extent' }
   4.107 +    def transform ((partition, part_device, part_offset, nr_sectors)):
   4.108 +        return {
   4.109 +                 # the disk device this extent is on - for passing to Xen
   4.110 +                 'device' : lookup_raw_partn(partition)[0]['device'],
   4.111 +                 # the offset of this extent within the disk - for passing to Xen
   4.112 +                 'start_sector' : int(part_offset + lookup_raw_partn(partition)[0]['start_sector']),
   4.113 +                 # extent size, in sectors
   4.114 +                 'nr_sectors' : nr_sectors,
   4.115 +                 # partition device this extent is on (useful to know for XenoUtil fns)
   4.116 +                 'part_device' : part_device,
   4.117 +                 # start sector within this partition (useful to know for XenoUtil fns)
   4.118 +                 'part_start_sector' : part_offset,
   4.119 +                 # type of this extent - handy to know
   4.120 +                 'type' : 'VD Extent' }
   4.121  
   4.122      cx.commit()
   4.123      cx.close()
   4.124 @@ -427,9 +439,9 @@ def vd_enlarge(vdisk_id, extra_size_mb):
   4.125      # about their size
   4.126      cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
   4.127                           vdisk_extents.part_id, extent_size
   4.128 -                  FROM vdisk_extents NATURAL JOIN vdisks
   4.129 +                  FROM vdisks NATURAL JOIN vdisk_extents
   4.130                                                    NATURAL JOIN vdisk_part
   4.131 -                  WHERE expires AND expiry_time < datetime('now')
   4.132 +                  WHERE expires AND expiry_time <= datetime('now')
   4.133                    ORDER BY expiry_time asc, vdisk_extent_no desc
   4.134                 """)  # aims to reuse the last extents
   4.135                       # from the longest-expired disks first
   4.136 @@ -639,6 +651,8 @@ def vd_freespace():
   4.137  
   4.138      sum, = cu.fetchone()
   4.139  
   4.140 +    cx.close()
   4.141 +
   4.142      return sum / 2048
   4.143  
   4.144  
   4.145 @@ -686,6 +700,104 @@ def vd_init_db(path):
   4.146  
   4.147  
   4.148  
   4.149 +def vd_cp_to_file(vdisk_id,filename):
   4.150 +    """Writes the contents of a specified vdisk out into a disk file, leaving
   4.151 +    the original copy in the virtual disk pool."""
   4.152 +
   4.153 +    cx = sqlite.connect(VD_DB_FILE)
   4.154 +    cu = cx.cursor()
   4.155 +
   4.156 +    extents = vd_lookup(vdisk_id)
   4.157 +
   4.158 +    if extents < 0:
   4.159 +        return -1
   4.160 +    
   4.161 +    file_idx = 0 # index into source file, in sectors
   4.162 +
   4.163 +    for i in extents:
   4.164 +        cu.execute("""SELECT partition, extent_size FROM vdisk_part
   4.165 +                      WHERE part_id =  """ + str(i['part_device']))
   4.166 +
   4.167 +        (partition, extent_size) = cu.fetchone()
   4.168 +
   4.169 +        os.system("dd bs=1b if=" + partition + " of=" + filename
   4.170 +                  + " skip=" + str(i['part_start_sector'])
   4.171 +                  + " seek=" + str(file_idx)
   4.172 +                  + " count=" + str(i['nr_sectors'])
   4.173 +                  + " > /dev/null")
   4.174 +
   4.175 +        file_idx += i['nr_sectors']
   4.176 +
   4.177 +    cx.close()
   4.178 +
   4.179 +    return 0 # should return -1 if something breaks
   4.180 +    
   4.181 +
   4.182 +def vd_mv_to_file(vdisk_id,filename):
   4.183 +    """Writes a vdisk out into a disk file and frees the space originally
   4.184 +    taken within the virtual disk pool.
   4.185 +    vdisk_id [string]: ID of the vdisk to write out
   4.186 +    filename [string]: file to write vdisk contents out to
   4.187 +    returns [int]: zero on success, nonzero on failure
   4.188 +    """
   4.189 +
   4.190 +    if vd_cp_to_file(vdisk_id,filename):
   4.191 +        return -1
   4.192 +
   4.193 +    if vd_delete(vdisk_id):
   4.194 +        return -1
   4.195 +
   4.196 +    return 0
   4.197 +
   4.198 +
   4.199 +def vd_read_from_file(filename,expiry):
   4.200 +    """Reads the contents of a file directly into a vdisk, which is
   4.201 +    automatically allocated to fit.
   4.202 +    filename [string]: file to read disk contents from
   4.203 +    returns [string] : vdisk ID for the destination vdisk
   4.204 +    """
   4.205 +
   4.206 +    size_sectors = os.stat(filename).st_size / 512
   4.207 +
   4.208 +    vdisk_id = vd_create(size_sectors / ( 2 * 1024 ),expiry)
   4.209 +
   4.210 +    if vdisk_id < 0:
   4.211 +        return -1
   4.212 +
   4.213 +    cx = sqlite.connect(VD_DB_FILE)
   4.214 +    cu = cx.cursor()
   4.215 +
   4.216 +    cu.execute("""SELECT partition, extent_size, part_extent_no
   4.217 +                  FROM vdisk_part NATURAL JOIN vdisk_extents
   4.218 +                  WHERE vdisk_id =  """ + vdisk_id + """
   4.219 +                  ORDER BY vdisk_extent_no""")
   4.220 +
   4.221 +    extents = cu.fetchall()
   4.222 +
   4.223 +    file_idx = 0 # index into source file, in sectors
   4.224 +
   4.225 +    def write_extent_to_vd((partition, extent_size, part_extent_no),
   4.226 +                           file_idx, filename):
   4.227 +        """Write an extent out to disk and update file_idx"""
   4.228 +
   4.229 +        os.system("dd bs=512 if=" + filename + " of=" + partition
   4.230 +                  + " skip=" + str(file_idx)
   4.231 +                  + " seek=" + str(part_extent_no * extent_size)
   4.232 +                  + " count=" + str(min(extent_size, size_sectors - file_idx))
   4.233 +                  + " > /dev/null")
   4.234 +
   4.235 +        return file_idx + extent_size
   4.236 +
   4.237 +    for i in extents:
   4.238 +        file_idx += write_extent_to_vd(i, file_idx, filename)
   4.239 +
   4.240 +    cx.close()
   4.241 +
   4.242 +    return vdisk_id
   4.243 +    
   4.244 +
   4.245 +
   4.246 +
   4.247  def vd_extents_validate(new_extents,new_writeable):
   4.248      """Validate the extents against the existing extents.
   4.249      Complains if the list supplied clashes against the extents that