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# 

16# Miscellaneous LVM utility functions 

17# 

18 

19import re 

20import os 

21import errno 

22import time 

23 

24import lock 

25import util 

26import xs_errors 

27import xml.dom.minidom 

28from lvhdutil import VG_LOCATION, VG_PREFIX 

29from constants import EXT_PREFIX 

30import lvmcache 

31import srmetadata 

32 

33MDVOLUME_NAME = 'MGT' 

34VDI_UUID_TAG_PREFIX = 'vdi_' 

35LVM_BIN = os.path.isfile('/sbin/lvdisplay') and '/sbin' or '/usr/sbin' 

36CMD_VGS = "vgs" 

37CMD_VGCREATE = "vgcreate" 

38CMD_VGREMOVE = "vgremove" 

39CMD_VGCHANGE = "vgchange" 

40CMD_VGEXTEND = "vgextend" 

41CMD_PVS = "pvs" 

42CMD_PVCREATE = "pvcreate" 

43CMD_PVREMOVE = "pvremove" 

44CMD_PVRESIZE = "pvresize" 

45CMD_LVS = "lvs" 

46CMD_LVDISPLAY = "lvdisplay" 

47CMD_LVCREATE = "lvcreate" 

48CMD_LVREMOVE = "lvremove" 

49CMD_LVCHANGE = "lvchange" 

50CMD_LVRENAME = "lvrename" 

51CMD_LVRESIZE = "lvresize" 

52CMD_LVEXTEND = "lvextend" 

53CMD_DMSETUP = "/sbin/dmsetup" 

54 

55MAX_OPERATION_DURATION = 15 

56 

57LVM_SIZE_INCREMENT = 4 * 1024 * 1024 

58LV_TAG_HIDDEN = "hidden" 

59LVM_FAIL_RETRIES = 10 

60 

61MASTER_LVM_CONF = '/etc/lvm/master' 

62DEF_LVM_CONF = '/etc/lvm' 

63 

64VG_COMMANDS = frozenset({CMD_VGS, CMD_VGCREATE, CMD_VGREMOVE, CMD_VGCHANGE, 

65 CMD_VGEXTEND}) 

66PV_COMMANDS = frozenset({CMD_PVS, CMD_PVCREATE, CMD_PVREMOVE, CMD_PVRESIZE}) 

67LV_COMMANDS = frozenset({CMD_LVS, CMD_LVDISPLAY, CMD_LVCREATE, CMD_LVREMOVE, 

68 CMD_LVCHANGE, CMD_LVRENAME, CMD_LVRESIZE, 

69 CMD_LVEXTEND}) 

70DM_COMMANDS = frozenset({CMD_DMSETUP}) 

71 

72LVM_COMMANDS = VG_COMMANDS.union(PV_COMMANDS, LV_COMMANDS, DM_COMMANDS) 

73 

74LVM_LOCK = 'lvm' 

75 

76 

77def extract_vgname(str_in): 

78 """Search for and return a VG name 

79 

80 Search 'str_in' for a substring in the form of 'VG_XenStorage-<UUID>'.  

81 If there are more than one VG names, the first is returned. 

82 

83 Input: 

84 str_in -- (str) string to search for a VG name 

85 in the format specified above. 

86 

87 Return: 

88 vgname -- if found -> (str) 

89 if not found -> None 

90 

91 Raise: 

92 TypeError 

93 """ 

94 

95 if not util.is_string(str_in): 

96 raise TypeError("'str_in' not of type 'str'.") 

97 

98 i = str_in.find(VG_PREFIX) 

99 prefix = VG_PREFIX 

100 

101 if i == -1: 

102 i = str_in.find(EXT_PREFIX) 

103 prefix = EXT_PREFIX 

104 

105 uuid_start = i + len(prefix) 

106 re_obj = util.match_uuid(str_in[uuid_start:]) 

107 

108 if i != -1 and re_obj: 

109 return prefix + re_obj.group(0) # vgname 

110 

111 return None 

112 

113class LvmLockContext(object): 

114 """ 

115 Context manager around the LVM lock. 

116 

117 To allow for higher level operations, e.g. VDI snapshot to pre-emptively 

118 acquire the lock to encapsulte a set of calls and avoid having to reacquire 

119 the locks for each LVM call. 

120 """ 

