diff --git a/kvm-Drop-bogus-IPv6-messages.patch b/kvm-Drop-bogus-IPv6-messages.patch new file mode 100644 index 0000000..337dee8 --- /dev/null +++ b/kvm-Drop-bogus-IPv6-messages.patch @@ -0,0 +1,51 @@ +From 6ceab004edfb7c1f0f03701bc2ae443941468fd7 Mon Sep 17 00:00:00 2001 +From: Jon Maloy +Date: Mon, 17 Aug 2020 22:06:08 -0400 +Subject: [PATCH 1/6] Drop bogus IPv6 messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Jon Maloy +Message-id: <20200817220608.1142611-2-jmaloy@redhat.com> +Patchwork-id: 98161 +O-Subject: [RHEL-AV-8.3.0 qemu-kvm PATCH 1/1] Drop bogus IPv6 messages +Bugzilla: 1867075 +RH-Acked-by: Danilo de Paula +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau + +From: Ralf Haferkamp + +Drop IPv6 message shorter than what's mentioned in the payload +length header (+ the size of the IPv6 header). They're invalid an could +lead to data leakage in icmp6_send_echoreply(). + +(cherry picked from libslirp commit c7ede54cbd2e2b25385325600958ba0124e31cc0) +Signed-off-by: Jon Maloy +Signed-off-by: Danilo C. L. de Paula +--- + slirp/src/ip6_input.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/slirp/src/ip6_input.c b/slirp/src/ip6_input.c +index a83e4f8e3d..f7ef354ee4 100644 +--- a/slirp/src/ip6_input.c ++++ b/slirp/src/ip6_input.c +@@ -56,6 +56,13 @@ void ip6_input(struct mbuf *m) + goto bad; + } + ++ // Check if the message size is big enough to hold what's ++ // set in the payload length header. If not this is an invalid ++ // packet ++ if (m->m_len < ntohs(ip6->ip_pl) + sizeof(struct ip6)) { ++ goto bad; ++ } ++ + /* check ip_ttl for a correct ICMP reply */ + if (ip6->ip_hl == 0) { + icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); +-- +2.27.0 + diff --git a/kvm-iotests-Test-node-bitmap-aliases-during-migration.patch b/kvm-iotests-Test-node-bitmap-aliases-during-migration.patch new file mode 100644 index 0000000..98c3433 --- /dev/null +++ b/kvm-iotests-Test-node-bitmap-aliases-during-migration.patch @@ -0,0 +1,655 @@ +From 2877fd4f92a86f43a113691f56738b09a0b4d500 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 24 Aug 2020 09:20:38 -0400 +Subject: [PATCH 6/6] iotests: Test node/bitmap aliases during migration + +RH-Author: Max Reitz +Message-id: <20200824092038.227913-4-mreitz@redhat.com> +Patchwork-id: 98214 +O-Subject: [RHEL-AV-8.3.0 qemu-kvm PATCH 3/3] iotests: Test node/bitmap aliases during migration +Bugzilla: 1790492 +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Stefan Hajnoczi + +Signed-off-by: Max Reitz +Message-Id: <20200820150725.68687-4-mreitz@redhat.com> +Reviewed-by: Eric Blake +Tested-by: Eric Blake +[eblake: fold in python cleanups recommended by Vladimir] +Signed-off-by: Eric Blake +(cherry picked from commit cb5c6cd2dc984812f560fbe41f57a6bfc34d8708) +Signed-off-by: Max Reitz +Signed-off-by: Danilo C. L. de Paula +--- + tests/qemu-iotests/300 | 593 +++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/300.out | 5 + + tests/qemu-iotests/group | 1 + + 3 files changed, 599 insertions(+) + create mode 100755 tests/qemu-iotests/300 + create mode 100644 tests/qemu-iotests/300.out + +diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300 +new file mode 100755 +index 0000000000..5b75121b84 +--- /dev/null ++++ b/tests/qemu-iotests/300 +@@ -0,0 +1,593 @@ ++#!/usr/bin/env python3 ++# ++# Copyright (C) 2020 Red Hat, Inc. ++# ++# Tests for dirty bitmaps migration with node aliases ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++import os ++import random ++import re ++from typing import Dict, List, Optional, Union ++import iotests ++import qemu ++ ++BlockBitmapMapping = List[Dict[str, Union[str, List[Dict[str, str]]]]] ++ ++assert iotests.sock_dir is not None ++mig_sock = os.path.join(iotests.sock_dir, 'mig_sock') ++ ++ ++class TestDirtyBitmapMigration(iotests.QMPTestCase): ++ src_node_name: str = '' ++ dst_node_name: str = '' ++ src_bmap_name: str = '' ++ dst_bmap_name: str = '' ++ ++ def setUp(self) -> None: ++ self.vm_a = iotests.VM(path_suffix='-a') ++ self.vm_a.add_blockdev(f'node-name={self.src_node_name},' ++ 'driver=null-co') ++ self.vm_a.launch() ++ ++ self.vm_b = iotests.VM(path_suffix='-b') ++ self.vm_b.add_blockdev(f'node-name={self.dst_node_name},' ++ 'driver=null-co') ++ self.vm_b.add_incoming(f'unix:{mig_sock}') ++ self.vm_b.launch() ++ ++ result = self.vm_a.qmp('block-dirty-bitmap-add', ++ node=self.src_node_name, ++ name=self.src_bmap_name) ++ self.assert_qmp(result, 'return', {}) ++ ++ # Dirty some random megabytes ++ for _ in range(9): ++ mb_ofs = random.randrange(1024) ++ self.vm_a.hmp_qemu_io(self.src_node_name, f'discard {mb_ofs}M 1M') ++ ++ result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256', ++ node=self.src_node_name, ++ name=self.src_bmap_name) ++ self.bitmap_hash_reference = result['return']['sha256'] ++ ++ caps = [{'capability': name, 'state': True} ++ for name in ('dirty-bitmaps', 'events')] ++ ++ for vm in (self.vm_a, self.vm_b): ++ result = vm.qmp('migrate-set-capabilities', capabilities=caps) ++ self.assert_qmp(result, 'return', {}) ++ ++ def tearDown(self) -> None: ++ self.vm_a.shutdown() ++ self.vm_b.shutdown() ++ try: ++ os.remove(mig_sock) ++ except OSError: ++ pass ++ ++ def check_bitmap(self, bitmap_name_valid: bool) -> None: ++ result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', ++ node=self.dst_node_name, ++ name=self.dst_bmap_name) ++ if bitmap_name_valid: ++ self.assert_qmp(result, 'return/sha256', ++ self.bitmap_hash_reference) ++ else: ++ self.assert_qmp(result, 'error/desc', ++ f"Dirty bitmap '{self.dst_bmap_name}' not found") ++ ++ def migrate(self, bitmap_name_valid: bool = True, ++ migration_success: bool = True) -> None: ++ result = self.vm_a.qmp('migrate', uri=f'unix:{mig_sock}') ++ self.assert_qmp(result, 'return', {}) ++ ++ with iotests.Timeout(5, 'Timeout waiting for migration to complete'): ++ self.assertEqual(self.vm_a.wait_migration('postmigrate'), ++ migration_success) ++ self.assertEqual(self.vm_b.wait_migration('running'), ++ migration_success) ++ ++ if migration_success: ++ self.check_bitmap(bitmap_name_valid) ++ ++ def verify_dest_error(self, msg: Optional[str]) -> None: ++ """ ++ Check whether the given error message is present in vm_b's log. ++ (vm_b is shut down to do so.) ++ If @msg is None, check that there has not been any error. ++ """ ++ self.vm_b.shutdown() ++ if msg is None: ++ self.assertNotIn('qemu-system-', self.vm_b.get_log()) ++ else: ++ self.assertIn(msg, self.vm_b.get_log()) ++ ++ @staticmethod ++ def mapping(node_name: str, node_alias: str, ++ bitmap_name: str, bitmap_alias: str) -> BlockBitmapMapping: ++ return [{ ++ 'node-name': node_name, ++ 'alias': node_alias, ++ 'bitmaps': [{ ++ 'name': bitmap_name, ++ 'alias': bitmap_alias ++ }] ++ }] ++ ++ def set_mapping(self, vm: iotests.VM, mapping: BlockBitmapMapping, ++ error: Optional[str] = None) -> None: ++ """ ++ Invoke migrate-set-parameters on @vm to set the given @mapping. ++ Check for success if @error is None, or verify the error message ++ if it is not. ++ On success, verify that "info migrate_parameters" on HMP returns ++ our mapping. (Just to check its formatting code.) ++ """ ++ result = vm.qmp('migrate-set-parameters', ++ block_bitmap_mapping=mapping) ++ ++ if error is None: ++ self.assert_qmp(result, 'return', {}) ++ ++ result = vm.qmp('human-monitor-command', ++ command_line='info migrate_parameters') ++ ++ m = re.search(r'^block-bitmap-mapping:\r?(\n .*)*\n', ++ result['return'], flags=re.MULTILINE) ++ hmp_mapping = m.group(0).replace('\r', '') if m else None ++ ++ self.assertEqual(hmp_mapping, self.to_hmp_mapping(mapping)) ++ else: ++ self.assert_qmp(result, 'error/desc', error) ++ ++ @staticmethod ++ def to_hmp_mapping(mapping: BlockBitmapMapping) -> str: ++ result = 'block-bitmap-mapping:\n' ++ ++ for node in mapping: ++ result += f" '{node['node-name']}' -> '{node['alias']}'\n" ++ ++ assert isinstance(node['bitmaps'], list) ++ for bitmap in node['bitmaps']: ++ result += f" '{bitmap['name']}' -> '{bitmap['alias']}'\n" ++ ++ return result ++ ++ ++class TestAliasMigration(TestDirtyBitmapMigration): ++ src_node_name = 'node0' ++ dst_node_name = 'node0' ++ src_bmap_name = 'bmap0' ++ dst_bmap_name = 'bmap0' ++ ++ def test_migration_without_alias(self) -> None: ++ self.migrate(self.src_node_name == self.dst_node_name and ++ self.src_bmap_name == self.dst_bmap_name) ++ ++ # Check for error message on the destination ++ if self.src_node_name != self.dst_node_name: ++ self.verify_dest_error(f"Cannot find " ++ f"device={self.src_node_name} nor " ++ f"node_name={self.src_node_name}") ++ else: ++ self.verify_dest_error(None) ++ ++ def test_alias_on_src_migration(self) -> None: ++ mapping = self.mapping(self.src_node_name, self.dst_node_name, ++ self.src_bmap_name, self.dst_bmap_name) ++ ++ self.set_mapping(self.vm_a, mapping) ++ self.migrate() ++ self.verify_dest_error(None) ++ ++ def test_alias_on_dst_migration(self) -> None: ++ mapping = self.mapping(self.dst_node_name, self.src_node_name, ++ self.dst_bmap_name, self.src_bmap_name) ++ ++ self.set_mapping(self.vm_b, mapping) ++ self.migrate() ++ self.verify_dest_error(None) ++ ++ def test_alias_on_both_migration(self) -> None: ++ src_map = self.mapping(self.src_node_name, 'node-alias', ++ self.src_bmap_name, 'bmap-alias') ++ ++ dst_map = self.mapping(self.dst_node_name, 'node-alias', ++ self.dst_bmap_name, 'bmap-alias') ++ ++ self.set_mapping(self.vm_a, src_map) ++ self.set_mapping(self.vm_b, dst_map) ++ self.migrate() ++ self.verify_dest_error(None) ++ ++ ++class TestNodeAliasMigration(TestAliasMigration): ++ src_node_name = 'node-src' ++ dst_node_name = 'node-dst' ++ ++ ++class TestBitmapAliasMigration(TestAliasMigration): ++ src_bmap_name = 'bmap-src' ++ dst_bmap_name = 'bmap-dst' ++ ++ ++class TestFullAliasMigration(TestAliasMigration): ++ src_node_name = 'node-src' ++ dst_node_name = 'node-dst' ++ src_bmap_name = 'bmap-src' ++ dst_bmap_name = 'bmap-dst' ++ ++ ++class TestLongBitmapNames(TestAliasMigration): ++ # Giving long bitmap names is OK, as long as there is a short alias for ++ # migration ++ src_bmap_name = 'a' * 512 ++ dst_bmap_name = 'b' * 512 ++ ++ # Skip all tests that do not use the intermediate alias ++ def test_migration_without_alias(self) -> None: ++ pass ++ ++ def test_alias_on_src_migration(self) -> None: ++ pass ++ ++ def test_alias_on_dst_migration(self) -> None: ++ pass ++ ++ ++class TestBlockBitmapMappingErrors(TestDirtyBitmapMigration): ++ src_node_name = 'node0' ++ dst_node_name = 'node0' ++ src_bmap_name = 'bmap0' ++ dst_bmap_name = 'bmap0' ++ ++ """ ++ Note that mapping nodes or bitmaps that do not exist is not an error. ++ """ ++ ++ def test_non_injective_node_mapping(self) -> None: ++ mapping: BlockBitmapMapping = [ ++ { ++ 'node-name': 'node0', ++ 'alias': 'common-alias', ++ 'bitmaps': [{ ++ 'name': 'bmap0', ++ 'alias': 'bmap-alias0' ++ }] ++ }, ++ { ++ 'node-name': 'node1', ++ 'alias': 'common-alias', ++ 'bitmaps': [{ ++ 'name': 'bmap1', ++ 'alias': 'bmap-alias1' ++ }] ++ } ++ ] ++ ++ self.set_mapping(self.vm_a, mapping, ++ "Invalid mapping given for block-bitmap-mapping: " ++ "The node alias 'common-alias' is used twice") ++ ++ def test_non_injective_bitmap_mapping(self) -> None: ++ mapping: BlockBitmapMapping = [{ ++ 'node-name': 'node0', ++ 'alias': 'node-alias0', ++ 'bitmaps': [ ++ { ++ 'name': 'bmap0', ++ 'alias': 'common-alias' ++ }, ++ { ++ 'name': 'bmap1', ++ 'alias': 'common-alias' ++ } ++ ] ++ }] ++ ++ self.set_mapping(self.vm_a, mapping, ++ "Invalid mapping given for block-bitmap-mapping: " ++ "The bitmap alias 'node-alias0'/'common-alias' is " ++ "used twice") ++ ++ def test_ambiguous_node_mapping(self) -> None: ++ mapping: BlockBitmapMapping = [ ++ { ++ 'node-name': 'node0', ++ 'alias': 'node-alias0', ++ 'bitmaps': [{ ++ 'name': 'bmap0', ++ 'alias': 'bmap-alias0' ++ }] ++ }, ++ { ++ 'node-name': 'node0', ++ 'alias': 'node-alias1', ++ 'bitmaps': [{ ++ 'name': 'bmap0', ++ 'alias': 'bmap-alias0' ++ }] ++ } ++ ] ++ ++ self.set_mapping(self.vm_a, mapping, ++ "Invalid mapping given for block-bitmap-mapping: " ++ "The node name 'node0' is mapped twice") ++ ++ def test_ambiguous_bitmap_mapping(self) -> None: ++ mapping: BlockBitmapMapping = [{ ++ 'node-name': 'node0', ++ 'alias': 'node-alias0', ++ 'bitmaps': [ ++ { ++ 'name': 'bmap0', ++ 'alias': 'bmap-alias0' ++ }, ++ { ++ 'name': 'bmap0', ++ 'alias': 'bmap-alias1' ++ } ++ ] ++ }] ++ ++ self.set_mapping(self.vm_a, mapping, ++ "Invalid mapping given for block-bitmap-mapping: " ++ "The bitmap 'node0'/'bmap0' is mapped twice") ++ ++ def test_migratee_node_is_not_mapped_on_src(self) -> None: ++ self.set_mapping(self.vm_a, []) ++ # Should just ignore all bitmaps on unmapped nodes ++ self.migrate(False) ++ self.verify_dest_error(None) ++ ++ def test_migratee_node_is_not_mapped_on_dst(self) -> None: ++ self.set_mapping(self.vm_b, []) ++ self.migrate(False) ++ self.verify_dest_error(f"Unknown node alias '{self.src_node_name}'") ++ ++ def test_migratee_bitmap_is_not_mapped_on_src(self) -> None: ++ mapping: BlockBitmapMapping = [{ ++ 'node-name': self.src_node_name, ++ 'alias': self.dst_node_name, ++ 'bitmaps': [] ++ }] ++ ++ self.set_mapping(self.vm_a, mapping) ++ # Should just ignore all unmapped bitmaps ++ self.migrate(False) ++ self.verify_dest_error(None) ++ ++ def test_migratee_bitmap_is_not_mapped_on_dst(self) -> None: ++ mapping: BlockBitmapMapping = [{ ++ 'node-name': self.dst_node_name, ++ 'alias': self.src_node_name, ++ 'bitmaps': [] ++ }] ++ ++ self.set_mapping(self.vm_b, mapping) ++ self.migrate(False) ++ self.verify_dest_error(f"Unknown bitmap alias " ++ f"'{self.src_bmap_name}' " ++ f"on node '{self.dst_node_name}' " ++ f"(alias '{self.src_node_name}')") ++ ++ def test_unused_mapping_on_dst(self) -> None: ++ # Let the source not send any bitmaps ++ self.set_mapping(self.vm_a, []) ++ ++ # Establish some mapping on the destination ++ self.set_mapping(self.vm_b, []) ++ ++ # The fact that there is a mapping on B without any bitmaps ++ # being received should be fine, not fatal ++ self.migrate(False) ++ self.verify_dest_error(None) ++ ++ def test_non_wellformed_node_alias(self) -> None: ++ alias = '123-foo' ++ ++ mapping: BlockBitmapMapping = [{ ++ 'node-name': self.src_node_name, ++ 'alias': alias, ++ 'bitmaps': [] ++ }] ++ ++ self.set_mapping(self.vm_a, mapping, ++ f"Invalid mapping given for block-bitmap-mapping: " ++ f"The node alias '{alias}' is not well-formed") ++ ++ def test_node_alias_too_long(self) -> None: ++ alias = 'a' * 256 ++ ++ mapping: BlockBitmapMapping = [{ ++ 'node-name': self.src_node_name, ++ 'alias': alias, ++ 'bitmaps': [] ++ }] ++ ++ self.set_mapping(self.vm_a, mapping, ++ f"Invalid mapping given for block-bitmap-mapping: " ++ f"The node alias '{alias}' is longer than 255 bytes") ++ ++ def test_bitmap_alias_too_long(self) -> None: ++ alias = 'a' * 256 ++ ++ mapping = self.mapping(self.src_node_name, self.dst_node_name, ++ self.src_bmap_name, alias) ++ ++ self.set_mapping(self.vm_a, mapping, ++ f"Invalid mapping given for block-bitmap-mapping: " ++ f"The bitmap alias '{alias}' is longer than 255 " ++ f"bytes") ++ ++ def test_bitmap_name_too_long(self) -> None: ++ name = 'a' * 256 ++ ++ result = self.vm_a.qmp('block-dirty-bitmap-add', ++ node=self.src_node_name, ++ name=name) ++ self.assert_qmp(result, 'return', {}) ++ ++ self.migrate(False, False) ++ ++ # Check for the error in the source's log ++ self.vm_a.shutdown() ++ self.assertIn(f"Cannot migrate bitmap '{name}' on node " ++ f"'{self.src_node_name}': Name is longer than 255 bytes", ++ self.vm_a.get_log()) ++ ++ # Expect abnormal shutdown of the destination VM because of ++ # the failed migration ++ try: ++ self.vm_b.shutdown() ++ except qemu.machine.AbnormalShutdown: ++ pass ++ ++ def test_aliased_bitmap_name_too_long(self) -> None: ++ # Longer than the maximum for bitmap names ++ self.dst_bmap_name = 'a' * 1024 ++ ++ mapping = self.mapping(self.dst_node_name, self.src_node_name, ++ self.dst_bmap_name, self.src_bmap_name) ++ ++ # We would have to create this bitmap during migration, and ++ # that would fail, because the name is too long. Better to ++ # catch it early. ++ self.set_mapping(self.vm_b, mapping, ++ f"Invalid mapping given for block-bitmap-mapping: " ++ f"The bitmap name '{self.dst_bmap_name}' is longer " ++ f"than 1023 bytes") ++ ++ def test_node_name_too_long(self) -> None: ++ # Longer than the maximum for node names ++ self.dst_node_name = 'a' * 32 ++ ++ mapping = self.mapping(self.dst_node_name, self.src_node_name, ++ self.dst_bmap_name, self.src_bmap_name) ++ ++ # During migration, this would appear simply as a node that ++ # cannot be found. Still better to catch impossible node ++ # names early (similar to test_non_wellformed_node_alias). ++ self.set_mapping(self.vm_b, mapping, ++ f"Invalid mapping given for block-bitmap-mapping: " ++ f"The node name '{self.dst_node_name}' is longer " ++ f"than 31 bytes") ++ ++ ++class TestCrossAliasMigration(TestDirtyBitmapMigration): ++ """ ++ Swap aliases, both to see that qemu does not get confused, and ++ that we can migrate multiple things at once. ++ ++ So we migrate this: ++ node-a.bmap-a -> node-b.bmap-b ++ node-a.bmap-b -> node-b.bmap-a ++ node-b.bmap-a -> node-a.bmap-b ++ node-b.bmap-b -> node-a.bmap-a ++ """ ++ ++ src_node_name = 'node-a' ++ dst_node_name = 'node-b' ++ src_bmap_name = 'bmap-a' ++ dst_bmap_name = 'bmap-b' ++ ++ def setUp(self) -> None: ++ TestDirtyBitmapMigration.setUp(self) ++ ++ # Now create another block device and let both have two bitmaps each ++ result = self.vm_a.qmp('blockdev-add', ++ node_name='node-b', driver='null-co') ++ self.assert_qmp(result, 'return', {}) ++ ++ result = self.vm_b.qmp('blockdev-add', ++ node_name='node-a', driver='null-co') ++ self.assert_qmp(result, 'return', {}) ++ ++ bmaps_to_add = (('node-a', 'bmap-b'), ++ ('node-b', 'bmap-a'), ++ ('node-b', 'bmap-b')) ++ ++ for (node, bmap) in bmaps_to_add: ++ result = self.vm_a.qmp('block-dirty-bitmap-add', ++ node=node, name=bmap) ++ self.assert_qmp(result, 'return', {}) ++ ++ @staticmethod ++ def cross_mapping() -> BlockBitmapMapping: ++ return [ ++ { ++ 'node-name': 'node-a', ++ 'alias': 'node-b', ++ 'bitmaps': [ ++ { ++ 'name': 'bmap-a', ++ 'alias': 'bmap-b' ++ }, ++ { ++ 'name': 'bmap-b', ++ 'alias': 'bmap-a' ++ } ++ ] ++ }, ++ { ++ 'node-name': 'node-b', ++ 'alias': 'node-a', ++ 'bitmaps': [ ++ { ++ 'name': 'bmap-b', ++ 'alias': 'bmap-a' ++ }, ++ { ++ 'name': 'bmap-a', ++ 'alias': 'bmap-b' ++ } ++ ] ++ } ++ ] ++ ++ def verify_dest_has_all_bitmaps(self) -> None: ++ bitmaps = self.vm_b.query_bitmaps() ++ ++ # Extract and sort bitmap names ++ for node in bitmaps: ++ bitmaps[node] = sorted((bmap['name'] for bmap in bitmaps[node])) ++ ++ self.assertEqual(bitmaps, ++ {'node-a': ['bmap-a', 'bmap-b'], ++ 'node-b': ['bmap-a', 'bmap-b']}) ++ ++ def test_alias_on_src(self) -> None: ++ self.set_mapping(self.vm_a, self.cross_mapping()) ++ ++ # Checks that node-a.bmap-a was migrated to node-b.bmap-b, and ++ # that is enough ++ self.migrate() ++ self.verify_dest_has_all_bitmaps() ++ self.verify_dest_error(None) ++ ++ def test_alias_on_dst(self) -> None: ++ self.set_mapping(self.vm_b, self.cross_mapping()) ++ ++ # Checks that node-a.bmap-a was migrated to node-b.bmap-b, and ++ # that is enough ++ self.migrate() ++ self.verify_dest_has_all_bitmaps() ++ self.verify_dest_error(None) ++ ++ ++if __name__ == '__main__': ++ iotests.main(supported_protocols=['file']) +diff --git a/tests/qemu-iotests/300.out b/tests/qemu-iotests/300.out +new file mode 100644 +index 0000000000..cafb8161f7 +--- /dev/null ++++ b/tests/qemu-iotests/300.out +@@ -0,0 +1,5 @@ ++..................................... ++---------------------------------------------------------------------- ++Ran 37 tests ++ ++OK +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 025ed5238d..b0b55e241c 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -307,5 +307,6 @@ + 296 rw + 297 meta + 299 auto quick ++300 migration + 301 backing quick + 302 quick +-- +2.27.0 + diff --git a/kvm-iotests.py-Let-wait_migration-return-on-failure.patch b/kvm-iotests.py-Let-wait_migration-return-on-failure.patch new file mode 100644 index 0000000..452d080 --- /dev/null +++ b/kvm-iotests.py-Let-wait_migration-return-on-failure.patch @@ -0,0 +1,66 @@ +From 2a597bba9b1e07adb6531628962682a0e53d29b1 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 24 Aug 2020 09:20:37 -0400 +Subject: [PATCH 5/6] iotests.py: Let wait_migration() return on failure + +RH-Author: Max Reitz +Message-id: <20200824092038.227913-3-mreitz@redhat.com> +Patchwork-id: 98213 +O-Subject: [RHEL-AV-8.3.0 qemu-kvm PATCH 2/3] iotests.py: Let wait_migration() return on failure +Bugzilla: 1790492 +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Stefan Hajnoczi + +Let wait_migration() return on failure (with the return value indicating +whether the migration was completed or has failed), so we can use it for +migrations that are expected to fail, too. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20200820150725.68687-3-mreitz@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 4bf63c80357031be4eb8fff8a751f40e73ef1c10) +Signed-off-by: Max Reitz +Signed-off-by: Danilo C. L. de Paula +--- + tests/qemu-iotests/iotests.py | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 717b5b652c..e197c73ca5 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -729,16 +729,22 @@ class VM(qtest.QEMUQtestMachine): + } + ])) + +- def wait_migration(self, expect_runstate): ++ def wait_migration(self, expect_runstate: Optional[str]) -> bool: + while True: + event = self.event_wait('MIGRATION') + log(event, filters=[filter_qmp_event]) +- if event['data']['status'] == 'completed': ++ if event['data']['status'] in ('completed', 'failed'): + break +- # The event may occur in finish-migrate, so wait for the expected +- # post-migration runstate +- while self.qmp('query-status')['return']['status'] != expect_runstate: +- pass ++ ++ if event['data']['status'] == 'completed': ++ # The event may occur in finish-migrate, so wait for the expected ++ # post-migration runstate ++ runstate = None ++ while runstate != expect_runstate: ++ runstate = self.qmp('query-status')['return']['status'] ++ return True ++ else: ++ return False + + def node_info(self, node_name): + nodes = self.qmp('query-named-block-nodes') +-- +2.27.0 + diff --git a/kvm-machine-types-numa-set-numa_mem_supported-on-old-mac.patch b/kvm-machine-types-numa-set-numa_mem_supported-on-old-mac.patch new file mode 100644 index 0000000..7816d07 --- /dev/null +++ b/kvm-machine-types-numa-set-numa_mem_supported-on-old-mac.patch @@ -0,0 +1,77 @@ +From 6d7ba662e980fcc6f3056173043136063e6d68db Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Thu, 20 Aug 2020 15:14:18 -0400 +Subject: [PATCH 2/6] machine types/numa: set numa_mem_supported on old machine + types + +RH-Author: Dr. David Alan Gilbert +Message-id: <20200820151419.14723-2-dgilbert@redhat.com> +Patchwork-id: 98197 +O-Subject: [RHEL-AV 8.3.0 qemu-kvm PATCH 1/2] machine types/numa: set numa_mem_supported on old machine types +Bugzilla: 1849707 +RH-Acked-by: Eduardo Habkost +RH-Acked-by: David Hildenbrand +RH-Acked-by: Igor Mammedov + +From: "Dr. David Alan Gilbert" + +Reenable the -numa mem= syntax for old machine types, this is making +the downstream old machines behave in the same way as the upstream old +machines changed in upstream 32a354dc6c07d7. + +Power already seems to have the change. + +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Danilo C. L. de Paula +--- + hw/arm/virt.c | 2 +- + hw/i386/pc_piix.c | 1 + + hw/i386/pc_q35.c | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index f087483a04..26a7920081 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2755,7 +2755,6 @@ static void rhel_machine_class_init(ObjectClass *oc, void *data) + hc->plug = virt_machine_device_plug_cb; + hc->unplug_request = virt_machine_device_unplug_request_cb; + hc->unplug = virt_machine_device_unplug_cb; +- mc->numa_mem_supported = true; + mc->nvdimm_supported = true; + mc->auto_enable_numa_with_memhp = true; + mc->default_ram_id = "mach-virt.ram"; +@@ -2860,5 +2859,6 @@ static void rhel820_virt_options(MachineClass *mc) + rhel830_virt_options(mc); + compat_props_add(mc->compat_props, hw_compat_rhel_8_2, + hw_compat_rhel_8_2_len); ++ mc->numa_mem_supported = true; + } + DEFINE_RHEL_MACHINE(8, 2, 0) +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index 4af4497a0c..bda2d9ffc8 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -1009,6 +1009,7 @@ static void pc_machine_rhel7_options(MachineClass *m) + pcmc->default_nic_model = "e1000"; + m->default_display = "std"; + m->no_parallel = 1; ++ m->numa_mem_supported = true; + machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); + compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len); + m->alias = "pc"; +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index c709460ab7..d1e3a9b575 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -617,6 +617,7 @@ static void pc_q35_machine_rhel820_options(MachineClass *m) + pc_q35_machine_rhel_options(m); + m->desc = "RHEL-8.2.0 PC (Q35 + ICH9, 2009)"; + m->alias = NULL; ++ m->numa_mem_supported = true; + pcmc->smbios_stream_product = "RHEL-AV"; + pcmc->smbios_stream_version = "8.2.0"; + compat_props_add(m->compat_props, hw_compat_rhel_8_2, +-- +2.27.0 + diff --git a/kvm-machine_types-numa-compatibility-for-auto_enable_num.patch b/kvm-machine_types-numa-compatibility-for-auto_enable_num.patch new file mode 100644 index 0000000..6296a75 --- /dev/null +++ b/kvm-machine_types-numa-compatibility-for-auto_enable_num.patch @@ -0,0 +1,81 @@ +From 25c5644164e3286dc722d59c8d7876b1c49c1385 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Thu, 20 Aug 2020 15:14:19 -0400 +Subject: [PATCH 3/6] machine_types/numa: compatibility for + auto_enable_numa_with_memdev + +RH-Author: Dr. David Alan Gilbert +Message-id: <20200820151419.14723-3-dgilbert@redhat.com> +Patchwork-id: 98196 +O-Subject: [RHEL-AV 8.3.0 qemu-kvm PATCH 2/2] machine_types/numa: compatibility for auto_enable_numa_with_memdev +Bugzilla: 1849707 +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Igor Mammedov +RH-Acked-by: David Hildenbrand + +From: "Dr. David Alan Gilbert" + +The auto_enable_numa_with_memdev flag automatically creates NUMA a +NUMA node in a case like: + + -m 8G,maxmem=16G + +but we need it to keep old machine types the same. +This is (mostly) done for upstream machine types in 195784a0cfad. + +Power seems to have auto_enable_numa permenantly on anyway. + +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Danilo C. L. de Paula +--- + hw/arm/virt.c | 2 ++ + hw/i386/pc_piix.c | 1 + + hw/i386/pc_q35.c | 1 + + 3 files changed, 4 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 26a7920081..26102f22ff 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2757,6 +2757,7 @@ static void rhel_machine_class_init(ObjectClass *oc, void *data) + hc->unplug = virt_machine_device_unplug_cb; + mc->nvdimm_supported = true; + mc->auto_enable_numa_with_memhp = true; ++ mc->auto_enable_numa_with_memdev = true; + mc->default_ram_id = "mach-virt.ram"; + + object_class_property_add(oc, "acpi", "OnOffAuto", +@@ -2860,5 +2861,6 @@ static void rhel820_virt_options(MachineClass *mc) + compat_props_add(mc->compat_props, hw_compat_rhel_8_2, + hw_compat_rhel_8_2_len); + mc->numa_mem_supported = true; ++ mc->auto_enable_numa_with_memdev = false; + } + DEFINE_RHEL_MACHINE(8, 2, 0) +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index bda2d9ffc8..2415c5edd6 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -1010,6 +1010,7 @@ static void pc_machine_rhel7_options(MachineClass *m) + m->default_display = "std"; + m->no_parallel = 1; + m->numa_mem_supported = true; ++ m->auto_enable_numa_with_memdev = false; + machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); + compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len); + m->alias = "pc"; +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index d1e3a9b575..87a0572ec1 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -618,6 +618,7 @@ static void pc_q35_machine_rhel820_options(MachineClass *m) + m->desc = "RHEL-8.2.0 PC (Q35 + ICH9, 2009)"; + m->alias = NULL; + m->numa_mem_supported = true; ++ m->auto_enable_numa_with_memdev = false; + pcmc->smbios_stream_product = "RHEL-AV"; + pcmc->smbios_stream_version = "8.2.0"; + compat_props_add(m->compat_props, hw_compat_rhel_8_2, +-- +2.27.0 + diff --git a/kvm-migration-Add-block-bitmap-mapping-parameter.patch b/kvm-migration-Add-block-bitmap-mapping-parameter.patch new file mode 100644 index 0000000..1944c27 --- /dev/null +++ b/kvm-migration-Add-block-bitmap-mapping-parameter.patch @@ -0,0 +1,947 @@ +From 8ac15801169cb8744b57b939a3c751ea9d381d98 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 24 Aug 2020 09:20:36 -0400 +Subject: [PATCH 4/6] migration: Add block-bitmap-mapping parameter + +RH-Author: Max Reitz +Message-id: <20200824092038.227913-2-mreitz@redhat.com> +Patchwork-id: 98211 +O-Subject: [RHEL-AV-8.3.0 qemu-kvm PATCH 1/3] migration: Add block-bitmap-mapping parameter +Bugzilla: 1790492 +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Stefan Hajnoczi + +This migration parameter allows mapping block node names and bitmap +names to aliases for the purpose of block dirty bitmap migration. + +This way, management tools can use different node and bitmap names on +the source and destination and pass the mapping of how bitmaps are to be +transferred to qemu (on the source, the destination, or even both with +arbitrary aliases in the migration stream). + +While touching this code, fix a bug where bitmap names longer than 255 +bytes would fail an assertion in qemu_put_counted_string(). + +Suggested-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Max Reitz +Message-Id: <20200820150725.68687-2-mreitz@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake +(cherry picked from commit 31e4c354b38cd42a051ad030eb7779d5e7ee32fe) +Signed-off-by: Max Reitz +Signed-off-by: Danilo C. L. de Paula +--- + migration/block-dirty-bitmap.c | 412 ++++++++++++++++++++++++++++----- + migration/migration.c | 30 +++ + migration/migration.h | 3 + + monitor/hmp-cmds.c | 30 +++ + qapi/migration.json | 104 ++++++++- + 5 files changed, 522 insertions(+), 57 deletions(-) + +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 784330ebe1..549e14daba 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -29,10 +29,10 @@ + * + * # Header (shared for different chunk types) + * 1, 2 or 4 bytes: flags (see qemu_{put,put}_flags) +- * [ 1 byte: node name size ] \ flags & DEVICE_NAME +- * [ n bytes: node name ] / +- * [ 1 byte: bitmap name size ] \ flags & BITMAP_NAME +- * [ n bytes: bitmap name ] / ++ * [ 1 byte: node alias size ] \ flags & DEVICE_NAME ++ * [ n bytes: node alias ] / ++ * [ 1 byte: bitmap alias size ] \ flags & BITMAP_NAME ++ * [ n bytes: bitmap alias ] / + * + * # Start of bitmap migration (flags & START) + * header +@@ -72,7 +72,9 @@ + #include "migration/register.h" + #include "qemu/hbitmap.h" + #include "qemu/cutils.h" ++#include "qemu/id.h" + #include "qapi/error.h" ++#include "qapi/qapi-commands-migration.h" + #include "trace.h" + + #define CHUNK_SIZE (1 << 10) +@@ -104,7 +106,8 @@ + typedef struct SaveBitmapState { + /* Written during setup phase. */ + BlockDriverState *bs; +- const char *node_name; ++ char *node_alias; ++ char *bitmap_alias; + BdrvDirtyBitmap *bitmap; + uint64_t total_sectors; + uint64_t sectors_per_chunk; +@@ -138,8 +141,9 @@ typedef struct LoadBitmapState { + /* State of the dirty bitmap migration (DBM) during load process */ + typedef struct DBMLoadState { + uint32_t flags; +- char node_name[256]; +- char bitmap_name[256]; ++ char node_alias[256]; ++ char bitmap_alias[256]; ++ char bitmap_name[BDRV_BITMAP_MAX_NAME_SIZE + 1]; + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + +@@ -165,6 +169,188 @@ typedef struct DBMState { + + static DBMState dbm_state; + ++/* For hash tables that map node/bitmap names to aliases */ ++typedef struct AliasMapInnerNode { ++ char *string; ++ GHashTable *subtree; ++} AliasMapInnerNode; ++ ++static void free_alias_map_inner_node(void *amin_ptr) ++{ ++ AliasMapInnerNode *amin = amin_ptr; ++ ++ g_free(amin->string); ++ g_hash_table_unref(amin->subtree); ++ g_free(amin); ++} ++ ++/** ++ * Construct an alias map based on the given QMP structure. ++ * ++ * (Note that we cannot store such maps in the MigrationParameters ++ * object, because that struct is defined by the QAPI schema, which ++ * makes it basically impossible to have dicts with arbitrary keys. ++ * Therefore, we instead have to construct these maps when migration ++ * starts.) ++ * ++ * @bbm is the block_bitmap_mapping from the migration parameters. ++ * ++ * If @name_to_alias is true, the returned hash table will map node ++ * and bitmap names to their respective aliases (for outgoing ++ * migration). ++ * ++ * If @name_to_alias is false, the returned hash table will map node ++ * and bitmap aliases to their respective names (for incoming ++ * migration). ++ * ++ * The hash table maps node names/aliases to AliasMapInnerNode ++ * objects, whose .string is the respective node alias/name, and whose ++ * .subtree table maps bitmap names/aliases to the respective bitmap ++ * alias/name. ++ */ ++static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm, ++ bool name_to_alias, ++ Error **errp) ++{ ++ GHashTable *alias_map; ++ size_t max_node_name_len = sizeof_field(BlockDriverState, node_name) - 1; ++ ++ alias_map = g_hash_table_new_full(g_str_hash, g_str_equal, ++ g_free, free_alias_map_inner_node); ++ ++ for (; bbm; bbm = bbm->next) { ++ const BitmapMigrationNodeAlias *bmna = bbm->value; ++ const BitmapMigrationBitmapAliasList *bmbal; ++ AliasMapInnerNode *amin; ++ GHashTable *bitmaps_map; ++ const char *node_map_from, *node_map_to; ++ ++ if (!id_wellformed(bmna->alias)) { ++ error_setg(errp, "The node alias '%s' is not well-formed", ++ bmna->alias); ++ goto fail; ++ } ++ ++ if (strlen(bmna->alias) > UINT8_MAX) { ++ error_setg(errp, "The node alias '%s' is longer than %u bytes", ++ bmna->alias, UINT8_MAX); ++ goto fail; ++ } ++ ++ if (strlen(bmna->node_name) > max_node_name_len) { ++ error_setg(errp, "The node name '%s' is longer than %zu bytes", ++ bmna->node_name, max_node_name_len); ++ goto fail; ++ } ++ ++ if (name_to_alias) { ++ if (g_hash_table_contains(alias_map, bmna->node_name)) { ++ error_setg(errp, "The node name '%s' is mapped twice", ++ bmna->node_name); ++ goto fail; ++ } ++ ++ node_map_from = bmna->node_name; ++ node_map_to = bmna->alias; ++ } else { ++ if (g_hash_table_contains(alias_map, bmna->alias)) { ++ error_setg(errp, "The node alias '%s' is used twice", ++ bmna->alias); ++ goto fail; ++ } ++ ++ node_map_from = bmna->alias; ++ node_map_to = bmna->node_name; ++ } ++ ++ bitmaps_map = g_hash_table_new_full(g_str_hash, g_str_equal, ++ g_free, g_free); ++ ++ amin = g_new(AliasMapInnerNode, 1); ++ *amin = (AliasMapInnerNode){ ++ .string = g_strdup(node_map_to), ++ .subtree = bitmaps_map, ++ }; ++ ++ g_hash_table_insert(alias_map, g_strdup(node_map_from), amin); ++ ++ for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) { ++ const BitmapMigrationBitmapAlias *bmba = bmbal->value; ++ const char *bmap_map_from, *bmap_map_to; ++ ++ if (strlen(bmba->alias) > UINT8_MAX) { ++ error_setg(errp, ++ "The bitmap alias '%s' is longer than %u bytes", ++ bmba->alias, UINT8_MAX); ++ goto fail; ++ } ++ ++ if (strlen(bmba->name) > BDRV_BITMAP_MAX_NAME_SIZE) { ++ error_setg(errp, "The bitmap name '%s' is longer than %d bytes", ++ bmba->name, BDRV_BITMAP_MAX_NAME_SIZE); ++ goto fail; ++ } ++ ++ if (name_to_alias) { ++ bmap_map_from = bmba->name; ++ bmap_map_to = bmba->alias; ++ ++ if (g_hash_table_contains(bitmaps_map, bmba->name)) { ++ error_setg(errp, "The bitmap '%s'/'%s' is mapped twice", ++ bmna->node_name, bmba->name); ++ goto fail; ++ } ++ } else { ++ bmap_map_from = bmba->alias; ++ bmap_map_to = bmba->name; ++ ++ if (g_hash_table_contains(bitmaps_map, bmba->alias)) { ++ error_setg(errp, "The bitmap alias '%s'/'%s' is used twice", ++ bmna->alias, bmba->alias); ++ goto fail; ++ } ++ } ++ ++ g_hash_table_insert(bitmaps_map, ++ g_strdup(bmap_map_from), g_strdup(bmap_map_to)); ++ } ++ } ++ ++ return alias_map; ++ ++fail: ++ g_hash_table_destroy(alias_map); ++ return NULL; ++} ++ ++/** ++ * Run construct_alias_map() in both directions to check whether @bbm ++ * is valid. ++ * (This function is to be used by migration/migration.c to validate ++ * the user-specified block-bitmap-mapping migration parameter.) ++ * ++ * Returns true if and only if the mapping is valid. ++ */ ++bool check_dirty_bitmap_mig_alias_map(const BitmapMigrationNodeAliasList *bbm, ++ Error **errp) ++{ ++ GHashTable *alias_map; ++ ++ alias_map = construct_alias_map(bbm, true, errp); ++ if (!alias_map) { ++ return false; ++ } ++ g_hash_table_destroy(alias_map); ++ ++ alias_map = construct_alias_map(bbm, false, errp); ++ if (!alias_map) { ++ return false; ++ } ++ g_hash_table_destroy(alias_map); ++ ++ return true; ++} ++ + static uint32_t qemu_get_bitmap_flags(QEMUFile *f) + { + uint8_t flags = qemu_get_byte(f); +@@ -207,11 +393,11 @@ static void send_bitmap_header(QEMUFile *f, DBMSaveState *s, + qemu_put_bitmap_flags(f, flags); + + if (flags & DIRTY_BITMAP_MIG_FLAG_DEVICE_NAME) { +- qemu_put_counted_string(f, dbms->node_name); ++ qemu_put_counted_string(f, dbms->node_alias); + } + + if (flags & DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME) { +- qemu_put_counted_string(f, bdrv_dirty_bitmap_name(bitmap)); ++ qemu_put_counted_string(f, dbms->bitmap_alias); + } + } + +@@ -282,18 +468,25 @@ static void dirty_bitmap_do_save_cleanup(DBMSaveState *s) + QSIMPLEQ_REMOVE_HEAD(&s->dbms_list, entry); + bdrv_dirty_bitmap_set_busy(dbms->bitmap, false); + bdrv_unref(dbms->bs); ++ g_free(dbms->node_alias); ++ g_free(dbms->bitmap_alias); + g_free(dbms); + } + } + + /* Called with iothread lock taken. */ + static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, +- const char *bs_name) ++ const char *bs_name, GHashTable *alias_map) + { + BdrvDirtyBitmap *bitmap; + SaveBitmapState *dbms; ++ GHashTable *bitmap_aliases; ++ const char *node_alias, *bitmap_name, *bitmap_alias; + Error *local_err = NULL; + ++ /* When an alias map is given, @bs_name must be @bs's node name */ ++ assert(!alias_map || !strcmp(bs_name, bdrv_get_node_name(bs))); ++ + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { + if (bdrv_dirty_bitmap_name(bitmap)) { + break; +@@ -303,21 +496,39 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, + return 0; + } + ++ bitmap_name = bdrv_dirty_bitmap_name(bitmap); ++ + if (!bs_name || strcmp(bs_name, "") == 0) { + error_report("Bitmap '%s' in unnamed node can't be migrated", +- bdrv_dirty_bitmap_name(bitmap)); ++ bitmap_name); + return -1; + } + +- if (bs_name[0] == '#') { ++ if (alias_map) { ++ const AliasMapInnerNode *amin = g_hash_table_lookup(alias_map, bs_name); ++ ++ if (!amin) { ++ /* Skip bitmaps on nodes with no alias */ ++ return 0; ++ } ++ ++ node_alias = amin->string; ++ bitmap_aliases = amin->subtree; ++ } else { ++ node_alias = bs_name; ++ bitmap_aliases = NULL; ++ } ++ ++ if (node_alias[0] == '#') { + error_report("Bitmap '%s' in a node with auto-generated " + "name '%s' can't be migrated", +- bdrv_dirty_bitmap_name(bitmap), bs_name); ++ bitmap_name, node_alias); + return -1; + } + + FOR_EACH_DIRTY_BITMAP(bs, bitmap) { +- if (!bdrv_dirty_bitmap_name(bitmap)) { ++ bitmap_name = bdrv_dirty_bitmap_name(bitmap); ++ if (!bitmap_name) { + continue; + } + +@@ -326,12 +537,29 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, + return -1; + } + ++ if (bitmap_aliases) { ++ bitmap_alias = g_hash_table_lookup(bitmap_aliases, bitmap_name); ++ if (!bitmap_alias) { ++ /* Skip bitmaps with no alias */ ++ continue; ++ } ++ } else { ++ if (strlen(bitmap_name) > UINT8_MAX) { ++ error_report("Cannot migrate bitmap '%s' on node '%s': " ++ "Name is longer than %u bytes", ++ bitmap_name, bs_name, UINT8_MAX); ++ return -1; ++ } ++ bitmap_alias = bitmap_name; ++ } ++ + bdrv_ref(bs); + bdrv_dirty_bitmap_set_busy(bitmap, true); + + dbms = g_new0(SaveBitmapState, 1); + dbms->bs = bs; +- dbms->node_name = bs_name; ++ dbms->node_alias = g_strdup(node_alias); ++ dbms->bitmap_alias = g_strdup(bitmap_alias); + dbms->bitmap = bitmap; + dbms->total_sectors = bdrv_nb_sectors(bs); + dbms->sectors_per_chunk = CHUNK_SIZE * 8 * +@@ -356,43 +584,52 @@ static int init_dirty_bitmap_migration(DBMSaveState *s) + SaveBitmapState *dbms; + GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL); + BlockBackend *blk; ++ const MigrationParameters *mig_params = &migrate_get_current()->parameters; ++ GHashTable *alias_map = NULL; ++ ++ if (mig_params->has_block_bitmap_mapping) { ++ alias_map = construct_alias_map(mig_params->block_bitmap_mapping, true, ++ &error_abort); ++ } + + s->bulk_completed = false; + s->prev_bs = NULL; + s->prev_bitmap = NULL; + s->no_bitmaps = false; + +- /* +- * Use blockdevice name for direct (or filtered) children of named block +- * backends. +- */ +- for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { +- const char *name = blk_name(blk); +- +- if (!name || strcmp(name, "") == 0) { +- continue; +- } ++ if (!alias_map) { ++ /* ++ * Use blockdevice name for direct (or filtered) children of named block ++ * backends. ++ */ ++ for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { ++ const char *name = blk_name(blk); + +- bs = blk_bs(blk); ++ if (!name || strcmp(name, "") == 0) { ++ continue; ++ } + +- /* Skip filters without bitmaps */ +- while (bs && bs->drv && bs->drv->is_filter && +- !bdrv_has_named_bitmaps(bs)) +- { +- if (bs->backing) { +- bs = bs->backing->bs; +- } else if (bs->file) { +- bs = bs->file->bs; +- } else { +- bs = NULL; ++ bs = blk_bs(blk); ++ ++ /* Skip filters without bitmaps */ ++ while (bs && bs->drv && bs->drv->is_filter && ++ !bdrv_has_named_bitmaps(bs)) ++ { ++ if (bs->backing) { ++ bs = bs->backing->bs; ++ } else if (bs->file) { ++ bs = bs->file->bs; ++ } else { ++ bs = NULL; ++ } + } +- } + +- if (bs && bs->drv && !bs->drv->is_filter) { +- if (add_bitmaps_to_list(s, bs, name)) { +- goto fail; ++ if (bs && bs->drv && !bs->drv->is_filter) { ++ if (add_bitmaps_to_list(s, bs, name, NULL)) { ++ goto fail; ++ } ++ g_hash_table_add(handled_by_blk, bs); + } +- g_hash_table_add(handled_by_blk, bs); + } + } + +@@ -401,7 +638,7 @@ static int init_dirty_bitmap_migration(DBMSaveState *s) + continue; + } + +- if (add_bitmaps_to_list(s, bs, bdrv_get_node_name(bs))) { ++ if (add_bitmaps_to_list(s, bs, bdrv_get_node_name(bs), alias_map)) { + goto fail; + } + } +@@ -416,11 +653,17 @@ static int init_dirty_bitmap_migration(DBMSaveState *s) + } + + g_hash_table_destroy(handled_by_blk); ++ if (alias_map) { ++ g_hash_table_destroy(alias_map); ++ } + + return 0; + + fail: + g_hash_table_destroy(handled_by_blk); ++ if (alias_map) { ++ g_hash_table_destroy(alias_map); ++ } + dirty_bitmap_do_save_cleanup(s); + + return -1; +@@ -770,8 +1013,10 @@ static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s) + return 0; + } + +-static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) ++static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s, ++ GHashTable *alias_map) + { ++ GHashTable *bitmap_alias_map = NULL; + Error *local_err = NULL; + bool nothing; + s->flags = qemu_get_bitmap_flags(f); +@@ -780,28 +1025,75 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) + nothing = s->flags == (s->flags & DIRTY_BITMAP_MIG_FLAG_EOS); + + if (s->flags & DIRTY_BITMAP_MIG_FLAG_DEVICE_NAME) { +- if (!qemu_get_counted_string(f, s->node_name)) { +- error_report("Unable to read node name string"); ++ if (!qemu_get_counted_string(f, s->node_alias)) { ++ error_report("Unable to read node alias string"); + return -EINVAL; + } ++ + if (!s->cancelled) { +- s->bs = bdrv_lookup_bs(s->node_name, s->node_name, &local_err); ++ if (alias_map) { ++ const AliasMapInnerNode *amin; ++ ++ amin = g_hash_table_lookup(alias_map, s->node_alias); ++ if (!amin) { ++ error_setg(&local_err, "Error: Unknown node alias '%s'", ++ s->node_alias); ++ s->bs = NULL; ++ } else { ++ bitmap_alias_map = amin->subtree; ++ s->bs = bdrv_lookup_bs(NULL, amin->string, &local_err); ++ } ++ } else { ++ s->bs = bdrv_lookup_bs(s->node_alias, s->node_alias, ++ &local_err); ++ } + if (!s->bs) { + error_report_err(local_err); + cancel_incoming_locked(s); + } + } +- } else if (!s->bs && !nothing && !s->cancelled) { ++ } else if (s->bs) { ++ if (alias_map) { ++ const AliasMapInnerNode *amin; ++ ++ /* Must be present in the map, or s->bs would not be set */ ++ amin = g_hash_table_lookup(alias_map, s->node_alias); ++ assert(amin != NULL); ++ ++ bitmap_alias_map = amin->subtree; ++ } ++ } else if (!nothing && !s->cancelled) { + error_report("Error: block device name is not set"); + cancel_incoming_locked(s); + } + ++ assert(nothing || s->cancelled || !!alias_map == !!bitmap_alias_map); ++ + if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME) { +- if (!qemu_get_counted_string(f, s->bitmap_name)) { +- error_report("Unable to read bitmap name string"); ++ const char *bitmap_name; ++ ++ if (!qemu_get_counted_string(f, s->bitmap_alias)) { ++ error_report("Unable to read bitmap alias string"); + return -EINVAL; + } ++ ++ if (!s->cancelled) { ++ if (bitmap_alias_map) { ++ bitmap_name = g_hash_table_lookup(bitmap_alias_map, ++ s->bitmap_alias); ++ if (!bitmap_name) { ++ error_report("Error: Unknown bitmap alias '%s' on node " ++ "'%s' (alias '%s')", s->bitmap_alias, ++ s->bs->node_name, s->node_alias); ++ cancel_incoming_locked(s); ++ } ++ } else { ++ bitmap_name = s->bitmap_alias; ++ } ++ } ++ + if (!s->cancelled) { ++ g_strlcpy(s->bitmap_name, bitmap_name, sizeof(s->bitmap_name)); + s->bitmap = bdrv_find_dirty_bitmap(s->bs, s->bitmap_name); + + /* +@@ -811,7 +1103,7 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) + if (!s->bitmap && !(s->flags & DIRTY_BITMAP_MIG_FLAG_START)) { + error_report("Error: unknown dirty bitmap " + "'%s' for block device '%s'", +- s->bitmap_name, s->node_name); ++ s->bitmap_name, s->bs->node_name); + cancel_incoming_locked(s); + } + } +@@ -835,6 +1127,8 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s) + */ + static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) + { ++ GHashTable *alias_map = NULL; ++ const MigrationParameters *mig_params = &migrate_get_current()->parameters; + DBMLoadState *s = &((DBMState *)opaque)->load; + int ret = 0; + +@@ -846,13 +1140,18 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) + return -EINVAL; + } + ++ if (mig_params->has_block_bitmap_mapping) { ++ alias_map = construct_alias_map(mig_params->block_bitmap_mapping, ++ false, &error_abort); ++ } ++ + do { + QEMU_LOCK_GUARD(&s->lock); + +- ret = dirty_bitmap_load_header(f, s); ++ ret = dirty_bitmap_load_header(f, s, alias_map); + if (ret < 0) { + cancel_incoming_locked(s); +- return ret; ++ goto fail; + } + + if (s->flags & DIRTY_BITMAP_MIG_FLAG_START) { +@@ -869,12 +1168,17 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) + + if (ret) { + cancel_incoming_locked(s); +- return ret; ++ goto fail; + } + } while (!(s->flags & DIRTY_BITMAP_MIG_FLAG_EOS)); + + trace_dirty_bitmap_load_success(); +- return 0; ++ ret = 0; ++fail: ++ if (alias_map) { ++ g_hash_table_destroy(alias_map); ++ } ++ return ret; + } + + static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque) +diff --git a/migration/migration.c b/migration/migration.c +index bf684185b7..7a89ce39a7 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -36,6 +36,7 @@ + #include "block/block.h" + #include "qapi/error.h" + #include "qapi/clone-visitor.h" ++#include "qapi/qapi-visit-migration.h" + #include "qapi/qapi-visit-sockets.h" + #include "qapi/qapi-commands-migration.h" + #include "qapi/qapi-events-migration.h" +@@ -845,6 +846,13 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) + params->has_announce_step = true; + params->announce_step = s->parameters.announce_step; + ++ if (s->parameters.has_block_bitmap_mapping) { ++ params->has_block_bitmap_mapping = true; ++ params->block_bitmap_mapping = ++ QAPI_CLONE(BitmapMigrationNodeAliasList, ++ s->parameters.block_bitmap_mapping); ++ } ++ + return params; + } + +@@ -1310,6 +1318,13 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) + "is invalid, it must be in the range of 1 to 10000 ms"); + return false; + } ++ ++ if (params->has_block_bitmap_mapping && ++ !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) { ++ error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: "); ++ return false; ++ } ++ + return true; + } + +@@ -1404,6 +1419,11 @@ static void migrate_params_test_apply(MigrateSetParameters *params, + if (params->has_announce_step) { + dest->announce_step = params->announce_step; + } ++ ++ if (params->has_block_bitmap_mapping) { ++ dest->has_block_bitmap_mapping = true; ++ dest->block_bitmap_mapping = params->block_bitmap_mapping; ++ } + } + + static void migrate_params_apply(MigrateSetParameters *params, Error **errp) +@@ -1516,6 +1536,16 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) + if (params->has_announce_step) { + s->parameters.announce_step = params->announce_step; + } ++ ++ if (params->has_block_bitmap_mapping) { ++ qapi_free_BitmapMigrationNodeAliasList( ++ s->parameters.block_bitmap_mapping); ++ ++ s->parameters.has_block_bitmap_mapping = true; ++ s->parameters.block_bitmap_mapping = ++ QAPI_CLONE(BitmapMigrationNodeAliasList, ++ params->block_bitmap_mapping); ++ } + } + + void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) +diff --git a/migration/migration.h b/migration/migration.h +index 721e272713..4be42e8c11 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -337,6 +337,9 @@ void migrate_send_rp_resume_ack(MigrationIncomingState *mis, uint32_t value); + void dirty_bitmap_mig_before_vm_start(void); + void dirty_bitmap_mig_cancel_outgoing(void); + void dirty_bitmap_mig_cancel_incoming(void); ++bool check_dirty_bitmap_mig_alias_map(const BitmapMigrationNodeAliasList *bbm, ++ Error **errp); ++ + void migrate_add_address(SocketAddress *address); + + int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); +diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c +index ae4b6a4246..7711726fd2 100644 +--- a/monitor/hmp-cmds.c ++++ b/monitor/hmp-cmds.c +@@ -469,6 +469,32 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) + monitor_printf(mon, "%s: '%s'\n", + MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ), + params->tls_authz); ++ ++ if (params->has_block_bitmap_mapping) { ++ const BitmapMigrationNodeAliasList *bmnal; ++ ++ monitor_printf(mon, "%s:\n", ++ MigrationParameter_str( ++ MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING)); ++ ++ for (bmnal = params->block_bitmap_mapping; ++ bmnal; ++ bmnal = bmnal->next) ++ { ++ const BitmapMigrationNodeAlias *bmna = bmnal->value; ++ const BitmapMigrationBitmapAliasList *bmbal; ++ ++ monitor_printf(mon, " '%s' -> '%s'\n", ++ bmna->node_name, bmna->alias); ++ ++ for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) { ++ const BitmapMigrationBitmapAlias *bmba = bmbal->value; ++ ++ monitor_printf(mon, " '%s' -> '%s'\n", ++ bmba->name, bmba->alias); ++ } ++ } ++ } + } + + qapi_free_MigrationParameters(params); +@@ -1384,6 +1410,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) + p->has_announce_step = true; + visit_type_size(v, param, &p->announce_step, &err); + break; ++ case MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING: ++ error_setg(&err, "The block-bitmap-mapping parameter can only be set " ++ "through QMP"); ++ break; + default: + assert(0); + } +diff --git a/qapi/migration.json b/qapi/migration.json +index ea53b23dca..5f6b06172c 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -508,6 +508,44 @@ + 'data': [ 'none', 'zlib', + { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } + ++## ++# @BitmapMigrationBitmapAlias: ++# ++# @name: The name of the bitmap. ++# ++# @alias: An alias name for migration (for example the bitmap name on ++# the opposite site). ++# ++# Since: 5.2 ++## ++{ 'struct': 'BitmapMigrationBitmapAlias', ++ 'data': { ++ 'name': 'str', ++ 'alias': 'str' ++ } } ++ ++## ++# @BitmapMigrationNodeAlias: ++# ++# Maps a block node name and the bitmaps it has to aliases for dirty ++# bitmap migration. ++# ++# @node-name: A block node name. ++# ++# @alias: An alias block node name for migration (for example the ++# node name on the opposite site). ++# ++# @bitmaps: Mappings for the bitmaps on this node. ++# ++# Since: 5.2 ++## ++{ 'struct': 'BitmapMigrationNodeAlias', ++ 'data': { ++ 'node-name': 'str', ++ 'alias': 'str', ++ 'bitmaps': [ 'BitmapMigrationBitmapAlias' ] ++ } } ++ + ## + # @MigrationParameter: + # +@@ -642,6 +680,25 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # ++# @block-bitmap-mapping: Maps block nodes and bitmaps on them to ++# aliases for the purpose of dirty bitmap migration. Such ++# aliases may for example be the corresponding names on the ++# opposite site. ++# The mapping must be one-to-one, but not necessarily ++# complete: On the source, unmapped bitmaps and all bitmaps ++# on unmapped nodes will be ignored. On the destination, ++# encountering an unmapped alias in the incoming migration ++# stream will result in a report, and all further bitmap ++# migration data will then be discarded. ++# Note that the destination does not know about bitmaps it ++# does not receive, so there is no limitation or requirement ++# regarding the number of bitmaps received, or how they are ++# named, or on which nodes they are placed. ++# By default (when this parameter has never been set), bitmap ++# names are mapped to themselves. Nodes are mapped to their ++# block device name if there is one, and to their node name ++# otherwise. (Since 5.2) ++# + # Since: 2.4 + ## + { 'enum': 'MigrationParameter', +@@ -656,7 +713,8 @@ + 'multifd-channels', + 'xbzrle-cache-size', 'max-postcopy-bandwidth', + 'max-cpu-throttle', 'multifd-compression', +- 'multifd-zlib-level' ,'multifd-zstd-level' ] } ++ 'multifd-zlib-level' ,'multifd-zstd-level', ++ 'block-bitmap-mapping' ] } + + ## + # @MigrateSetParameters: +@@ -782,6 +840,25 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # ++# @block-bitmap-mapping: Maps block nodes and bitmaps on them to ++# aliases for the purpose of dirty bitmap migration. Such ++# aliases may for example be the corresponding names on the ++# opposite site. ++# The mapping must be one-to-one, but not necessarily ++# complete: On the source, unmapped bitmaps and all bitmaps ++# on unmapped nodes will be ignored. On the destination, ++# encountering an unmapped alias in the incoming migration ++# stream will result in a report, and all further bitmap ++# migration data will then be discarded. ++# Note that the destination does not know about bitmaps it ++# does not receive, so there is no limitation or requirement ++# regarding the number of bitmaps received, or how they are ++# named, or on which nodes they are placed. ++# By default (when this parameter has never been set), bitmap ++# names are mapped to themselves. Nodes are mapped to their ++# block device name if there is one, and to their node name ++# otherwise. (Since 5.2) ++# + # Since: 2.4 + ## + # TODO either fuse back into MigrationParameters, or make +@@ -812,7 +889,8 @@ + '*max-cpu-throttle': 'int', + '*multifd-compression': 'MultiFDCompression', + '*multifd-zlib-level': 'int', +- '*multifd-zstd-level': 'int' } } ++ '*multifd-zstd-level': 'int', ++ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + + ## + # @migrate-set-parameters: +@@ -958,6 +1036,25 @@ + # will consume more CPU. + # Defaults to 1. (Since 5.0) + # ++# @block-bitmap-mapping: Maps block nodes and bitmaps on them to ++# aliases for the purpose of dirty bitmap migration. Such ++# aliases may for example be the corresponding names on the ++# opposite site. ++# The mapping must be one-to-one, but not necessarily ++# complete: On the source, unmapped bitmaps and all bitmaps ++# on unmapped nodes will be ignored. On the destination, ++# encountering an unmapped alias in the incoming migration ++# stream will result in a report, and all further bitmap ++# migration data will then be discarded. ++# Note that the destination does not know about bitmaps it ++# does not receive, so there is no limitation or requirement ++# regarding the number of bitmaps received, or how they are ++# named, or on which nodes they are placed. ++# By default (when this parameter has never been set), bitmap ++# names are mapped to themselves. Nodes are mapped to their ++# block device name if there is one, and to their node name ++# otherwise. (Since 5.2) ++# + # Since: 2.4 + ## + { 'struct': 'MigrationParameters', +@@ -986,7 +1083,8 @@ + '*max-cpu-throttle': 'uint8', + '*multifd-compression': 'MultiFDCompression', + '*multifd-zlib-level': 'uint8', +- '*multifd-zstd-level': 'uint8' } } ++ '*multifd-zstd-level': 'uint8', ++ '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + + ## + # @query-migrate-parameters: +-- +2.27.0 + diff --git a/qemu-kvm.spec b/qemu-kvm.spec index e32e40f..b80c4b7 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -69,7 +69,7 @@ Obsoletes: %1-rhev Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 5.1.0 -Release: 3%{?dist} +Release: 4%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 15 License: GPLv2 and GPLv2+ and CC-BY @@ -146,6 +146,18 @@ Patch38: kvm-redhat-Update-hw_compat_8_2.patch Patch39: kvm-redhat-update-pseries-rhel8.2.0-machine-type.patch # For bz#1801242 - [aarch64] vTPM support in machvirt Patch40: kvm-Disable-TPM-passthrough-backend-on-ARM.patch +# For bz#1867075 - CVE-2020-10756 virt:8.3/qemu-kvm: QEMU: slirp: networking out-of-bounds read information disclosure vulnerability [rhel-av-8] +Patch41: kvm-Drop-bogus-IPv6-messages.patch +# For bz#1849707 - 8.3 machine types for x86 - 5.1 update +Patch42: kvm-machine-types-numa-set-numa_mem_supported-on-old-mac.patch +# For bz#1849707 - 8.3 machine types for x86 - 5.1 update +Patch43: kvm-machine_types-numa-compatibility-for-auto_enable_num.patch +# For bz#1790492 - 'dirty-bitmaps' migration capability should allow configuring target nodenames +Patch44: kvm-migration-Add-block-bitmap-mapping-parameter.patch +# For bz#1790492 - 'dirty-bitmaps' migration capability should allow configuring target nodenames +Patch45: kvm-iotests.py-Let-wait_migration-return-on-failure.patch +# For bz#1790492 - 'dirty-bitmaps' migration capability should allow configuring target nodenames +Patch46: kvm-iotests-Test-node-bitmap-aliases-during-migration.patch BuildRequires: wget BuildRequires: rpm-build @@ -1114,6 +1126,20 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %changelog +* Thu Aug 27 2020 Danilo Cesar Lemes de Paula - 5.1.0-4.el8 +- kvm-Drop-bogus-IPv6-messages.patch [bz#1867075] +- kvm-machine-types-numa-set-numa_mem_supported-on-old-mac.patch [bz#1849707] +- kvm-machine_types-numa-compatibility-for-auto_enable_num.patch [bz#1849707] +- kvm-migration-Add-block-bitmap-mapping-parameter.patch [bz#1790492] +- kvm-iotests.py-Let-wait_migration-return-on-failure.patch [bz#1790492] +- kvm-iotests-Test-node-bitmap-aliases-during-migration.patch [bz#1790492] +- Resolves: bz#1790492 + ('dirty-bitmaps' migration capability should allow configuring target nodenames) +- Resolves: bz#1849707 + (8.3 machine types for x86 - 5.1 update) +- Resolves: bz#1867075 + (CVE-2020-10756 virt:8.3/qemu-kvm: QEMU: slirp: networking out-of-bounds read information disclosure vulnerability [rhel-av-8]) + * Wed Aug 19 2020 Danilo Cesar Lemes de Paula - 5.1.0-3.el8 - kvm-redhat-Update-hw_compat_8_2.patch [bz#1843348] - kvm-redhat-update-pseries-rhel8.2.0-machine-type.patch [bz#1843348]