--- /usr/lib/python2.7/site-packages/nova/virt/disk/api.py.old 2018-05-07 17:29:29.310129011 +0300 +++ /usr/lib/python2.7/site-packages/nova/virt/disk/api.py 2018-05-04 15:51:49.431347099 +0300 @@ -137,14 +137,14 @@ run_as_root=run_as_root) -def get_disk_size(path): +def get_disk_size(path, force_share=False): """Get the (virtual) size of a disk image :param path: Path to the disk image :returns: Size (in bytes) of the given disk image as it would be seen by a virtual machine. """ - return images.qemu_img_info(path).virtual_size + return images.qemu_img_info(path, force_share=force_share).virtual_size def extend(image, size): --- /usr/lib/python2.7/site-packages/nova/virt/images.py.old 2018-05-07 17:30:57.721863823 +0300 +++ /usr/lib/python2.7/site-packages/nova/virt/images.py 2018-05-04 15:52:06.985264486 +0300 @@ -43,7 +43,7 @@ address_space=1 * units.Gi) -def qemu_img_info(path, format=None): +def qemu_img_info(path, format=None, force_share=False): """Return an object containing the parsed output from qemu-img info.""" # TODO(mikal): this code should not be referring to a libvirt specific # flag. @@ -56,6 +56,8 @@ try: cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) + if force_share: + cmd = cmd + ('--force-share',) if format is not None: cmd = cmd + ('-f', format) out, err = utils.execute(*cmd, prlimit=QEMU_IMG_LIMITS) --- /usr/lib/python2.7/site-packages/nova/virt/libvirt/driver.py.old 2018-05-07 17:31:29.771822315 +0300 +++ /usr/lib/python2.7/site-packages/nova/virt/libvirt/driver.py 2018-05-04 15:51:02.773542630 +0300 @@ -403,6 +403,7 @@ # for all architectures/hypervisors, as this value rises to # meet them. MIN_LIBVIRT_VERSION = (0, 10, 2) +MIN_QEMU_VERSION = (2, 1, 0) # TODO(berrange): Re-evaluate this at start of each release cycle # to decide if we want to plan a future min version bump. # MIN_LIBVIRT_VERSION can be updated to match this after @@ -482,6 +483,11 @@ # libvirt 1.3 fix f391889f4e942e22b9ef8ecca492de05106ce41e MIN_LIBVIRT_PF_WITH_NO_VFS_CAP_VERSION = (1, 3, 0) +# qemu >= 2.10.0 +# Use '--force-share' to skip image locking during qemu-img info +# execution as running qemu process owns the write lock. +MIN_QEMU_FORCE_SHARE = (2, 10, 0) + # ppc64/ppc64le architectures with KVM # NOTE(rfolco): Same levels for Libvirt/Qemu on Big Endian and Little # Endian giving the nuance around guest vs host architectures @@ -580,6 +586,9 @@ self._remotefs = remotefs.RemoteFilesystem() self._live_migration_flags = self._block_migration_flags = None + + # Assume pre 2.10 version of qemu is in use + self._force_share = False def _get_volume_drivers(self): return libvirt_volume_drivers @@ -664,6 +673,16 @@ _('Nova requires libvirt version %s or greater.') % self._version_to_string(MIN_LIBVIRT_VERSION)) + if CONF.libvirt.virt_type in ("qemu", "kvm"): + if self._host.has_min_version(hv_ver=MIN_QEMU_VERSION): + self._force_share = ( + self._host.has_min_version(hv_ver=MIN_QEMU_FORCE_SHARE) + ) + else: + raise exception.InternalError( + _('Nova requires QEMU version %s or greater.') % + self._version_to_string(MIN_QEMU_VERSION)) + if (CONF.libvirt.virt_type == 'parallels' and not self._host.has_min_version(MIN_LIBVIRT_PARALLELS_VERSION)): raise exception.NovaException( @@ -1858,14 +1877,23 @@ # in QEMU 1.3. In order to do this, we need to create # a destination image with the original backing file # and matching size of the instance root disk. - src_disk_size = libvirt_utils.get_disk_size(disk_path, - format=source_format) - src_back_path = libvirt_utils.get_disk_backing_file(disk_path, - format=source_format, - basename=False) + src_disk_size = libvirt_utils.get_disk_size( + disk_path, + format=source_format, + force_share=self._force_share + ) + src_back_path = libvirt_utils.get_disk_backing_file( + disk_path, + format=source_format, + basename=False, + force_share=self._force_share + ) disk_delta = out_path + '.delta' - libvirt_utils.create_cow_image(src_back_path, disk_delta, - src_disk_size) + libvirt_utils.create_cow_image( + src_back_path, disk_delta, + src_disk_size, + force_share=self._force_share + ) quiesced = False try: @@ -6996,8 +7024,14 @@ disk_type = driver_nodes[cnt].get('type') if disk_type == "qcow2": - backing_file = libvirt_utils.get_disk_backing_file(path) - virt_size = disk.get_disk_size(path) + backing_file = libvirt_utils.get_disk_backing_file( + path, + force_share=self._force_share + ) + virt_size = disk.get_disk_size( + path, + force_share=self._force_share + ) over_commit_size = int(virt_size) - dk_size else: backing_file = "" --- /usr/lib/python2.7/site-packages/nova/virt/libvirt/utils.py.old 2018-05-07 17:31:55.222746021 +0300 +++ /usr/lib/python2.7/site-packages/nova/virt/libvirt/utils.py 2018-05-04 15:52:35.339131046 +0300 @@ -75,7 +75,7 @@ execute('qemu-img', 'create', '-f', disk_format, path, size) -def create_cow_image(backing_file, path, size=None): +def create_cow_image(backing_file, path, size=None, force_share=False): """Create COW image Creates a COW image with the given backing file @@ -87,7 +87,8 @@ cow_opts = [] if backing_file: cow_opts += ['backing_file=%s' % backing_file] - base_details = images.qemu_img_info(backing_file) + base_details = images.qemu_img_info(backing_file, + force_share=force_share) else: base_details = None # Explicitly inherit the value of 'cluster_size' property of a qcow2 @@ -163,25 +164,27 @@ return None -def get_disk_size(path, format=None): +def get_disk_size(path, format=None, force_share=False): """Get the (virtual) size of a disk image :param path: Path to the disk image :param format: the on-disk format of path + :param force_share: Inhibit write lock during qemu-img info call :returns: Size (in bytes) of the given disk image as it would be seen by a virtual machine. """ - size = images.qemu_img_info(path, format).virtual_size + size = images.qemu_img_info(path, format, force_share).virtual_size return int(size) -def get_disk_backing_file(path, basename=True, format=None): +def get_disk_backing_file(path, basename=True, format=None, force_share=False): """Get the backing file of a disk image :param path: Path to the disk image + :param force_share: Inhibit write lock during qemu-img info cal :returns: a path to the image's backing store """ - backing_file = images.qemu_img_info(path, format).backing_file + backing_file = images.qemu_img_info(path, format, force_share).backing_file if backing_file and basename: backing_file = os.path.basename(backing_file)