bitkeeper revision 1.1159.116.3 (4177deb5O2BSukkVC4mhGVTFnJJiwA)

Fix problem with block device recreation after xend restart.
Save device state info in the domain record and use when
the domain info and devices are recreated.
This commit is contained in:
mjw@wray-m-3.hpl.hp.com committed 2004-10-21 16:07:17 +00:00
1 parent 8745238a32
commit e1ab5a1d0d
4 files changed
+160 -125

No files matched your search

+48 -37
View File
@@ -33,8 +33,6 @@ xend = server.SrvDaemon.instance()
from XendError import VmError
from server.blkif import blkdev_name_to_number
"""The length of domain names that Xen can handle.
The names stored in Xen itself are not used for much, and
xend can handle domain names of any length.
@@ -92,24 +90,6 @@ def shutdown_reason(code):
"""
return shutdown_reasons.get(code, "?")
def make_disk(vm, config, uname, dev, mode, recreate=0):
"""Create a virtual disk device for a domain.
@param vm: vm
@param uname: device to export
@param dev: device name in domain
@param mode: read/write mode
@param recreate: recreate flag (after xend restart)
@return: deferred
"""
idx = vm.next_device_index('vbd')
# todo: The 'dev' should be looked up in the context of the domain.
vdev = blkdev_name_to_number(dev)
if not vdev:
raise VmError("vbd: Device not found: uname=%s dev=%s" % (uname, dev))
ctrl = xend.blkif_create(vm.dom, recreate=recreate)
return ctrl.attachDevice(idx, config, uname, vdev, mode, recreate=recreate)
def vif_up(iplist):
"""send an unsolicited ARP reply for all non link-local IP addresses.
@@ -222,6 +202,7 @@ def vm_recreate(savedinfo, info):
"""
vm = XendDomainInfo()
vm.recreate = 1
vm.savedinfo = savedinfo
vm.setdom(info['dom'])
#vm.name = info['name']
vm.memory = info['mem_kb']/1024
@@ -239,6 +220,7 @@ def vm_recreate(savedinfo, info):
vm.name = info['name']
d = defer.succeed(vm)
vm.recreate = 0
vm.savedinfo = None
return d
def vm_restore(src, progress=0):
@@ -336,6 +318,7 @@ class XendDomainInfo:
self.restart_state = None
self.restart_time = None
self.console_port = None
self.savedinfo = None
def setdom(self, dom):
"""Set the domain id.
@@ -397,10 +380,21 @@ class XendDomainInfo:
sxpr.append(['restart_state', self.restart_state])
if self.restart_time:
sxpr.append(['restart_time', str(self.restart_time)])
devs = self.sxpr_devices()
if devs:
sxpr.append(devs)
if self.config:
sxpr.append(['config', self.config])
return sxpr
def sxpr_devices(self):
sxpr = ['devices']
for devs in self.devices.values():
for dev in devs:
if hasattr(dev, 'sxpr'):
sxpr.append(dev.sxpr())
return sxpr
def check_name(self, name):
"""Check if a vm name is valid. Valid names start with a non-digit
and contain alphabetic characters, digits, or characters in '_-.:/+'.
@@ -586,6 +580,25 @@ class XendDomainInfo:
return d
return None
def get_device_savedinfo(self, type, index):
val = None
if self.savedinfo is None:
return val
index = str(index)
devinfo = sxp.child(self.savedinfo, 'devices')
if devinfo is None:
return val
for d in sxp.children(devinfo, type):
dindex = sxp.child_value(d, 'index')
if dindex is None: continue
if str(dindex) == index:
val = d
break
return val
def get_device_recreate(self, type, index):
return self.get_device_savedinfo(type, index) or self.recreate
def add_config(self, val):
"""Add configuration data to a virtual machine.
@@ -840,7 +853,7 @@ class XendDomainInfo:
def configure_memory(self):
"""Configure vm memory limit.
"""
maxmem = sxp.get_child_value(self.config, "maxmem")
maxmem = sxp.child_value(self.config, "maxmem")
if maxmem is None:
maxmem = self.memory
xc.domain_setmaxmem(self.dom, maxmem_kb = maxmem * 1024)
@@ -1070,9 +1083,11 @@ def vm_dev_vif(vm, val, index, change=0):
vmac = sxp.child_value(val, "mac")
ctrl = xend.netif_create(vm.dom, recreate=vm.recreate)
log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac))
defer = ctrl.attachDevice(vif, val, recreate=vm.recreate)
recreate = vm.get_device_recreate('vif', index)
defer = ctrl.attachDevice(vif, val, recreate=recreate)
def cbok(dev):
dev.vifctl('up', vmname=vm.name)
dev.setIndex(index)
vm.add_device('vif', dev)
if change:
dev.interfaceChanged()
@@ -1088,23 +1103,19 @@ def vm_dev_vbd(vm, val, index, change=0):
@param index: vbd index
@return: deferred
"""
idx = vm.next_device_index('vbd')
uname = sxp.child_value(val, 'uname')
if not uname:
raise VmError('vbd: Missing uname')
dev = sxp.child_value(val, 'dev')
if not dev:
raise VmError('vbd: Missing dev')
mode = sxp.child_value(val, 'mode', 'r')
log.debug("Creating vbd dom=%d uname=%s dev=%s", vm.dom, uname, dev)
defer = make_disk(vm, val, uname, dev, mode, vm.recreate)
def fn(vbd):
vbd.dev = dev
vbd.uname = uname
vm.add_device('vbd', vbd)
log.debug("Creating vbd dom=%d uname=%s", vm.dom, uname)
ctrl = xend.blkif_create(vm.dom, recreate=vm.recreate)
recreate = vm.get_device_recreate('vbd', index)
defer = ctrl.attachDevice(idx, val, recreate=recreate)
def cbok(dev):
dev.setIndex(index)
vm.add_device('vbd', dev)
if change:
vbd.interfaceChanged()
return vbd
defer.addCallback(fn)
dev.interfaceChanged()
return dev
defer.addCallback(cbok)
return defer
def parse_pci(val):
+103 -88
View File
@@ -16,6 +16,46 @@ import channel
import controller
from messages import *
def blkdev_name_to_number(name):
"""Take the given textual block-device name (e.g., '/dev/sda1',
'hda') and return the device number used by the OS. """
if re.match( '^/dev/', name ):
n = name
else:
n = '/dev/' + name
try:
return os.stat(n).st_rdev
except Exception, ex:
log.debug("exception looking up device number for %s: %s", name, ex)
pass
# see if this is a hex device number
if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
return string.atoi(name,16)
return None
def blkdev_segment(name):
"""Take the given block-device name (e.g. '/dev/sda1', 'hda')
and return a dictionary { device, start_sector,
nr_sectors, type }
device: Device number of the given partition
start_sector: Index of first sector of the partition
nr_sectors: Number of sectors comprising this partition
type: 'Disk' or identifying name for partition type
"""
val = None
n = blkdev_name_to_number(name)
if n:
val = { 'device' : n,
'start_sector' : long(0),
'nr_sectors' : long(1L<<63),
'type' : 'Disk' }
return val
class BlkifBackendController(controller.BackendController):
""" Handler for the 'back-end' channel to a block device driver domain.
"""
@@ -231,26 +271,70 @@ class BlkDev(controller.SplitDev):
"""Info record for a block device.
"""
def __init__(self, idx, ctrl, config, vdev, mode, segment):
def __init__(self, idx, ctrl, config):
controller.SplitDev.__init__(self, idx, ctrl)
self.config = config
self.dev = None
self.uname = None
self.vdev = vdev
self.mode = mode
self.device = segment['device']
self.start_sector = segment['start_sector']
self.nr_sectors = segment['nr_sectors']
self.vdev = None
self.mode = None
self.type = None
self.params = None
self.node = None
self.device = None
self.start_sector = None
self.nr_sectors = None
self.configure(config)
def configure(self, config):
self.config = config
self.uname = sxp.child_value(config, 'uname')
if not self.uname:
raise VmError('vbd: Missing uname')
# Split into type and type-specific params (which are passed to the
# type-specific control script).
(self.type, self.params) = string.split(self.uname, ':', 1)
self.dev = sxp.child_value(config, 'dev')
if not self.dev:
raise VmError('vbd: Missing dev')
self.mode = sxp.child_value(config, 'mode', 'r')
# todo: The 'dev' should be looked up in the context of the domain.
self.vdev = blkdev_name_to_number(self.dev)
if not self.vdev:
raise VmError('vbd: Device not found: %s' % self.dev)
try:
self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
except:
raise XendError('invalid backend domain')
def recreate(self, savedinfo):
node = sxp.child_value(savedinfo, 'node')
self.setNode(node)
def attach(self):
node = Blkctl.block('bind', self.type, self.params)
self.setNode(node)
return self.attachBackend()
def unbind(self):
if self.node is None: return
log.debug("Unbinding vbd (type %s) from %s"
% (self.type, self.node))
Blkctl.block('unbind', self.type, self.node)
def setNode(self, node):
segment = blkdev_segment(node)
if not segment:
raise VmError("vbd: Segment not found: uname=%s" % self.uname)
self.node = node
self.device = segment['device']
self.start_sector = segment['start_sector']
self.nr_sectors = segment['nr_sectors']
def readonly(self):
return 'w' not in self.mode
def sxpr(self):
val = ['blkdev',
val = ['vbd',
['idx', self.idx],
['vdev', self.vdev],
['device', self.device],
@@ -259,13 +343,12 @@ class BlkDev(controller.SplitDev):
val.append(['dev', self.dev])
if self.uname:
val.append(['uname', self.uname])
if self.node:
val.append(['node', self.node])
if self.index is not None:
val.append(['index', self.index])
return val
def unbind(self):
log.debug("Unbinding block dev (type %s) from %s"
% (self.type, self.node))
Blkctl.block('unbind', self.type, self.node)
def destroy(self, change=0):
"""Destroy the device. If 'change' is true notify the front-end interface.
@@ -283,7 +366,7 @@ class BlkDev(controller.SplitDev):
"""
self.getBackendInterface().interfaceChanged()
def attach(self):
def attachBackend(self):
"""Attach the device to its controller.
"""
@@ -356,46 +439,6 @@ class BlkDev(controller.SplitDev):
return d
def blkdev_name_to_number(name):
"""Take the given textual block-device name (e.g., '/dev/sda1',
'hda') and return the device number used by the OS. """
if not re.match( '^/dev/', name ):
n = '/dev/' + name
else:
n = name
try:
return os.stat(n).st_rdev
except Exception, e:
print "blkdev_name_to_number> exception looking up device number for %s: %s" % (name, e)
pass
# see if this is a hex device number
if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
return string.atoi(name,16)
return None
def lookup_raw_partn(name):
"""Take the given block-device name (e.g., '/dev/sda1', 'hda')
and return a dictionary { device, start_sector,
nr_sectors, type }
device: Device number of the given partition
start_sector: Index of first sector of the partition
nr_sectors: Number of sectors comprising this partition
type: 'Disk' or identifying name for partition type
"""
n = blkdev_name_to_number(name)
if n:
return [ { 'device' : n,
'start_sector' : long(0),
'nr_sectors' : long(1L<<63),
'type' : 'Disk' } ]
else:
return None
class BlkifController(controller.SplitController):
"""Block device interface controller. Handles all block devices
for a domain.
@@ -418,65 +461,37 @@ class BlkifController(controller.SplitController):
val = ['blkif', ['dom', self.dom]]
return val
def addDevice(self, idx, config, vdev, mode, segment):
def addDevice(self, idx, config):
"""Add a device to the device table.
@param vdev: device index
@type vdev: int
@param mode: read/write mode
@type mode: string
@param segment: segment
@type segment: int
@param config: device configuration
@return: device
@rtype: BlkDev
"""
if idx in self.devices:
raise XendError('device exists: ' + str(idx))
dev = BlkDev(idx, self, config, vdev, mode, segment)
dev = BlkDev(idx, self, config )
self.devices[idx] = dev
return dev
def attachDevice(self, idx, config, uname, vdev, mode, recreate=0):
def attachDevice(self, idx, config, recreate=0):
"""Attach a device to the specified interface.
On success the returned deferred will be called with the device.
@param idx: device id
@param config: device configuration
@param vdev: device index
@type vdev: int
@param mode: read/write mode
@type mode: string
@param segment: segment
@type segment: int
@param recreate: if true it's being recreated (after xend restart)
@type recreate: bool
@return: deferred
@rtype: Deferred
"""
if not recreate:
# Split into type and type-specific details (which are passed to the
# type-specific control script).
type, dets = string.split(uname, ':', 1)
# Special case: don't bother calling a script for phy. Could
# alternatively provide a "do nothing" script for phy devices...
node = Blkctl.block('bind', type, dets)
segments = lookup_raw_partn(node)
if not segments:
raise VmError("vbd: Segments not found: uname=%s" % uname)
if len(segments) > 1:
raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
segment = segments[0]
dev = self.addDevice(idx, config, vdev, mode, segment)
dev = self.addDevice(idx, config)
if recreate:
dev.recreate(recreate)
d = defer.succeed(dev)
else:
dev.node = node
dev.type = type
d = dev.attach()
return d
@@ -682,10 +682,17 @@ class SplitDev(Dev):
def __init__(self, idx, controller):
Dev.__init__(self, idx, controller)
self.backendDomain = 0
self.index = None
def getBackendInterface(self):
return self.controller.getBackendInterface(self.backendDomain)
def getIndex(self):
return self.index
def setIndex(self, index):
self.index = index
+2
View File
@@ -198,6 +198,8 @@ class NetDev(controller.SplitDev):
val.append(['evtchn',
self.evtchn['port1'],
self.evtchn['port2']])
if self.index is not None:
val.append(['index', self.index])
return val
def get_vifname(self):
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.