Hide keyboard shortcuts

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

1"""Fake scsiutil module""" 

2 

3import glob 

4import os 

5import re 

6import traceback 

7 

8from . import f_exceptions 

9from . import util 

10from . import mpath_cli 

11 

12SECTOR_SHIFT = 9 

13 

14def match_dm(s): 

15 regex = re.compile("mapper/") 

16 return regex.search(s, 0) 

17 

18 

19def getdev(path): 

20 realpath = os.path.realpath(path) 

21 if match_dm(realpath): 

22 newpath = realpath.replace("/dev/mapper/","/dev/disk/by-id/scsi-") 

23 else: 

24 newpath = path 

25 return os.path.realpath(newpath).split('/')[-1] 

26 

27 

28def getsize(path): 

29 dev = getdev(path) 

30 sysfs = os.path.join('/sys/block',dev,'size') 

31 size = 0 

32 if os.path.exists(sysfs): 

33 try: 

34 f=open(sysfs, 'r') 

35 size = (int(f.readline()) << SECTOR_SHIFT) 

36 f.close() 

37 except: 

38 pass 

39 return size 

40 

41 

42def get_vendor(device_path): 

43 vendor_command = ['sginfo', '-M', device_path] 

44 (rc, stdout, _) = util.doexec(vendor_command) 

45 if rc != 0: 

46 raise f_exceptions.XenError( 

47 'SCSIRead', 'sginfo failed {}, {}'.format(device_path, rc)) 

48 

49 match = re.search(r'(^|.*\n)Vendor:\s+(.*)[$|\n]', stdout) 

50 if not match: 

51 raise f_exceptions.XenError( 

52 'SCSIRead', 'sginfo no vendor match {}'.format(device_path)) 

53 return match.group(2).strip() 

54 

55 

56def get_serial(device_path): 

57 serial_command = ['sginfo', '-s', device_path] 

58 (rc, stdout, _) = util.doexec(serial_command) 

59 if rc != 0: 

60 raise f_exceptions.XenError( 

61 'SCSIRead', 'sginfo failed {}, {}'.format(device_path, rc)) 

62 

63 match = re.search(r'(^|.*\n)Serial Number\s+\'([^\']*)\'[$|\n]', stdout) 

64 if not match: 

65 raise f_exceptions.XenError( 

66 'SCSIRead', 'sginfo no serial match {}'.format(device_path)) 

67 return match.group(2).strip() 

68 

69 

70def get_devices_by_SCSIid(SCSIid): 

71 devices = os.listdir(os.path.join('/dev/disk/by-scsid', SCSIid)) 

72 if 'mapper' in devices: 

73 devices.remove('mapper') 

74 return devices 

75 

76 

77def get_device_provisioning_mode(SCSIid): 

78 device = get_devices_by_SCSIid(SCSIid)[0] 

79 glob_pattern = os.path.join('/sys', 'block', device, 'device', 'scsi_disk', '*', 'provisioning_mode') 

80 for file in glob.glob(glob_pattern): 80 ↛ exitline 80 didn't return from function 'get_device_provisioning_mode', because the loop on line 80 didn't complete

81 with open(file, 'r') as device_mode: 

82 mode = device_mode.readline().strip() 

83 return mode 

84 

85 

86def device_is_thin_provisioned(SCSIid): 

87 mode = get_device_provisioning_mode(SCSIid) 

88 # Kernel modes are 

89 # [SD_LBP_FULL] = "full", 

90 # [SD_LBP_UNMAP] = "unmap", 

91 # [SD_LBP_WS16] = "writesame_16", 

92 # [SD_LBP_WS10] = "writesame_10", 

93 # [SD_LBP_ZERO] = "writesame_zero", 

94 # [SD_LBP_DISABLE] = "disabled" 

95 return mode in ['unmap', 'writesame_16', 'writesame_10', 'writesame_zero'] 

96 

97 

98def sg_readcap(device): 

99 device = os.path.join('/dev', getdev(device)) 

100 readcapcommand = ['/usr/bin/sg_readcap', '-b', device] 

101 (rc,stdout,stderr) = util.doexec(readcapcommand) 

102 if rc == 6: 

