ia64/xen-unstable

view tools/python/xen/xend/server/blkif.py @ 2223:37ef3fbdde75

bitkeeper revision 1.1159.1.51 (411cb093WisMx6OYUPrSE3N1COOggA)

Fix construction of error message.
author mjw@wray-m-3.hpl.hp.com
date Fri Aug 13 12:14:11 2004 +0000 (2004-08-13)
parents 6c272033a2ed
children 6c85a89e99e3
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
2 """Support for virtual block devices.
3 """
5 from twisted.internet import defer
6 #defer.Deferred.debug = 1
8 from xen.xend import sxp
9 from xen.xend.XendLogging import log
10 from xen.xend.XendError import XendError
12 import channel
13 import controller
14 from messages import *
16 class BlkifControllerFactory(controller.ControllerFactory):
17 """Factory for creating block device interface controllers.
18 Also handles the 'back-end' channel to the device driver domain.
19 """
21 def __init__(self):
22 controller.ControllerFactory.__init__(self)
24 self.majorTypes = [ CMSG_BLKIF_BE ]
26 self.subTypes = {
27 CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
28 }
29 self.attached = 1
30 self.registerChannel()
32 def createInstance(self, dom, recreate=0):
33 """Create a block device controller for a domain.
35 @param dom: domain
36 @type dom: int
37 @param recreate: if true it's a recreate (after xend restart)
38 @type recreate: bool
39 @return: deferred
40 @rtype: twisted.internet.defer.Deferred
41 """
42 d = defer.Deferred()
43 blkif = self.getInstanceByDom(dom)
44 if blkif:
45 d.callback(blkif)
46 else:
47 blkif = BlkifController(self, dom)
48 self.addInstance(blkif)
49 if recreate:
50 d.callback(blkif)
51 else:
52 d1 = defer.Deferred()
53 d1.addCallback(self.respond_be_create, d)
54 d1.addErrback(d.errback)
55 blkif.send_be_create(response=d1)
56 return d
58 def getDomainDevices(self, dom):
59 """Get the block devices for a domain.
61 @param dom: domain
62 @type dom: int
63 @return: devices
64 @rtype: [device]
65 """
66 blkif = self.getInstanceByDom(dom)
67 return (blkif and blkif.getDevices()) or []
69 def getDomainDevice(self, dom, vdev):
70 """Get a block device from a domain.
72 @param dom: domain
73 @type dom: int
74 @param vdev: device index
75 @type vedv: int
76 @return: device
77 @rtype: device
78 """
79 blkif = self.getInstanceByDom(dom)
80 return (blkif and blkif.getDevice(vdev)) or None
82 def setControlDomain(self, dom, recreate=0):
83 """Set the back-end block device controller domain.
85 @param dom: domain
86 @type dom: int
87 @param recreate: if true it's a recreate (after xend restart)
88 @type recreate: int
89 """
90 if self.dom == dom: return
91 self.deregisterChannel()
92 if not recreate:
93 self.attached = 0
94 self.dom = dom
95 self.registerChannel()
97 def getControlDomain(self):
98 """Get the back-end block device controller domain.
100 @return: domain
101 @rtype: int
102 """
103 return self.dom
105 def reattachDevice(self, dom, vdev):
106 """Reattach a device (on changing control domain).
108 @param dom: domain
109 @type dom: int
110 @param vdev: device index
111 @type vdev: int
112 """
113 blkif = self.getInstanceByDom(dom)
114 if blkif:
115 blkif.reattachDevice(vdev)
116 self.attached = self.devicesAttached()
117 if self.attached:
118 self.reattached()
120 def devicesAttached(self):
121 """Check if all devices are attached.
123 @return: true if all devices attached
124 @rtype: bool
125 """
126 attached = 1
127 for blkif in self.getInstances():
128 if not blkif.attached:
129 attached = 0
130 break
131 return attached
133 def reattached(self):
134 """Notify all block interfaces we have been reattached
135 (after changing control domain).
136 """
137 for blkif in self.getInstances():
138 blkif.reattached()
140 def respond_be_create(self, msg, d):
141 """Response handler for a be_create message.
142 Calls I{d} with the block interface created.
144 @param msg: message
145 @type msg: xu message
146 @param d: deferred to call
147 @type d: Deferred
148 """
149 val = unpackMsg('blkif_be_create_t', msg)
150 blkif = self.getInstanceByDom(val['domid'])
151 d.callback(blkif)
153 def respond_be_connect(self, msg):
154 """Response handler for a be_connect message.
156 @param msg: message
157 @type msg: xu message
158 """
159 val = unpackMsg('blkif_be_connect_t', msg)
160 blkif = self.getInstanceByDom(val['domid'])
161 if blkif:
162 blkif.send_fe_interface_status_changed()
163 else:
164 pass
166 def respond_be_vbd_create(self, msg, dev, d):
167 """Response handler for a be_vbd_create message.
168 Tries to grow the vbd, and passes the deferred I{d} on for
169 the grow to call.
171 @param msg: message
172 @type msg: xu message
173 @param dev: device
174 @type dev: BlkDev
175 @param d: deferred to call
176 @type d: Deferred
177 """
178 val = unpackMsg('blkif_be_vbd_create_t', msg)
179 blkif = self.getInstanceByDom(val['domid'])
180 if blkif:
181 d1 = defer.Deferred()
182 d1.addCallback(self.respond_be_vbd_grow, dev, d)
183 if d: d1.addErrback(d.errback)
184 blkif.send_be_vbd_grow(val['vdevice'], response=d1)
185 else:
186 pass
188 def respond_be_vbd_grow(self, msg, dev, d):
189 """Response handler for a be_vbd_grow message.
191 @param msg: message
192 @type msg: xu message
193 @param dev: device
194 @type dev: BlkDev
195 @param d: deferred to call
196 @type d: Deferred or None
197 """
198 val = unpackMsg('blkif_be_vbd_grow_t', msg)
199 status = val['status']
200 if status != BLKIF_BE_STATUS_OKAY:
201 raise XendError("Adding extent to vbd failed: device %x, error %d"
202 % (val['extent.device'], status))
203 if self.attached:
204 if d:
205 d.callback(dev)
206 else:
207 self.reattachDevice(val['domid'], val['vdevice'])
209 def recv_be_driver_status_changed(self, msg, req):
210 """Request handler for be_driver_status_changed messages.
212 @param msg: message
213 @type msg: xu message
214 @param req: request flag (true if the msg is a request)
215 @type req: bool
216 """
217 val = unpackMsg('blkif_be_driver_status_changed_t', msg)
218 status = val['status']
219 if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
220 for blkif in self.getInstances():
221 blkif.detach()
223 class BlkDev(controller.Dev):
224 """Info record for a block device.
225 """
227 def __init__(self, ctrl, vdev, mode, segment):
228 controller.Dev.__init__(self, segment['device'], ctrl)
229 self.dev = None
230 self.uname = None
231 self.vdev = vdev
232 self.mode = mode
233 self.device = segment['device']
234 self.start_sector = segment['start_sector']
235 self.nr_sectors = segment['nr_sectors']
236 self.attached = 1
238 def readonly(self):
239 return 'w' not in self.mode
241 def sxpr(self):
242 val = ['blkdev',
243 ['idx', self.idx],
244 ['vdev', self.vdev],
245 ['device', self.device],
246 ['mode', self.mode]]
247 if self.dev:
248 val.append(['dev', self.dev])
249 if self.uname:
250 val.append(['uname', self.uname])
251 return val
253 def destroy(self):
254 log.debug("Destroying vbd domain=%d vdev=%d", self.controller.dom, self.vdev)
255 self.controller.send_be_vbd_destroy(self.vdev)
257 class BlkifController(controller.Controller):
258 """Block device interface controller. Handles all block devices
259 for a domain.
260 """
262 def __init__(self, factory, dom):
263 controller.Controller.__init__(self, factory, dom)
264 self.devices = {}
266 self.majorTypes = [ CMSG_BLKIF_FE ]
268 self.subTypes = {
269 CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
270 self.recv_fe_driver_status_changed,
271 CMSG_BLKIF_FE_INTERFACE_CONNECT :
272 self.recv_fe_interface_connect,
273 }
274 self.attached = 1
275 self.evtchn = None
276 self.registerChannel()
278 def sxpr(self):
279 val = ['blkif', ['dom', self.dom]]
280 if self.evtchn:
281 val.append(['evtchn',
282 self.evtchn['port1'],
283 self.evtchn['port2']])
284 return val
286 def getDevices(self):
287 return self.devices.values()
289 def getDevice(self, vdev):
290 return self.devices.get(vdev)
292 def addDevice(self, vdev, mode, segment):
293 """Add a device to the device table.
295 @param vdev: device index
296 @type vdev: int
297 @param mode: read/write mode
298 @type mode: string
299 @param segment: segment
300 @type segment: int
301 @return: device
302 @rtype: BlkDev
303 """
304 if vdev in self.devices: return None
305 dev = BlkDev(self, vdev, mode, segment)
306 self.devices[vdev] = dev
307 return dev
309 def attachDevice(self, vdev, mode, segment, recreate=0):
310 """Attach a device to the specified interface.
311 On success the returned deferred will be called with the device.
313 @param vdev: device index
314 @type vdev: int
315 @param mode: read/write mode
316 @type mode: string
317 @param segment: segment
318 @type segment: int
319 @param recreate: if true it's being recreated (after xend restart)
320 @type recreate: bool
321 @return: deferred
322 @rtype: Deferred
323 """
324 dev = self.addDevice(vdev, mode, segment)
325 if not dev: return -1
326 d = defer.Deferred()
327 if recreate:
328 d.callback(dev)
329 else:
330 d1 = defer.Deferred()
331 d1.addCallback(self.factory.respond_be_vbd_create, dev, d)
332 d1.addErrback(d.errback)
333 self.send_be_vbd_create(vdev, response=d1)
334 return d
336 def destroy(self):
337 def cb_destroy(val):
338 self.send_be_destroy()
339 log.debug("Destroying blkif domain=%d", self.dom)
340 d = defer.Deferred()
341 d.addCallback(cb_destroy)
342 self.send_be_disconnect(response=d)
344 def destroyDevices(self):
345 for dev in self.getDevices():
346 dev.destroy()
348 def detach(self):
349 """Detach all devices, when the back-end control domain has changed.
350 """
351 self.attached = 0
352 for dev in self.devices.values():
353 dev.attached = 0
354 d1 = defer.Deferred()
355 d1.addCallback(self.factory.respond_be_vbd_create, None, None)
356 self.send_be_vbd_create(vdev, response=d1)
358 def reattachDevice(self, vdev):
359 """Reattach a device, when the back-end control domain has changed.
360 """
361 dev = self.devices[vdev]
362 dev.attached = 1
363 attached = 1
364 for dev in self.devices.values():
365 if not dev.attached:
366 attached = 0
367 break
368 self.attached = attached
369 return self.attached
371 def reattached(self):
372 """All devices have been reattached after the back-end control
373 domain has changed.
374 """
375 msg = packMsg('blkif_fe_interface_status_changed_t',
376 { 'handle' : 0,
377 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED})
378 self.writeRequest(msg)
380 def recv_fe_driver_status_changed(self, msg, req):
381 msg = packMsg('blkif_fe_interface_status_changed_t',
382 { 'handle' : 0,
383 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
384 'evtchn' : 0 })
385 self.writeRequest(msg)
387 def recv_fe_interface_connect(self, msg, req):
388 val = unpackMsg('blkif_fe_interface_connect_t', msg)
389 self.evtchn = channel.eventChannel(0, self.dom)
390 log.debug("Connecting blkif to event channel dom=%d ports=%d:%d",
391 self.dom, self.evtchn['port1'], self.evtchn['port2'])
392 msg = packMsg('blkif_be_connect_t',
393 { 'domid' : self.dom,
394 'blkif_handle' : val['handle'],
395 'evtchn' : self.evtchn['port1'],
396 'shmem_frame' : val['shmem_frame'] })
397 d = defer.Deferred()
398 d.addCallback(self.factory.respond_be_connect)
399 self.factory.writeRequest(msg, response=d)
401 def send_fe_interface_status_changed(self, response=None):
402 msg = packMsg('blkif_fe_interface_status_changed_t',
403 { 'handle' : 0,
404 'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
405 'evtchn' : self.evtchn['port2'] })
406 self.writeRequest(msg, response=response)
408 def send_be_create(self, response=None):
409 msg = packMsg('blkif_be_create_t',
410 { 'domid' : self.dom,
411 'blkif_handle' : 0 })
412 self.factory.writeRequest(msg, response=response)
414 def send_be_disconnect(self, response=None):
415 log.debug('>BlkifController>send_be_disconnect> dom=%d', self.dom)
416 msg = packMsg('blkif_be_disconnect_t',
417 { 'domid' : self.dom,
418 'blkif_handle' : 0 })
419 self.factory.writeRequest(msg, response=response)
421 def send_be_destroy(self, response=None):
422 log.debug('>BlkifController>send_be_destroy> dom=%d', self.dom)
423 msg = packMsg('blkif_be_destroy_t',
424 { 'domid' : self.dom,
425 'blkif_handle' : 0 })
426 self.factory.writeRequest(msg, response=response)
428 def send_be_vbd_create(self, vdev, response=None):
429 dev = self.devices[vdev]
430 msg = packMsg('blkif_be_vbd_create_t',
431 { 'domid' : self.dom,
432 'blkif_handle' : 0,
433 'vdevice' : dev.vdev,
434 'readonly' : dev.readonly() })
435 self.factory.writeRequest(msg, response=response)
437 def send_be_vbd_grow(self, vdev, response=None):
438 dev = self.devices[vdev]
439 msg = packMsg('blkif_be_vbd_grow_t',
440 { 'domid' : self.dom,
441 'blkif_handle' : 0,
442 'vdevice' : dev.vdev,
443 'extent.device' : dev.device,
444 'extent.sector_start' : dev.start_sector,
445 'extent.sector_length' : dev.nr_sectors })
446 self.factory.writeRequest(msg, response=response)
448 def send_be_vbd_destroy(self, vdev, response=None):
449 log.debug('>BlkifController>send_be_vbd_destroy> dom=%d vdev=%d', self.dom, vdev)
450 dev = self.devices[vdev]
451 msg = packMsg('blkif_be_vbd_destroy_t',
452 { 'domid' : self.dom,
453 'blkif_handle' : 0,
454 'vdevice' : dev.vdev })
455 del self.devices[vdev]
456 self.factory.writeRequest(msg, response=response)