Skip to content

Commit 8ca9de0

Browse files
committed
CA-324971: lock LVM commands to avoid concurrency clashes
Signed-off-by: Mark Syms <[email protected]>
1 parent cf00f1c commit 8ca9de0

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

drivers/lvutil.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import errno
2525
import time
2626

27+
import lock
2728
import util
2829
import xs_errors
2930
import xml.dom.minidom
@@ -69,8 +70,9 @@
6970
LV_COMMANDS = frozenset({CMD_LVS, CMD_LVDISPLAY, CMD_LVCREATE, CMD_LVREMOVE,
7071
CMD_LVCHANGE, CMD_LVRENAME, CMD_LVRESIZE,
7172
CMD_LVEXTEND})
73+
DM_COMMANDS = frozenset({CMD_DMSETUP})
7274

73-
LVM_COMMANDS = VG_COMMANDS.union(PV_COMMANDS, LV_COMMANDS)
75+
LVM_COMMANDS = VG_COMMANDS.union(PV_COMMANDS, LV_COMMANDS, DM_COMMANDS)
7476

7577
def extract_vgname(str_in):
7678
"""Search for and return a VG name
@@ -108,6 +110,16 @@ def extract_vgname(str_in):
108110

109111
return None
110112

113+
114+
def get_lvm_lock():
115+
"""
116+
Open and acquire a system wide lock to wrap LVM calls
117+
:return: the created lock
118+
"""
119+
new_lock = lock.Lock('lvm')
120+
new_lock.acquire()
121+
return new_lock
122+
111123
def cmd_lvm(cmd, pread_func=util.pread2, *args):
112124
""" Construct and run the appropriate lvm command.
113125
@@ -150,9 +162,14 @@ def cmd_lvm(cmd, pread_func=util.pread2, *args):
150162
util.SMlog("CMD_LVM: Not all lvm arguments are of type 'str'")
151163
return None
152164

153-
start_time = time.time()
154-
stdout = pread_func([os.path.join(LVM_BIN, lvm_cmd)] + lvm_args, *args)
155-
end_time = time.time()
165+
lvm_lock = get_lvm_lock()
166+
167+
try:
168+
start_time = time.time()
169+
stdout = pread_func([os.path.join(LVM_BIN, lvm_cmd)] + lvm_args, *args)
170+
end_time = time.time()
171+
finally:
172+
lvm_lock.release()
156173

157174
if (end_time - start_time > MAX_OPERATION_DURATION):
158175
util.SMlog("***** Long LVM call of '%s' took %s" % (lvm_cmd, (end_time - start_time)))
@@ -705,7 +722,7 @@ def removeDevMapperEntry(path, strict=True):
705722
try:
706723
# remove devmapper entry using dmsetup
707724
cmd = [CMD_DMSETUP, "remove", path]
708-
util.pread2(cmd)
725+
cmd_lvm(cmd)
709726
return True
710727
except Exception, e:
711728
if not strict:

tests/test_lvutil.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ def decorated(self, context, *args, **kwargs):
2121

2222

2323
class TestCreate(unittest.TestCase):
24+
def setUp(self):
25+
lock_patcher = mock.patch('lvutil.lock', autospec=True)
26+
self.addCleanup(lock_patcher.stop)
27+
self.mock_lock = lock_patcher.start()
28+
2429
@with_lvm_subsystem
2530
def test_create_volume_size(self, lvsystem):
2631
lvsystem.add_volume_group('VG_XenStorage-b3b18d06-b2ba-5b67-f098-3cdd5087a2a7')
@@ -88,6 +93,11 @@ def test_create_percentage_has_precedence_over_size(self, mock_pread):
8893
self.assertIn("10%F", mock_pread.call_args[0][0])
8994

9095
class TestRemove(unittest.TestCase):
96+
def setUp(self):
97+
lock_patcher = mock.patch('lvutil.lock', autospec=True)
98+
self.addCleanup(lock_patcher.stop)
99+
self.mock_lock = lock_patcher.start()
100+
91101
@with_lvm_subsystem
92102
def test_remove_removes_volume(self, lvsystem):
93103
lvsystem.add_volume_group('VG_XenStorage-b3b18d06-b2ba-5b67-f098-3cdd5087a2a7')

0 commit comments

Comments
 (0)