[LVM,Generic drivers] Fix relationships between parent and child shares

Reportedly [1], the kernel-nfs-server has a bug where we have overlap of
filesystem identifiers using LVM volumes and their snapshots.

We face this bug in manila LVM driver and Generic driver when we use
cinder LVM driver. So, fix it generating unique UUID for all
snapshots (only for LVM, because we cannot do it in Generic driver
while we do not have "mount-snapshot" feature support there) and
child volumes that will be exported as child shares.

[1] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1071733

Change-Id: Ib93bfb0d4184da1e70ecece6fde6931e44d05a30
Closes-Bug: #1645751
This commit is contained in:
Valeriy Ponomaryov 2016-12-06 14:32:26 +03:00
parent 4936ffceac
commit c93e812a58
6 changed files with 50 additions and 16 deletions

View File

@ -57,6 +57,9 @@ lvcreate: CommandFilter, lvcreate, root
# manila/share/drivers/lvm.py: 'vgs', %s, '--rows', '--units', 'g'
vgs: CommandFilter, vgs, root
# manila/share/drivers/lvm.py: 'tune2fs', '-U', 'random', '%volume-snapshot%'
tune2fs: CommandFilter, tune2fs, root
# manila/share/drivers/glusterfs.py: 'mkdir', '%s'
# manila/share/drivers/ganesha/manager.py: 'mkdir', '-p', '%s'
mkdir: CommandFilter, mkdir, root

View File

@ -335,8 +335,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
'%s' % server_details['instance_id'])
def _mount_device_with_lock():
mount_path = self._get_mount_path(share)
device_path = volume['mountpoint']
log_data = {
'dev': volume['mountpoint'],
'dev': device_path,
'path': mount_path,
'server': server_details['instance_id'],
}
@ -345,11 +346,21 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
volume):
LOG.debug("Mounting '%(dev)s' to path '%(path)s' on "
"server '%(server)s'.", log_data)
mount_cmd = ['sudo', 'mkdir', '-p', mount_path, '&&']
mount_cmd.extend(['sudo', 'mount', volume['mountpoint'],
mount_path])
mount_cmd.extend(['&&', 'sudo', 'chmod', '777',
mount_path])
mount_cmd = (
'sudo', 'mkdir', '-p', mount_path,
'&&', 'sudo', 'mount', device_path, mount_path,
'&&', 'sudo', 'chmod', '777', mount_path,
'&&', 'sudo', 'umount', mount_path,
# NOTE(vponomaryov): 'tune2fs' is required to make
# filesystem of share created from snapshot have
# unique ID, in case of LVM volumes, by default,
# it will have the same UUID as source volume one.
# 'tune2fs' command can be executed only when device
# is not mounted and also, in current case, it takes
# effect only after it was mounted. Closes #1645751
'&&', 'sudo', 'tune2fs', '-U', 'random', device_path,
'&&', 'sudo', 'mount', device_path, mount_path,
)
self._ssh_exec(server_details, mount_cmd)
# Add mount permanently

View File

@ -116,6 +116,10 @@ class LVMMixin(driver.ExecuteMixin):
'lvcreate', '-L', '%sG' % snapshot['share']['size'],
'--name', snapshot['name'],
'--snapshot', orig_lv_name, run_as_root=True)
snapshot_device_name = self._get_local_path(snapshot)
self._execute(
'tune2fs', '-U', 'random', snapshot_device_name, run_as_root=True,
)
def delete_snapshot(self, context, snapshot, share_server=None):
"""Deletes a snapshot."""
@ -215,12 +219,16 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
share_server=None):
"""Is called to create share from snapshot."""
self._allocate_container(share)
device_name = self._get_local_path(snapshot)
self._copy_volume(device_name, self._get_local_path(share),
share['size'])
snapshot_device_name = self._get_local_path(snapshot)
share_device_name = self._get_local_path(share)
self._execute(
'tune2fs', '-U', 'random', share_device_name, run_as_root=True,
)
self._copy_volume(
snapshot_device_name, share_device_name, share['size'])
location = self._get_helper(share).create_export(self.share_server,
share['name'])
self._mount_device(share, device_name)
self._mount_device(share, share_device_name)
return location
def delete_share(self, context, share, share_server=None):

View File

@ -407,10 +407,14 @@ class GenericShareDriverTestCase(test.TestCase):
self._driver._sync_mount_temp_and_perm_files.assert_called_once_with(
server)
self._driver._ssh_exec.assert_called_once_with(
server,
['sudo', 'mkdir', '-p', mount_path,
'&&', 'sudo', 'mount', volume['mountpoint'], mount_path,
'&&', 'sudo', 'chmod', '777', mount_path],
server, (
'sudo', 'mkdir', '-p', mount_path,
'&&', 'sudo', 'mount', volume['mountpoint'], mount_path,
'&&', 'sudo', 'chmod', '777', mount_path,
'&&', 'sudo', 'umount', mount_path,
'&&', 'sudo', 'tune2fs', '-U', 'random', volume['mountpoint'],
'&&', 'sudo', 'mount', volume['mountpoint'], mount_path,
),
)
def test_mount_device_present(self):

View File

@ -200,6 +200,7 @@ class LVMShareDriverTestCase(test.TestCase):
expected_exec = [
'lvcreate -L 1G -n fakename fakevg',
'mkfs.ext4 /dev/mapper/fakevg-fakename',
'tune2fs -U random %s' % mount_share,
("dd count=0 if=%s of=%s iflag=direct oflag=direct" %
(mount_snapshot, mount_share)),
("dd if=%s of=%s count=1024 bs=1M iflag=direct oflag=direct" %
@ -319,8 +320,9 @@ class LVMShareDriverTestCase(test.TestCase):
self._driver.create_snapshot(self._context, self.snapshot,
self.share_server)
expected_exec = [
("lvcreate -L 1G --name fakesnapshotname --snapshot "
"%s/fakename" % (CONF.lvm_share_volume_group,)),
"lvcreate -L 1G --name %s --snapshot %s/fakename" % (
self.snapshot['name'], CONF.lvm_share_volume_group,),
"tune2fs -U random /dev/mapper/fakevg-%s" % self.snapshot['name'],
]
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())

View File

@ -0,0 +1,6 @@
---
fixes:
- Fixed shares created from snapshots on the LVM and Generic drivers to
no longer share the same filesystem handle as the source shares.
The cause was the same as described in Ubuntu launchpad bug
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1071733