diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/examples/xc_dom_create.py | 110 | ||||
-rw-r--r-- | tools/xend/lib/blkif.py | 71 | ||||
-rwxr-xr-x | tools/xend/lib/main.py | 6 | ||||
-rw-r--r-- | tools/xend/lib/manager.py | 10 |
4 files changed, 139 insertions, 58 deletions
diff --git a/tools/examples/xc_dom_create.py b/tools/examples/xc_dom_create.py index 8f1cfdb053..f1e759d4f6 100755 --- a/tools/examples/xc_dom_create.py +++ b/tools/examples/xc_dom_create.py @@ -274,71 +274,83 @@ def make_domain(): # set the expertise level appropriately xenctl.utils.VBD_EXPERT_MODE = vbd_expert - if new_io_world: - cmsg = 'new_block_interface(dom='+str(id)+')' - xend_response = xenctl.utils.xend_control_message(cmsg) - if not xend_response['success']: - print "Error creating block interface" - print "Error type: " + xend_response['error_type'] - if xend_response['error_type'] == 'exception': - print "Exception type: " + xend_response['exception_type'] - print "Exception val: " + xend_response['exception_value'] - xc.domain_destroy ( dom=id ) - sys.exit() - - for ( uname, virt_name, rw ) in vbd_list: - virt_dev = xenctl.utils.blkdev_name_to_number( virt_name ) - - segments = xenctl.utils.lookup_disk_uname( uname ) - if not segments: - print "Error looking up %s\n" % uname - xc.domain_destroy ( dom=id ) - sys.exit() - + if not (flags & 1<<4): # It's not a block backend (or it's old IO world) if new_io_world: - if len(segments) > 1: - print "New I/O world cannot deal with multi-extent vdisks" - xc.domain_destroy ( dom=id ) - sys.exit() - seg = segments[0] - cmsg = 'new_block_device(dom=' + str(id) + \ - ',handle=0,vdev=' + str(virt_dev) + \ - ',pdev=' + str(seg['device']) + \ - ',start_sect=' + str(seg['start_sector']) + \ - ',nr_sect=' + str(seg['nr_sectors']) + \ - ',readonly=' + str(not re.match('w',rw)) + ')' + cmsg = 'new_block_interface(dom='+str(id)+')' xend_response = xenctl.utils.xend_control_message(cmsg) if not xend_response['success']: - print "Error creating virtual block device" + print "Error creating block interface" print "Error type: " + xend_response['error_type'] if xend_response['error_type'] == 'exception': print "Exception type: " + xend_response['exception_type'] print "Exception val: " + xend_response['exception_value'] xc.domain_destroy ( dom=id ) sys.exit() - else: - # check that setting up this VBD won't violate the sharing - # allowed by the current VBD expertise level - if xenctl.utils.vd_extents_validate(segments, - rw=='w' or rw=='rw') < 0: - xc.domain_destroy( dom = id ) - sys.exit() - - if xc.vbd_create( dom=id, vbd=virt_dev, - writeable= rw=='w' or rw=='rw' ): - print "Error creating VBD %d (writeable=%d)\n" % (virt_dev,rw) + + for ( uname, virt_name, rw ) in vbd_list: + virt_dev = xenctl.utils.blkdev_name_to_number( virt_name ) + + segments = xenctl.utils.lookup_disk_uname( uname ) + if not segments: + print "Error looking up %s\n" % uname xc.domain_destroy ( dom=id ) sys.exit() + + if new_io_world: + if len(segments) > 1: + print "New I/O world cannot deal with multi-extent vdisks" + xc.domain_destroy ( dom=id ) + sys.exit() + seg = segments[0] + cmsg = 'new_block_device(dom=' + str(id) + \ + ',handle=0,vdev=' + str(virt_dev) + \ + ',pdev=' + str(seg['device']) + \ + ',start_sect=' + str(seg['start_sector']) + \ + ',nr_sect=' + str(seg['nr_sectors']) + \ + ',readonly=' + str(not re.match('w',rw)) + ')' + xend_response = xenctl.utils.xend_control_message(cmsg) + if not xend_response['success']: + print "Error creating virtual block device" + print "Error type: " + xend_response['error_type'] + if xend_response['error_type'] == 'exception': + print "Exception type: " + xend_response['exception_type'] + print "Exception val: " + xend_response['exception_value'] + xc.domain_destroy ( dom=id ) + sys.exit() + else: + # check that setting up this VBD won't violate the sharing + # allowed by the current VBD expertise level + if xenctl.utils.vd_extents_validate(segments, + rw=='w' or rw=='rw') < 0: + xc.domain_destroy( dom = id ) + sys.exit() + + if xc.vbd_create( dom=id, vbd=virt_dev, + writeable= rw=='w' or rw=='rw' ): + print "Error creating VBD %d (writeable=%d)\n" % (virt_dev,rw) + xc.domain_destroy ( dom=id ) + sys.exit() - if xc.vbd_setextents( dom=id, - vbd=virt_dev, - extents=segments): - print "Error populating VBD vbd=%d\n" % virt_dev + if xc.vbd_setextents( dom=id, + vbd=virt_dev, + extents=segments): + print "Error populating VBD vbd=%d\n" % virt_dev + xc.domain_destroy ( dom=id ) + sys.exit() + else: # It's a block backend - notify Xend. + cmsg = 'set_block_backend(dom='+str(id)+')' + xend_response = xenctl.utils.xend_control_message(cmsg) + if not xend_response['success']: + print "Error registering network backend" + print "Error type: " + xend_response['error_type'] + if xend_response['error_type'] == 'exception': + print "Exception type: " + xend_response['exception_type'] + print "Exception val: " + xend_response['exception_value'] xc.domain_destroy ( dom=id ) sys.exit() if new_io_world: - if not (flags & 8): # If it's not the net backend, give it a frontend. + if not (flags & 1<<5): # If it's not the net backend, give it a frontend. cmsg = 'new_network_interface(dom='+str(id)+')' xend_response = xenctl.utils.xend_control_message(cmsg) if not xend_response['success']: diff --git a/tools/xend/lib/blkif.py b/tools/xend/lib/blkif.py index a35d1bcea1..51431b694a 100644 --- a/tools/xend/lib/blkif.py +++ b/tools/xend/lib/blkif.py @@ -4,13 +4,14 @@ ## Copyright (c) 2004, K A Fraser (University of Cambridge) ################################################################# -import errno, re, os, select, signal, socket, struct, sys +import errno, re, os, select, signal, socket, sys import xend.main, xend.console, xend.manager, xend.utils, Xc CMSG_BLKIF_BE = 1 CMSG_BLKIF_FE = 2 CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0 CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32 +CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32 CMSG_BLKIF_FE_INTERFACE_CONNECT = 33 CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34 CMSG_BLKIF_BE_CREATE = 0 @@ -22,11 +23,19 @@ CMSG_BLKIF_BE_VBD_DESTROY = 5 CMSG_BLKIF_BE_VBD_GROW = 6 CMSG_BLKIF_BE_VBD_SHRINK = 7 +BLKIF_DRIVER_STATUS_DOWN = 0 +BLKIF_DRIVER_STATUS_UP = 1 + pendmsg = None pendaddr = None +recovery = False # Is a recovery in progress? (if so we'll need to notify guests) +be_port = None # Port object for backend domain + def backend_tx_req(msg): - port = xend.main.dom0_port + port = xend.blkif.be_port + if not port: + print "BUG: attempt to transmit request to non-existant blkif driver" if port.space_to_write_request(): port.write_request(msg) port.notify() @@ -35,6 +44,26 @@ def backend_tx_req(msg): def backend_rx_req(port, msg): port.write_response(msg) + subtype = (msg.get_header())['subtype'] + print "Received blkif-be request, subtype %d" % subtype + if subtype == CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: + status = (msg.get_payload())['status'] + if status == BLKIF_DRIVER_STATUS_UP: + if xend.blkif.recovery: + # Nasty hack: we count the number of VBDs we reattach so that + # we'll know when to notify the guests. Must make this better! + interface.rebuilt_so_far = 0 + interface.nr_to_rebuild = 0 + print "New blkif backend now UP, rebuilding VBDs:" + for blkif_key in interface.list.keys(): + blkif = interface.list[blkif_key] + blkif.create() + for vdev in blkif.devices.keys(): + blkif.reattach_device(vdev) + interface.nr_to_rebuild += 1 + else: + print "Unexpected block backend driver status: %d" % status + def backend_rx_rsp(port, msg): subtype = (msg.get_header())['subtype'] @@ -68,8 +97,23 @@ def backend_rx_rsp(port, msg): 'extent.device' : pdev }) backend_tx_req(msg) elif subtype == CMSG_BLKIF_BE_VBD_GROW: - rsp = { 'success': True } - xend.main.send_management_response(rsp, xend.blkif.pendaddr) + if not xend.blkif.recovery: + rsp = { 'success': True } + xend.main.send_management_response(rsp, xend.blkif.pendaddr) + else: + interface.rebuilt_so_far += 1 + if interface.rebuilt_so_far == interface.nr_to_rebuild: + print "Rebuilt VBDs, notifying guests:" + for blkif_key in interface.list.keys(): + blkif = interface.list[blkif_key] + print " Notifying %d" % blkif.dom + msg = xend.utils.message(CMSG_BLKIF_FE, + CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED, + 0, { 'handle' : 0, 'status' : 1 }) + blkif.ctrlif_tx_req(xend.main.port_from_dom(blkif.dom),msg) + xend.blkif.recovery = False + print "Done notifying guests" + def backend_do_work(port): global pendmsg @@ -85,7 +129,6 @@ class interface: # Dictionary of all block-device interfaces. list = {} - # NB. 'key' is an opaque value that has no meaning in this class. def __init__(self, dom, key): self.dom = dom @@ -93,8 +136,11 @@ class interface: self.devices = {} self.pendmsg = None interface.list[key] = self + self.create() + + def create(self): msg = xend.utils.message(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE, 0, - { 'domid' : dom, 'blkif_handle' : 0 }) + { 'domid' : self.dom, 'blkif_handle' : 0 }) xend.blkif.pendaddr = xend.main.mgmt_req_addr backend_tx_req(msg) @@ -110,6 +156,15 @@ class interface: backend_tx_req(msg) return True + def reattach_device(self, vdev): + (pdev, start_sect, nr_sect, readonly) = self.devices[vdev] + msg = xend.utils.message(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE, + 0, { 'domid' : self.dom, + 'blkif_handle' : 0, + 'vdevice' : vdev, + 'readonly' : readonly }) + xend.blkif.pendaddr = xend.main.mgmt_req_addr + backend_tx_req(msg) # Completely destroy this interface. def destroy(self): @@ -148,7 +203,9 @@ class interface: pl = msg.get_payload() (hnd, frame) = (pl['handle'], pl['shmem_frame']) xc = Xc.new() - self.evtchn = xc.evtchn_bind_interdomain(dom1=0,dom2=self.dom) + self.evtchn = xc.evtchn_bind_interdomain( + dom1=xend.blkif.be_port.remote_dom, + dom2=self.dom) msg = xend.utils.message(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT, 0, { 'domid' : self.dom, 'blkif_handle' : 0, diff --git a/tools/xend/lib/main.py b/tools/xend/lib/main.py index ce7c9ec44b..08a51a9cb1 100755 --- a/tools/xend/lib/main.py +++ b/tools/xend/lib/main.py @@ -72,6 +72,8 @@ def daemon_loop(): # Note that console messages don't come our way (actually, only driver # back-ends should use the DOM0 control interface). dom0_port = xend.utils.port(0) + xend.netif.be_port = dom0_port + xend.blkif_be_port = dom0_port notifier.bind(dom0_port.local_port) port_list[dom0_port.local_port] = dom0_port @@ -197,7 +199,7 @@ def daemon_loop(): con_if.ctrlif_rx_req(port, msg) elif type == CMSG_BLKIF_FE and blk_if: blk_if.ctrlif_rx_req(port, msg) - elif type == CMSG_BLKIF_BE and port == dom0_port: + elif type == CMSG_BLKIF_BE and port == xend.blkif.be_port: xend.blkif.backend_rx_req(port, msg) elif type == CMSG_NETIF_FE and net_if: net_if.ctrlif_rx_req(port, msg) @@ -211,7 +213,7 @@ def daemon_loop(): msg = port.read_response() work_done = True type = (msg.get_header())['type'] - if type == CMSG_BLKIF_BE and port == dom0_port: + if type == CMSG_BLKIF_BE and port == xend.blkif.be_port: xend.blkif.backend_rx_rsp(port, msg) elif type == CMSG_NETIF_BE and port == xend.netif.be_port: xend.netif.backend_rx_rsp(port, msg) diff --git a/tools/xend/lib/manager.py b/tools/xend/lib/manager.py index 3975aa7232..49517583b5 100644 --- a/tools/xend/lib/manager.py +++ b/tools/xend/lib/manager.py @@ -162,3 +162,13 @@ def set_network_backend(dom): xend.netif.recovery = True xend.netif.be_port = xend.main.port_from_dom(dom) return { 'success' : True } + +## +## set_block_backend +## Authorise a domain to act as the block backend (assumes we only have one +## backend driver for now). After this call, back end "up" notifications +## for the network will only be accepted from this domain. +def set_block_backend(dom): + if xend.blkif.be_port: xend.blkif.recovery = True + xend.blkif.be_port = xend.main.port_from_dom(dom) + return { 'success' : True } |