Coverage for drivers/lvmanager.py : 52%

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#
19import time
20import util
21import lvhdutil
24class LVManagerException(util.SMException):
25 pass
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"""
35 OPEN_RETRY_ATTEMPTS = 10
36 OPEN_RETRY_INTERVAL = 2
38 NORMAL = False
39 BINARY = True
41 TEMPORARY = False
42 PERSISTENT = True
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()
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
61 self.lvActivations[persistent][binary][uuid] = lvName
62 self.lvmCache.activate(self.ns, uuid, lvName, binary)
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)
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)
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
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]
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()
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]
129 def add(self, uuid, lvName, binary):
130 self.lvActivations[self.TEMPORARY][binary][uuid] = lvName
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]
137 def get(self, uuid, binary):
138 return self.lvActivations[self.TEMPORARY][binary].get(uuid)