ia64/xen-unstable

view tools/python/xen/xend/server/blkif.py @ 1770:1331621fe269

bitkeeper revision 1.1076 (40f3f7b4Cj4P09-PODiTO2MMFlKicw)

Add device create and device destroy for an existing domain.
author mjw@wray-m-3.hpl.hp.com
date Tue Jul 13 14:54:44 2004 +0000 (2004-07-13)
parents 3b98f6df869f
children b5427b1bb6c1 dae98734f12e
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
3 from twisted.internet import defer
4 #defer.Deferred.debug = 1
6 from xen.xend import sxp
7 from xen.xend import PrettyPrint
9 import channel
10 import controller
11 from messages import *
13 class BlkifControllerFactory(controller.ControllerFactory):
14 """Factory for creating block device interface controllers.
15 Also handles the 'back-end' channel to the device driver domain.
16 """
18 def __init__(self):
19 controller.ControllerFactory.__init__(self)
21 self.majorTypes = [ CMSG_BLKIF_BE ]
23 self.subTypes = {
24 CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
25 }
26 self.attached = 1
27 self.registerChannel()
29 def createInstance(self, dom, recreate=0):
30 """Create a block device controller for a domain.
32 @param dom: domain
33 @type dom: int
34 @param recreate: if true it's a recreate (after xend restart)
35 @type recreate: bool
36 @return: deferred
37 @rtype: twisted.internet.defer.Deferred
38 """
39 d = defer.Deferred()
40 blkif = self.getInstanceByDom(dom)
41 if blkif:
42 d.callback(blkif)
43 else:
44 blkif = BlkifController(self, dom)
45 self.addInstance(blkif)
46 if recreate:
47 d.callback(blkif)
48 else:
49 d1 = defer.Deferred()
50 d1.addCallback(self.respond_be_create, d)
51 d1.addErrback(d.errback)
52 blkif.send_be_create(response=d1)
53 return d
55 def getDomainDevices(self, dom):
56 """Get the block devices for a domain.
58 @param dom: domain
59 @type dom: int
60 @return: devices
61 @rtype: [device]
62 """
63 blkif = self.getInstanceByDom(dom)
64 return (blkif and blkif.getDevices()) or []
66 def getDomainDevice(self, dom, vdev):
67 """Get a block device from a domain.
69 @param dom: domain
70 @type dom: int
71 @param vdev: device index
72 @type vedv: int
73 @return: device
74 @rtype: device
75 """
76 blkif = self.getInstanceByDom(dom)
77 return (blkif and blkif.getDevice(vdev)) or None
79 def setControlDomain(self, dom, recreate=0):
80 """Set the back-end block device controller domain.
82 @param dom: domain
83 @type dom: int
84 @param recreate: if true it's a recreate (after xend restart)
85 @type recreate: int
86 """
87 if self.dom == dom: return
88 self.deregisterChannel()
89 if not recreate:
90 self.attached = 0
91 self.dom = dom
92 self.registerChannel()
94 def getControlDomain(self):
95 """Get the back-end block device controller domain.
97 @return: domain
98 @rtype: int
99 """
100 return self.dom
102 def reattachDevice(self, dom, vdev):
103 """Reattach a device (on changing control domain).
105 @param dom: domain
106 @type dom: int
107 @param vdev: device index
108 @type vdev: int
109 """
110 blkif = self.getInstanceByDom(dom)
111 if blkif:
112 blkif.reattachDevice(vdev)
113 self.attached = self.devicesAttached()
114 if self.attached:
115 self.reattached()
117 def devicesAttached(self):
118 """Check if all devices are attached.
120 @return: true if all devices attached
121 @rtype: bool
122 """
123 attached = 1
124 for blkif in self.getInstances():
125 if not blkif.attached:
126 attached = 0
127 break
128 return attached
130 def reattached(self):
131 """Notify all block interfaces we have been reattached
132 (after changing control domain).
133 """
134 for blkif in self.getInstances():
135 blkif.reattached()
137 def respond_be_create(self, msg, d):
138 """Response handler for a be_create message.
139 Calls I{d} with the block interface created.
141 @param msg: message
142 @type msg: xu message
143 @param d: deferred to call
144 @type d: Deferred
145 """
146 print 'respond_be_create>'
147 val = unpackMsg('blkif_be_create_t', msg)
148 blkif = self.getInstanceByDom(val['domid'])
149 d.callback(blkif)
151 def respond_be_connect(self, msg):
152 """Response handler for a be_connect message.
154 @param msg: message
155 @type msg: xu message
156 """
157 print 'respond_be_connect>', self
158 val = unpackMsg('blkif_be_connect_t', msg)
159 blkif = self.getInstanceByDom(val['domid'])
160 if blkif:
161 blkif.send_fe_interface_status_changed()
162 else:
163 pass
165 def respond_be_vbd_create(self, msg, d):
166 """Response handler for a be_vbd_create message.
167 Tries to grow the vbd, and passes the deferred I{d} on for
168 the grow to call.
170 @param msg: message
171 @type msg: xu message
172 @param d: deferred to call
173 @type d: Deferred
174 """
175 print 'recv_be_vbd_create>', self
176 val = unpackMsg('blkif_be_vbd_create_t', msg)
177 blkif = self.getInstanceByDom(val['domid'])
178 if blkif:
179 d1 = defer.Deferred()
180 d1.addCallback(self.respond_be_vbd_grow, d)
181 if d: d1.addErrback(d.errback)
182 blkif.send_be_vbd_grow(val['vdevice'], response=d1)
183 else:
184 pass
186 def respond_be_vbd_grow(self, msg, d):
187 """Response handler for a be_vbd_grow message.
189 @param msg: message
190 @type msg: xu message
191 @param d: deferred to call
192 @type d: Deferred or None
193 """
194 print 'recv_be_vbd_grow>', self
195 val = unpackMsg('blkif_be_vbd_grow_t', msg)
196 # Check status?
197 if self.attached:
198 if d:
199 d.callback(0)
200 else:
201 self.reattachDevice(val['domid'], val['vdevice'])
203 def recv_be_driver_status_changed(self, msg, req):
204 """Request handler for be_driver_status_changed messages.
206 @param msg: message
207 @type msg: xu message
208 @param req: request flag (true if the msg is a request)
209 @type req: bool
210 """
211 print 'recv_be_driver_status_changed>', self, req
212 val = unpackMsg('blkif_be_driver_status_changed_t', msg)
213 status = val['status']
214 if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
215 for blkif in self.getInstances():
216 blkif.detach()
218 class BlkDev(controller.Dev):
219 """Info record for a block device.
220 """
222 def __init__(self, ctrl, vdev, mode, segment):
223 controller.Dev.__init__(self, ctrl)
224 self.vdev = vdev
225 self.mode = mode
226 self.device = segment['device']
227 self.start_sector = segment['start_sector']
228 self.nr_sectors = segment['nr_sectors']
229 self.attached = 1
231 def readonly(self):
232 return 'w' not in self.mode
234 def sxpr(self):
235 val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ]
236 return val
238 def destroy(self):
239 self.controller.send_be_vbd_destroy(self.vdev)
241 class BlkifController(controller.Controller):
242 """Block device interface controller. Handles all block devices
243 for a domain.
244 """
246 def __init__(self, factory, dom):
247 controller.Controller.__init__(self, factory, dom)
248 self.devices = {}
250 self.majorTypes = [ CMSG_BLKIF_FE ]
252 self.subTypes = {
253 CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
254 self.recv_fe_driver_status_changed,
255 CMSG_BLKIF_FE_INTERFACE_CONNECT :
256 self.recv_fe_interface_connect,
257 }
258 self.attached = 1
259 self.evtchn = None
260 self.registerChannel()
262 def sxpr(self):
263 val = ['blkif', ['dom', self.dom]]
264 if self.evtchn:
265 val.append(['evtchn',
266 self.evtchn['port1'],
267 self.evtchn['port2']])
268 return val
270 def getDevices(self):
271 return self.devices.values()
273 def getDevice(self, vdev):
274 return self.devices.get(vdev)
276 def addDevice(self, vdev, mode, segment):
277 """Add a device to the device table.
279 @param vdev: device index
280 @type vdev: int
281 @param mode: read/write mode
282 @type mode: string
283 @param segment: segment
284 @type segment: int
285 @return: device
286 @rtype: BlkDev
287 """
288 if vdev in self.devices: return None
289 dev = BlkDev(self, vdev, mode, segment)
290 self.devices[vdev] = dev
291 return dev
293 def attachDevice(self, vdev, mode, segment, recreate=0):
294 """Attach a device to the specified interface.
296 @param vdev: device index
297 @type vdev: int
298 @param mode: read/write mode
299 @type mode: string
300 @param segment: segment
301 @type segment: int
302 @param recreate: if true it's being recreated (after xend restart)
303 @type recreate: bool
304 @return: deferred
305 @rtype: Deferred
306 """
307 dev = self.addDevice(vdev, mode, segment)
308 if not dev: return -1
309 d = defer.Deferred()
310 if recreate:
311 d.callback(self)
312 else:
313 d1 = defer.Deferred()
314 d1.addCallback(self.factory.respond_be_vbd_create, d)
315 d1.addErrback(d.errback)
316 self.send_be_vbd_create(vdev, response=d1)
317 return d
319 def destroy(self):
320 def cb_destroy(val):
321 self.send_be_destroy()
322 d = defer.Deferred()
323 d.addCallback(cb_destroy)
324 self.send_be_disconnect(response=d)
326 def destroyDevices(self):
327 for dev in self.getDevices():
328 dev.destroy()
330 def detach(self):
331 """Detach all devices, when the back-end control domain has changed.
332 """
333 self.attached = 0
334 for dev in self.devices.values():
335 dev.attached = 0
336 d1 = defer.Deferred()
337 d1.addCallback(self.factory.respond_be_vbd_create, None)
338 self.send_be_vbd_create(vdev, response=d1)
340 def reattachDevice(self, vdev):
341 """Reattach a device, when the back-end control domain has changed.
342 """
343 dev = self.devices[vdev]
344 dev.attached = 1
345 attached = 1
346 for dev in self.devices.values():
347 if not dev.attached:
348 attached = 0
349 break
350 self.attached = attached
351 return self.attached
353 def reattached(self):
354 """All devices have been reattached after the back-end control
355 domain has changed.
356 """
357 msg = packMsg('blkif_fe_interface_status_changed_t',
358 { 'handle' : 0,
359 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED})
360 self.writeRequest(msg)
362 def recv_fe_driver_status_changed(self, msg, req):
363 msg = packMsg('blkif_fe_interface_status_changed_t',
364 { 'handle' : 0,
365 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
366 'evtchn' : 0 })
367 self.writeRequest(msg)
369 def recv_fe_interface_connect(self, msg, req):
370 val = unpackMsg('blkif_fe_interface_connect_t', msg)
371 self.evtchn = channel.eventChannel(0, self.dom)
372 print 'recv_fe_interface_connect>'
373 PrettyPrint.prettyprint(self.sxpr())
374 msg = packMsg('blkif_be_connect_t',
375 { 'domid' : self.dom,
376 'blkif_handle' : val['handle'],
377 'evtchn' : self.evtchn['port1'],
378 'shmem_frame' : val['shmem_frame'] })
379 d = defer.Deferred()
380 d.addCallback(self.factory.respond_be_connect)
381 self.factory.writeRequest(msg, response=d)
383 def send_fe_interface_status_changed(self, response=None):
384 msg = packMsg('blkif_fe_interface_status_changed_t',
385 { 'handle' : 0,
386 'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
387 'evtchn' : self.evtchn['port2'] })
388 self.writeRequest(msg, response=response)
390 def send_be_create(self, response=None):
391 msg = packMsg('blkif_be_create_t',
392 { 'domid' : self.dom,
393 'blkif_handle' : 0 })
394 self.factory.writeRequest(msg, response=response)
396 def send_be_disconnect(self, response=None):
397 print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
398 msg = packMsg('blkif_be_disconnect_t',
399 { 'domid' : self.dom,
400 'blkif_handle' : 0 })
401 self.factory.writeRequest(msg, response=response)
403 def send_be_destroy(self, response=None):
404 print '>BlkifController>send_be_destroy>', 'dom=', self.dom
405 msg = packMsg('blkif_be_destroy_t',
406 { 'domid' : self.dom,
407 'blkif_handle' : 0 })
408 self.factory.writeRequest(msg, response=response)
410 def send_be_vbd_create(self, vdev, response=None):
411 dev = self.devices[vdev]
412 msg = packMsg('blkif_be_vbd_create_t',
413 { 'domid' : self.dom,
414 'blkif_handle' : 0,
415 'vdevice' : dev.vdev,
416 'readonly' : dev.readonly() })
417 self.factory.writeRequest(msg, response=response)
419 def send_be_vbd_grow(self, vdev, response=None):
420 dev = self.devices[vdev]
421 msg = packMsg('blkif_be_vbd_grow_t',
422 { 'domid' : self.dom,
423 'blkif_handle' : 0,
424 'vdevice' : dev.vdev,
425 'extent.device' : dev.device,
426 'extent.sector_start' : dev.start_sector,
427 'extent.sector_length' : dev.nr_sectors })
428 self.factory.writeRequest(msg, response=response)
430 def send_be_vbd_destroy(self, vdev, response=None):
431 print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
432 PrettyPrint.prettyprint(self.sxpr())
433 dev = self.devices[vdev]
434 msg = packMsg('blkif_be_vbd_destroy_t',
435 { 'domid' : self.dom,
436 'blkif_handle' : 0,
437 'vdevice' : dev.vdev })
438 del self.devices[vdev]
439 self.factory.writeRequest(msg, response=response)