103 # retry one time for "Capacity data has changed" 

104 (rc,stdout,stderr) = util.doexec(readcapcommand) 

105 if rc != 0: 

106 raise f_exceptions.XenError("SCSIRead", 

107 "scsiutil.sg_readcap(%s) failed" % (device)) 

108 match = re.search('(^|.*\n)(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)\n$', stdout) 

109 if not match: 

110 raise f_exceptions.XenError("SCSIRead", 

111 "scsiutil.sg_readcap(%s) failed to parse: %s" 

112 % (device, stdout)) 

113 (blockcount, blocksize) = match.group(2, 3) 

114 return (int(blockcount, 0) * int(blocksize, 0)) 

115 

116 

117def refreshdev(pathlist): 

118 """ 

119 Refresh block devices given a path list 

120 """ 

121 for path in pathlist: 

122 dev = getdev(path) 

123 util.SMlog("Refreshing size for device %s (%s)" % (path, dev)) 

124 sysfs = os.path.join('/sys/block',dev,'device/rescan') 

125 if os.path.exists(sysfs): 

126 try: 

127 f = os.open(sysfs, os.O_WRONLY) 

128 os.write(f, b'1') 

129 os.close(f) 

130 except: 

131 pass 

132 

133 

134def refresh_lun_size_by_SCSIid(SCSIid): 

135 """ 

136 Refresh all devices for the SCSIid. 

137 Returns True if all known devices and the mapper device are up to date. 

138 """ 

139 def get_primary_device(SCSIid): 

140 mapperdevice = os.path.join('/dev/mapper', SCSIid) 

141 if os.path.exists(mapperdevice): 

142 return mapperdevice 

143 else: 

144 devices = get_devices_by_SCSIid(SCSIid) 

145 if devices: 

146 return devices[0] 

147 else: 

148 return None 

149 

150 def get_outdated_size_devices(currentcapacity, devices): 

151 devicesthatneedrefresh = [] 

152 for device in devices: 

153 if getsize(device) != currentcapacity: 

154 devicesthatneedrefresh.append(device) 

155 return devicesthatneedrefresh 

156 

157 def refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity): 

158 devices = get_devices_by_SCSIid(SCSIid) 

159 if "/dev/mapper/" in primarydevice: 

160 devices = set(devices + mpath_cli.list_paths(SCSIid)) 

161 devicesthatneedrefresh = get_outdated_size_devices(currentcapacity, 

162 devices) 

163 if devicesthatneedrefresh: 

164 # timing out avoids waiting for min(dev_loss_tmo, fast_io_fail_tmo) 

165 # if one or multiple devices don't answer 

166 util.timeout_call(10, refreshdev, devicesthatneedrefresh) 

167 if get_outdated_size_devices(currentcapacity, 

168 devicesthatneedrefresh): 

169 # in this state we shouldn't force resizing the mapper dev 

170 raise f_exceptions.XenError("DeviceResize", 

171 "Failed to get %s to agree on the " 

172 "current capacity." 

173 % devicesthatneedrefresh) 

174 

175 def refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity): 

176 if ("/dev/mapper/" in primarydevice 

177 and get_outdated_size_devices(currentcapacity, [primarydevice])): 

178 util.SMlog("Resizing multpath map for device %s" % SCSIid) 

179 mpath_cli.resize_map(SCSIid) 

180 if get_outdated_size_devices(currentcapacity, [primarydevice]): 

181 raise f_exceptions.XenError("DeviceResize", 

182 "Failed to get the mapper dev to " 

183 "agree on the current capacity.") 

184 

185 try: 

186 primarydevice = get_primary_device(SCSIid) 

187 if primarydevice: 

188 currentcapacity = sg_readcap(primarydevice) 

189 refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity) 

190 refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity) 

191 else: 

192 util.SMlog("scsiutil.refresh_lun_size_by_SCSIid(%s) could not " 

193 "find any devices for the SCSIid." % SCSIid) 

194 return True 

195 except: 

196 util.SMlog("Error in scsiutil.refresh_lun_size_by_SCSIid(%s: %s)" % (SCSIid, traceback.format_exc())) 

197 return False