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# Manage LV activations 

17# 

18 

19import time 

20import util 

21import lvhdutil 

22 

23 

24class LVManagerException(util.SMException): 

25 pass 

26 

27 

28class LVActivator: 

29 """Keep track of LV activations and make LV activations transactional, 

30 so that when the SM operation finishes, either all LVs that needed to be 

31 activated are activated (in the success case), or none of them are (in a 

32 failure case). We don't want leave a random subset of activated LVs if 

33 something failed part way through""" 

34 

35 OPEN_RETRY_ATTEMPTS = 10 

36 OPEN_RETRY_INTERVAL = 2 

37 

38 NORMAL = False 

39 BINARY = True 

40 

41 TEMPORARY = False 

42 PERSISTENT = True 

43 

44 def __init__(self, srUuid, lvmCache): 

45 self.ns = lvhdutil.NS_PREFIX_LVM + srUuid 

46 self.lvmCache = lvmCache 

47 self.lvActivations = dict() 

48 self.openFiles = dict() 

49 for persistent in [self.TEMPORARY, self.PERSISTENT]: 

50 self.lvActivations[persistent] = dict() 

51 for binary in [self.NORMAL, self.BINARY]: 

52 self.lvActivations[persistent][binary] = dict() 

53 

54 def activate(self, uuid, lvName, binary, persistent=False): 

55 if self.lvActivations[persistent][binary].get(uuid): 55 ↛ 56line 55 didn't jump to line 56, because the condition on line 55 was never true

56 if persistent: 

57 raise LVManagerException("Double persistent activation: %s" % \ 

58 uuid) 

59 return 

60 

61 self.lvActivations[persistent][binary][uuid] = lvName 

62 self.lvmCache.activate(self.ns, uuid, lvName, binary) 

63 

64 def activateEnforce(self, uuid, lvName, lvPath): 

65 """incrementing the refcount is not enough to keep an LV activated if 

66 another party is unaware of refcounting. For example, blktap does  

67 direct "lvchange -an, lvchange -ay" during VBD.attach/resume without 

68 any knowledge of refcounts. Therefore, we need to keep the device open  

69 to prevent unwanted deactivations. Note that blktap can do "lvchange 

70 -an" the very moment we try to open the file, so retry on failure""" 

71 if self.lvActivations[self.TEMPORARY][self.NORMAL].get(uuid): 

72 return 

73 self.activate(uuid, lvName, self.NORMAL) 

74 

75 f = None 

76 for i in range(self.OPEN_RETRY_ATTEMPTS): 

77 try: 

78 f = open(lvPath, 'r') 

79 break 

80 except IOError: 

81 util.SMlog("(Failed to open %s on attempt %d)" % (lvPath, i)) 

82 time.sleep(self.OPEN_RETRY_INTERVAL) 

83 if not f: 

84 raise LVManagerException("Failed to open %s" % lvPath) 

85 self.openFiles[uuid] = f 

86 self.lvmCache.changeOpen(lvName, 1) 

87 

88 def deactivateAll(self): 

89 # this is the cleanup step that will be performed even if the original 

90 # operation failed - don't throw exceptions here 

91 success = True 

92 for persistent in [self.TEMPORARY, self.PERSISTENT]: 

93 for binary in [self.NORMAL, self.BINARY]: 

94 uuids = list(self.lvActivations[persistent][binary].keys()) 

95 for uuid in uuids: 95 ↛ 96line 95 didn't jump to line 96, because the loop on line 95 never started

96 try: 

97 self.deactivate(uuid, binary, persistent) 

98 except: 

99 success = False 

100 util.logException("_deactivateAll") 

101 return success 

102 

103 def deactivate(self, uuid, binary, persistent=False): 

104 lvName = self.lvActivations[persistent][binary][uuid] 

105 if self.openFiles.get(uuid): 

106 self.openFiles[uuid].close() 

107 del self.openFiles[uuid] 

108 self.lvmCache.changeOpen(lvName, -1) 

109 self.lvmCache.deactivate(self.ns, uuid, lvName, binary) 

110 del self.lvActivations[persistent][binary][uuid] 

111 

112 def persist(self): 

113 """Only commit LV chain activations when all LVs have been successfully 

114 activated. This ensures that if there is a failure part way through, 

115 the entire chain activation will be rolled back and we aren't left with 

116 random active LVs""" 

117 for binary in [self.NORMAL, self.BINARY]: 

118 self.lvActivations[self.PERSISTENT][binary].clear() 

119 

120 def replace(self, oldUuid, uuid, lvName, binary): 

121 del self.lvActivations[self.TEMPORARY][binary][oldUuid] 

122 self.lvActivations[self.TEMPORARY][binary][uuid] = lvName 

123 if self.openFiles.get(oldUuid): 123 ↛ 125line 123 didn't jump to line 125, because the condition on line 123 was never true

124 # an open fd follows the file object through renames 

125 assert(not self.openFiles.get(uuid)) 

126 self.openFiles[uuid] = self.openFiles[oldUuid] 

127 del self.openFiles[oldUuid] 

128 

129 def add(self, uuid, lvName, binary): 

130 self.lvActivations[self.TEMPORARY][binary][uuid] = lvName 

131 

132 def remove(self, uuid, binary): 

133 if (self.openFiles.get(uuid)): 133 ↛ 134line 133 didn't jump to line 134, because the condition on line 133 was never true

134 raise LVManagerException("Open file reference for %s" % uuid) 

135 del self.lvActivations[self.TEMPORARY][binary][uuid] 

136 

137 def get(self, uuid, binary): 

138 return self.lvActivations[self.TEMPORARY][binary].get(uuid)