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# Copyright (C) Citrix Systems Inc. 

2# 

3# This program is free software; you can redistribute it and/or modify 

4# it under the terms of the GNU Lesser General Public License as published 

5# by the Free Software Foundation; version 2.1 only. 

6# 

7# This program is distributed in the hope that it will be useful, 

8# but WITHOUT ANY WARRANTY; without even the implied warranty of 

9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

10# GNU Lesser General Public License for more details. 

11# 

12# You should have received a copy of the GNU Lesser General Public License 

13# along with this program; if not, write to the Free Software Foundation, Inc., 

14# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

15 

16import util 

17import xs_errors 

18import iscsilib 

19import mpath_cli 

20import os 

21import glob 

22import time 

23import scsiutil 

24import wwid_conf 

25import errno 

26 

27DMPBIN = "/sbin/multipath" 

28DEVMAPPERPATH = "/dev/mapper" 

29DEVBYIDPATH = "/dev/disk/by-id" 

30DEVBYSCSIPATH = "/dev/disk/by-scsibus" 

31DEVBYMPPPATH = "/dev/disk/by-mpp" 

32SYSFS_PATH = '/sys/class/scsi_host' 

33MP_INUSEDIR = "/dev/disk/mpInuse" 

34 

35MPPGETAIDLNOBIN = "/opt/xensource/bin/xe-get-arrayid-lunnum" 

36 

37 

38def _is_mpath_daemon_running(): 

39 cmd = ["/sbin/pidof", "-s", "/sbin/multipathd"] 

40 (rc, stdout, stderr) = util.doexec(cmd) 

41 return (rc == 0) 

42 

43 

44def activate_MPdev(sid, dst): 

45 try: 

46 os.mkdir(MP_INUSEDIR) 

47 except OSError as exc: 

48 if exc.errno == errno.EEXIST: 

49 pass 

50 else: 

51 raise 

52 path = os.path.join(MP_INUSEDIR, sid) 

53 cmd = ['ln', '-sf', dst, path] 

54 util.pread2(cmd) 

55 

56 

57def deactivate_MPdev(sid): 

58 path = os.path.join(MP_INUSEDIR, sid) 

59 if os.path.exists(path): 59 ↛ 60line 59 didn't jump to line 60, because the condition on line 59 was never true

60 os.unlink(path) 

61 

62 

63def reset(sid, explicit_unmap=False): 

64 util.SMlog("Resetting LUN %s" % sid) 

65 _resetDMP(sid, explicit_unmap) 

66 

67 

68def _resetDMP(sid, explicit_unmap=False): 

69# If mpath has been turned on since the sr/vdi was attached, we 

70# might be trying to unmap it before the daemon has been started 

71# This is unnecessary (and will fail) so just return. 

72 deactivate_MPdev(sid) 

73 if not _is_mpath_daemon_running(): 73 ↛ 74line 73 didn't jump to line 74, because the condition on line 73 was never true

74 util.SMlog("Warning: Trying to unmap mpath device when multipathd not running") 

75 return 

76 

77# If the multipath daemon is running, but we were initially plugged 

78# with multipathing set to no, there may be no map for us in the multipath 

79# tables. In that case, list_paths will return [], but remove_map might 

80# throw an exception. Catch it and ignore it. 

81 if explicit_unmap: 

82 util.retry(lambda: util.pread2(['/usr/sbin/multipath', '-f', sid]), 

83 maxretry=3, period=4) 

84 util.retry(lambda: util.pread2(['/usr/sbin/multipath', '-W']), maxretry=3, 

85 period=4) 

86 else: 

87 mpath_cli.ensure_map_gone(sid) 

88 

89 path = "/dev/mapper/%s" % sid 

90 

91 if not util.wait_for_nopath(path, 10): 91 ↛ 92line 91 didn't jump to line 92, because the condition on line 91 was never true

92 util.SMlog("MPATH: WARNING - path did not disappear [%s]" % path) 

93 else: 

94 util.SMlog("MPATH: path disappeared [%s]" % path) 

95 

96 

97def refresh(sid, npaths): 

98 # Refresh the multipath status 

99 util.SMlog("Refreshing LUN %s" % sid) 

100 if len(sid): 

101 path = DEVBYIDPATH + "/scsi-" + sid 

102 if not os.path.exists(path): 

103 scsiutil.rescan(scsiutil._genHostList("")) 

104 if not util.wait_for_path(path, 60): 

105 raise xs_errors.XenError('MultipathDeviceNotAppeared', path) 

106 _refresh_DMP(sid, npaths) 

107 else: 

108 raise xs_errors.XenError('MultipathDeviceNoScsiid') 

109 

110 

111def _is_valid_multipath_device(sid): 

112 

113 # Check if device is already multipathed 

114 (ret, stdout, stderr) = util.doexec(['/usr/sbin/multipath', '-l', sid]) 

115 if not stdout + stderr: 

116 (ret, stdout, stderr) = util.doexec(['/usr/sbin/multipath', '-ll', sid]) 

117 if not stdout + stderr: 

118 (ret, stdout, stderr) = util.doexec(['/usr/sbin/multipath', '-a', sid]) 

119 if ret < 0: 119 ↛ 120line 119 didn't jump to line 120, because the condition on line 119 was never true

120 util.SMlog("Failed to add {}: wwid could be explicitly " 

121 "blacklisted\n Continue with multipath disabled for " 

122 "this SR".format(sid)) 

123 return False 

124 

125 by_scsid_path = "/dev/disk/by-scsid/" + sid 

126 if os.path.exists(by_scsid_path): 

127 devs = os.listdir(by_scsid_path) 

128 else: 

129 util.SMlog("Device {} is not ready yet, skipping multipath check" 

130 .format(by_scsid_path)) 

131 return False 

132 ret = 1 

133 # Some paths might be down, check all associated devices 

134 for dev in devs: 

135 devpath = os.path.join(by_scsid_path, dev) 

136 real_path = util.get_real_path(devpath) 

137 (ret, stdout, stderr) = util.doexec(['/usr/sbin/multipath', '-c', 

138 real_path]) 

139 if ret == 0: 

140 break 

141 

142 if ret == 1: 

143 # This is very fragile but it is not a good sign to fail without 

144 # any output. At least until multipath 0.4.9, for example, 

145 # multipath -c fails without any log if it is able to retrieve the 

146 # wwid of the device. 

147 # In this case it is better to fail immediately. 

148 if not stdout + stderr: 

149 # Attempt to cleanup wwids file before raising 

150 try: 

151 (ret, stdout, stderr) = util.doexec(['/usr/sbin/multipath', 

152 '-w', sid]) 

153 except OSError: 

154 util.SMlog("Error removing {} from wwids file".format(sid)) 

155 raise xs_errors.XenError('MultipathGenericFailure', 

156 '"multipath -c" failed without any' 

157 ' output on {}'.format(real_path)) 

158 util.SMlog("When dealing with {} multipath status returned:\n " 

159 "{}{} Continue with multipath disabled for this SR" 

160 .format(sid, stdout, stderr)) 

161 return False 

162 return True 

163 

164 

165def _refresh_DMP(sid, npaths): 

166 if not _is_valid_multipath_device(sid): 166 ↛ 167line 166 didn't jump to line 167, because the condition on line 166 was never true

167 return 

168 path = os.path.join(DEVMAPPERPATH, sid) 

169 # If the mapper path doesn't exist force a reload in multipath 

170 if not os.path.exists(path): 

171 util.retry(lambda: util.pread2( 

172 ['/usr/sbin/multipath', '-r', sid]), 

173 maxretry=3, 

174 period=4) 

175 util.wait_for_path(path, 10) 

176 if not os.path.exists(path): 

177 raise xs_errors.XenError('MultipathMapperPathMissing', 

178 'Device mapper path {} not found'.format( 

179 path)) 

180 lvm_path = "/dev/disk/by-scsid/" + sid + "/mapper" 

181 util.wait_for_path(lvm_path, 10) 

182 activate_MPdev(sid, path) 

183 

184 

185def activate(): 

186 util.SMlog("MPATH: multipath activate called") 

187 

188 # If we've got no active sessions, and the deamon is already running, 

189 # we're ok to restart the daemon 

190 if iscsilib.is_iscsi_daemon_running(): 

191 if not iscsilib._checkAnyTGT(): 

192 iscsilib.restart_daemon() 

193 

194 if not _is_mpath_daemon_running(): 

195 util.SMlog("Warning: multipath daemon not running. Starting daemon!") 

196 cmd = ["service", "multipathd", "start"] 

197 util.pread2(cmd) 

198 

199 for i in range(0, 120): 

200 if mpath_cli.is_working(): 

201 util.SMlog("MPATH: dm-multipath activated.") 

202 return 

203 time.sleep(1) 

204 

205 util.SMlog("Failed to communicate with the multipath daemon!") 

206 raise xs_errors.XenError('MultipathdCommsFailure') 

207 

208 

209def deactivate(): 

210 util.SMlog("MPATH: multipath deactivate called") 

211 

212 if _is_mpath_daemon_running(): 212 ↛ 218line 212 didn't jump to line 218, because the condition on line 212 was never false

213 # Flush the multipath nodes 

214 for sid in mpath_cli.list_maps(): 

215 reset(sid, True) 

216 

217 # Disable any active MPP LUN maps (except the root dev) 

218 systemroot = os.path.realpath(util.getrootdev()) 

219 for dev in glob.glob(DEVBYMPPPATH + "/*"): 

220 if os.path.realpath(dev) != systemroot: 

221 sid = os.path.basename(dev).split('-')[0] 

222 reset(sid) 

223 else: 

224 util.SMlog("MPP: Found root dev node, not resetting") 

225 

226 # Check the ISCSI daemon doesn't have any active sessions, if not, 

227 # restart in the new mode 

228 if iscsilib.is_iscsi_daemon_running() and not iscsilib._checkAnyTGT(): 

229 iscsilib.restart_daemon() 

230 

231 util.SMlog("MPATH: multipath deactivated.") 

232 

233 

234def path(SCSIid): 

235 if _is_valid_multipath_device(SCSIid) and _is_mpath_daemon_running(): 

236 path = os.path.join(MP_INUSEDIR, SCSIid) 

237 return path 

238 else: 

239 return DEVBYIDPATH + "/scsi-" + SCSIid