121 

122 def __init__(self, cmd=None): 

123 self.lock = lock.Lock(LVM_LOCK) 

124 self.cmd = cmd 

125 self.locked = False 

126 

127 def __enter__(self): 

128 if self.cmd and '--readonly' in self.cmd: 128 ↛ 129line 128 didn't jump to line 129, because the condition on line 128 was never true

129 return 

130 

131 self.lock.acquire() 

132 self.locked = True 

133 

134 def __exit__(self, exc_type, value, traceback): 

135 if self.locked: 135 ↛ exitline 135 didn't return from function '__exit__', because the condition on line 135 was never false

136 self.lock.release() 

137 

138 

139LVM_RETRY_ERRORS = [ 

140 "Incorrect checksum in metadata area header" 

141] 

142 

143 

144def lvmretry(func): 

145 def check_exception(exception): 

146 retry = False 

147 for error in LVM_RETRY_ERRORS: 

148 if error in exception.reason: 

149 retry = True 

150 return retry 

151 

152 def decorated(*args, **kwargs): 

153 for i in range(LVM_FAIL_RETRIES): 153 ↛ exitline 153 didn't return from function 'decorated', because the loop on line 153 didn't complete

154 try: 

155 return func(*args, **kwargs) 

156 except util.CommandException as ce: 

157 retry = check_exception(ce) 

158 if not retry or (i == LVM_FAIL_RETRIES - 1): 

159 raise 

160 

161 time.sleep(1) 

162 

163 decorated.__name__ = func.__name__ 

164 return decorated 

165 

166 

167def cmd_lvm(cmd, pread_func=util.pread2, *args): 

168 """ Construct and run the appropriate lvm command. 

169 

170 For PV commands, the full path to the device is required. 

171 

172 Input: 

173 cmd -- (list) lvm command 

174 cmd[0] -- (str) lvm command name 

175 cmd[1:] -- (str) lvm command parameters 

176 

177 pread_func -- (function) the flavor of util.pread to use 

178 to execute the lvm command 

179 Default: util.pread2() 

180 

181 *args -- extra arguments passed to cmd_lvm will be passed 

182 to 'pread_func' 

183 

184 Return: 

185 stdout -- (str) stdout after running the lvm command. 

186 

187 Raise: 

188 util.CommandException 

189 """ 

190 

191 if type(cmd) is not list: 191 ↛ 192line 191 didn't jump to line 192, because the condition on line 191 was never true

192 util.SMlog("CMD_LVM: Argument 'cmd' not of type 'list'") 

193 return None 

194 if not len(cmd): 194 ↛ 195line 194 didn't jump to line 195, because the condition on line 194 was never true

195 util.SMlog("CMD_LVM: 'cmd' list is empty") 

196 return None 

197 

198 lvm_cmd, lvm_args = cmd[0], cmd[1:] 

199 

200 if lvm_cmd not in LVM_COMMANDS: 200 ↛ 201line 200 didn't jump to line 201, because the condition on line 200 was never true

201 util.SMlog("CMD_LVM: '{}' is not a valid lvm command".format(lvm_cmd)) 

202 return None 

203 

204 for arg in lvm_args: 

205 if not util.is_string(arg): 205 ↛ 206line 205 didn't jump to line 206, because the condition on line 205 was never true

206 util.SMlog("CMD_LVM: Not all lvm arguments are of type 'str'") 

207 return None 

208 

209 with LvmLockContext(cmd): 

210 start_time = time.time() 

211 stdout = pread_func([os.path.join(LVM_BIN, lvm_cmd)] + lvm_args, * args) 

212 end_time = time.time() 

213 

214 if (end_time - start_time > MAX_OPERATION_DURATION): 214 ↛ 215line 214 didn't jump to line 215, because the condition on line 214 was never true

215 util.SMlog("***** Long LVM call of '%s' took %s" % (lvm_cmd, (end_time - start_time))) 

216 

217 return stdout 

218 

219 

220class LVInfo: 

221 name = "" 

222 size = 0 

223 active = False 

224 open = False 

225 hidden = False 

226 readonly = False 

227 

228 def __init__(self, name): 

