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" 

31SYSFS_PATH = '/sys/class/scsi_host' 

32MP_INUSEDIR = "/dev/disk/mpInuse" 

33 

34 

35def _is_mpath_daemon_running(): 

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

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

38 return (rc == 0) 

39 

40 

41def activate_MPdev(sid, dst): 

42 try: 

43 os.mkdir(MP_INUSEDIR) 

44 except OSError as exc: 

45 if exc.errno == errno.EEXIST: 

46 pass 

47 else: 

48 raise 

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

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

51 util.pread2(cmd) 

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

53 

54 

55def deactivate_MPdev(sid): 

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

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

58 os.unlink(path) 

59 

60 

61def reset(sid, explicit_unmap=False): 

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

63 _resetDMP(sid, explicit_unmap) 

64 

65 

66def _resetDMP(sid, explicit_unmap=False): 

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

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

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

70 deactivate_MPdev(sid) 

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

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

73 return 

74 

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

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

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

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

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

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

81 maxretry=3, period=4) 

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

83 period=4) 

84 else: 

85 mpath_cli.ensure_map_gone(sid) 

86 

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

88 

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

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

91 else: 

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

93 

94 

95def refresh(sid, npaths): 

96 # Refresh the multipath status 

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

98 if len(sid): 

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

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

101 scsiutil.rescan(scsiutil._genHostList("")) 

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

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

104 _refresh_DMP(sid, npaths) 

105 else: 

106 raise xs_errors.XenError('MultipathDeviceNoScsiid') 

107 

108 

109def _is_valid_multipath_device(sid): 

110 

111 # Check if device is already multipathed 

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

113 if not stdout + stderr: 

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

115 if not stdout + stderr: 

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

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

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

119 "blacklisted\n Continue with multipath disabled for " 

120 "this SR".format(sid)) 

121 return False 

122 

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

124 if os.path.exists(by_scsid_path): 

125 devs = os.listdir(by_scsid_path) 

126 else: 

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

128 .format(by_scsid_path)) 

129 return False 

130 ret = 1 

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

132 for dev in devs: 

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

134 real_path = util.get_real_path(devpath) 

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

136 real_path]) 

137 if ret == 0: 

138 break 

139 

140 if ret == 1: 

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

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

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

144 # wwid of the device. 

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

146 if not stdout + stderr: 

147 # Attempt to cleanup wwids file before raising 

148 try: 

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

150 '-w', sid]) 

151 except OSError: 

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

153 raise xs_errors.XenError('MultipathGenericFailure', 

154 '"multipath -c" failed without any' 

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

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

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

158 .format(sid, stdout, stderr)) 

159 return False 

160 return True 

161 

162 

163def _refresh_DMP(sid, npaths): 

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

165 return 

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

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

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

169 util.retry(lambda: util.pread2( 

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

171 maxretry=3, 

172 period=4) 

173 util.wait_for_path(path, 30) 

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

175 raise xs_errors.XenError('MultipathMapperPathMissing', 

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

177 path)) 

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

179 util.wait_for_path(lvm_path, 30) 

180 activate_MPdev(sid, path) 

181 

182 

183def activate(): 

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

185 

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

187 # we're ok to restart the daemon 

188 if iscsilib.is_iscsi_daemon_running(): 

189 if not iscsilib._checkAnyTGT(): 

190 iscsilib.restart_daemon() 

191 

192 if not _is_mpath_daemon_running(): 

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

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

195 util.pread2(cmd) 

196 

197 for i in range(0, 120): 

198 if mpath_cli.is_working(): 

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

200 return 

201 time.sleep(1) 

202 

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

204 raise xs_errors.XenError('MultipathdCommsFailure') 

205 

206 

207def deactivate(): 

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

209 

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

211 # Flush the multipath nodes 

212 for sid in mpath_cli.list_maps(): 

213 reset(sid, True) 

214 

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

216 # restart in the new mode 

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

218 iscsilib.restart_daemon() 

219 

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

221 

222 

223def path(SCSIid): 

224 if _is_valid_multipath_device(SCSIid) and _is_mpath_daemon_running(): 

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

226 return path 

227 else: 

228 return DEVBYIDPATH + "/scsi-" + SCSIid