debuggers.hg

view tools/python/xen/xend/server/BlktapController.py @ 19840:f3211c71e8f0

xend: fix BlktapController's device creation

Reset BlktapController's device class back to 'tap' once the device
has been created. This fixes save/restore for VMs with blktap2 disks.

Signed-off-by: Ryan O'Connor <rjo@cs.ubc.ca>
Signed-off-by: Dutch Meyer <dmeyer@cs.ubc.ca>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 19 08:43:28 2009 +0100 (2009-06-19)
parents 4f779d41b0ba
children bfbd7a85d2f8
line source
1 # Copyright (c) 2005, XenSource Ltd.
2 import string, re
3 import popen2
5 from xen.xend.server.blkif import BlkifController
6 from xen.xend.XendLogging import log
8 phantomDev = 0;
9 phantomId = 0;
11 TAPDISK_SYSFS = '/sys/class/blktap2'
12 TAPDISK_BINARY = '/usr/sbin/tapdisk2'
13 TAPDISK_DEVICE = '/dev/xen/blktap-2/tapdev'
14 TAPDISK_CONTROL = TAPDISK_SYSFS + '/blktap'
16 blktap_disk_types = [
17 'aio',
18 'sync',
19 'vmdk',
20 'ram',
21 'qcow',
22 'qcow2',
23 'vhd',
24 'ioemu',
25 'tapdisk',
26 ]
28 def doexec(args, inputtext=None):
29 """Execute a subprocess, then return its return code, stdout and stderr"""
30 proc = popen2.Popen3(args, True)
31 if inputtext != None:
32 proc.tochild.write(inputtext)
33 stdout = proc.fromchild
34 stderr = proc.childerr
35 rc = proc.wait()
36 return (rc,stdout,stderr)
38 def parseDeviceString(device):
39 if device.find('/dev') == -1:
40 raise Exception, 'invalid tap device: ' + device
42 pattern = re.compile(TAPDISK_DEVICE + '(\d+)$')
43 groups = pattern.search(device)
44 if not groups:
45 raise Exception, 'malformed tap device: ' + device
47 minor = groups.group(1)
48 control = TAPDISK_CONTROL + minor
50 return minor, device, control
54 class BlktapController(BlkifController):
55 def __init__(self, vm):
56 BlkifController.__init__(self, vm)
58 def frontendRoot(self):
59 """@see DevController#frontendRoot"""
61 return "%s/device/vbd" % self.vm.getDomainPath()
63 def getDeviceDetails(self, config):
64 (devid, back, front) = BlkifController.getDeviceDetails(self, config)
66 phantomDevid = 0
67 wrapped = False
69 try:
70 imagetype = self.vm.info['image']['type']
71 except:
72 imagetype = ""
74 if imagetype == 'hvm':
75 tdevname = back['dev']
76 index = ['c', 'd', 'e', 'f', 'g', 'h', 'i', \
77 'j', 'l', 'm', 'n', 'o', 'p']
78 while True:
79 global phantomDev
80 global phantomId
81 import os, stat
83 phantomId = phantomId + 1
84 if phantomId == 16:
85 if index[phantomDev] == index[-1]:
86 if wrapped:
87 raise VmError(" No loopback block \
88 devices are available. ")
89 wrapped = True
90 phantomDev = 0
91 else:
92 phantomDev = phantomDev + 1
93 phantomId = 1
94 devname = 'xvd%s%d' % (index[phantomDev], phantomId)
95 try:
96 info = os.stat('/dev/%s' % devname)
97 except:
98 break
100 vbd = { 'mode': 'w', 'device': devname }
101 fn = 'tap:%s' % back['params']
103 # recurse ... by creating the vbd, then fallthrough
104 # and finish creating the original device
106 from xen.xend import XendDomain
107 dom0 = XendDomain.instance().privilegedDomain()
108 phantomDevid = dom0.create_phantom_vbd_with_vdi(vbd, fn)
109 # we need to wait for this device at a higher level
110 # the vbd that gets created will have a link to us
111 # and will let them do it there
113 # add a hook to point to the phantom device,
114 # root path is always the same (dom0 tap)
115 if phantomDevid != 0:
116 front['phantom_vbd'] = '/local/domain/0/backend/tap/0/%s' \
117 % str(phantomDevid)
119 return (devid, back, front)
121 def createDevice(self, config):
123 uname = config.get('uname', '')
124 try:
125 (typ, subtyp, params, file) = string.split(uname, ':', 3)
126 except:
127 (typ, params, file) = string.split(uname, ':', 2)
128 subtyp = 'tapdisk'
130 #check for blktap2 installation.
131 blktap2_installed=0;
132 (rc,stdout, stderr) = doexec("cat /proc/devices");
133 out = stdout.read();
134 stdout.close();
135 stderr.close();
136 if( out.find("blktap2") >= 0 ):
137 blktap2_installed=1;
139 if typ in ('tap'):
140 if subtyp in ('tapdisk'):
141 if params in ('ioemu', 'qcow2', 'vmdk', 'sync') or not blktap2_installed:
142 log.warn('WARNING: using deprecated blktap module');
143 return BlkifController.createDevice(self, config);
145 cmd = [ TAPDISK_BINARY, '-n', '%s:%s' % (params, file) ]
146 (rc,stdout,stderr) = doexec(cmd)
148 if rc != 0:
149 err = stderr.read();
150 out = stdout.read();
151 stdout.close();
152 stderr.close();
153 raise Exception, 'Failed to create device.\n stdout: %s\n stderr: %s\nCheck that target \"%s\" exists and that blktap2 driver installed in dom0.' % (out.rstrip(), err.rstrip(), file);
155 minor, device, control = parseDeviceString(stdout.readline())
156 stdout.close();
157 stderr.close();
159 #modify the configuration to attach as a vbd, now that the
160 #device is configured. Then continue to create the device
161 config.update({'uname' : 'phy:' + device.rstrip()})
163 self.deviceClass='vbd'
164 devid = BlkifController.createDevice(self, config)
165 self.deviceClass='tap'
166 return devid