229 self.name = name 

230 

231 def toString(self): 

232 return "%s, size=%d, active=%s, open=%s, hidden=%s, ro=%s" % \ 

233 (self.name, self.size, self.active, self.open, self.hidden, \ 

234 self.readonly) 

235 

236 

237def _checkVG(vgname): 

238 try: 

239 cmd_lvm([CMD_VGS, "--readonly", vgname]) 

240 return True 

241 except: 

242 return False 

243 

244 

245def _checkPV(pvname): 

246 try: 

247 cmd_lvm([CMD_PVS, pvname]) 

248 return True 

249 except: 

250 return False 

251 

252 

253def _checkLV(path): 

254 try: 

255 cmd_lvm([CMD_LVDISPLAY, path]) 

256 return True 

257 except: 

258 return False 

259 

260 

261def _getLVsize(path): 

262 try: 

263 lines = cmd_lvm([CMD_LVDISPLAY, "-c", path]).split(':') 

264 return int(lines[6]) * 512 

265 except: 

266 raise xs_errors.XenError('VDIUnavailable', \ 

267 opterr='no such VDI %s' % path) 

268 

269 

270def _getVGstats(vgname): 

271 try: 

272 text = cmd_lvm([CMD_VGS, "--noheadings", "--nosuffix", 

273 "--units", "b", vgname], 

274 pread_func=util.pread).split() 

275 size = int(text[5]) 

276 freespace = int(text[6]) 

277 utilisation = size - freespace 

278 stats = {} 

279 stats['physical_size'] = size 

280 stats['physical_utilisation'] = utilisation 

281 stats['freespace'] = freespace 

282 return stats 

283 except util.CommandException as inst: 

284 raise xs_errors.XenError('VDILoad', \ 

285 opterr='rvgstats failed error is %d' % inst.code) 

286 except ValueError: 

287 raise xs_errors.XenError('VDILoad', opterr='rvgstats failed') 

288 

289 

290def _getPVstats(dev): 

291 try: 

292 text = cmd_lvm([CMD_PVS, "--noheadings", "--nosuffix", 

293 "--units", "b", dev], 

294 pread_func=util.pread).split() 

295 size = int(text[4]) 

296 freespace = int(text[5]) 

297 utilisation = size - freespace 

298 stats = {} 

299 stats['physical_size'] = size 

300 stats['physical_utilisation'] = utilisation 

301 stats['freespace'] = freespace 

302 return stats 

303 except util.CommandException as inst: 

304 raise xs_errors.XenError('VDILoad', \ 

305 opterr='pvstats failed error is %d' % inst.code) 

306 except ValueError: 

307 raise xs_errors.XenError('VDILoad', opterr='rvgstats failed') 

308 

309 

310# Retrieves the UUID of the SR that corresponds to the specified Physical 

311# Volume (pvname). Each element in prefix_list is checked whether it is a 

312# prefix of Volume Groups that correspond to the specified PV. If so, the 

313# prefix is stripped from the matched VG name and the remainder is returned 

314# (effectively the SR UUID). If no match if found, the empty string is 

315# returned. 

316# E.g. 

317# PV VG Fmt Attr PSize PFree 

318# /dev/sda4 VG_XenStorage-some-hex-value lvm2 a- 224.74G 223.73G 

319# will return "some-hex-value". 

320def _get_sr_uuid(pvname, prefix_list): 

321 try: 

322 return match_VG(cmd_lvm([CMD_PVS, "--noheadings", 

323 "-o", "vg_name", pvname]), prefix_list) 

324 except: 

325 return "" 

326 

327 

328# Retrieves the names of the Physical Volumes which are used by the specified 

329# Volume Group 

330# e.g. 

331# PV VG Fmt Attr PSize PFree 

332# /dev/sda4 VG_XenStorage-some-hex-value lvm2 a- 224.74G 223.73G 

333# will return "/dev/sda4" when given the argument "VG_XenStorage-some-hex-value". 

334def get_pv_for_vg(vgname): 

335 try: 

336 result = cmd_lvm([CMD_PVS, "--noheadings", 

337 '-S', 'vg_name=%s' % vgname, '-o', 'name']) 

338 return [x.strip() for x in result.splitlines()] 

339 except util.CommandException: 

340 return [] 

341 

342 

343# Tries to match any prefix contained in prefix_list in s. If matched, the 

344# remainder string is returned, else the empty string is returned. E.g. if s is 

345# "VG_XenStorage-some-hex-value" and prefix_list contains "VG_XenStorage-", 

346# "some-hex-value" is returned. 

347# 

348# TODO Items in prefix_list are expected to be found at the beginning of the 

349# target string, though if any of them is found inside it a match will be 

350# produced. This could be remedied by making the regular expression more 

351# specific. 

352def match_VG(s, prefix_list): 

353 for val in prefix_list: 

354 regex = re.compile(val) 

355 if regex.search(s, 0): 

356 return s.split(val)[1] 

357 return "" 

358 

359 

360# Retrieves the devices an SR is composed of. A dictionary is returned, indexed 

361# by the SR UUID, where each SR UUID is mapped to a comma-separated list of 

362# devices. Exceptions are ignored. 

363def scan_srlist(prefix, root): 

364 VGs = {} 

365 for dev in root.split(','): 

366 try: 

367 sr_uuid = _get_sr_uuid(dev, [prefix]).strip(' \n') 

368 if len(sr_uuid): 

369 if sr_uuid in VGs: 

370 VGs[sr_uuid] += ",%s" % dev 

371 else: 

372 VGs[sr_uuid] = dev 

373 except Exception as e: 

374 util.logException("exception (ignored): %s" % e) 

375 continue 

376 return VGs 

377 

378 

379# Converts an SR list to an XML document with the following structure: 

380# <SRlist> 

381# <SR> 

382# <UUID>...</UUID> 

383# <Devlist>...</Devlist> 

384# <size>...</size> 

385# <!-- If includeMetadata is set to True, the following additional nodes 

386# are supplied. --> 

387# <name_label>...</name_label> 

388# <name_description>...</name_description> 

389# <pool_metadata_detected>...</pool_metadata_detected> 

390# </SR> 

391# 

392# <SR>...</SR> 

393# </SRlist> 

394# 

395# Arguments: 

396# VGs: a dictionary containing the SR UUID to device list mappings 

397# prefix: the prefix that if prefixes the SR UUID the VG is produced 

398# includeMetadata (optional): include additional information 

399def srlist_toxml(VGs, prefix, includeMetadata=False): 

400 dom = xml.dom.minidom.Document() 

401 element = dom.createElement("SRlist") 

402 dom.appendChild(element) 

403 

404 for val in VGs: 

405 entry = dom.createElement('SR') 

406 element.appendChild(entry) 

407 

408 subentry = dom.createElement("UUID") 

409 entry.appendChild(subentry) 

410 textnode = dom.createTextNode(val) 

411 subentry.appendChild(textnode) 

412 

413 subentry = dom.createElement("Devlist") 

414 entry.appendChild(subentry) 

415 textnode = dom.createTextNode(VGs[val]) 

416 subentry.appendChild(textnode) 

417 

418 subentry = dom.createElement("size") 

419 entry.appendChild(subentry) 

420 size = str(_getVGstats(prefix + val)['physical_size']) 

421 textnode = dom.createTextNode(size) 

422 subentry.appendChild(textnode) 

423 

424 if includeMetadata: 

425 metadataVDI = None 

426 

427 # add SR name_label 

428 mdpath = os.path.join(VG_LOCATION, VG_PREFIX + val) 

429 mdpath = os.path.join(mdpath, MDVOLUME_NAME) 

430 try: 

431 mgtVolActivated = False 

432 if not os.path.exists(mdpath): 

433 # probe happens out of band with attach so this volume 

434 # may not have been activated at this point 

435 lvmCache = lvmcache.LVMCache(VG_PREFIX + val) 

436 lvmCache.activateNoRefcount(MDVOLUME_NAME) 

437 mgtVolActivated = True 

438 

439 sr_metadata = \ 

440 srmetadata.LVMMetadataHandler(mdpath, \ 

441 False).getMetadata()[0] 

442 subentry = dom.createElement("name_label") 

443 entry.appendChild(subentry) 

444 textnode = dom.createTextNode(sr_metadata[srmetadata.NAME_LABEL_TAG]) 

445 subentry.appendChild(textnode) 

446 

447 # add SR description 

448 subentry = dom.createElement("name_description") 

449 entry.appendChild(subentry) 

450 textnode = dom.createTextNode(sr_metadata[srmetadata.NAME_DESCRIPTION_TAG]) 

451 subentry.appendChild(textnode) 

452 

453 # add metadata VDI UUID 

454 metadataVDI = srmetadata.LVMMetadataHandler(mdpath, \ 

455 False).findMetadataVDI() 

456 subentry = dom.createElement("pool_metadata_detected") 

457 entry.appendChild(subentry) 

458 if metadataVDI is not None: 

459 subentry.appendChild(dom.createTextNode("true")) 

460 else: 

461 subentry.appendChild(dom.createTextNode("false")) 

462 finally: 

463 if mgtVolActivated: 

464 # deactivate only if we activated it 

465 lvmCache.deactivateNoRefcount(MDVOLUME_NAME) 

466 

467 return dom.toprettyxml() 

468 

469 

470def _openExclusive(dev, retry): 

471 try: 

472 return os.open("%s" % dev, os.O_RDWR | os.O_EXCL) 

473 except OSError as ose: 

474 opened_by = '' 

475 if ose.errno == 16: 

476 if retry: 

477 util.SMlog('Device %s is busy, settle and one shot retry' % 

478 dev) 

479 util.pread2(['/usr/sbin/udevadm', 'settle']) 

480 return _openExclusive(dev, False) 

481 else: 

482 util.SMlog('Device %s is busy after retry' % dev) 

483 

484 util.SMlog('Opening device %s failed with %d' % (dev, ose.errno)) 

485 raise xs_errors.XenError( 

486 'SRInUse', opterr=('Device %s in use, please check your existing ' 

487 + 'SRs for an instance of this device') % dev) 

488 

489 

490def createVG(root, vgname): 

491 systemroot = util.getrootdev() 

492 rootdev = root.split(',')[0] 

493 

494 # Create PVs for each device 

495 for dev in root.split(','): 

496 if dev in [systemroot, '%s1' % systemroot, '%s2' % systemroot]: 

497 raise xs_errors.XenError('Rootdev', \ 

498 opterr=('Device %s contains core system files, ' \ 

499 + 'please use another device') % dev) 

500 if not os.path.exists(dev): 

501 raise xs_errors.XenError('InvalidDev', \ 

502 opterr=('Device %s does not exist') % dev) 

503 

504 f = _openExclusive(dev, True) 

505 os.close(f) 

506 try: 

507 # Overwrite the disk header, try direct IO first 

508 cmd = [util.CMD_DD, "if=/dev/zero", "of=%s" % dev, "bs=1M", 

509 "count=10", "oflag=direct"] 

510 util.pread2(cmd) 

511 except util.CommandException as inst: 

512 if inst.code == errno.EPERM: 

513 try: 

514 # Overwrite the disk header, try normal IO 

515 cmd = [util.CMD_DD, "if=/dev/zero", "of=%s" % dev, 

516 "bs=1M", "count=10"] 

517 util.pread2(cmd) 

518 except util.CommandException as inst: 

519 raise xs_errors.XenError('LVMWrite', \ 

520 opterr='device %s' % dev) 

521 else: 

522 raise xs_errors.XenError('LVMWrite', \ 

523 opterr='device %s' % dev) 

524 

525 if not (dev == rootdev): 

526 try: 

527 cmd_lvm([CMD_PVCREATE, "-ff", "-y", "--metadatasize", "10M", dev]) 

528 except util.CommandException as inst: 

529 raise xs_errors.XenError('LVMPartCreate', 

530 opterr='error is %d' % inst.code) 

531 

532 # Create VG on first device 

533 try: 

534 cmd_lvm([CMD_VGCREATE, "--metadatasize", "10M", vgname, rootdev]) 

535 except: 

536 raise xs_errors.XenError('LVMGroupCreate') 

537 

538 # Then add any additional devs into the VG 

539 for dev in root.split(',')[1:]: 

540 try: 

541 cmd_lvm([CMD_VGEXTEND, vgname, dev]) 

542 except util.CommandException as inst: 

543 # One of the PV args failed, delete SR 

544 try: 

545 cmd_lvm([CMD_VGREMOVE, vgname]) 

546 except: 

547 pass 

548 raise xs_errors.XenError('LVMGroupCreate') 

549 

550 try: 

551 cmd_lvm([CMD_VGCHANGE, "-an", vgname]) 

552 except util.CommandException as inst: 

553 raise xs_errors.XenError('LVMUnMount', opterr='errno is %d' % inst.code) 

554 

555 # End block 

556 

557def removeVG(root, vgname): 

558 # Check PVs match VG 

559 try: 

560 for dev in root.split(','): 

561 txt = cmd_lvm([CMD_PVS, dev]) 

562 if txt.find(vgname) == -1: 

563 raise xs_errors.XenError('LVMNoVolume', \ 

564 opterr='volume is %s' % vgname) 

565 except util.CommandException as inst: 

566 raise xs_errors.XenError('PVSfailed', \ 

567 opterr='error is %d' % inst.code) 

568 

569 try: 

570 cmd_lvm([CMD_VGREMOVE, vgname]) 

571 

572 for dev in root.split(','): 

573 cmd_lvm([CMD_PVREMOVE, dev]) 

574 except util.CommandException as inst: 

575 raise xs_errors.XenError('LVMDelete', \ 

576 opterr='errno is %d' % inst.code) 

577 

578 

579def resizePV(dev): 

580 try: 

581 cmd_lvm([CMD_PVRESIZE, dev]) 

582 except util.CommandException as inst: 

583 util.SMlog("Failed to grow the PV, non-fatal") 

584 

585 

586def setActiveVG(path, active): 

587 "activate or deactivate VG 'path'" 

588 val = "n" 

589 if active: 

590 val = "y" 

591 text = cmd_lvm([CMD_VGCHANGE, "-a" + val, path]) 

592 

593 

594@lvmretry 

595def create(name, size, vgname, tag=None, size_in_percentage=None): 

596 if size_in_percentage: 

597 cmd = [CMD_LVCREATE, "-n", name, "-l", size_in_percentage, vgname] 

598 else: 

599 size_mb = size // (1024 * 1024) 

600 cmd = [CMD_LVCREATE, "-n", name, "-L", str(size_mb), vgname] 

601 if tag: 

602 cmd.extend(["--addtag", tag]) 

603 

604 cmd.extend(['-W', 'n']) 

605 cmd_lvm(cmd) 

606 

607 

608def remove(path, config_param=None): 

609 # see deactivateNoRefcount() 

610 for i in range(LVM_FAIL_RETRIES): 610 ↛ 618line 610 didn't jump to line 618, because the loop on line 610 didn't complete

611 try: 

612 _remove(path, config_param) 

613 break 

614 except util.CommandException as e: 

615 if i >= LVM_FAIL_RETRIES - 1: 

616 raise 

617 util.SMlog("*** lvremove failed on attempt #%d" % i) 

618 _lvmBugCleanup(path) 

619 

620 

621@lvmretry 

622def _remove(path, config_param=None): 

623 CONFIG_TAG = "--config" 

624 cmd = [CMD_LVREMOVE, "-f", path] 

625 if config_param: 

626 cmd.extend([CONFIG_TAG, "devices{" + config_param + "}"]) 

627 ret = cmd_lvm(cmd) 

628 

629 

630@lvmretry 

631def rename(path, newName): 

632 cmd_lvm([CMD_LVRENAME, path, newName], pread_func=util.pread) 

633 

634 

635@lvmretry 

636def setReadonly(path, readonly): 

637 val = "r" 

638 if not readonly: 

639 val += "w" 

640 ret = cmd_lvm([CMD_LVCHANGE, path, "-p", val], pread_func=util.pread) 

641 

642 

643def exists(path): 

644 (rc, stdout, stderr) = cmd_lvm([CMD_LVS, "--noheadings", path], pread_func=util.doexec) 

645 return rc == 0 

646 

647 

648@lvmretry 

649def setSize(path, size, confirm): 

650 sizeMB = size // (1024 * 1024) 

651 if confirm: 

652 cmd_lvm([CMD_LVRESIZE, "-L", str(sizeMB), path], util.pread3, "y\n") 

653 else: 

654 cmd_lvm([CMD_LVRESIZE, "-L", str(sizeMB), path], pread_func=util.pread) 

655 

656 

657@lvmretry 

658def setHidden(path, hidden=True): 

659 opt = "--addtag" 

660 if not hidden: 

661 opt = "--deltag" 

662 cmd_lvm([CMD_LVCHANGE, opt, LV_TAG_HIDDEN, path]) 

663 

664 

665@lvmretry 

666def _activate(path): 

667 cmd = [CMD_LVCHANGE, "-ay", path] 

668 cmd_lvm(cmd) 

669 if not _checkActive(path): 

670 raise util.CommandException(-1, str(cmd), "LV not activated") 

671 

672 

673def activateNoRefcount(path, refresh): 

674 _activate(path) 

675 if refresh: 675 ↛ 677line 675 didn't jump to line 677, because the condition on line 675 was never true

676 # Override slave mode lvm.conf for this command 

677 os.environ['LVM_SYSTEM_DIR'] = MASTER_LVM_CONF 

678 text = cmd_lvm([CMD_LVCHANGE, "--refresh", path]) 

679 mapperDevice = path[5:].replace("-", "--").replace("/", "-") 

680 cmd = [CMD_DMSETUP, "table", mapperDevice] 

681 ret = util.pread(cmd) 

682 util.SMlog("DM table for %s: %s" % (path, ret.strip())) 

683 # Restore slave mode lvm.conf 

684 os.environ['LVM_SYSTEM_DIR'] = DEF_LVM_CONF 

685 

686 

687def deactivateNoRefcount(path): 

688 # LVM has a bug where if an "lvs" command happens to run at the same time 

689 # as "lvchange -an", it might hold the device in use and cause "lvchange 

690 # -an" to fail. Thus, we need to retry if "lvchange -an" fails. Worse yet, 

691 # the race could lead to "lvchange -an" starting to deactivate (removing 

692 # the symlink), failing to "dmsetup remove" the device, and still returning 

693 # success. Thus, we need to check for the device mapper file existence if 

694 # "lvchange -an" returns success. 

695 for i in range(LVM_FAIL_RETRIES): 695 ↛ 703line 695 didn't jump to line 703, because the loop on line 695 didn't complete

696 try: 

697 _deactivate(path) 

698 break 

699 except util.CommandException: 

700 if i >= LVM_FAIL_RETRIES - 1: 

701 raise 

702 util.SMlog("*** lvchange -an failed on attempt #%d" % i) 

703 _lvmBugCleanup(path) 

704 

705 

706@lvmretry 

707def _deactivate(path): 

708 text = cmd_lvm([CMD_LVCHANGE, "-an", path]) 

709 

710 

711def _checkActive(path): 

712 if util.pathexists(path): 

713 return True 

714 

715 util.SMlog("_checkActive: %s does not exist!" % path) 

716 symlinkExists = os.path.lexists(path) 

717 util.SMlog("_checkActive: symlink exists: %s" % symlinkExists) 

718 

719 mapperDeviceExists = False 

720 mapperDevice = path[5:].replace("-", "--").replace("/", "-") 

721 cmd = [CMD_DMSETUP, "status", mapperDevice] 

722 try: 

723 ret = util.pread2(cmd) 

724 mapperDeviceExists = True 

725 util.SMlog("_checkActive: %s: %s" % (mapperDevice, ret)) 

726 except util.CommandException: 

727 util.SMlog("_checkActive: device %s does not exist" % mapperDevice) 

728 

729 mapperPath = "/dev/mapper/" + mapperDevice 

730 mapperPathExists = util.pathexists(mapperPath) 

731 util.SMlog("_checkActive: path %s exists: %s" % \ 

732 (mapperPath, mapperPathExists)) 

733 

734 if mapperDeviceExists and mapperPathExists and not symlinkExists: 734 ↛ 736line 734 didn't jump to line 736, because the condition on line 734 was never true

735 # we can fix this situation manually here 

736 try: 

737 util.SMlog("_checkActive: attempt to create the symlink manually.") 

738 os.symlink(mapperPath, path) 

739 except OSError as e: 

740 util.SMlog("ERROR: failed to symlink!") 

741 if e.errno != errno.EEXIST: 

742 raise 

743 if util.pathexists(path): 

744 util.SMlog("_checkActive: created the symlink manually") 

745 return True 

746 

747 return False 

748 

749 

750def _lvmBugCleanup(path): 

751 # the device should not exist at this point. If it does, this was an LVM 

752 # bug, and we manually clean up after LVM here 

753 mapperDevice = path[5:].replace("-", "--").replace("/", "-") 

754 mapperPath = "/dev/mapper/" + mapperDevice 

755 

756 nodeExists = False 

757 cmd_st = [CMD_DMSETUP, "status", mapperDevice] 

758 cmd_rm = [CMD_DMSETUP, "remove", mapperDevice] 

759 cmd_rf = [CMD_DMSETUP, "remove", mapperDevice, "--force"] 

760 

761 try: 

762 util.pread(cmd_st, expect_rc=1) 

763 except util.CommandException as e: 

764 if e.code == 0: 764 ↛ 767line 764 didn't jump to line 767, because the condition on line 764 was never false

765 nodeExists = True 

766 

767 if not util.pathexists(mapperPath) and not nodeExists: 

768 return 

769 

770 util.SMlog("_lvmBugCleanup: seeing dm file %s" % mapperPath) 

771 

772 # destroy the dm device 

773 if nodeExists: 773 ↛ 798line 773 didn't jump to line 798, because the condition on line 773 was never false

774 util.SMlog("_lvmBugCleanup: removing dm device %s" % mapperDevice) 

775 for i in range(LVM_FAIL_RETRIES): 775 ↛ 798line 775 didn't jump to line 798, because the loop on line 775 didn't complete

776 try: 

777 util.pread2(cmd_rm) 

778 break 

779 except util.CommandException as e: 

780 if i < LVM_FAIL_RETRIES - 1: 

781 util.SMlog("Failed on try %d, retrying" % i) 

782 try: 

783 util.pread(cmd_st, expect_rc=1) 

784 util.SMlog("_lvmBugCleanup: dm device {}" 

785 " removed".format(mapperDevice) 

786 ) 

787 break 

788 except: 

789 cmd_rm = cmd_rf 

790 time.sleep(1) 

791 else: 

792 # make sure the symlink is still there for consistency 

793 if not os.path.lexists(path): 793 ↛ 796line 793 didn't jump to line 796, because the condition on line 793 was never false

794 os.symlink(mapperPath, path) 

795 util.SMlog("_lvmBugCleanup: restored symlink %s" % path) 

796 raise e 

797 

798 if util.pathexists(mapperPath): 

799 os.unlink(mapperPath) 

800 util.SMlog("_lvmBugCleanup: deleted devmapper file %s" % mapperPath) 

801 

802 # delete the symlink 

803 if os.path.lexists(path): 

804 os.unlink(path) 

805 util.SMlog("_lvmBugCleanup: deleted symlink %s" % path) 

806 

807 

808# mdpath is of format /dev/VG-SR-UUID/MGT 

809# or in other words /VG_LOCATION/VG_PREFIXSR-UUID/MDVOLUME_NAME 

810def ensurePathExists(mdpath): 

811 if not os.path.exists(mdpath): 

812 vgname = mdpath.split('/')[2] 

813 lvmCache = lvmcache.LVMCache(vgname) 

814 lvmCache.activateNoRefcount(MDVOLUME_NAME) 

815 

816 

817def removeDevMapperEntry(path, strict=True): 

818 try: 

819 # remove devmapper entry using dmsetup 

820 cmd = [CMD_DMSETUP, "remove", path] 

821 cmd_lvm(cmd) 

822 return True 

823 except Exception as e: 

824 if not strict: 

825 cmd = [CMD_DMSETUP, "status", path] 

826 try: 

827 util.pread(cmd, expect_rc=1) 

828 return True 

829 except: 

830 pass # Continuining will fail and log the right way 

831 ret = util.pread2(["lsof", path]) 

832 util.SMlog("removeDevMapperEntry: dmsetup remove failed for file %s " \ 

833 "with error %s, and lsof ret is %s." % (path, str(e), ret)) 

834 return False