[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] xend: Device duplicate check fix
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1243420125 -3600 # Node ID 9ff5c79b0ceba3fba89c15bef6f228e8dca9a9d7 # Parent 87c411a7c1df29002b087ea3b751983594e05078 xend: Device duplicate check fix I've checked the duplicate-check code here and I found that's checked only in the context of one domain but not cross-domain. The thing is that we should check tap/vbd device cross-domain not to allow another guest to use the same disk image in some circumstances to prevent VM's disk corruption. The patch included denies disk image addition under those circumstances: 1. We're adding read-only disk that's already used as write-exclusive 2. We're adding write-shared disk that's already used as write-exclusive 3. We're adding write-exclusive disk that's already used 4. We're adding read-only disk that's already used as write-shared* (because of I/O caching issues etc.) The vif device duplicate check remains the same it was and it's checked in the context of current domain only so that behaviour has been preserved. Signed-off-by: Michal Novotny <minovotn@xxxxxxxxxx> --- tools/python/xen/xend/XendConfig.py | 194 +++++++++++++++++++++++++----------- 1 files changed, 136 insertions(+), 58 deletions(-) diff -r 87c411a7c1df -r 9ff5c79b0ceb tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed May 27 11:27:13 2009 +0100 +++ b/tools/python/xen/xend/XendConfig.py Wed May 27 11:28:45 2009 +0100 @@ -19,6 +19,7 @@ import re import re import time import types +import XendDomain from xen.xend import sxp from xen.xend import uuid @@ -1162,65 +1163,142 @@ class XendConfig(dict): return None return devid + def device_tuple_value_from_dev_info(self, dev_info, key): + for x in dev_info: + if (type(x) != str): + for xx in x: + if (xx[0] == key): + return xx[1] + return None + + # This function translates all block device modes (incl. aliases) to + # one common label per each device mode. Those modes can be: + # read-only (ro), write-exclusive (wx) and write-shared (ws) + def block_device_mode_translate(self, mode): + # Device modes can be read-only (ro), write-exclusive (wx) or + # write-shared (ws), otherwise an error is raised + if mode == "w" or mode == "wr": + return "wx" + elif mode == "r" or mode == "ro": + return "ro" + elif mode == "!" or mode == "w!": + return "ws" + + # If no mode defined we consider this as write-exclusive + return "wx" + + # Detect device duplicates for vbd, tap and vif devices for domain and + # duplicate unames in global context not to destroy virtual block devices def device_duplicate_check(self, dev_type, dev_info, defined_config, config): - defined_devices_sxpr = self.all_devices_sxpr(target = defined_config) - - if dev_type == 'vbd' or dev_type == 'tap': - dev_uname = dev_info.get('uname') - blkdev_name = dev_info.get('dev') - devid = self._blkdev_name_to_number(blkdev_name) - if devid == None or dev_uname == None: - return - - for o_dev_type, o_dev_info in defined_devices_sxpr: - if o_dev_type == 'vbd' or o_dev_type == 'tap': - blkdev_file = blkdev_uname_to_file(dev_uname) - o_dev_uname = sxp.child_value(o_dev_info, 'uname') - if o_dev_uname != None: - o_blkdev_file = blkdev_uname_to_file(o_dev_uname) - if blkdev_file == o_blkdev_file: - raise XendConfigError('The file "%s" is already used' % - blkdev_file) - if dev_uname == o_dev_uname: - raise XendConfigError('The uname "%s" is already defined' % - dev_uname) - o_blkdev_name = sxp.child_value(o_dev_info, 'dev') - o_devid = self._blkdev_name_to_number(o_blkdev_name) - if o_devid != None and devid == o_devid: - name_array = blkdev_name.split(':', 2) - if len(name_array) == 2 and name_array[1] == 'cdrom': - # - # Since the device is a cdrom, we are most likely - # inserting, changing, or removing a cd. We can - # update the old device instead of creating a new - # one. - # - if o_dev_uname != None and dev_uname == None: - # - # We are removing a cd. We can simply update - # the uname on the existing device. - # - merge_sxp = sxp.from_string("('vbd' ('uname' ''))") - else: - merge_sxp = config - - dev_uuid = sxp.child_value(o_dev_info, 'uuid') - if dev_uuid != None and \ - self.device_update(dev_uuid, cfg_sxp = merge_sxp): - return dev_uuid - - raise XendConfigError('The device "%s" is already defined' % - blkdev_name) - - elif dev_type == 'vif': - dev_mac = dev_info.get('mac') - - for o_dev_type, o_dev_info in defined_devices_sxpr: - if dev_type == o_dev_type: - if dev_mac.lower() == sxp.child_value(o_dev_info, 'mac').lower(): - raise XendConfigError('The mac "%s" is already defined' % - dev_mac) - return None + # Enumerate all devices for all domains + allSxprs = [] + val = XendDomain.instance().domains.values() + for v in val: + sxpr = v.getDeviceSxprs(dev_type) + for key in sxpr: + try: + index = allSxprs.index(key) + except: + allSxprs.append(key) + + # Enumerate devices for current domain + sxpr = self.all_devices_sxpr(target = defined_config) + + # For vif interface we won't check cross-domain + if sxpr == None and dev_type == 'vif': + return + + # Preset None values to all variables we'll be checking + new_uname = None + uname = None + dev = None + mac = None + mode = None + + # Disk device + if dev_type in ['vbd', 'tap']: + for x in config: + if type(x) != str and (x[0] in ['uname', 'dev', 'mode']): + if x[0] == 'uname': + new_uname = x[1] + if x[0] == 'dev': + dev = x[1] + if x[0] == 'mode': + mode = x[1] + + # If we don't have uname entry (happens in virt-manager) return + if new_uname == None: + return + + new_uname = new_uname.split(":")[len(new_uname.split(":"))-1] + # We need to allow when uname is zero length, eg. hdc:cdrom device + if len(new_uname) == 0: + log.debug("Null uname when attaching disk device, allowing %s..." + % dev) + return + + log.debug("Checking for duplicate for uname: %s, dev: %s, mode: %s" + % (new_uname, dev, mode)) + # No device in dev found + if dev == None: + return + + devid = self._blkdev_name_to_number(dev) + if devid == None: + return + + for o_dev_info in sxpr: + # Get information only for tap/vbd block devices + if o_dev_info[0] in ['tap', 'vbd']: + uname = self.device_tuple_value_from_dev_info(o_dev_info, "uname") + dev = self.device_tuple_value_from_dev_info(o_dev_info, "dev") + dev_uname = None + if uname != None: + dev_uname = uname.split(":")[len(uname.split(":"))-1] + if new_uname == dev_uname: + raise XendConfigError('The uname "%s" is already defined' % + dev_uname) + + blkdev = dev.split(":")[0] + blkdevid = self._blkdev_name_to_number(blkdev) + if blkdevid != None and devid == blkdevid: + raise XendConfigError('The device "%s" is already defined' % + blkdev) + + tMode = self.block_device_mode_translate(mode) + + # Device/uname not found in the context of current domain but we + # need to have a look to global context. We deny addition of device + # in those cases: + # 1. We're adding read-only disk that's already used as write-exclusive + # 2. We're adding write-shared disk that's already used as write-exclusive + # 3. We're adding write-exclusive disk that's already used + # 4. We're adding read-only disk that's already used as write-shared + for o_dev_info in allSxprs: + backend = self.device_tuple_value_from_dev_info(o_dev_info, "backend") + params = xstransact.Read(backend, "params") + aMode = self.block_device_mode_translate( + xstransact.Read(backend, "mode") ) + dev_uname = params.split(":")[len(params.split(":"))-1] + if new_uname == dev_uname: + if ((tMode == "ro" and aMode == "wx") + or (tMode == "ws" and aMode == "wx") + or (tMode == "ro" and aMode == "ws") + or (tMode == "wx")): + raise XendConfigError('The uname "%s" is already used by another domain' % + dev_uname) + + # Virtual network adapter + elif dev_type == 'vif': + dev_mac = dev_info.get('mac') + + for o_dev_type, o_dev_info in sxpr: + if dev_type == o_dev_type: + if dev_mac.lower() == sxp.child_value(o_dev_info, 'mac').lower(): + raise XendConfigError('The mac "%s" is already defined' % + dev_mac) + + return None def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None, target = None): _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |