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 

26from fairlock import Fairlock 

27 

28DMPBIN = "/sbin/multipath" 

29DEVMAPPERPATH = "/dev/mapper" 

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

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

32SYSFS_PATH = '/sys/class/scsi_host' 

33MP_INUSEDIR = "/dev/disk/mpInuse" 

34 

35 

36def _is_mpath_daemon_running(): 

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

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

39 return (rc == 0) 

40 

41 

42def activate_MPdev(sid, dst): 

43 try: 

44 os.mkdir(MP_INUSEDIR) 

45 except OSError as exc: 

46 if exc.errno == errno.EEXIST: 

47 pass 

48 else: 

49 raise 

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

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

52 util.pread2(cmd) 

53 util.set_scheduler(os.path.realpath(path)) 

54 

55 

56def deactivate_MPdev(sid): 

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

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

59 os.unlink(path) 

60 

61 

62def reset(sid, explicit_unmap=False): 

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

64 _resetDMP(sid, explicit_unmap) 

65 

66 

67def _resetDMP(sid, explicit_unmap=False): 

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

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

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

71 deactivate_MPdev(sid) 

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

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

74 return 

75 

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

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

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

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

80 if explicit_unmap: 80 ↛ 87line 80 didn't jump to line 87, because the condition on line 80 was never false

81 with Fairlock("devicemapper"): 

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 with Fairlock("devicemapper"): 

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

116 if not stdout + stderr: 

117 with Fairlock("devicemapper"): 

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

119 if not stdout + stderr: 

120 with Fairlock("devicemapper"): 

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

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

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

124 "blacklisted\n Continue with multipath disabled for " 

125 "this SR".format(sid)) 

126 return False 

127 

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

129 if os.path.exists(by_scsid_path): 

130 devs = os.listdir(by_scsid_path) 

131 else: 

132 util.SMlog("Device {} is not ready yet, skipping multipath check".format(by_scsid_path)) 

133 return False 

134 ret = 1 

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

136 for dev in devs: 

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

138 real_path = util.get_real_path(devpath) 

139 with Fairlock("devicemapper"): 

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

141 if ret == 0: 

142 break 

143 

144 if ret == 1: 

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

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

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

148 # wwid of the device. 

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

150 if not stdout + stderr: 

151 # Attempt to cleanup wwids file before raising 

152 try: 

153 with Fairlock("devicemapper"): 

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

155 except OSError: 

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

157 raise xs_errors.XenError('MultipathGenericFailure', 

158 '"multipath -c" failed without any' 

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

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

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

162 .format(sid, stdout, stderr)) 

163 return False 

164 return True 

165 

166 

167def _refresh_DMP(sid, npaths): 

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

169 return 

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

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

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

173 with Fairlock("devicemapper"): 

174 util.retry(lambda: util.pread2(['/usr/sbin/multipath', '-r', sid]), maxretry=3, period=4) 

175 util.wait_for_path(path, 30) 

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, 30) 

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 = ["/usr/bin/systemctl", "start", "multipathd.service"] 

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 ↛ 219line 212 didn't jump to line 219, 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 # Check the ISCSI daemon doesn't have any active sessions, if not, 

218 # restart in the new mode 

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

220 iscsilib.restart_daemon() 

221 

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

223 

224 

225def path(SCSIid): 

226 if _is_valid_multipath_device(SCSIid) and _is_mpath_daemon_running(): 

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

228 return path 

229 else: 

230 return DEVBYIDPATH + "/scsi-" + SCSIid