Coverage for drivers/scsiutil : 25%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#!/usr/bin/python # # Copyright (C) Citrix Systems Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; version 2.1 only. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Miscellaneous scsi utility functions #
hs = 0 for i in st: hs = ord(i) + (hs << 6) + (hs << 16) - hs return str(hs)[0:len]
if len(serial) < SUFFIX_LEN: raise util.CommandException(1) prefix = gen_hash(iqn, PREFIX_LEN) suffix = gen_hash(serial, SUFFIX_LEN) str = prefix.encode("hex") + suffix.encode("hex") return str[0:8]+'-'+str[8:12]+'-'+str[12:16]+'-'+str[16:20]+'-'+str[20:32]
str = uuid.replace('-','') prefix = gen_hash(iqn, PREFIX_LEN) if str[0:(PREFIX_LEN * 2)].decode("hex") != prefix: raise util.CommandException(1) return str[(PREFIX_LEN * 2):].decode("hex")
dev = getdev(path) sysfs = os.path.join('/sys/block',dev,'size') size = 0 if os.path.exists(sysfs): try: f=open(sysfs, 'r') size = (long(f.readline()) << SECTOR_SHIFT) f.close() except: pass return size
dev = getdev(path) output = gen_rdmfile() try: cmd = ["md5sum"] txt = util.pread3(cmd, getSCSIid(path)) return txt.split(' ')[0] except: return ''
if len(str) < (PREFIX_LEN + SUFFIX_LEN): raise util.CommandException(1) return str[0:8]+'-'+str[8:12]+'-'+str[12:16]+'-'+str[16:20]+'-'+str[20:32]
text = str.strip() return re.sub("\s+","_",text)
"""Get the SCSI id of a block device
Input: path -- (str) path to block device; can be symlink
Return: scsi_id -- (str) the device's SCSI id
Raise: util.CommandException """
util.SMlog("getSCSIid: fixing invalid input {}".format(path), priority=util.LOG_WARNING) path = '/dev/' + path.lstrip('/')
return SCSIid_sanitise(stdout)
serial = getserial(path) len_serial = len(serial) if (len_serial == 0 ) or (len_serial > (len(SCSIid) - 1)): return False list_SCSIid = list(SCSIid) list_serial = list_SCSIid[1:(len_serial + 1)] serial_2_6_18 = ''.join(list_serial) if (serial == serial_2_6_18): return True else: return False
dev = os.path.join('/dev',getdev(path)) try: cmd = ["sginfo", "-s", dev] text = re.sub("\s+","",util.pread2(cmd)) except: raise xs_errors.XenError('EIO', \ opterr='An error occured querying device serial number [%s]' \ % dev) try: return text.split("'")[1] except: return ''
cmd = ["sginfo", "-M", path] try: for line in filter(match_vendor, util.pread2(cmd).split('\n')): return line.replace(' ','').split(':')[-1] except: return ''
continue (HBTL[0],HBTL[1],HBTL[2],HBTL[3],dev)
f = None for i in range(0,10): try: str = "scsi %s-single-device %s %s %s %s" % \ (cmd, ids[1],ids[2],ids[3],ids[4]) util.SMlog(str) f=open('/proc/scsi/scsi', 'w') print >>f, str f.close() return except IOError, e: util.SMlog("SCSI_DEV_CTRL: Failure, %s [%d]" % (e.strerror,e.errno)) if f is not None: f.close() f = None if e.errno == errno.ENXIO: util.SMlog("Device has disappeared already") return time.sleep(6) continue raise xs_errors.XenError('EIO', \ opterr='An error occured during the scsi operation')
newpath = realpath.replace("/dev/mapper/","/dev/disk/by-id/scsi-") else:
devices = os.listdir(os.path.join('/dev/disk/by-scsid', SCSIid)) if 'mapper' in devices: devices.remove('mapper') return devices
device = getdev(dev) if device.startswith('dm-') and device[3:].isdigit(): return device
return re.sub('[0-9]*$', '', device)
for line in filter(match_session, util.listdir(path)): return line.split('-')[-1]
regex = re.compile("^SESSIONID-") return regex.search(s, 0)
regex = re.compile("^Vendor:") return regex.search(s, 0)
regex = re.compile("/dev/sd") return regex.search(s, 0)
if match_dm(dev): path = dev.replace("/dev/mapper/","/dev/disk/by-id/scsi-") else: path = dev return match_sd(os.path.realpath(path))
return "/tmp/%s" % util.gen_uuid()
try: conf = session.xenapi.SR.get_sm_config(sr_ref) conf['devserial'] = devstring session.xenapi.SR.set_sm_config(sr_ref, conf) except: pass
try: conf = session.xenapi.SR.get_sm_config(sr_ref) return conf['devserial'] except: return ""
serial = '' for dev in devlist: try: devserial = "scsi-%s" % getSCSIid(dev) if not len(devserial) > 0: continue if len(serial): serial += ',' serial += devserial except: pass
return serial
# For generating synthetic page data for non-raw LUNs # we set the vendor ID to XENSRC # Note that the Page 80 serial number must be limited # to 16 characters
default = "" page80 = "" page83 = "" try: cmd = ["sg_inq", "-r", path] text = util.pread2(cmd) default = base64.b64encode(text)
cmd = ["sg_inq", "--page=0x80", "-r", path] text = util.pread2(cmd) page80 = base64.b64encode(text)
cmd = ["sg_inq", "--page=0x83", "-r", path] text = util.pread2(cmd) page83 = base64.b64encode(text) except: pass return [default,page80,page83]
# XXX: PR-1255: passing through SCSI data doesn't make sense when # it will change over storage migration. It also doesn't make sense # to preserve one array's identity and copy it when a VM moves to # a new array because the drivers in the VM may attempt to contact # the original array, fail and bluescreen.
xenstore_data["scsi/0x12/default"]=data[0]
try: cmd = ["sg_inq", "--page=0xc8", "-r", dev] id = util.pread2(cmd) return id.encode("hex")[180:212] except: return ""
# loop through and check all adapters ids = [] try: for dir in util.listdir('/sys/class/scsi_host'): filename = os.path.join('/sys/class/scsi_host',dir,'proc_name') if os.path.exists(filename): f = open(filename, 'r') if f.readline().find(procname) != -1: ids.append(dir.replace("host","")) f.close() except: pass return ids
util.SMlog("map_by_scsibus: sid=%s" % SCSIid)
devices = [] for link in glob.glob('/dev/disk/by-%s/%s-*' % (pathname,SCSIid)): realpath = os.path.realpath(link) if os.path.exists(realpath): devices.append(realpath) return devices
devices = [] for link in glob.glob('/dev/disk/by-scsibus/%s-*' % SCSIid): devices.append(link.split('-')[-1]) return devices
regex=re.compile("([^:]*):\s+scsi([0-9]+)\s+channel=([0-9]+)\s+id=([0-9]+)\s+lun=([0-9]+)") scan=util.pread2(["/usr/bin/sg_scan"]).split('\n') sgs=[] for line in scan: m=regex.match(line) if m: device=m.group(1) host=m.group(2) channel=m.group(3) sid=m.group(4) lun=m.group(5) sgs.append([device,host,channel,sid,lun]) return sgs
for c in li: if not refresh_scsi_channel(c): fullrescan = True
try: scanstring = "- - -" f=open(path, 'w') f.write('%s\n' % scanstring) f.close() if len(li): # Channels already exist, allow some time for # undiscovered LUNs/channels to appear time.sleep(2) except: pass # Host Bus scan issued, now try to detect channels # At least one LUN is mapped
# a) Find a LUN to issue a Query LUNs command li = [] Query = False for lun in LUNs: try: hbtl = lun.split('-')[-1] h = hbtl.split(':') l=util.pread2(["/usr/bin/sg_luns","-q",lun]).split('\n') li = [] for i in l: if len(i): li.append(int(i[0:4], 16)) util.SMlog("sg_luns query returned %s" % li) Query = True break except: pass if not Query: util.SMlog("Failed to detect or query LUN on Channel %s" % channel) return False
# b) Remove stale LUNs current = glob.glob('/dev/disk/by-scsibus/*-%s:%s:%s*' % (h[0],h[1],h[2])) for cur in current: lunID = int(cur.split(':')[-1]) newhbtl = ['',h[0],h[1],h[2],str(lunID)] if os.path.realpath(cur) in rootdevs: # Don't touch the rootdev if lunID in li: li.remove(lunID) continue
# Check if LUN is stale, and remove it if not lunID in li: util.SMlog("Stale LUN detected. Removing HBTL: %s" % newhbtl) scsi_dev_ctrl(newhbtl,"remove") util.wait_for_nopath(cur, DEV_WAIT) continue else: li.remove(lunID)
# Check if the device is still present if not os.path.exists(cur): continue
# Query SCSIid, check it matches, if not, re-probe cur_SCSIid = os.path.basename(cur).split("-%s:%s:%s" % (h[0],h[1],h[2]))[0] real_SCSIid = getSCSIid(cur) if cur_SCSIid != real_SCSIid: util.SMlog("HBTL %s does not match, re-probing" % newhbtl) scsi_dev_ctrl(newhbtl,"remove") util.wait_for_nopath(cur, DEV_WAIT) scsi_dev_ctrl(newhbtl,"add") util.wait_for_path('/dev/disk/by-scsibus/%s-%s' % (real_SCSIid,hbtl), DEV_WAIT) pass
# c) Probe for any LUNs that are not present in the system for l in li: newhbtl = ['',h[0],h[1],h[2],str(l)] newhbtlstr = "%s:%s:%s:%s" % (h[0],h[1],h[2],str(l)) util.SMlog("Probing new HBTL: %s" % newhbtl) scsi_dev_ctrl(newhbtl,"add") util.wait_for_path('/dev/disk/by-scsibus/*-%s' % newhbtlstr, DEV_WAIT)
return True
""" Refresh block devices given a path list """ for path in pathlist: dev = getdev(path) sysfs = os.path.join('/sys/block',dev,'device/rescan') if os.path.exists(sysfs): try: f = os.open(sysfs, os.O_WRONLY) os.write(f,'1') os.close(f) except: pass
""" Refresh all devices for the SCSIid. Returns True if all known devices and the mapper device are up to date. """ def get_primary_device(SCSIid): mapperdevice = os.path.join('/dev/mapper', SCSIid) if os.path.exists(mapperdevice): return mapperdevice else: devices = get_devices_by_SCSIid(SCSIid) if devices: return devices[0] else: return None
def get_outdated_size_devices(currentcapacity, devices): devicesthatneedrefresh = [] for device in devices: if getsize(device) != currentcapacity: devicesthatneedrefresh.append(device) return devicesthatneedrefresh
def refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity): devices = get_devices_by_SCSIid(SCSIid) if "/dev/mapper/" in primarydevice: devices = set(devices + mpath_cli.list_paths(SCSIid)) devicesthatneedrefresh = get_outdated_size_devices(currentcapacity, devices) if devicesthatneedrefresh: # timing out avoids waiting for min(dev_loss_tmo, fast_io_fail_tmo) # if one or multiple devices don't answer util.timeout_call(10, refreshdev, devicesthatneedrefresh) if get_outdated_size_devices(currentcapacity, devicesthatneedrefresh): # in this state we shouldn't force resizing the mapper dev raise util.SMException("Failed to get %s to agree on the " "current capacity." % devicesthatneedrefresh)
def refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity): if "/dev/mapper/" in primarydevice \ and get_outdated_size_devices(currentcapacity, [primarydevice]): mpath_cli.resize_map(SCSIid) if get_outdated_size_devices(currentcapacity, [primarydevice]): raise util.SMException("Failed to get the mapper dev to agree " "on the current capacity.")
try: primarydevice = get_primary_device(SCSIid) if primarydevice: currentcapacity = sg_readcap(primarydevice) refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity) refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity) else: util.SMlog("scsiutil.refresh_lun_size_by_SCSIid(%s) could not " "find any devices for the SCSIid." % SCSIid) return True except: util.logException("Error in scsiutil.refresh_lun_size_by_SCSIid(%s)" % SCSIid) return False
for slave in util.get_all_slaves(session): util.SMlog("Calling on-slave.refresh_lun_size_by_SCSIid(%s) on %s." % (SCSIid, slave)) resulttext = session.xenapi.host.call_plugin( slave, "on-slave", "refresh_lun_size_by_SCSIid", {'SCSIid': SCSIid }) if "True" == resulttext: util.SMlog("Calling on-slave.refresh_lun_size_by_SCSIid(%s) on" " %s succeeded." % (SCSIid, slave)) else: message = ("Failed in on-slave.refresh_lun_size_by_SCSIid(%s) " "on %s." % (SCSIid, slave)) raise util.SMException("Slave %s failed in on-slave.refresh_lun_" "size_by_SCSIid(%s) " % (slave, SCSIid))
try: for hostid in hostids: # get all LUNs of the format hostid:x:y:lunid luns = glob.glob('/dev/disk/by-scsibus/*-%s:*:*:%s' % (hostid, lunid))
# try to get the scsiid for each of these luns for lun in luns: try: getSCSIid(lun) # if it works, we have a problem as this device should not # be present and be valid on this system util.SMlog("Warning! The lun %s should not be present and" \ " be valid on this system." % lun) except: # Now do the rest. pass
# get the HBTL basename = os.path.basename(lun) hbtl_list = basename.split(':') hbtl = basename.split('-')[1]
# the first one in scsiid-hostid hbtl_list[0] = hbtl_list[0].split('-')[1]
expectedPath = expectedPath + '*' + hbtl if not os.path.exists(expectedPath): # wait for sometime and check if the expected path exists # check if a rescan was done outside of this process time.sleep(2)
if os.path.exists(expectedPath): # do not remove device, this might be dangerous util.SMlog("Path %s appeared before checking for "\ "stale LUNs, ignore this LUN %s." % (expectedPath, lun)) continue
# remove the scsi device l = [os.path.realpath(lun), hbtl_list[0], hbtl_list[1], \ hbtl_list[2], hbtl_list[3]] scsi_dev_ctrl(l, 'remove')
# if multipath is enabled, do a best effort cleanup if mpath: try: path = os.path.basename(os.path.realpath(lun)) mpath_cli.remove_path(path) except Exception, e: util.SMlog("Failed to remove path %s, ignoring "\ "exception as path may not be present." % path) except Exception, e: util.SMlog("Exception removing stale LUNs, new devices may not come"\ " up properly! Error: %s" % str(e))
# retry one time for "Capacity data has changed" raise util.SMException("scsiutil.sg_readcap(%s) failed" % (device)) raise util.SMException("scsiutil.sg_readcap(%s) failed to parse: %s" % (device, stdout)) |