From 7711c0112161623c3a09fb02f515537368d3b1b7 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 06 2019 10:05:26 +0000 Subject: import qemu-kvm-ma-2.12.0-33.el7 --- diff --git a/SOURCES/kvm-Introduce-new-no_guest_reset-parameter-for-usb-host-.patch b/SOURCES/kvm-Introduce-new-no_guest_reset-parameter-for-usb-host-.patch new file mode 100644 index 0000000..2c94790 --- /dev/null +++ b/SOURCES/kvm-Introduce-new-no_guest_reset-parameter-for-usb-host-.patch @@ -0,0 +1,140 @@ +From 8db99b422a6de4d19a93429a221e26afa03f32ef Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 3 Jun 2019 13:45:47 +0200 +Subject: [PATCH 4/9] Introduce new "no_guest_reset" parameter for usb-host + device + +RH-Author: Gerd Hoffmann +Message-id: <20190603134550.30153-2-kraxel@redhat.com> +Patchwork-id: 88446 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/4] Introduce new "no_guest_reset" parameter for usb-host device +Bugzilla: 1710861 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Alexander Kappner + +With certain USB devices passed through via usb-host, a guest attempting to +reset a usb-host device can trigger a reset loop that renders the USB device +unusable. In my use case, the device was an iPhone XR that was passed through to +a Mac OS X Mojave guest. Upon connecting the device, the following happens: + +1) Guest recognizes new device, sends reset to emulated USB host +2) QEMU's USB host sends reset to host kernel +3) Host kernel resets device +4) After reset, host kernel determines that some part of the device descriptor +has changed ("device firmware changed" in dmesg), so host kernel decides to +re-enumerate the device. +5) Re-enumeration causes QEMU to disconnect and reconnect the device in the +guest. +6) goto 1) + +Here's from the host kernel (note the "device firmware changed" lines") + +[3677704.473050] usb 1-1.3: new high-speed USB device number 53 using ehci-pci +[3677704.555594] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8, bcdDevice=11.08 +[3677704.555599] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 +[3677704.555602] usb 1-1.3: Product: iPhone +[3677704.555605] usb 1-1.3: Manufacturer: Apple Inc. +[3677704.555607] usb 1-1.3: SerialNumber: [[removed]] +[3677709.401040] usb 1-1.3: reset high-speed USB device number 53 using ehci-pci +[3677709.479486] usb 1-1.3: device firmware changed +[3677709.479842] usb 1-1.3: USB disconnect, device number 53 +[3677709.546039] usb 1-1.3: new high-speed USB device number 54 using ehci-pci +[3677709.627471] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8, bcdDevice=11.08 +[3677709.627476] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 +[3677709.627479] usb 1-1.3: Product: iPhone +[3677709.627481] usb 1-1.3: Manufacturer: Apple Inc. +[3677709.627483] usb 1-1.3: SerialNumber: [[removed]] +[3677762.320044] usb 1-1.3: reset high-speed USB device number 54 using ehci-pci +[3677762.615630] usb 1-1.3: USB disconnect, device number 54 +[3677762.787043] usb 1-1.3: new high-speed USB device number 55 using ehci-pci +[3677762.869016] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8, bcdDevice=11.08 +[3677762.869024] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 +[3677762.869028] usb 1-1.3: Product: iPhone +[3677762.869032] usb 1-1.3: Manufacturer: Apple Inc. +[3677762.869035] usb 1-1.3: SerialNumber: [[removed]] +[3677815.662036] usb 1-1.3: reset high-speed USB device number 55 using ehci-pci + +Here's from QEMU: + +libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/005/022: No such file or directory +libusb: error [udev_hotplug_event] ignoring udev action bind +libusb: error [udev_hotplug_event] ignoring udev action bind +libusb: error [_open_sysfs_attr] open /sys/bus/usb/devices/5-1/bConfigurationValue failed ret=-1 errno=2 +libusb: error [_get_usbfs_fd] File doesn't exist, wait 10 ms and try again + +libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/005/024: No such file or directory +libusb: error [udev_hotplug_event] ignoring udev action bind +libusb: error [udev_hotplug_event] ignoring udev action bind +libusb: error [_open_sysfs_attr] open /sys/bus/usb/devices/5-1/bConfigurationValue failed ret=-1 errno=2 +libusb: error [_get_usbfs_fd] File doesn't exist, wait 10 ms and try again + +libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/005/026: No such file or directory + +The result of this is that the device remains permanently unusable in the guest. +The same problem has been previously reported for an iPad: +https://stackoverflow.com/questions/52617634/how-do-i-get-qemu-usb-passthrough-to-work-for-ipad-iphone + +This problem can be elegantly solved by interrupting step 2) above. Instead of +passing through the reset, QEMU simply ignores it. To allow this to be +configured on a per-device level, a new parameter "no_guest_reset" is +introduced for the usb-host device. I can confirm that the configuration +described above (iPhone XS + Mojave guest) works flawlessly with +no_guest_reset=True specified. + +Working command line for my scenario: +device_add usb-host,vendorid=0x05ac,productid=0x12a8,no_guest_reset=True,id=iphone + +Best regards +Alexander + +Signed-off-by: Alexander Kappner +Signed-off-by: Gerd Hoffmann +Message-id: 20190128140027.9448-1-kraxel@redhat.com + +[ kraxel: rename parameter to "guest-reset" ] + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ba4c735b4fc74e309ce4b2551d258e442ef513a5) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/host-libusb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c +index 0290fb8..0425f0e 100644 +--- a/hw/usb/host-libusb.c ++++ b/hw/usb/host-libusb.c +@@ -82,7 +82,7 @@ struct USBHostDevice { + uint32_t options; + uint32_t loglevel; + bool needs_autoscan; +- ++ bool allow_guest_reset; + /* state */ + QTAILQ_ENTRY(USBHostDevice) next; + int seen, errcount; +@@ -1447,6 +1447,10 @@ static void usb_host_handle_reset(USBDevice *udev) + USBHostDevice *s = USB_HOST_DEVICE(udev); + int rc; + ++ if (!s->allow_guest_reset) { ++ return; ++ } ++ + trace_usb_host_reset(s->bus_num, s->addr); + + rc = libusb_reset_device(s->dh); +@@ -1564,6 +1568,7 @@ static Property usb_host_dev_properties[] = { + DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0), + DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), + DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32), ++ DEFINE_PROP_BOOL("guest-reset", USBHostDevice, allow_guest_reset, true), + DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel, + LIBUSB_LOG_LEVEL_WARNING), + DEFINE_PROP_BIT("pipeline", USBHostDevice, options, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Re-enable-disabled-Hyper-V-enlightenments.patch b/SOURCES/kvm-Re-enable-disabled-Hyper-V-enlightenments.patch new file mode 100644 index 0000000..8bb5959 --- /dev/null +++ b/SOURCES/kvm-Re-enable-disabled-Hyper-V-enlightenments.patch @@ -0,0 +1,48 @@ +From 5967994372c21a8504d7f1b7a61275a647a52c52 Mon Sep 17 00:00:00 2001 +From: Vitaly Kuznetsov +Date: Fri, 12 Oct 2018 07:44:45 +0200 +Subject: [PATCH] Re-enable disabled Hyper-V enlightenments + +RH-Author: Vitaly Kuznetsov +Message-id: <20181012074445.29864-1-vkuznets@redhat.com> +Patchwork-id: 82672 +O-Subject: [RHEL7.7 qemu-kvm-rhev PATCH] Re-enable disabled Hyper-V enlightenments +Bugzilla: 1638835 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: vrozenfe +RH-Acked-by: Miroslav Rezanina + +RHEL-only. + +With the latest Win10 update stimer/synic enlightenments are a must, the +rest is re-enabled for consistency. + +Partially revert 9746c405955 ("Enable/disable devices for RHEL 7"). + +Signed-off-by: Vitaly Kuznetsov +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 91f5a97..8454532 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5366,13 +5366,11 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false), + DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false), + DEFINE_PROP_BOOL("hv-crash", X86CPU, hyperv_crash, false), +-#if 0 /* Disabled for Red Hat Enterprise Linux */ + DEFINE_PROP_BOOL("hv-reset", X86CPU, hyperv_reset, false), + DEFINE_PROP_BOOL("hv-vpindex", X86CPU, hyperv_vpindex, false), + DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false), + DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false), + DEFINE_PROP_BOOL("hv-stimer", X86CPU, hyperv_stimer, false), +-#endif + DEFINE_PROP_BOOL("hv-frequencies", X86CPU, hyperv_frequencies, false), + DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true), + DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Revert-block-dirty-bitmap-Add-bdrv_dirty_iter_next_a.patch b/SOURCES/kvm-Revert-block-dirty-bitmap-Add-bdrv_dirty_iter_next_a.patch new file mode 100644 index 0000000..e4f7296 --- /dev/null +++ b/SOURCES/kvm-Revert-block-dirty-bitmap-Add-bdrv_dirty_iter_next_a.patch @@ -0,0 +1,113 @@ +From 4ff0b9ce2eca5f96d7c99b0d95bafdfae917958f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:33 +0100 +Subject: [PATCH 040/163] Revert "block/dirty-bitmap: Add + bdrv_dirty_iter_next_area" + +RH-Author: John Snow +Message-id: <20190320214838.22027-6-jsnow@redhat.com> +Patchwork-id: 84997 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/10] Revert "block/dirty-bitmap: Add bdrv_dirty_iter_next_area" +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +This reverts commit 72d10a94213a954ad569095cb4491f2ae0853c40. + +The function is unused now. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 166cd551254f4ea6226d7e687b19928747247500) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 55 -------------------------------------------- + include/block/dirty-bitmap.h | 2 -- + 2 files changed, 57 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index c151837..4d9a8af 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -518,61 +518,6 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter) + return hbitmap_iter_next(&iter->hbi, true); + } + +-/** +- * Return the next consecutively dirty area in the dirty bitmap +- * belonging to the given iterator @iter. +- * +- * @max_offset: Maximum value that may be returned for +- * *offset + *bytes +- * @offset: Will contain the start offset of the next dirty area +- * @bytes: Will contain the length of the next dirty area +- * +- * Returns: True if a dirty area could be found before max_offset +- * (which means that *offset and *bytes then contain valid +- * values), false otherwise. +- * +- * Note that @iter is never advanced if false is returned. If an area +- * is found (which means that true is returned), it will be advanced +- * past that area. +- */ +-bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset, +- uint64_t *offset, int *bytes) +-{ +- uint32_t granularity = bdrv_dirty_bitmap_granularity(iter->bitmap); +- uint64_t gran_max_offset; +- int64_t ret; +- int size; +- +- if (max_offset == iter->bitmap->size) { +- /* If max_offset points to the image end, round it up by the +- * bitmap granularity */ +- gran_max_offset = ROUND_UP(max_offset, granularity); +- } else { +- gran_max_offset = max_offset; +- } +- +- ret = hbitmap_iter_next(&iter->hbi, false); +- if (ret < 0 || ret + granularity > gran_max_offset) { +- return false; +- } +- +- *offset = ret; +- size = 0; +- +- assert(granularity <= INT_MAX); +- +- do { +- /* Advance iterator */ +- ret = hbitmap_iter_next(&iter->hbi, true); +- size += granularity; +- } while (ret + granularity <= gran_max_offset && +- hbitmap_iter_next(&iter->hbi, false) == ret + granularity && +- size <= INT_MAX - granularity); +- +- *bytes = MIN(size, max_offset - *offset); +- return true; +-} +- + /* Called within bdrv_dirty_bitmap_lock..unlock */ + void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t offset, int64_t bytes) +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 4ef00ca..04a117f 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -83,8 +83,6 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t offset, int64_t bytes); + int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter); +-bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset, +- uint64_t *offset, int *bytes); + void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset); + int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); + int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Revert-hbitmap-Add-advance-param-to-hbitmap_iter_nex.patch b/SOURCES/kvm-Revert-hbitmap-Add-advance-param-to-hbitmap_iter_nex.patch new file mode 100644 index 0000000..0004c51 --- /dev/null +++ b/SOURCES/kvm-Revert-hbitmap-Add-advance-param-to-hbitmap_iter_nex.patch @@ -0,0 +1,193 @@ +From b404e1ea2e0315a8031fe67005e2921eab23e7a4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:35 +0100 +Subject: [PATCH 042/163] Revert "hbitmap: Add @advance param to + hbitmap_iter_next()" + +RH-Author: John Snow +Message-id: <20190320214838.22027-8-jsnow@redhat.com> +Patchwork-id: 84995 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/10] Revert "hbitmap: Add @advance param to hbitmap_iter_next()" +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +This reverts commit a33fbb4f8b64226becf502a123733776ce319b24. + +The functionality is unused. + +Note: in addition to automatic revert, drop second parameter in +hbitmap_iter_next() call from hbitmap_next_dirty_area() too. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 19c021e1948a81c4ba19b3ff735432b45b6aebee) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/dirty-bitmap.c | 2 +- + include/qemu/hbitmap.h | 5 +---- + tests/test-hbitmap.c | 26 +++++++++++++------------- + util/hbitmap.c | 12 ++++-------- + 5 files changed, 20 insertions(+), 27 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 6a66b1c..90680c4 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -409,7 +409,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) + HBitmapIter hbi; + + hbitmap_iter_init(&hbi, job->copy_bitmap, 0); +- while ((cluster = hbitmap_iter_next(&hbi, true)) != -1) { ++ while ((cluster = hbitmap_iter_next(&hbi)) != -1) { + do { + if (yield_and_check(job)) { + return 0; +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 4d9a8af..00ea36f 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -515,7 +515,7 @@ void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter) + + int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter) + { +- return hbitmap_iter_next(&iter->hbi, true); ++ return hbitmap_iter_next(&iter->hbi); + } + + /* Called within bdrv_dirty_bitmap_lock..unlock */ +diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h +index 097dce3..4afbe62 100644 +--- a/include/qemu/hbitmap.h ++++ b/include/qemu/hbitmap.h +@@ -351,14 +351,11 @@ void hbitmap_free_meta(HBitmap *hb); + /** + * hbitmap_iter_next: + * @hbi: HBitmapIter to operate on. +- * @advance: If true, advance the iterator. Otherwise, the next call +- * of this function will return the same result (if that +- * position is still dirty). + * + * Return the next bit that is set in @hbi's associated HBitmap, + * or -1 if all remaining bits are zero. + */ +-int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance); ++int64_t hbitmap_iter_next(HBitmapIter *hbi); + + /** + * hbitmap_iter_next_word: +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index 6358f35..592d821 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -46,7 +46,7 @@ static void hbitmap_test_check(TestHBitmapData *data, + + i = first; + for (;;) { +- next = hbitmap_iter_next(&hbi, true); ++ next = hbitmap_iter_next(&hbi); + if (next < 0) { + next = data->size; + } +@@ -435,25 +435,25 @@ static void test_hbitmap_iter_granularity(TestHBitmapData *data, + /* Note that hbitmap_test_check has to be invoked manually in this test. */ + hbitmap_test_init(data, 131072 << 7, 7); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_test_set(data, (131072 << 7) - 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + } + + static void hbitmap_test_set_boundary_bits(TestHBitmapData *data, ssize_t diff) +@@ -893,7 +893,7 @@ static void test_hbitmap_serialize_zeroes(TestHBitmapData *data, + for (i = 0; i < num_positions; i++) { + hbitmap_deserialize_zeroes(data->hb, positions[i], min_l1, true); + hbitmap_iter_init(&iter, data->hb, 0); +- next = hbitmap_iter_next(&iter, true); ++ next = hbitmap_iter_next(&iter); + if (i == num_positions - 1) { + g_assert_cmpint(next, ==, -1); + } else { +@@ -919,10 +919,10 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + + hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); + +- hbitmap_iter_next(&hbi, true); ++ hbitmap_iter_next(&hbi); + + hbitmap_reset_all(data->hb); +- hbitmap_iter_next(&hbi, true); ++ hbitmap_iter_next(&hbi); + } + + static void test_hbitmap_next_zero_check_range(TestHBitmapData *data, +diff --git a/util/hbitmap.c b/util/hbitmap.c +index fa35652..7905212 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -144,7 +144,7 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) + return cur; + } + +-int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance) ++int64_t hbitmap_iter_next(HBitmapIter *hbi) + { + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] & + hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos]; +@@ -157,12 +157,8 @@ int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance) + } + } + +- if (advance) { +- /* The next call will resume work from the next bit. */ +- hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); +- } else { +- hbi->cur[HBITMAP_LEVELS - 1] = cur; +- } ++ /* The next call will resume work from the next bit. */ ++ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur); + + return item << hbi->granularity; +@@ -261,7 +257,7 @@ bool hbitmap_next_dirty_area(const HBitmap *hb, uint64_t *start, + end = *count > hb->orig_size - *start ? hb->orig_size : *start + *count; + + hbitmap_iter_init(&hbi, hb, *start); +- firt_dirty_off = hbitmap_iter_next(&hbi, false); ++ firt_dirty_off = hbitmap_iter_next(&hbi); + + if (firt_dirty_off < 0 || firt_dirty_off >= end) { + return false; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Revert-migration-move-only_migratable-to-MigrationSt.patch b/SOURCES/kvm-Revert-migration-move-only_migratable-to-MigrationSt.patch new file mode 100644 index 0000000..f1da546 --- /dev/null +++ b/SOURCES/kvm-Revert-migration-move-only_migratable-to-MigrationSt.patch @@ -0,0 +1,206 @@ +From 99c200d1a05ef50fedcb6b86387af3b60fe54a0e Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:19 +0200 +Subject: [PATCH 52/53] Revert "migration: move only_migratable to + MigrationState" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-31-armbru@redhat.com> +Patchwork-id: 88007 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 30/31] Revert "migration: move only_migratable to MigrationState" +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +This reverts commit 3df663e575f1876d7f3bc684f80e72fca0703d39. +This reverts commit b605c47b57b58e61a901a50a0762dccf43d94783. + +Command line option --only-migratable is for disallowing any +configuration that can block migration. + +Initially, --only-migratable set global variable @only_migratable. + +Commit 3df663e575 "migration: move only_migratable to MigrationState" +replaced it by MigrationState member @only_migratable. That was a +mistake. + +First, it doesn't make sense on the design level. MigrationState +captures the state of an individual migration, but --only-migratable +isn't a property of an individual migration, it's a restriction on +QEMU configuration. With fault tolerance, we could have several +migrations at once. --only-migratable would certainly protect all of +them. Storing it in MigrationState feels inappropriate. + +Second, it contributes to a dependency cycle that manifests itself as +a bug now. + +Putting @only_migratable into MigrationState means its available only +after migration_object_init(). + +We can't set it before migration_object_init(), so we delay setting it +with a global property (this is fixup commit b605c47b57 "migration: +fix handling for --only-migratable"). + +We can't get it before migration_object_init(), so anything that uses +it can only run afterwards. + +Since migrate_add_blocker() needs to obey --only-migratable, any code +adding migration blockers can run only afterwards. This contributes +to the following dependency cycle: + +* configure_blockdev() must run before machine_set_property() + so machine properties can refer to block backends + +* machine_set_property() before configure_accelerator() + so machine properties like kvm-irqchip get applied + +* configure_accelerator() before migration_object_init() + so that Xen's accelerator compat properties get applied. + +* migration_object_init() before configure_blockdev() + so configure_blockdev() can add migration blockers + +The cycle was closed when recent commit cda4aa9a5a0 "Create block +backends before setting machine properties" added the first +dependency, and satisfied it by violating the last one. Broke block +backends that add migration blockers. + +Moving @only_migratable into MigrationState was a mistake. Revert it. + +This doesn't quite break the "migration_object_init() before +configure_blockdev() dependency, since migrate_add_blocker() still has +another dependency on migration_object_init(). To be addressed the +next commit. + +Note that the reverted commit made -only-migratable sugar for -global +migration.only-migratable=on below the hood. Documentation has only +ever mentioned -only-migratable. This commit removes the arcane & +undocumented alternative to -only-migratable again. Nobody should be +using it. + +Signed-off-by: Miroslav Rezanina + +Conflicts: + include/migration/misc.h + migration/migration.c + migration/migration.h + vl.c + +Signed-off-by: Markus Armbruster +Message-Id: <20190401090827.20793-3-armbru@redhat.com> +Reviewed-by: Igor Mammedov +(cherry picked from commit 811f8652712a4ec2ff73c2c5dca35581a25112a4) +[Conflicts in migration/migration.c and vl.c because we lack conflicts +there] +Signed-off-by: Markus Armbruster +--- + include/sysemu/sysemu.h | 1 + + migration/migration.c | 5 ++--- + migration/migration.h | 3 --- + migration/savevm.c | 2 +- + vl.c | 9 ++------- + 5 files changed, 6 insertions(+), 14 deletions(-) + +diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h +index 5d8634b..2a6f4a5 100644 +--- a/include/sysemu/sysemu.h ++++ b/include/sysemu/sysemu.h +@@ -14,6 +14,7 @@ + /* vl.c */ + + extern const char *bios_name; ++extern int only_migratable; + extern const char *qemu_name; + extern QemuUUID qemu_uuid; + extern bool qemu_uuid_set; +diff --git a/migration/migration.c b/migration/migration.c +index edf1c06..83b8d6a 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1330,7 +1330,7 @@ static GSList *migration_blockers; + + int migrate_add_blocker(Error *reason, Error **errp) + { +- if (migrate_get_current()->only_migratable) { ++ if (only_migratable) { + error_propagate(errp, error_copy(reason)); + error_prepend(errp, "disallowing migration blocker " + "(--only_migratable) for: "); +@@ -2498,7 +2498,7 @@ void migration_global_dump(Monitor *mon) + monitor_printf(mon, "store-global-state: %s\n", + ms->store_global_state ? "on" : "off"); + monitor_printf(mon, "only-migratable: %s\n", +- ms->only_migratable ? "on" : "off"); ++ only_migratable ? "on" : "off"); + monitor_printf(mon, "send-configuration: %s\n", + ms->send_configuration ? "on" : "off"); + monitor_printf(mon, "send-section-footer: %s\n", +@@ -2513,7 +2513,6 @@ void migration_global_dump(Monitor *mon) + static Property migration_properties[] = { + DEFINE_PROP_BOOL("store-global-state", MigrationState, + store_global_state, true), +- DEFINE_PROP_BOOL("only-migratable", MigrationState, only_migratable, false), + DEFINE_PROP_BOOL("send-configuration", MigrationState, + send_configuration, true), + DEFINE_PROP_BOOL("send-section-footer", MigrationState, +diff --git a/migration/migration.h b/migration/migration.h +index a9c5c7f..84bdcb7 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -175,9 +175,6 @@ struct MigrationState + */ + bool store_global_state; + +- /* Whether the VM is only allowing for migratable devices */ +- bool only_migratable; +- + /* Whether we send QEMU_VM_CONFIGURATION during migration */ + bool send_configuration; + /* Whether we send section footer during migration */ +diff --git a/migration/savevm.c b/migration/savevm.c +index e5d57fa..6c398d1 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -2530,7 +2530,7 @@ void vmstate_register_ram_global(MemoryRegion *mr) + bool vmstate_check_only_migratable(const VMStateDescription *vmsd) + { + /* check needed if --only-migratable is specified */ +- if (!migrate_get_current()->only_migratable) { ++ if (!only_migratable) { + return true; + } + +diff --git a/vl.c b/vl.c +index 15e87a4..61247eb 100644 +--- a/vl.c ++++ b/vl.c +@@ -192,6 +192,7 @@ bool boot_strict; + uint8_t *boot_splash_filedata; + size_t boot_splash_filedata_size; + uint8_t qemu_extra_params_fw[2]; ++int only_migratable; /* turn it off unless user states otherwise */ + + int icount_align_option; + +@@ -3994,13 +3995,7 @@ int main(int argc, char **argv, char **envp) + incoming = optarg; + break; + case QEMU_OPTION_only_migratable: +- /* +- * TODO: we can remove this option one day, and we +- * should all use: +- * +- * "-global migration.only-migratable=true" +- */ +- qemu_global_option("migration.only-migratable=true"); ++ only_migratable = 1; + break; + case QEMU_OPTION_nodefaults: + has_defaults = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Revert-test-hbitmap-Add-non-advancing-iter_next-test.patch b/SOURCES/kvm-Revert-test-hbitmap-Add-non-advancing-iter_next-test.patch new file mode 100644 index 0000000..28ac38d --- /dev/null +++ b/SOURCES/kvm-Revert-test-hbitmap-Add-non-advancing-iter_next-test.patch @@ -0,0 +1,121 @@ +From 882e1e9983aee5f98b3ad7c65ced43d7cacfd000 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:34 +0100 +Subject: [PATCH 041/163] Revert "test-hbitmap: Add non-advancing iter_next + tests" + +RH-Author: John Snow +Message-id: <20190320214838.22027-7-jsnow@redhat.com> +Patchwork-id: 84999 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/10] Revert "test-hbitmap: Add non-advancing iter_next tests" +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +This reverts commit 269576848ec3d57d2d958cf5ac69b08c44adf816. + +The functionality is unused. Drop tests. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 4294c4ab4825a2ce4d816e52f95a6f08b56aa69c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-hbitmap.c | 36 ++++++++++++------------------------ + 1 file changed, 12 insertions(+), 24 deletions(-) + +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index 4f312e9..6358f35 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -30,18 +30,6 @@ typedef struct TestHBitmapData { + } TestHBitmapData; + + +-static int64_t check_hbitmap_iter_next(HBitmapIter *hbi) +-{ +- int next0, next1; +- +- next0 = hbitmap_iter_next(hbi, false); +- next1 = hbitmap_iter_next(hbi, true); +- +- g_assert_cmpint(next0, ==, next1); +- +- return next0; +-} +- + /* Check that the HBitmap and the shadow bitmap contain the same data, + * ignoring the same "first" bits. + */ +@@ -58,7 +46,7 @@ static void hbitmap_test_check(TestHBitmapData *data, + + i = first; + for (;;) { +- next = check_hbitmap_iter_next(&hbi); ++ next = hbitmap_iter_next(&hbi, true); + if (next < 0) { + next = data->size; + } +@@ -447,25 +435,25 @@ static void test_hbitmap_iter_granularity(TestHBitmapData *data, + /* Note that hbitmap_test_check has to be invoked manually in this test. */ + hbitmap_test_init(data, 131072 << 7, 7); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_test_set(data, (131072 << 7) - 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, 131071 << 7); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, 131071 << 7); +- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + } + + static void hbitmap_test_set_boundary_bits(TestHBitmapData *data, ssize_t diff) +@@ -905,7 +893,7 @@ static void test_hbitmap_serialize_zeroes(TestHBitmapData *data, + for (i = 0; i < num_positions; i++) { + hbitmap_deserialize_zeroes(data->hb, positions[i], min_l1, true); + hbitmap_iter_init(&iter, data->hb, 0); +- next = check_hbitmap_iter_next(&iter); ++ next = hbitmap_iter_next(&iter, true); + if (i == num_positions - 1) { + g_assert_cmpint(next, ==, -1); + } else { +@@ -931,10 +919,10 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + + hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); + +- check_hbitmap_iter_next(&hbi); ++ hbitmap_iter_next(&hbi, true); + + hbitmap_reset_all(data->hb); +- check_hbitmap_iter_next(&hbi); ++ hbitmap_iter_next(&hbi, true); + } + + static void test_hbitmap_next_zero_check_range(TestHBitmapData *data, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Use-inhibit-to-prevent-ballooning-without-synchr.patch b/SOURCES/kvm-Use-inhibit-to-prevent-ballooning-without-synchr.patch new file mode 100644 index 0000000..fbdf1ec --- /dev/null +++ b/SOURCES/kvm-Use-inhibit-to-prevent-ballooning-without-synchr.patch @@ -0,0 +1,80 @@ +From c9168134e8e35b61d2b06a1fc34a672a7e9cec85 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:52:53 +0100 +Subject: [PATCH 19/34] kvm: Use inhibit to prevent ballooning without + synchronous mmu + +RH-Author: Alex Williamson +Message-id: <154387397293.26945.13950211291934514410.stgit@gimli.home> +Patchwork-id: 83228 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/7] kvm: Use inhibit to prevent ballooning without synchronous mmu +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +Remove KVM specific tests in balloon_page(), instead marking +ballooning as inhibited without KVM_CAP_SYNC_MMU support. + +Reviewed-by: David Hildenbrand +Reviewed-by: Peter Xu +Reviewed-by: Cornelia Huck +Acked-by: Paolo Bonzini +Signed-off-by: Alex Williamson +(cherry picked from commit f59489423ab79852e98d9b3025b7d99ba8da584f) +Signed-off-by: Miroslav Rezanina +--- + accel/kvm/kvm-all.c | 4 ++++ + hw/virtio/virtio-balloon.c | 4 +--- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 3f1c06e..3a7c8a3 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -39,6 +39,7 @@ + #include "trace.h" + #include "hw/irq.h" + #include "sysemu/sev.h" ++#include "sysemu/balloon.h" + + #include "hw/boards.h" + +@@ -1711,6 +1712,9 @@ static int kvm_init(MachineState *ms) + s->many_ioeventfds = kvm_check_many_ioeventfds(); + + s->sync_mmu = !!kvm_vm_check_extension(kvm_state, KVM_CAP_SYNC_MMU); ++ if (!s->sync_mmu) { ++ qemu_balloon_inhibit(true); ++ } + + return 0; + +diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c +index f456cea..4aab291 100644 +--- a/hw/virtio/virtio-balloon.c ++++ b/hw/virtio/virtio-balloon.c +@@ -21,7 +21,6 @@ + #include "hw/mem/pc-dimm.h" + #include "sysemu/balloon.h" + #include "hw/virtio/virtio-balloon.h" +-#include "sysemu/kvm.h" + #include "exec/address-spaces.h" + #include "qapi/error.h" + #include "qapi/qapi-events-misc.h" +@@ -36,8 +35,7 @@ + + static void balloon_page(void *addr, int deflate) + { +- if (!qemu_balloon_is_inhibited() && (!kvm_enabled() || +- kvm_has_sync_mmu())) { ++ if (!qemu_balloon_is_inhibited()) { + qemu_madvise(addr, BALLOON_PAGE_SIZE, + deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-balloon-Allow-multiple-inhibit-users.patch b/SOURCES/kvm-balloon-Allow-multiple-inhibit-users.patch new file mode 100644 index 0000000..a56812b --- /dev/null +++ b/SOURCES/kvm-balloon-Allow-multiple-inhibit-users.patch @@ -0,0 +1,72 @@ +From d3e302f2ab9543e1fb52c9d7b6c2167d054a62f5 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:52:37 +0100 +Subject: [PATCH 18/34] balloon: Allow multiple inhibit users + +RH-Author: Alex Williamson +Message-id: <154387395708.26945.11708135028435449926.stgit@gimli.home> +Patchwork-id: 83227 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/7] balloon: Allow multiple inhibit users +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +A simple true/false internal state does not allow multiple users. Fix +this within the existing interface by converting to a counter, so long +as the counter is elevated, ballooning is inhibited. + +Reviewed-by: David Hildenbrand +Reviewed-by: Peter Xu +Reviewed-by: Cornelia Huck +Signed-off-by: Alex Williamson +(cherry picked from commit 01ccbec7bdf6f89f1b7d46dda05e4c1fd2dd5ade) +Signed-off-by: Miroslav Rezanina +--- + balloon.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/balloon.c b/balloon.c +index 6bf0a96..9319879 100644 +--- a/balloon.c ++++ b/balloon.c +@@ -26,6 +26,7 @@ + + #include "qemu/osdep.h" + #include "qemu-common.h" ++#include "qemu/atomic.h" + #include "exec/cpu-common.h" + #include "sysemu/kvm.h" + #include "sysemu/balloon.h" +@@ -37,16 +38,22 @@ + static QEMUBalloonEvent *balloon_event_fn; + static QEMUBalloonStatus *balloon_stat_fn; + static void *balloon_opaque; +-static bool balloon_inhibited; ++static int balloon_inhibit_count; + + bool qemu_balloon_is_inhibited(void) + { +- return balloon_inhibited; ++ return atomic_read(&balloon_inhibit_count) > 0; + } + + void qemu_balloon_inhibit(bool state) + { +- balloon_inhibited = state; ++ if (state) { ++ atomic_inc(&balloon_inhibit_count); ++ } else { ++ atomic_dec(&balloon_inhibit_count); ++ } ++ ++ assert(atomic_read(&balloon_inhibit_count) >= 0); + } + + static bool have_balloon(Error **errp) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-bdrv_query_image_info-Error-parameter-added.patch b/SOURCES/kvm-bdrv_query_image_info-Error-parameter-added.patch new file mode 100644 index 0000000..d10454a --- /dev/null +++ b/SOURCES/kvm-bdrv_query_image_info-Error-parameter-added.patch @@ -0,0 +1,202 @@ +From d48c917f7bcc56fce488c129884abee39dbf0df4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:36 +0100 +Subject: [PATCH 043/163] bdrv_query_image_info Error parameter added + +RH-Author: John Snow +Message-id: <20190320214838.22027-9-jsnow@redhat.com> +Patchwork-id: 85002 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/10] bdrv_query_image_info Error parameter added +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Andrey Shinkevich + +Inform a user in case qcow2_get_specific_info fails to obtain +QCOW2 image specific information. This patch is preliminary to +the one "qcow2: Add list of bitmaps to ImageInfoSpecificQCow2". + +Signed-off-by: Andrey Shinkevich +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Kevin Wolf +Message-Id: <1549638368-530182-2-git-send-email-andrey.shinkevich@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit 1bf6e9ca9234e1dbcaa18baa06eca9d55cc2dbbb) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block.c | 5 +++-- + block/crypto.c | 9 +++------ + block/qapi.c | 7 ++++++- + block/qcow2.c | 10 ++++++++-- + block/vmdk.c | 3 ++- + include/block/block.h | 3 ++- + include/block/block_int.h | 3 ++- + qemu-io-cmds.c | 7 ++++++- + 8 files changed, 32 insertions(+), 15 deletions(-) + +diff --git a/block.c b/block.c +index bcf277d..e3e0e34 100644 +--- a/block.c ++++ b/block.c +@@ -4204,11 +4204,12 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) + return drv->bdrv_get_info(bs, bdi); + } + +-ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs) ++ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, ++ Error **errp) + { + BlockDriver *drv = bs->drv; + if (drv && drv->bdrv_get_specific_info) { +- return drv->bdrv_get_specific_info(bs); ++ return drv->bdrv_get_specific_info(bs, errp); + } + return NULL; + } +diff --git a/block/crypto.c b/block/crypto.c +index 0bb0db6..fd88782 100644 +--- a/block/crypto.c ++++ b/block/crypto.c +@@ -664,20 +664,17 @@ static int block_crypto_get_info_luks(BlockDriverState *bs, + } + + static ImageInfoSpecific * +-block_crypto_get_specific_info_luks(BlockDriverState *bs) ++block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) + { + BlockCrypto *crypto = bs->opaque; + ImageInfoSpecific *spec_info; + QCryptoBlockInfo *info; + +- info = qcrypto_block_get_info(crypto->block, NULL); ++ info = qcrypto_block_get_info(crypto->block, errp); + if (!info) { + return NULL; + } +- if (info->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) { +- qapi_free_QCryptoBlockInfo(info); +- return NULL; +- } ++ assert(info->format == Q_CRYPTO_BLOCK_FORMAT_LUKS); + + spec_info = g_new(ImageInfoSpecific, 1); + spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS; +diff --git a/block/qapi.c b/block/qapi.c +index 339727f..42ce4a3 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -282,7 +282,12 @@ void bdrv_query_image_info(BlockDriverState *bs, + info->dirty_flag = bdi.is_dirty; + info->has_dirty_flag = true; + } +- info->format_specific = bdrv_get_specific_info(bs); ++ info->format_specific = bdrv_get_specific_info(bs, &err); ++ if (err) { ++ error_propagate(errp, err); ++ qapi_free_ImageInfo(info); ++ goto out; ++ } + info->has_format_specific = info->format_specific != NULL; + + backing_filename = bs->backing_file; +diff --git a/block/qcow2.c b/block/qcow2.c +index 114dcdd..de9872f 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -4166,14 +4166,20 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) + return 0; + } + +-static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs) ++static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, ++ Error **errp) + { + BDRVQcow2State *s = bs->opaque; + ImageInfoSpecific *spec_info; + QCryptoBlockInfo *encrypt_info = NULL; ++ Error *local_err = NULL; + + if (s->crypto != NULL) { +- encrypt_info = qcrypto_block_get_info(s->crypto, &error_abort); ++ encrypt_info = qcrypto_block_get_info(s->crypto, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return NULL; ++ } + } + + spec_info = g_new(ImageInfoSpecific, 1); +diff --git a/block/vmdk.c b/block/vmdk.c +index 84f8bbe..f52f291 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -2287,7 +2287,8 @@ static int coroutine_fn vmdk_co_check(BlockDriverState *bs, + return ret; + } + +-static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) ++static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, ++ Error **errp) + { + int i; + BDRVVmdkState *s = bs->opaque; +diff --git a/include/block/block.h b/include/block/block.h +index 36a702c..5f40140 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -472,7 +472,8 @@ const char *bdrv_get_device_name(const BlockDriverState *bs); + const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); + int bdrv_get_flags(BlockDriverState *bs); + int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); +-ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs); ++ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, ++ Error **errp); + void bdrv_round_to_clusters(BlockDriverState *bs, + int64_t offset, int64_t bytes, + int64_t *cluster_offset, +diff --git a/include/block/block_int.h b/include/block/block_int.h +index f457acb..f241bd9 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -321,7 +321,8 @@ struct BlockDriver { + const char *name, + Error **errp); + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); +- ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs); ++ ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, ++ Error **errp); + + int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs, + QEMUIOVector *qiov, +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 5bf5f28..9c51e57 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -1660,6 +1660,7 @@ static int info_f(BlockBackend *blk, int argc, char **argv) + BlockDriverState *bs = blk_bs(blk); + BlockDriverInfo bdi; + ImageInfoSpecific *spec_info; ++ Error *local_err = NULL; + char s1[64], s2[64]; + int ret; + +@@ -1681,7 +1682,11 @@ static int info_f(BlockBackend *blk, int argc, char **argv) + printf("cluster size: %s\n", s1); + printf("vm state offset: %s\n", s2); + +- spec_info = bdrv_get_specific_info(bs); ++ spec_info = bdrv_get_specific_info(bs, &local_err); ++ if (local_err) { ++ error_report_err(local_err); ++ return -EIO; ++ } + if (spec_info) { + printf("Format specific information:\n"); + bdrv_image_info_specific_dump(fprintf, stdout, spec_info); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-bitmap-Update-count-after-a-merge.patch b/SOURCES/kvm-bitmap-Update-count-after-a-merge.patch new file mode 100644 index 0000000..a8f8520 --- /dev/null +++ b/SOURCES/kvm-bitmap-Update-count-after-a-merge.patch @@ -0,0 +1,56 @@ +From 56152f8d7cb931e6172a9e44bec7fe274716a240 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:37 +0100 +Subject: [PATCH 27/33] bitmap: Update count after a merge + +RH-Author: John Snow +Message-id: <20190206221243.7407-18-jsnow@redhat.com> +Patchwork-id: 84282 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 17/23] bitmap: Update count after a merge +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Eric Blake + +We need an accurate count of the number of bits set in a bitmap +after a merge. In particular, since the merge operation short-circuits +a merge from an empty source, if you have bitmaps A, B, and C where +B started empty, then merge C into B, and B into A, an inaccurate +count meant that A did not get the contents of C. + +In the worst case, we may falsely regard the bitmap as empty when +it has had new writes merged into it. + +Fixes: be58721db +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +Signed-off-by: John Snow +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20181002233314.30159-1-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit d1dde7149e376d72b422a529ec4bf3ed47f3ba30) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + util/hbitmap.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/util/hbitmap.c b/util/hbitmap.c +index d5aca51..8d402c5 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -759,6 +759,9 @@ bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) + } + } + ++ /* Recompute the dirty count */ ++ result->count = hb_count_between(result, 0, result->size - 1); ++ + return true; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-bitmaps-Fix-typo-in-function-name.patch b/SOURCES/kvm-bitmaps-Fix-typo-in-function-name.patch new file mode 100644 index 0000000..f44c5d6 --- /dev/null +++ b/SOURCES/kvm-bitmaps-Fix-typo-in-function-name.patch @@ -0,0 +1,155 @@ +From e7e2710ac920bb8c62d0b4bb9b95700a087509b5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:56 +0200 +Subject: [PATCH 151/163] bitmaps: Fix typo in function name + +RH-Author: John Snow +Message-id: <20190403181857.9693-21-jsnow@redhat.com> +Patchwork-id: 85430 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 20/21] bitmaps: Fix typo in function name +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +From: Eric Blake + +Commit a88b179f introduced the ability to set and query bitmap +persistence, but with an atypical spelling. + +Signed-off-by: Eric Blake +Message-id: 20190308205845.25734-1-eblake@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 796a3798ab882ae78a8203acd335ded4e10e3afb) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 4 ++-- + block/qcow2-bitmap.c | 6 +++--- + blockdev.c | 4 ++-- + include/block/dirty-bitmap.h | 4 ++-- + migration/block-dirty-bitmap.c | 4 ++-- + 5 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 2139354..59e6ebb 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -740,7 +740,7 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs) + } + + /* Called with BQL taken. */ +-void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent) ++void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent) + { + qemu_mutex_lock(bitmap->mutex); + bitmap->persistent = persistent; +@@ -765,7 +765,7 @@ void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration) + qemu_mutex_unlock(bitmap->mutex); + } + +-bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap) ++bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap) + { + return bitmap->persistent && !bitmap->migration; + } +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index cbab0e5..4d093da 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -970,7 +970,7 @@ bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp) + goto fail; + } + +- bdrv_dirty_bitmap_set_persistance(bitmap, true); ++ bdrv_dirty_bitmap_set_persistence(bitmap, true); + if (bm->flags & BME_FLAG_IN_USE) { + bdrv_dirty_bitmap_set_inconsistent(bitmap); + } else { +@@ -1428,7 +1428,7 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) + uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap); + Qcow2Bitmap *bm; + +- if (!bdrv_dirty_bitmap_get_persistance(bitmap) || ++ if (!bdrv_dirty_bitmap_get_persistence(bitmap) || + bdrv_dirty_bitmap_readonly(bitmap) || + bdrv_dirty_bitmap_inconsistent(bitmap)) { + continue; +@@ -1546,7 +1546,7 @@ int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp) + for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL; + bitmap = bdrv_dirty_bitmap_next(bs, bitmap)) + { +- if (bdrv_dirty_bitmap_get_persistance(bitmap)) { ++ if (bdrv_dirty_bitmap_get_persistence(bitmap)) { + bdrv_dirty_bitmap_set_readonly(bitmap, true); + } + } +diff --git a/blockdev.c b/blockdev.c +index e497939..61218b4 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3014,7 +3014,7 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + bdrv_disable_dirty_bitmap(bitmap); + } + +- bdrv_dirty_bitmap_set_persistance(bitmap, persistent); ++ bdrv_dirty_bitmap_set_persistence(bitmap, persistent); + out: + if (aio_context) { + aio_context_release(aio_context); +@@ -3039,7 +3039,7 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_get_persistance(bitmap)) { ++ if (bdrv_dirty_bitmap_get_persistence(bitmap)) { + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err); +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 2a78243..8044ace 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -78,7 +78,7 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, + void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); + + void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); +-void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, ++void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, + bool persistent); + void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap); + void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy); +@@ -103,7 +103,7 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes); + bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); + bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); + bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); +-bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); ++bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap); + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); + BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 06ab58d..3beac29 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -321,7 +321,7 @@ static int init_dirty_bitmap_migration(void) + if (bdrv_dirty_bitmap_enabled(bitmap)) { + dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_ENABLED; + } +- if (bdrv_dirty_bitmap_get_persistance(bitmap)) { ++ if (bdrv_dirty_bitmap_get_persistence(bitmap)) { + dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; + } + +@@ -473,7 +473,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DirtyBitmapLoadState *s) + } + + if (flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT) { +- bdrv_dirty_bitmap_set_persistance(s->bitmap, true); ++ bdrv_dirty_bitmap_set_persistence(s->bitmap, true); + } + + bdrv_disable_dirty_bitmap(s->bitmap); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-bloc-qcow2-drop-dirty_bitmaps_loaded-state-variable.patch b/SOURCES/kvm-bloc-qcow2-drop-dirty_bitmaps_loaded-state-variable.patch new file mode 100644 index 0000000..aa4900a --- /dev/null +++ b/SOURCES/kvm-bloc-qcow2-drop-dirty_bitmaps_loaded-state-variable.patch @@ -0,0 +1,84 @@ +From 428b1ae675f8018ef457d095d726bc2e4cc5b5d4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:40 +0100 +Subject: [PATCH 30/33] bloc/qcow2: drop dirty_bitmaps_loaded state variable + +RH-Author: John Snow +Message-id: <20190206221243.7407-21-jsnow@redhat.com> +Patchwork-id: 84279 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 20/23] bloc/qcow2: drop dirty_bitmaps_loaded state variable +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +This variable doesn't work as it should, because it is actually cleared +in qcow2_co_invalidate_cache() by memset(). Drop it, as the following +patch will introduce new behavior. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +Signed-off-by: John Snow +(cherry picked from commit 2ea427effff61efa5d0dc69f9cae126d13879617) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 19 ++----------------- + block/qcow2.h | 1 - + 2 files changed, 2 insertions(+), 18 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 5c5530d..d260cd6 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1149,7 +1149,6 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, + uint64_t ext_end; + uint64_t l1_vm_state_index; + bool update_header = false; +- bool header_updated = false; + + ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); + if (ret < 0) { +@@ -1488,23 +1487,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, + s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; + } + +- if (s->dirty_bitmaps_loaded) { +- /* It's some kind of reopen. There are no known cases where we need to +- * reload bitmaps in such a situation, so it's safer to skip them. +- * +- * Moreover, if we have some readonly bitmaps and we are reopening for +- * rw we should reopen bitmaps correspondingly. +- */ +- if (bdrv_has_readonly_bitmaps(bs) && +- !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) +- { +- qcow2_reopen_bitmaps_rw_hint(bs, &header_updated, &local_err); +- } +- } else { +- header_updated = qcow2_load_dirty_bitmaps(bs, &local_err); +- s->dirty_bitmaps_loaded = true; ++ if (qcow2_load_dirty_bitmaps(bs, &local_err)) { ++ update_header = false; + } +- update_header = update_header && !header_updated; + if (local_err != NULL) { + error_propagate(errp, local_err); + ret = -EINVAL; +diff --git a/block/qcow2.h b/block/qcow2.h +index d2c63e4..43163b2 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -299,7 +299,6 @@ typedef struct BDRVQcow2State { + uint32_t nb_bitmaps; + uint64_t bitmap_directory_size; + uint64_t bitmap_directory_offset; +- bool dirty_bitmaps_loaded; + + int flags; + int qcow_version; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-auto-read-only-option.patch b/SOURCES/kvm-block-Add-auto-read-only-option.patch new file mode 100644 index 0000000..7087ec1 --- /dev/null +++ b/SOURCES/kvm-block-Add-auto-read-only-option.patch @@ -0,0 +1,201 @@ +From c42a88a203211360e20281a8f6bd554f46062178 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:44 +0100 +Subject: [PATCH 03/34] block: Add auto-read-only option + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-3-kwolf@redhat.com> +Patchwork-id: 83111 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 02/12] block: Add auto-read-only option +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +If a management application builds the block graph node by node, the +protocol layer doesn't inherit its read-only option from the format +layer any more, so it must be set explicitly. + +Backing files should work on read-only storage, but at the same time, a +block job like commit should be able to reopen them read-write if they +are on read-write storage. However, without option inheritance, reopen +only changes the read-only option for the root node (typically the +format layer), but not the protocol layer, so reopening fails (the +format layer wants to get write permissions, but the protocol layer is +still read-only). + +A simple workaround for the problem in the management tool would be to +open the protocol layer always read-write and to make only the format +layer read-only for backing files. However, sometimes the file is +actually stored on read-only storage and we don't know whether the image +can be opened read-write (for example, for NBD it depends on the server +we're trying to connect to). This adds an option that makes QEMU try to +open the image read-write, but allows it to degrade to a read-only mode +without returning an error. + +The documentation for this option is consciously phrased in a way that +allows QEMU to switch to a better model eventually: Instead of trying +when the image is first opened, making the read-only flag dynamic and +changing it automatically whenever the first BLK_PERM_WRITE user is +attached or the last one is detached would be much more useful +behaviour. + +Unfortunately, this more useful behaviour is also a lot harder to +implement, and libvirt needs a solution now before it can switch to +-blockdev, so let's start with this easier approach for now. + +Instead of adding a new auto-read-only option, turning the existing +read-only into an enum (with a bool alternate for compatibility) was +considered, but it complicated the implementation to the point that it +didn't seem to be worth it. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit e35bdc123a4ace9f4d3fccaaf88907014e2438cd) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 17 +++++++++++++++++ + block/vvfat.c | 1 + + blockdev.c | 2 +- + include/block/block.h | 2 ++ + qapi/block-core.json | 7 +++++++ + 5 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/block.c b/block.c +index d3ea21a..ff3ea92 100644 +--- a/block.c ++++ b/block.c +@@ -905,6 +905,7 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, + + /* Inherit the read-only option from the parent if it's not set */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); ++ qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY); + + /* Our block drivers take care to send flushes and respect unmap policy, + * so we can default to enable both on lower layers regardless of the +@@ -1028,6 +1029,7 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options, + + /* backing files always opened read-only */ + qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on"); ++ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off"); + flags &= ~BDRV_O_COPY_ON_READ; + + /* snapshot=on is handled on the top layer */ +@@ -1117,6 +1119,10 @@ static void update_flags_from_options(int *flags, QemuOpts *opts) + *flags |= BDRV_O_RDWR; + } + ++ assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY)); ++ if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) { ++ *flags |= BDRV_O_AUTO_RDONLY; ++ } + } + + static void update_options_from_flags(QDict *options, int flags) +@@ -1131,6 +1137,10 @@ static void update_options_from_flags(QDict *options, int flags) + if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) { + qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR)); + } ++ if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) { ++ qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY, ++ flags & BDRV_O_AUTO_RDONLY); ++ } + } + + static void bdrv_assign_node_name(BlockDriverState *bs, +@@ -1304,6 +1314,11 @@ QemuOptsList bdrv_runtime_opts = { + .help = "Node is opened in read-only mode", + }, + { ++ .name = BDRV_OPT_AUTO_READ_ONLY, ++ .type = QEMU_OPT_BOOL, ++ .help = "Node can become read-only if opening read-write fails", ++ }, ++ { + .name = "detect-zeroes", + .type = QEMU_OPT_STRING, + .help = "try to optimize zero writes (off, on, unmap)", +@@ -2490,6 +2505,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) + qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off"); + qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off"); + qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off"); ++ qdict_set_default_str(qdict, BDRV_OPT_AUTO_READ_ONLY, "off"); ++ + } + + bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp); +diff --git a/block/vvfat.c b/block/vvfat.c +index c7d2ed2..3efce9e 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -3130,6 +3130,7 @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) + { + qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off"); ++ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off"); + qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on"); + } + +diff --git a/blockdev.c b/blockdev.c +index 6e8a1e9..3d73f05 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2758,7 +2758,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, + + bdrv_flags = blk_get_open_flags_from_root_state(blk); + bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | +- BDRV_O_PROTOCOL); ++ BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY); + + if (!has_read_only) { + read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN; +diff --git a/include/block/block.h b/include/block/block.h +index 8e78daf..6ee8b2a 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -114,6 +114,7 @@ typedef struct HDGeometry { + select an appropriate protocol driver, + ignoring the format layer */ + #define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */ ++#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read-write fails */ + + #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH) + +@@ -124,6 +125,7 @@ typedef struct HDGeometry { + #define BDRV_OPT_CACHE_DIRECT "cache.direct" + #define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush" + #define BDRV_OPT_READ_ONLY "read-only" ++#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only" + #define BDRV_OPT_DISCARD "discard" + #define BDRV_OPT_FORCE_SHARE "force-share" + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 2706012..9741555 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -3608,6 +3608,12 @@ + # either generally or in certain configurations. In this case, + # the default value does not work and the option must be + # specified explicitly. ++# @auto-read-only: if true and @read-only is false, QEMU may automatically ++# decide not to open the image read-write as requested, but ++# fall back to read-only instead (and switch between the modes ++# later), e.g. depending on whether the image file is writable ++# or whether a writing user is attached to the node ++# (default: false, since 3.1) + # @detect-zeroes: detect and optimize zero writes (Since 2.1) + # (default: off) + # @force-share: force share all permission on added nodes. +@@ -3623,6 +3629,7 @@ + '*discard': 'BlockdevDiscardOptions', + '*cache': 'BlockdevCacheOptions', + '*read-only': 'bool', ++ '*auto-read-only': 'bool', + '*force-share': 'bool', + '*detect-zeroes': 'BlockdevDetectZeroesOptions' }, + 'discriminator': 'driver', +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-bdrv_get_request_alignment.patch b/SOURCES/kvm-block-Add-bdrv_get_request_alignment.patch new file mode 100644 index 0000000..e5dc5fb --- /dev/null +++ b/SOURCES/kvm-block-Add-bdrv_get_request_alignment.patch @@ -0,0 +1,65 @@ +From c4d49803aeb1d6304c2728cb1475f8314ae1f8a8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:22 +0200 +Subject: [PATCH 12/53] block: Add bdrv_get_request_alignment() + +RH-Author: John Snow +Message-id: <20190506175629.11079-13-jsnow@redhat.com> +Patchwork-id: 87195 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/19] block: Add bdrv_get_request_alignment() +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +The next patch needs access to a device's minimum permitted +alignment, since NBD wants to advertise this to clients. Add +an accessor function, borrowing from blk_get_max_transfer() +for accessing a backend's block limits. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190329042750.14704-6-eblake@redhat.com> +(cherry picked from commit 4841211e0d1628cd386b35835676d7f6f9a4fa9d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 7 +++++++ + include/sysemu/block-backend.h | 1 + + 2 files changed, 8 insertions(+) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 52eebeb..f6480f6 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -1834,6 +1834,13 @@ int blk_get_flags(BlockBackend *blk) + } + } + ++/* Returns the minimum request alignment, in bytes; guaranteed nonzero */ ++uint32_t blk_get_request_alignment(BlockBackend *blk) ++{ ++ BlockDriverState *bs = blk_bs(blk); ++ return bs ? bs->bl.request_alignment : BDRV_SECTOR_SIZE; ++} ++ + /* Returns the maximum transfer length, in bytes; guaranteed nonzero */ + uint32_t blk_get_max_transfer(BlockBackend *blk) + { +diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h +index 6b6d882..815b6e5 100644 +--- a/include/sysemu/block-backend.h ++++ b/include/sysemu/block-backend.h +@@ -178,6 +178,7 @@ bool blk_is_available(BlockBackend *blk); + void blk_lock_medium(BlockBackend *blk, bool locked); + void blk_eject(BlockBackend *blk, bool eject_flag); + int blk_get_flags(BlockBackend *blk); ++uint32_t blk_get_request_alignment(BlockBackend *blk); + uint32_t blk_get_max_transfer(BlockBackend *blk); + int blk_get_max_iov(BlockBackend *blk); + void blk_set_guest_block_size(BlockBackend *blk, int align); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Always-abort-reopen-after-prepare-succeeded.patch b/SOURCES/kvm-block-Always-abort-reopen-after-prepare-succeeded.patch new file mode 100644 index 0000000..7c107ef --- /dev/null +++ b/SOURCES/kvm-block-Always-abort-reopen-after-prepare-succeeded.patch @@ -0,0 +1,84 @@ +From 168f27ca545f530ac694ed596bdafc8fa3c26860 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:00 +0100 +Subject: [PATCH 004/163] block: Always abort reopen after prepare succeeded + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-5-kwolf@redhat.com> +Patchwork-id: 84881 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/14] block: Always abort reopen after prepare succeeded +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +bdrv_reopen_multiple() does not invoke bdrv_reopen_abort() for the +element of the reopen queue for which bdrv_reopen_prepare() failed, +because it assumes that the prepare function will have rolled back all +changes already. + +However, bdrv_reopen_prepare() does not do this in every case: It may +notice an error after BlockDriver.bdrv_reopen_prepare() succeeded, and +it will not invoke BlockDriver.bdrv_reopen_abort() then; and neither +will bdrv_reopen_multiple(), as explained above. + +This is wrong because we must always call .bdrv_reopen_commit() or +.bdrv_reopen_abort() after .bdrv_reopen_prepare() has succeeded. +Otherwise, the block driver has no chance to undo what it has done in +its implementation of .bdrv_reopen_prepare(). + +To fix this, bdrv_reopen_prepare() has to call .bdrv_reopen_abort() if +it wants to return an error after .bdrv_reopen_prepare() has succeeded. + +Signed-off-by: Max Reitz +Reviewed-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 9ad08c44566bf4466c6263c71d43e9f7a354d4ba) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/block.c b/block.c +index c3148cc..2f1b4d1 100644 +--- a/block.c ++++ b/block.c +@@ -3191,6 +3191,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, + QemuOpts *opts; + const char *value; + bool read_only; ++ bool drv_prepared = false; + + assert(reopen_state != NULL); + assert(reopen_state->bs->drv != NULL); +@@ -3260,6 +3261,8 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, + goto error; + } + ++ drv_prepared = true; ++ + /* Options that are not handled are only okay if they are unchanged + * compared to the old state. It is expected that some options are only + * used for the initial open, but not reopen (e.g. filename) */ +@@ -3303,6 +3306,15 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, + ret = 0; + + error: ++ if (ret < 0 && drv_prepared) { ++ /* drv->bdrv_reopen_prepare() has succeeded, so we need to ++ * call drv->bdrv_reopen_abort() before signaling an error ++ * (bdrv_reopen_multiple() will not call bdrv_reopen_abort() ++ * when the respective bdrv_reopen_prepare() has failed) */ ++ if (drv->bdrv_reopen_abort) { ++ drv->bdrv_reopen_abort(reopen_state); ++ } ++ } + qemu_opts_del(opts); + return ret; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Apply-auto-read-only-for-ro-whitelist-drivers.patch b/SOURCES/kvm-block-Apply-auto-read-only-for-ro-whitelist-drivers.patch new file mode 100644 index 0000000..9534937 --- /dev/null +++ b/SOURCES/kvm-block-Apply-auto-read-only-for-ro-whitelist-drivers.patch @@ -0,0 +1,66 @@ +From c13468845efde058e464deeaf8b58508f33dc948 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 16:29:56 +0100 +Subject: [PATCH 09/23] block: Apply auto-read-only for ro-whitelist drivers + +RH-Author: Kevin Wolf +Message-id: <20190219162956.16183-2-kwolf@redhat.com> +Patchwork-id: 84539 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] block: Apply auto-read-only for ro-whitelist drivers +Bugzilla: 1667320 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +If QEMU was configured with a driver in --block-drv-ro-whitelist, trying +to use that driver read-write resulted in an error message even if +auto-read-only=on was set. + +Consider auto-read-only=on for the whitelist checking and use it to +automatically degrade to read-only for block drivers on the read-only +whitelist. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 8be25de64315ef768353eb61f2b2bf6cddc34230) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/block.c b/block.c +index 82b16df..a69d0a2 100644 +--- a/block.c ++++ b/block.c +@@ -1418,13 +1418,19 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, + bs->read_only = !(bs->open_flags & BDRV_O_RDWR); + + if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) { +- error_setg(errp, +- !bs->read_only && bdrv_is_whitelisted(drv, true) +- ? "Driver '%s' can only be used for read-only devices" +- : "Driver '%s' is not whitelisted", +- drv->format_name); +- ret = -ENOTSUP; +- goto fail_opts; ++ if (!bs->read_only && bdrv_is_whitelisted(drv, true)) { ++ ret = bdrv_apply_auto_read_only(bs, NULL, NULL); ++ } else { ++ ret = -ENOTSUP; ++ } ++ if (ret < 0) { ++ error_setg(errp, ++ !bs->read_only && bdrv_is_whitelisted(drv, true) ++ ? "Driver '%s' can only be used for read-only devices" ++ : "Driver '%s' is not whitelisted", ++ drv->format_name); ++ goto fail_opts; ++ } + } + + /* bdrv_new() and bdrv_close() make it so */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Avoid-useless-local_err.patch b/SOURCES/kvm-block-Avoid-useless-local_err.patch new file mode 100644 index 0000000..a772e0c --- /dev/null +++ b/SOURCES/kvm-block-Avoid-useless-local_err.patch @@ -0,0 +1,47 @@ +From 6e21eb2623d4103257fc9d849a639eb70ae20920 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:09:58 +0100 +Subject: [PATCH 002/163] block: Avoid useless local_err + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-3-kwolf@redhat.com> +Patchwork-id: 84879 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/14] block: Avoid useless local_err +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Kevin Wolf +Reviewed-by: Alberto Garcia +Reviewed-by: Eric Blake +(cherry picked from commit a4615ab31cade201641cbb17a81dcac1b3bea624) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/block.c b/block.c +index c47e5b0..ccf9acb 100644 +--- a/block.c ++++ b/block.c +@@ -3061,14 +3061,12 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er + { + int ret = -1; + BlockReopenQueueEntry *bs_entry, *next; +- Error *local_err = NULL; + + assert(bs_queue != NULL); + + QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) { + assert(bs_entry->state.bs->quiesce_counter > 0); +- if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) { +- error_propagate(errp, local_err); ++ if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) { + goto cleanup; + } + bs_entry->prepared = true; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Don-t-inactivate-children-before-parents.patch b/SOURCES/kvm-block-Don-t-inactivate-children-before-parents.patch new file mode 100644 index 0000000..61895e7 --- /dev/null +++ b/SOURCES/kvm-block-Don-t-inactivate-children-before-parents.patch @@ -0,0 +1,182 @@ +From 747fd28a2c5947940c5f17426ba7a91738f1481c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 28 Nov 2018 09:29:46 +0100 +Subject: [PATCH 15/34] block: Don't inactivate children before parents + +RH-Author: Kevin Wolf +Message-id: <20181128092947.24543-2-kwolf@redhat.com> +Patchwork-id: 83179 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH 1/2] block: Don't inactivate children before parents +Bugzilla: 1633536 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laurent Vivier + +bdrv_child_cb_inactivate() asserts that parents are already inactive +when children get inactivated. This precondition is necessary because +parents could still issue requests in their inactivation code. + +When block nodes are created individually with -blockdev, all of them +are monitor owned and will be returned by bdrv_next() in an undefined +order (in practice, in the order of their creation, which is usually +children before parents), which obviously fails the assertion: + +qemu: block.c:899: bdrv_child_cb_inactivate: Assertion `bs->open_flags & BDRV_O_INACTIVE' failed. + +This patch fixes the ordering by skipping nodes with still active +parents in bdrv_inactivate_recurse() because we know that they will be +covered by recursion when the last active parent becomes inactive. + +With the correct parents-before-children ordering, we also got rid of +the reason why commit aad0b7a0bfb introduced two passes, so we can go +back to a single-pass recursion. This is necessary so we can rely on the +BDRV_O_INACTIVE flag to skip nodes with active parents (the flag used +to be set only in pass 2, so we would always skip non-root nodes in +pass 1 because all parents would still be considered active; setting the +flag in pass 1 would mean, that we never skip anything in pass 2 because +all parents are already considered inactive). + +Because of the change to single pass, this patch is best reviewed with +whitespace changes ignored. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 9e37271f50ec2e95f299dc297ac08f9be0096b48) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 84 +++++++++++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 53 insertions(+), 31 deletions(-) + +diff --git a/block.c b/block.c +index 037d2b0..da9b1a6 100644 +--- a/block.c ++++ b/block.c +@@ -4469,45 +4469,68 @@ void bdrv_invalidate_cache_all(Error **errp) + } + } + +-static int bdrv_inactivate_recurse(BlockDriverState *bs, +- bool setting_flag) ++static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) ++{ ++ BdrvChild *parent; ++ ++ QLIST_FOREACH(parent, &bs->parents, next_parent) { ++ if (parent->role->parent_is_bds) { ++ BlockDriverState *parent_bs = parent->opaque; ++ if (!only_active || !(parent_bs->open_flags & BDRV_O_INACTIVE)) { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++} ++ ++static int bdrv_inactivate_recurse(BlockDriverState *bs) + { + BdrvChild *child, *parent; ++ uint64_t perm, shared_perm; + int ret; + + if (!bs->drv) { + return -ENOMEDIUM; + } + +- if (!setting_flag && bs->drv->bdrv_inactivate) { ++ /* Make sure that we don't inactivate a child before its parent. ++ * It will be covered by recursion from the yet active parent. */ ++ if (bdrv_has_bds_parent(bs, true)) { ++ return 0; ++ } ++ ++ assert(!(bs->open_flags & BDRV_O_INACTIVE)); ++ ++ /* Inactivate this node */ ++ if (bs->drv->bdrv_inactivate) { + ret = bs->drv->bdrv_inactivate(bs); + if (ret < 0) { + return ret; + } + } + +- if (setting_flag && !(bs->open_flags & BDRV_O_INACTIVE)) { +- uint64_t perm, shared_perm; +- +- QLIST_FOREACH(parent, &bs->parents, next_parent) { +- if (parent->role->inactivate) { +- ret = parent->role->inactivate(parent); +- if (ret < 0) { +- return ret; +- } ++ QLIST_FOREACH(parent, &bs->parents, next_parent) { ++ if (parent->role->inactivate) { ++ ret = parent->role->inactivate(parent); ++ if (ret < 0) { ++ return ret; + } + } ++ } + +- bs->open_flags |= BDRV_O_INACTIVE; ++ bs->open_flags |= BDRV_O_INACTIVE; ++ ++ /* Update permissions, they may differ for inactive nodes */ ++ bdrv_get_cumulative_perm(bs, &perm, &shared_perm); ++ bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort); ++ bdrv_set_perm(bs, perm, shared_perm); + +- /* Update permissions, they may differ for inactive nodes */ +- bdrv_get_cumulative_perm(bs, &perm, &shared_perm); +- bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort); +- bdrv_set_perm(bs, perm, shared_perm); +- } + ++ /* Recursively inactivate children */ + QLIST_FOREACH(child, &bs->children, next) { +- ret = bdrv_inactivate_recurse(child->bs, setting_flag); ++ ret = bdrv_inactivate_recurse(child->bs); + if (ret < 0) { + return ret; + } +@@ -4525,7 +4548,6 @@ int bdrv_inactivate_all(void) + BlockDriverState *bs = NULL; + BdrvNextIterator it; + int ret = 0; +- int pass; + GSList *aio_ctxs = NULL, *ctx; + + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { +@@ -4537,17 +4559,17 @@ int bdrv_inactivate_all(void) + } + } + +- /* We do two passes of inactivation. The first pass calls to drivers' +- * .bdrv_inactivate callbacks recursively so all cache is flushed to disk; +- * the second pass sets the BDRV_O_INACTIVE flag so that no further write +- * is allowed. */ +- for (pass = 0; pass < 2; pass++) { +- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { +- ret = bdrv_inactivate_recurse(bs, pass); +- if (ret < 0) { +- bdrv_next_cleanup(&it); +- goto out; +- } ++ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ++ /* Nodes with BDS parents are covered by recursion from the last ++ * parent that gets inactivated. Don't inactivate them a second ++ * time if that has already happened. */ ++ if (bdrv_has_bds_parent(bs, false)) { ++ continue; ++ } ++ ret = bdrv_inactivate_recurse(bs); ++ if (ret < 0) { ++ bdrv_next_cleanup(&it); ++ goto out; + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-AioContext-switch-for-bs-drv-NULL.patch b/SOURCES/kvm-block-Fix-AioContext-switch-for-bs-drv-NULL.patch new file mode 100644 index 0000000..5cd09a1 --- /dev/null +++ b/SOURCES/kvm-block-Fix-AioContext-switch-for-bs-drv-NULL.patch @@ -0,0 +1,118 @@ +From b495f8e19a84ce58d711fd1ec34b2d8234e4b542 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 9 May 2019 15:34:15 +0200 +Subject: [PATCH 12/12] block: Fix AioContext switch for bs->drv == NULL + +RH-Author: Kevin Wolf +Message-id: <20190509153415.29673-2-kwolf@redhat.com> +Patchwork-id: 87216 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] block: Fix AioContext switch for bs->drv == NULL +Bugzilla: 1631227 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Miroslav Rezanina + +Even for block nodes with bs->drv == NULL, we can't just ignore a +bdrv_set_aio_context() call. Leaving the node in its old context can +mean that it's still in an iothread context in bdrv_close_all() during +shutdown, resulting in an attempted unlock of the AioContext lock which +we don't hold. + +This is an example stack trace of a related crash: + + #0 0x00007ffff59da57f in raise () at /lib64/libc.so.6 + #1 0x00007ffff59c4895 in abort () at /lib64/libc.so.6 + #2 0x0000555555b97b1e in error_exit (err=, msg=msg@entry=0x555555d386d0 <__func__.19059> "qemu_mutex_unlock_impl") at util/qemu-thread-posix.c:36 + #3 0x0000555555b97f7f in qemu_mutex_unlock_impl (mutex=mutex@entry=0x5555568002f0, file=file@entry=0x555555d378df "util/async.c", line=line@entry=507) at util/qemu-thread-posix.c:97 + #4 0x0000555555b92f55 in aio_context_release (ctx=ctx@entry=0x555556800290) at util/async.c:507 + #5 0x0000555555b05cf8 in bdrv_prwv_co (child=child@entry=0x7fffc80012f0, offset=offset@entry=131072, qiov=qiov@entry=0x7fffffffd4f0, is_write=is_write@entry=true, flags=flags@entry=0) + at block/io.c:833 + #6 0x0000555555b060a9 in bdrv_pwritev (qiov=0x7fffffffd4f0, offset=131072, child=0x7fffc80012f0) at block/io.c:990 + #7 0x0000555555b060a9 in bdrv_pwrite (child=0x7fffc80012f0, offset=131072, buf=, bytes=) at block/io.c:990 + #8 0x0000555555ae172b in qcow2_cache_entry_flush (bs=bs@entry=0x555556810680, c=c@entry=0x5555568cc740, i=i@entry=0) at block/qcow2-cache.c:51 + #9 0x0000555555ae18dd in qcow2_cache_write (bs=bs@entry=0x555556810680, c=0x5555568cc740) at block/qcow2-cache.c:248 + #10 0x0000555555ae15de in qcow2_cache_flush (bs=0x555556810680, c=) at block/qcow2-cache.c:259 + #11 0x0000555555ae16b1 in qcow2_cache_flush_dependency (c=0x5555568a1700, c=0x5555568a1700, bs=0x555556810680) at block/qcow2-cache.c:194 + #12 0x0000555555ae16b1 in qcow2_cache_entry_flush (bs=bs@entry=0x555556810680, c=c@entry=0x5555568a1700, i=i@entry=0) at block/qcow2-cache.c:194 + #13 0x0000555555ae18dd in qcow2_cache_write (bs=bs@entry=0x555556810680, c=0x5555568a1700) at block/qcow2-cache.c:248 + #14 0x0000555555ae15de in qcow2_cache_flush (bs=bs@entry=0x555556810680, c=) at block/qcow2-cache.c:259 + #15 0x0000555555ad242c in qcow2_inactivate (bs=bs@entry=0x555556810680) at block/qcow2.c:2124 + #16 0x0000555555ad2590 in qcow2_close (bs=0x555556810680) at block/qcow2.c:2153 + #17 0x0000555555ab0c62 in bdrv_close (bs=0x555556810680) at block.c:3358 + #18 0x0000555555ab0c62 in bdrv_delete (bs=0x555556810680) at block.c:3542 + #19 0x0000555555ab0c62 in bdrv_unref (bs=0x555556810680) at block.c:4598 + #20 0x0000555555af4d72 in blk_remove_bs (blk=blk@entry=0x5555568103d0) at block/block-backend.c:785 + #21 0x0000555555af4dbb in blk_remove_all_bs () at block/block-backend.c:483 + #22 0x0000555555aae02f in bdrv_close_all () at block.c:3412 + #23 0x00005555557f9796 in main (argc=, argv=, envp=) at vl.c:4776 + +The reproducer I used is a qcow2 image on gluster volume, where the +virtual disk size (4 GB) is larger than the gluster volume size (64M), +so we can easily trigger an ENOSPC. This backend is assigned to a +virtio-blk device using an iothread, and then from the guest a +'dd if=/dev/zero of=/dev/vda bs=1G count=1' causes the VM to stop +because of an I/O error. qemu_gluster_co_flush_to_disk() sets +bs->drv = NULL on error, so when virtio-blk stops the dataplane, the +block nodes stay in the iothread AioContext. A 'quit' monitor command +issued from this paused state crashes the process. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1631227 +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: Stefano Garzarella +(cherry picked from commit 1bffe1ae7a7b707c3a14ea2ccd00d3609d3ce4d8) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/block.c b/block.c +index e3e0e34..7061f9b 100644 +--- a/block.c ++++ b/block.c +@@ -4946,10 +4946,6 @@ void bdrv_detach_aio_context(BlockDriverState *bs) + BdrvAioNotifier *baf, *baf_tmp; + BdrvChild *child; + +- if (!bs->drv) { +- return; +- } +- + assert(!bs->walking_aio_notifiers); + bs->walking_aio_notifiers = true; + QLIST_FOREACH_SAFE(baf, &bs->aio_notifiers, list, baf_tmp) { +@@ -4964,7 +4960,7 @@ void bdrv_detach_aio_context(BlockDriverState *bs) + */ + bs->walking_aio_notifiers = false; + +- if (bs->drv->bdrv_detach_aio_context) { ++ if (bs->drv && bs->drv->bdrv_detach_aio_context) { + bs->drv->bdrv_detach_aio_context(bs); + } + QLIST_FOREACH(child, &bs->children, next) { +@@ -4983,10 +4979,6 @@ void bdrv_attach_aio_context(BlockDriverState *bs, + BdrvAioNotifier *ban, *ban_tmp; + BdrvChild *child; + +- if (!bs->drv) { +- return; +- } +- + if (bs->quiesce_counter) { + aio_disable_external(new_context); + } +@@ -4996,7 +4988,7 @@ void bdrv_attach_aio_context(BlockDriverState *bs, + QLIST_FOREACH(child, &bs->children, next) { + bdrv_attach_aio_context(child->bs, new_context); + } +- if (bs->drv->bdrv_attach_aio_context) { ++ if (bs->drv && bs->drv->bdrv_attach_aio_context) { + bs->drv->bdrv_attach_aio_context(bs, new_context); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-AioContext-switch-for-drained-node.patch b/SOURCES/kvm-block-Fix-AioContext-switch-for-drained-node.patch new file mode 100644 index 0000000..2ecbaf6 --- /dev/null +++ b/SOURCES/kvm-block-Fix-AioContext-switch-for-drained-node.patch @@ -0,0 +1,57 @@ +From 3c3659acadf5891119a70e6dd7a2525c2706e1de Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Mar 2019 14:27:45 +0100 +Subject: [PATCH 3/9] block: Fix AioContext switch for drained node + +RH-Author: Kevin Wolf +Message-id: <20190301142747.12251-4-kwolf@redhat.com> +Patchwork-id: 84763 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/5] block: Fix AioContext switch for drained node +Bugzilla: 1671173 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow + +When a drained node changes its AioContext, we need to move its +aio_disable_external() to the new context, too. + +Without this fix, drain_end will try to reenable the new context, which +has never been disabled, so an assertion failure is triggered. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit e64f25f30b80a71bd4e409ed518c39eeb5905166) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/block.c b/block.c +index a69d0a2..7cd3651 100644 +--- a/block.c ++++ b/block.c +@@ -4954,6 +4954,9 @@ void bdrv_detach_aio_context(BlockDriverState *bs) + bdrv_detach_aio_context(child->bs); + } + ++ if (bs->quiesce_counter) { ++ aio_enable_external(bs->aio_context); ++ } + bs->aio_context = NULL; + } + +@@ -4967,6 +4970,10 @@ void bdrv_attach_aio_context(BlockDriverState *bs, + return; + } + ++ if (bs->quiesce_counter) { ++ aio_disable_external(new_context); ++ } ++ + bs->aio_context = new_context; + + QLIST_FOREACH(child, &bs->children, next) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-invalidate_cache-error-path-for-parent-act.patch b/SOURCES/kvm-block-Fix-invalidate_cache-error-path-for-parent-act.patch new file mode 100644 index 0000000..36f7e6a --- /dev/null +++ b/SOURCES/kvm-block-Fix-invalidate_cache-error-path-for-parent-act.patch @@ -0,0 +1,69 @@ +From b7d8518d4d2e5d53c2f8eb6cc78d99a69dc4feff Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 4 Feb 2019 16:06:04 +0100 +Subject: [PATCH 7/8] block: Fix invalidate_cache error path for parent + activation + +RH-Author: Kevin Wolf +Message-id: <20190204160604.2723-2-kwolf@redhat.com> +Patchwork-id: 84202 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] block: Fix invalidate_cache error path for parent activation +Bugzilla: 1531888 +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz + +bdrv_co_invalidate_cache() clears the BDRV_O_INACTIVE flag before +actually activating a node so that the correct permissions etc. are +taken. In case of errors, the flag must be restored so that the next +call to bdrv_co_invalidate_cache() retries activation. + +Restoring the flag was missing in the error path for a failed +parent->role->activate() call. The consequence is that this attempt to +activate all images correctly fails because we still set errp, however +on the next attempt BDRV_O_INACTIVE is already clear, so we return +success without actually retrying the failed action. + +An example where this is observable in practice is migration to a QEMU +instance that has a raw format block node attached to a guest device +with share-rw=off (the default) while another process holds +BLK_PERM_WRITE for the same image. In this case, all activation steps +before parent->role->activate() succeed because raw can tolerate other +writers to the image. Only the parent callback (in particular +blk_root_activate()) tries to implement the share-rw=on property and +requests exclusive write permissions. This fails when the migration +completes and correctly displays an error. However, a manual 'cont' will +incorrectly resume the VM without calling blk_root_activate() again. + +This case is described in more detail in the following bug report: +https://bugzilla.redhat.com/show_bug.cgi?id=1531888 + +Fix this by correctly restoring the BDRV_O_INACTIVE flag in the error +path. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Tested-by: Markus Armbruster +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 78fc3b3a26c145eebcdee992988644974b243a74) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block.c b/block.c +index da9b1a6..ce85c65 100644 +--- a/block.c ++++ b/block.c +@@ -4410,6 +4410,7 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, + if (parent->role->activate) { + parent->role->activate(parent, &local_err); + if (local_err) { ++ bs->open_flags |= BDRV_O_INACTIVE; + error_propagate(errp, local_err); + return; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-update-of-BDRV_O_AUTO_RDONLY-in-update_fla.patch b/SOURCES/kvm-block-Fix-update-of-BDRV_O_AUTO_RDONLY-in-update_fla.patch new file mode 100644 index 0000000..6ae28c4 --- /dev/null +++ b/SOURCES/kvm-block-Fix-update-of-BDRV_O_AUTO_RDONLY-in-update_fla.patch @@ -0,0 +1,57 @@ +From e5cb59a02593db3efcb88f1dd0cc592cf5bb34b7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:54 +0100 +Subject: [PATCH 13/34] block: Fix update of BDRV_O_AUTO_RDONLY in + update_flags_from_options() + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-13-kwolf@redhat.com> +Patchwork-id: 83122 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 12/12] block: Fix update of BDRV_O_AUTO_RDONLY in update_flags_from_options() +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +From: Alberto Garcia + +Commit e35bdc123a4ace9f4d3fcca added the auto-read-only option and the +code to update its corresponding flag in update_flags_from_options(), +but forgot to clear the flag if auto-read-only is false. + +Signed-off-by: Alberto Garcia +Reported-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 2a3d4331fa2d40708188b8000f98ff1f7dcd33bc) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/block.c b/block.c +index 6e3b574..037d2b0 100644 +--- a/block.c ++++ b/block.c +@@ -1112,7 +1112,7 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) + + static void update_flags_from_options(int *flags, QemuOpts *opts) + { +- *flags &= ~BDRV_O_CACHE_MASK; ++ *flags &= ~(BDRV_O_CACHE_MASK | BDRV_O_RDWR | BDRV_O_AUTO_RDONLY); + + assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH)); + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { +@@ -1124,8 +1124,6 @@ static void update_flags_from_options(int *flags, QemuOpts *opts) + *flags |= BDRV_O_NOCACHE; + } + +- *flags &= ~BDRV_O_RDWR; +- + assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY)); + if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) { + *flags |= BDRV_O_RDWR; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-use-after-free-error-in-bdrv_open_inherit.patch b/SOURCES/kvm-block-Fix-use-after-free-error-in-bdrv_open_inherit.patch new file mode 100644 index 0000000..38a21ae --- /dev/null +++ b/SOURCES/kvm-block-Fix-use-after-free-error-in-bdrv_open_inherit.patch @@ -0,0 +1,50 @@ +From 9fbe06ec1dad1ffc7a2bcc138b7dbd6bf83e36cd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:02 +0100 +Subject: [PATCH 006/163] block: Fix use after free error in + bdrv_open_inherit() + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-7-kwolf@redhat.com> +Patchwork-id: 84883 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/14] block: Fix use after free error in bdrv_open_inherit() +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Alberto Garcia + +When a block device is opened with BDRV_O_SNAPSHOT and the +bdrv_append_temp_snapshot() call fails then the error code path tries +to unref the already destroyed 'options' QDict. + +This can be reproduced easily by setting TMPDIR to a location where +the QEMU process can't write: + + $ TMPDIR=/nonexistent $QEMU -drive driver=null-co,snapshot=on + +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 8961be33e8ca7e809c603223803ea66ef7ea5be7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block.c b/block.c +index b31124c..25b3fe5 100644 +--- a/block.c ++++ b/block.c +@@ -2834,6 +2834,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, + bdrv_parent_cb_change_media(bs, true); + + qobject_unref(options); ++ options = NULL; + + /* For snapshot=on, create a temporary qcow2 overlay. bs points to the + * temporary snapshot afterwards. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Make-auto-read-only-on-default-for-drive.patch b/SOURCES/kvm-block-Make-auto-read-only-on-default-for-drive.patch new file mode 100644 index 0000000..6e349b2 --- /dev/null +++ b/SOURCES/kvm-block-Make-auto-read-only-on-default-for-drive.patch @@ -0,0 +1,47 @@ +From b6ffe1491ccf08594837991b5a9ead762b65ca97 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:52 +0100 +Subject: [PATCH 11/34] block: Make auto-read-only=on default for -drive + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-11-kwolf@redhat.com> +Patchwork-id: 83115 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 10/12] block: Make auto-read-only=on default for -drive +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +While we want machine interfaces like -blockdev and QMP blockdev-add to +add as little auto-detection as possible so that management tools are +explicit about their needs, -drive is a convenience option for human +users. Enabling auto-read-only=on by default there enables users to use +read-only images for read-only guest devices without having to specify +read-only=on explicitly. If they try to attach the image to a read-write +device, they will still get an error message. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 9384a444f6ebcd66bba0ae3c8434120d03c8dfea) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/blockdev.c b/blockdev.c +index 3d73f05..3eb1880 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -631,6 +631,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off"); + qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY, + read_only ? "on" : "off"); ++ qdict_set_default_str(bs_opts, BDRV_OPT_AUTO_READ_ONLY, "on"); + assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0); + + if (runstate_check(RUN_STATE_INMIGRATE)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Make-permission-changes-in-reopen-less-wrong.patch b/SOURCES/kvm-block-Make-permission-changes-in-reopen-less-wrong.patch new file mode 100644 index 0000000..151b493 --- /dev/null +++ b/SOURCES/kvm-block-Make-permission-changes-in-reopen-less-wrong.patch @@ -0,0 +1,130 @@ +From f64042620963059859d0bbae60e8655ccc44736e Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:01 +0100 +Subject: [PATCH 005/163] block: Make permission changes in reopen less wrong + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-6-kwolf@redhat.com> +Patchwork-id: 84882 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/14] block: Make permission changes in reopen less wrong +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +The way that reopen interacts with permission changes has one big +problem: Both operations are recursive, and the permissions are changes +for each node in the reopen queue. + +For a simple graph that consists just of parent and child, +.bdrv_check_perm will be called twice for the child, once recursively +when adjusting the permissions of parent, and once again when the child +itself is reopened. + +Even worse, the first .bdrv_check_perm call happens before +.bdrv_reopen_prepare was called for the child and the second one is +called afterwards. + +Making sure that .bdrv_check_perm (and the other permission callbacks) +are called only once is hard. We can cope with multiple calls right now, +but as soon as file-posix gets a dynamic auto-read-only that may need to +open a new file descriptor, we get the additional requirement that all +of them are after the .bdrv_reopen_prepare call. + +So reorder things in bdrv_reopen_multiple() to first call +.bdrv_reopen_prepare for all involved nodes and only then adjust +permissions. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 69b736e76567ecbc9b9e55570bc0afc840614a98) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 35 ++++++++++++++++++++++++----------- + 1 file changed, 24 insertions(+), 11 deletions(-) + +diff --git a/block.c b/block.c +index 2f1b4d1..b31124c 100644 +--- a/block.c ++++ b/block.c +@@ -1661,6 +1661,7 @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); + + typedef struct BlockReopenQueueEntry { + bool prepared; ++ bool perms_checked; + BDRVReopenState state; + QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry; + } BlockReopenQueueEntry; +@@ -3072,6 +3073,16 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er + bs_entry->prepared = true; + } + ++ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) { ++ BDRVReopenState *state = &bs_entry->state; ++ ret = bdrv_check_perm(state->bs, bs_queue, state->perm, ++ state->shared_perm, NULL, errp); ++ if (ret < 0) { ++ goto cleanup_perm; ++ } ++ bs_entry->perms_checked = true; ++ } ++ + /* If we reach this point, we have success and just need to apply the + * changes + */ +@@ -3080,7 +3091,20 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er + } + + ret = 0; ++cleanup_perm: ++ QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { ++ BDRVReopenState *state = &bs_entry->state; ++ ++ if (!bs_entry->perms_checked) { ++ continue; ++ } + ++ if (ret == 0) { ++ bdrv_set_perm(state->bs, state->perm, state->shared_perm); ++ } else { ++ bdrv_abort_perm_update(state->bs); ++ } ++ } + cleanup: + QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { + if (ret) { +@@ -3297,12 +3321,6 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, + } while ((entry = qdict_next(reopen_state->options, entry))); + } + +- ret = bdrv_check_perm(reopen_state->bs, queue, reopen_state->perm, +- reopen_state->shared_perm, NULL, errp); +- if (ret < 0) { +- goto error; +- } +- + ret = 0; + + error: +@@ -3352,9 +3370,6 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) + + bdrv_refresh_limits(bs, NULL); + +- bdrv_set_perm(reopen_state->bs, reopen_state->perm, +- reopen_state->shared_perm); +- + new_can_write = + !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); + if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) { +@@ -3386,8 +3401,6 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) + if (drv->bdrv_reopen_abort) { + drv->bdrv_reopen_abort(reopen_state); + } +- +- bdrv_abort_perm_update(reopen_state->bs); + } + + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Require-auto-read-only-for-existing-fallbacks.patch b/SOURCES/kvm-block-Require-auto-read-only-for-existing-fallbacks.patch new file mode 100644 index 0000000..0ffe4b9 --- /dev/null +++ b/SOURCES/kvm-block-Require-auto-read-only-for-existing-fallbacks.patch @@ -0,0 +1,267 @@ +From f258c5ce8e80d9e21fbca9cc359c06f3ad02bab7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:46 +0100 +Subject: [PATCH 05/34] block: Require auto-read-only for existing fallbacks + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-5-kwolf@redhat.com> +Patchwork-id: 83114 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 04/12] block: Require auto-read-only for existing fallbacks +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +Some block drivers have traditionally changed their node to read-only +mode without asking the user. This behaviour has been marked deprecated +since 2.11, expecting users to provide an explicit read-only=on option. + +Now that we have auto-read-only=on, enable these drivers to make use of +the option. + +This is the only use of bdrv_set_read_only(), so we can make it a bit +more specific and turn it into a bdrv_apply_auto_read_only() that is +more convenient for drivers to use. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit eaa2410f1ea864609090c0a5fda9e0ce9499da79) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 42 +++++++++++++++++++++++++++--------------- + block/bochs.c | 17 ++++++----------- + block/cloop.c | 16 +++++----------- + block/dmg.c | 16 +++++----------- + block/rbd.c | 15 ++++----------- + block/vvfat.c | 10 ++-------- + include/block/block.h | 3 ++- + 7 files changed, 51 insertions(+), 68 deletions(-) + +diff --git a/block.c b/block.c +index ff3ea92..6e3b574 100644 +--- a/block.c ++++ b/block.c +@@ -266,29 +266,41 @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, + return 0; + } + +-/* TODO Remove (deprecated since 2.11) +- * Block drivers are not supposed to automatically change bs->read_only. +- * Instead, they should just check whether they can provide what the user +- * explicitly requested and error out if read-write is requested, but they can +- * only provide read-only access. */ +-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp) ++/* ++ * Called by a driver that can only provide a read-only image. ++ * ++ * Returns 0 if the node is already read-only or it could switch the node to ++ * read-only because BDRV_O_AUTO_RDONLY is set. ++ * ++ * Returns -EACCES if the node is read-write and BDRV_O_AUTO_RDONLY is not set ++ * or bdrv_can_set_read_only() forbids making the node read-only. If @errmsg ++ * is not NULL, it is used as the error message for the Error object. ++ */ ++int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, ++ Error **errp) + { + int ret = 0; + +- ret = bdrv_can_set_read_only(bs, read_only, false, errp); +- if (ret < 0) { +- return ret; ++ if (!(bs->open_flags & BDRV_O_RDWR)) { ++ return 0; ++ } ++ if (!(bs->open_flags & BDRV_O_AUTO_RDONLY)) { ++ goto fail; + } + +- bs->read_only = read_only; +- +- if (read_only) { +- bs->open_flags &= ~BDRV_O_RDWR; +- } else { +- bs->open_flags |= BDRV_O_RDWR; ++ ret = bdrv_can_set_read_only(bs, true, false, NULL); ++ if (ret < 0) { ++ goto fail; + } + ++ bs->read_only = true; ++ bs->open_flags &= ~BDRV_O_RDWR; ++ + return 0; ++ ++fail: ++ error_setg(errp, "%s", errmsg ?: "Image is read-only"); ++ return -EACCES; + } + + void bdrv_get_full_backing_filename_from_filename(const char *backed, +diff --git a/block/bochs.c b/block/bochs.c +index 50c6300..22e7d44 100644 +--- a/block/bochs.c ++++ b/block/bochs.c +@@ -105,23 +105,18 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, + struct bochs_header bochs; + int ret; + ++ /* No write support yet */ ++ ret = bdrv_apply_auto_read_only(bs, NULL, errp); ++ if (ret < 0) { ++ return ret; ++ } ++ + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + false, errp); + if (!bs->file) { + return -EINVAL; + } + +- if (!bdrv_is_read_only(bs)) { +- error_report("Opening bochs images without an explicit read-only=on " +- "option is deprecated. Future versions will refuse to " +- "open the image instead of automatically marking the " +- "image read-only."); +- ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */ +- if (ret < 0) { +- return ret; +- } +- } +- + ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)); + if (ret < 0) { + return ret; +diff --git a/block/cloop.c b/block/cloop.c +index 2be6898..df2b85f 100644 +--- a/block/cloop.c ++++ b/block/cloop.c +@@ -67,23 +67,17 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, + uint32_t offsets_size, max_compressed_block_size = 1, i; + int ret; + ++ ret = bdrv_apply_auto_read_only(bs, NULL, errp); ++ if (ret < 0) { ++ return ret; ++ } ++ + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + false, errp); + if (!bs->file) { + return -EINVAL; + } + +- if (!bdrv_is_read_only(bs)) { +- error_report("Opening cloop images without an explicit read-only=on " +- "option is deprecated. Future versions will refuse to " +- "open the image instead of automatically marking the " +- "image read-only."); +- ret = bdrv_set_read_only(bs, true, errp); +- if (ret < 0) { +- return ret; +- } +- } +- + /* read header */ + ret = bdrv_pread(bs->file, 128, &s->block_size, 4); + if (ret < 0) { +diff --git a/block/dmg.c b/block/dmg.c +index c9b3c51..1d9283b 100644 +--- a/block/dmg.c ++++ b/block/dmg.c +@@ -413,23 +413,17 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, + int64_t offset; + int ret; + ++ ret = bdrv_apply_auto_read_only(bs, NULL, errp); ++ if (ret < 0) { ++ return ret; ++ } ++ + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, + false, errp); + if (!bs->file) { + return -EINVAL; + } + +- if (!bdrv_is_read_only(bs)) { +- error_report("Opening dmg images without an explicit read-only=on " +- "option is deprecated. Future versions will refuse to " +- "open the image instead of automatically marking the " +- "image read-only."); +- ret = bdrv_set_read_only(bs, true, errp); +- if (ret < 0) { +- return ret; +- } +- } +- + block_module_load_one("dmg-bz2"); + + s->n_chunks = 0; +diff --git a/block/rbd.c b/block/rbd.c +index 8ce68c8..91ebb8b 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -772,17 +772,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + /* If we are using an rbd snapshot, we must be r/o, otherwise + * leave as-is */ + if (s->snap != NULL) { +- if (!bdrv_is_read_only(bs)) { +- error_report("Opening rbd snapshots without an explicit " +- "read-only=on option is deprecated. Future versions " +- "will refuse to open the image instead of " +- "automatically marking the image read-only."); +- r = bdrv_set_read_only(bs, true, &local_err); +- if (r < 0) { +- rbd_close(s->image); +- error_propagate(errp, local_err); +- goto failed_open; +- } ++ r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp); ++ if (r < 0) { ++ rbd_close(s->image); ++ goto failed_open; + } + } + +diff --git a/block/vvfat.c b/block/vvfat.c +index 3efce9e..a5a3fb9 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -1262,15 +1262,9 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, + "Unable to set VVFAT to 'rw' when drive is read-only"); + goto fail; + } +- } else if (!bdrv_is_read_only(bs)) { +- error_report("Opening non-rw vvfat images without an explicit " +- "read-only=on option is deprecated. Future versions " +- "will refuse to open the image instead of " +- "automatically marking the image read-only."); +- /* read only is the default for safety */ +- ret = bdrv_set_read_only(bs, true, &local_err); ++ } else { ++ ret = bdrv_apply_auto_read_only(bs, NULL, errp); + if (ret < 0) { +- error_propagate(errp, local_err); + goto fail; + } + } +diff --git a/include/block/block.h b/include/block/block.h +index 6ee8b2a..36a702c 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -433,7 +433,8 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, + bool bdrv_is_read_only(BlockDriverState *bs); + int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, + bool ignore_allow_rdw, Error **errp); +-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); ++int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, ++ Error **errp); + bool bdrv_is_writable(BlockDriverState *bs); + bool bdrv_is_sg(BlockDriverState *bs); + bool bdrv_is_inserted(BlockDriverState *bs); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Simplify-bdrv_reopen_abort.patch b/SOURCES/kvm-block-Simplify-bdrv_reopen_abort.patch new file mode 100644 index 0000000..7d178c3 --- /dev/null +++ b/SOURCES/kvm-block-Simplify-bdrv_reopen_abort.patch @@ -0,0 +1,62 @@ +From e790236fc17d7ceb73571bdd5f62c15693e7a071 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:09:59 +0100 +Subject: [PATCH 003/163] block: Simplify bdrv_reopen_abort() + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-4-kwolf@redhat.com> +Patchwork-id: 84880 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/14] block: Simplify bdrv_reopen_abort() +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Alberto Garcia + +If a bdrv_reopen_multiple() call fails, then the explicit_options +QDict has to be deleted for every entry in the reopen queue. This must +happen regardless of whether that entry's bdrv_reopen_prepare() call +succeeded or not. + +This patch simplifies the cleanup code a bit. + +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 1bab38e7bd29347aca642c55a1de91ec6680efce) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/block.c b/block.c +index ccf9acb..c3148cc 100644 +--- a/block.c ++++ b/block.c +@@ -3083,9 +3083,10 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er + + cleanup: + QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { +- if (ret && bs_entry->prepared) { +- bdrv_reopen_abort(&bs_entry->state); +- } else if (ret) { ++ if (ret) { ++ if (bs_entry->prepared) { ++ bdrv_reopen_abort(&bs_entry->state); ++ } + qobject_unref(bs_entry->state.explicit_options); + } + qobject_unref(bs_entry->state.options); +@@ -3374,8 +3375,6 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) + drv->bdrv_reopen_abort(reopen_state); + } + +- qobject_unref(reopen_state->explicit_options); +- + bdrv_abort_perm_update(reopen_state->bs); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Update-flags-in-bdrv_set_read_only.patch b/SOURCES/kvm-block-Update-flags-in-bdrv_set_read_only.patch new file mode 100644 index 0000000..b238404 --- /dev/null +++ b/SOURCES/kvm-block-Update-flags-in-bdrv_set_read_only.patch @@ -0,0 +1,49 @@ +From 0e48a34df1ebd61f5fd0e914d638de2646b09635 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:43 +0100 +Subject: [PATCH 02/34] block: Update flags in bdrv_set_read_only() + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-2-kwolf@redhat.com> +Patchwork-id: 83110 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 01/12] block: Update flags in bdrv_set_read_only() +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +To fully change the read-only state of a node, we must not only change +bs->read_only, but also update bs->open_flags. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Alberto Garcia +(cherry picked from commit eeae6a596b0efc092f5101c67683053e245e6250) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/block.c b/block.c +index fbd569c..d3ea21a 100644 +--- a/block.c ++++ b/block.c +@@ -281,6 +281,13 @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp) + } + + bs->read_only = read_only; ++ ++ if (read_only) { ++ bs->open_flags &= ~BDRV_O_RDWR; ++ } else { ++ bs->open_flags |= BDRV_O_RDWR; ++ } ++ + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Use-normal-drain-for-bdrv_set_aio_context.patch b/SOURCES/kvm-block-Use-normal-drain-for-bdrv_set_aio_context.patch new file mode 100644 index 0000000..d3ac85f --- /dev/null +++ b/SOURCES/kvm-block-Use-normal-drain-for-bdrv_set_aio_context.patch @@ -0,0 +1,76 @@ +From 1d47b2827170416abf387add121a3871194ddc40 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Mar 2019 14:27:47 +0100 +Subject: [PATCH 5/9] block: Use normal drain for bdrv_set_aio_context() + +RH-Author: Kevin Wolf +Message-id: <20190301142747.12251-6-kwolf@redhat.com> +Patchwork-id: 84765 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 5/5] block: Use normal drain for bdrv_set_aio_context() +Bugzilla: 1671173 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow + +Now that bdrv_set_aio_context() works inside drained sections, it can +also use the real drain function instead of open coding something +similar. + +Signed-off-by: Kevin Wolf +(cherry picked from commit d70d595429ecd9ac4917e53453dd8979db8e5ffd) + +RHEL: This conflicts because we didn't backport the removal of the +polling loop. The conflict is resolved so that the polling loop moves to +above the drain and any requests a BH would spawn would still be +correctly drained afterwards. The changed order alone would have +compensated for the virtio-blk bug and it potentially compensates for +other bugs, too (we know of bugs in the NBD client at least), so leaving +the polling loop in, with the new ordering, feels like the safe way for +a downstream backport. + +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/block.c b/block.c +index 7cd3651..c47e5b0 100644 +--- a/block.c ++++ b/block.c +@@ -4995,18 +4995,18 @@ void bdrv_attach_aio_context(BlockDriverState *bs, + bs->walking_aio_notifiers = false; + } + ++/* The caller must own the AioContext lock for the old AioContext of bs, but it ++ * must not own the AioContext lock for new_context (unless new_context is ++ * the same as the current context of bs). */ + void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) + { + AioContext *ctx = bdrv_get_aio_context(bs); + +- aio_disable_external(ctx); +- bdrv_parent_drained_begin(bs, NULL, false); +- bdrv_drain(bs); /* ensure there are no in-flight requests */ +- + while (aio_poll(ctx, false)) { + /* wait for all bottom halves to execute */ + } + ++ bdrv_drained_begin(bs); + bdrv_detach_aio_context(bs); + + /* This function executes in the old AioContext so acquire the new one in +@@ -5014,8 +5014,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) + */ + aio_context_acquire(new_context); + bdrv_attach_aio_context(bs, new_context); +- bdrv_parent_drained_end(bs, NULL, false); +- aio_enable_external(ctx); ++ bdrv_drained_end(bs); + aio_context_release(new_context); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backend-Make-blk_inc-dec_in_flight-public.patch b/SOURCES/kvm-block-backend-Make-blk_inc-dec_in_flight-public.patch new file mode 100644 index 0000000..c7c5800 --- /dev/null +++ b/SOURCES/kvm-block-backend-Make-blk_inc-dec_in_flight-public.patch @@ -0,0 +1,62 @@ +From fe68ddea8e2283fad78a3596ee0682d49294987f Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Mar 2019 14:27:43 +0100 +Subject: [PATCH 1/9] block-backend: Make blk_inc/dec_in_flight public + +RH-Author: Kevin Wolf +Message-id: <20190301142747.12251-2-kwolf@redhat.com> +Patchwork-id: 84764 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/5] block-backend: Make blk_inc/dec_in_flight public +Bugzilla: 1671173 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow + +For some users of BlockBackends, just increasing the in_flight counter +is easier than implementing separate handlers in BlockDevOps. Make the +helper functions for this public. + +Signed-off-by: Kevin Wolf +(cherry picked from commit c90e2a9cfd94bd02d92c53b97f04fd595001de7e) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 4 ++-- + include/sysemu/block-backend.h | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/block-backend.c b/block/block-backend.c +index ddec869..52eebeb 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -1294,12 +1294,12 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) + return bdrv_make_zero(blk->root, flags); + } + +-static void blk_inc_in_flight(BlockBackend *blk) ++void blk_inc_in_flight(BlockBackend *blk) + { + atomic_inc(&blk->in_flight); + } + +-static void blk_dec_in_flight(BlockBackend *blk) ++void blk_dec_in_flight(BlockBackend *blk) + { + atomic_dec(&blk->in_flight); + aio_wait_kick(); +diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h +index 830d873..6b6d882 100644 +--- a/include/sysemu/block-backend.h ++++ b/include/sysemu/block-backend.h +@@ -157,6 +157,8 @@ int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes); + int blk_co_flush(BlockBackend *blk); + int blk_flush(BlockBackend *blk); + int blk_commit_all(void); ++void blk_inc_in_flight(BlockBackend *blk); ++void blk_dec_in_flight(BlockBackend *blk); + void blk_drain(BlockBackend *blk); + void blk_drain_all(void); + void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backend-Set-werror-rerror-defaults-in-blk_new.patch b/SOURCES/kvm-block-backend-Set-werror-rerror-defaults-in-blk_new.patch new file mode 100644 index 0000000..7654783 --- /dev/null +++ b/SOURCES/kvm-block-backend-Set-werror-rerror-defaults-in-blk_new.patch @@ -0,0 +1,69 @@ +From db87a7100f44bbaeef9860cf3c313642586bf030 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 14:35:27 +0100 +Subject: [PATCH 08/23] block-backend: Set werror/rerror defaults in blk_new() + +RH-Author: Kevin Wolf +Message-id: <20190219143527.26763-2-kwolf@redhat.com> +Patchwork-id: 84537 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] block-backend: Set werror/rerror defaults in blk_new() +Bugzilla: 1631615 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz + +Currently, the default values for werror and rerror have to be set +explicitly with blk_set_on_error() by the callers of blk_new(). The only +caller actually doing this is blockdev_init(), which is called for +BlockBackends created using -drive. + +In particular, anonymous BlockBackends created with +-device ...,drive= didn't get the correct default set and +instead defaulted to the integer value 0 (= BLOCKDEV_ON_ERROR_REPORT). +This is the intended default for rerror anyway, but the default for +werror should be BLOCKDEV_ON_ERROR_ENOSPC. + +Set the defaults in blk_new() instead so that they apply no matter what +way the BlockBackend was created. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Fam Zheng +(cherry picked from commit cb53460b708db3617ab73248374d071d5552c263) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 3 +++ + tests/qemu-iotests/067.out | 1 + + 2 files changed, 4 insertions(+) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 36922d1..ddec869 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -325,6 +325,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm) + blk->shared_perm = shared_perm; + blk_set_enable_write_cache(blk, true); + ++ blk->on_read_error = BLOCKDEV_ON_ERROR_REPORT; ++ blk->on_write_error = BLOCKDEV_ON_ERROR_ENOSPC; ++ + block_acct_init(&blk->stats); + + notifier_list_init(&blk->remove_bs_notifiers); +diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out +index 2e71cff..b10c71d 100644 +--- a/tests/qemu-iotests/067.out ++++ b/tests/qemu-iotests/067.out +@@ -385,6 +385,7 @@ Testing: -device virtio-scsi -device scsi-cd,id=cd0 + { + "return": [ + { ++ "io-status": "ok", + "device": "", + "locked": false, + "removable": true, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backup-prohibit-backup-from-using-in-use-bitma.patch b/SOURCES/kvm-block-backup-prohibit-backup-from-using-in-use-bitma.patch new file mode 100644 index 0000000..c6c5e9b --- /dev/null +++ b/SOURCES/kvm-block-backup-prohibit-backup-from-using-in-use-bitma.patch @@ -0,0 +1,62 @@ +From 2b82b7986e02dfe32ed23724d7a6dfaef2c79031 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:35 +0100 +Subject: [PATCH 25/33] block/backup: prohibit backup from using in use bitmaps + +RH-Author: John Snow +Message-id: <20190206221243.7407-16-jsnow@redhat.com> +Patchwork-id: 84268 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 15/23] block/backup: prohibit backup from using in use bitmaps +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +If the bitmap is frozen, we shouldn't touch it. + +Signed-off-by: John Snow +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20181002230218.13949-6-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit b27a6b8b329a8dcbab9dc1af45586f7585f3d47b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 9921de6..c9bda43 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3669,10 +3669,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + bdrv_unref(target_bs); + goto out; + } +- if (bdrv_dirty_bitmap_qmp_locked(bmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bmap)) { + error_setg(errp, +- "Bitmap '%s' is currently locked and cannot be used for " +- "backup", backup->bitmap); ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be used for backup", backup->bitmap); + goto out; + } + } +@@ -3776,10 +3776,10 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); + goto out; + } +- if (bdrv_dirty_bitmap_qmp_locked(bmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bmap)) { + error_setg(errp, +- "Bitmap '%s' is currently locked and cannot be used for " +- "backup", backup->bitmap); ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be used for backup", backup->bitmap); + goto out; + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-Add-bdrv_dirty_iter_next_area.patch b/SOURCES/kvm-block-dirty-bitmap-Add-bdrv_dirty_iter_next_area.patch new file mode 100644 index 0000000..52e18d8 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-Add-bdrv_dirty_iter_next_area.patch @@ -0,0 +1,114 @@ +From 7e539b23b6911cb38bf70dcbf818acbc10790816 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:25 +0100 +Subject: [PATCH 15/33] block/dirty-bitmap: Add bdrv_dirty_iter_next_area + +RH-Author: John Snow +Message-id: <20190206221243.7407-6-jsnow@redhat.com> +Patchwork-id: 84265 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 05/23] block/dirty-bitmap: Add bdrv_dirty_iter_next_area +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Max Reitz + +This new function allows to look for a consecutively dirty area in a +dirty bitmap. + +Signed-off-by: Max Reitz +Reviewed-by: Fam Zheng +Reviewed-by: John Snow +Message-id: 20180613181823.13618-10-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 72d10a94213a954ad569095cb4491f2ae0853c40) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ + include/block/dirty-bitmap.h | 2 ++ + 2 files changed, 57 insertions(+) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index f4a4cb7..59027d4 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -528,6 +528,61 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter) + return hbitmap_iter_next(&iter->hbi, true); + } + ++/** ++ * Return the next consecutively dirty area in the dirty bitmap ++ * belonging to the given iterator @iter. ++ * ++ * @max_offset: Maximum value that may be returned for ++ * *offset + *bytes ++ * @offset: Will contain the start offset of the next dirty area ++ * @bytes: Will contain the length of the next dirty area ++ * ++ * Returns: True if a dirty area could be found before max_offset ++ * (which means that *offset and *bytes then contain valid ++ * values), false otherwise. ++ * ++ * Note that @iter is never advanced if false is returned. If an area ++ * is found (which means that true is returned), it will be advanced ++ * past that area. ++ */ ++bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset, ++ uint64_t *offset, int *bytes) ++{ ++ uint32_t granularity = bdrv_dirty_bitmap_granularity(iter->bitmap); ++ uint64_t gran_max_offset; ++ int64_t ret; ++ int size; ++ ++ if (max_offset == iter->bitmap->size) { ++ /* If max_offset points to the image end, round it up by the ++ * bitmap granularity */ ++ gran_max_offset = ROUND_UP(max_offset, granularity); ++ } else { ++ gran_max_offset = max_offset; ++ } ++ ++ ret = hbitmap_iter_next(&iter->hbi, false); ++ if (ret < 0 || ret + granularity > gran_max_offset) { ++ return false; ++ } ++ ++ *offset = ret; ++ size = 0; ++ ++ assert(granularity <= INT_MAX); ++ ++ do { ++ /* Advance iterator */ ++ ret = hbitmap_iter_next(&iter->hbi, true); ++ size += granularity; ++ } while (ret + granularity <= gran_max_offset && ++ hbitmap_iter_next(&iter->hbi, false) == ret + granularity && ++ size <= INT_MAX - granularity); ++ ++ *bytes = MIN(size, max_offset - *offset); ++ return true; ++} ++ + /* Called within bdrv_dirty_bitmap_lock..unlock */ + void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t offset, int64_t bytes) +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index bf68dd7..259bd27 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -83,6 +83,8 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t offset, int64_t bytes); + int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter); ++bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset, ++ uint64_t *offset, int *bytes); + void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset); + int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); + int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-Documentation-and-Comment-fixups.patch b/SOURCES/kvm-block-dirty-bitmap-Documentation-and-Comment-fixups.patch new file mode 100644 index 0000000..652f47f --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-Documentation-and-Comment-fixups.patch @@ -0,0 +1,131 @@ +From de38b4dad0dfce73080295923dd3e2d863f6f855 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:38 +0200 +Subject: [PATCH 133/163] block/dirty-bitmap: Documentation and Comment fixups + +RH-Author: John Snow +Message-id: <20190403181857.9693-3-jsnow@redhat.com> +Patchwork-id: 85416 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/21] block/dirty-bitmap: Documentation and Comment fixups +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +The meaning of the states has changed subtly over time, +this should bring the understanding more in-line with the +current, actual usages. + +Reported-by: Eric Blake +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190202011048.12343-1-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 73ab5d601c8b4311090a70e525f5970f70b8b2a0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 20 ++++++++++++++------ + qapi/block-core.json | 34 +++++++++++++++++++++++++--------- + 2 files changed, 39 insertions(+), 15 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index e46f72b..c6d4ace 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -29,12 +29,20 @@ + #include "block/blockjob.h" + + /** +- * A BdrvDirtyBitmap can be in three possible states: +- * (1) successor is NULL and disabled is false: full r/w mode +- * (2) successor is NULL and disabled is true: read only mode ("disabled") +- * (3) successor is set: frozen mode. +- * A frozen bitmap cannot be renamed, deleted, anonymized, cleared, set, +- * or enabled. A frozen bitmap can only abdicate() or reclaim(). ++ * A BdrvDirtyBitmap can be in four possible user-visible states: ++ * (1) Active: successor is NULL, and disabled is false: full r/w mode ++ * (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode, ++ * guest writes are dropped, but monitor writes are possible, ++ * through commands like merge and clear. ++ * (3) Frozen: successor is not NULL. ++ * A frozen bitmap cannot be renamed, deleted, cleared, set, ++ * enabled, merged to, etc. A frozen bitmap can only abdicate() ++ * or reclaim(). ++ * In this state, the anonymous successor bitmap may be either ++ * Active and recording writes from the guest (e.g. backup jobs), ++ * but it can be Disabled and not recording writes. ++ * (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap ++ * in any way from the monitor. + */ + struct BdrvDirtyBitmap { + QemuMutex *mutex; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 23c9462..5fe7897 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -421,17 +421,27 @@ + # + # An enumeration of possible states that a dirty bitmap can report to the user. + # +-# @frozen: The bitmap is currently in-use by a backup operation or block job, +-# and is immutable. +-# +-# @disabled: The bitmap is currently in-use by an internal operation and is +-# read-only. It can still be deleted. ++# @frozen: The bitmap is currently in-use by some operation and is immutable. ++# If the bitmap was @active prior to the operation, new writes by the ++# guest are being recorded in a temporary buffer, and will not be lost. ++# Generally, bitmaps are cleared on successful use in an operation and ++# the temporary buffer is committed into the bitmap. On failure, the ++# temporary buffer is merged back into the bitmap without first ++# clearing it. ++# Please refer to the documentation for each bitmap-using operation, ++# See also @blockdev-backup, @drive-backup. ++# ++# @disabled: The bitmap is not currently recording new writes by the guest. ++# This is requested explicitly via @block-dirty-bitmap-disable. ++# It can still be cleared, deleted, or used for backup operations. + # + # @active: The bitmap is actively monitoring for new writes, and can be cleared, + # deleted, or used for backup operations. + # +-# @locked: The bitmap is currently in-use by some operation and can not be +-# cleared, deleted, or used for backup operations. (Since 2.12) ++# @locked: The bitmap is currently in-use by some operation and is immutable. ++# If the bitmap was @active prior to the operation, it is still ++# recording new writes. If the bitmap was @disabled, it is not ++# recording new writes. (Since 2.12) + # + # Since: 2.4 + ## +@@ -1966,9 +1976,15 @@ + # @block-dirty-bitmap-merge: + # + # Merge dirty bitmaps listed in @bitmaps to the @target dirty bitmap. +-# The @bitmaps dirty bitmaps are unchanged. ++# Dirty bitmaps in @bitmaps will be unchanged, except if it also appears ++# as the @target bitmap. Any bits already set in @target will still be ++# set after the merge, i.e., this operation does not clear the target. + # On error, @target is unchanged. + # ++# The resulting bitmap will count as dirty any clusters that were dirty in any ++# of the source bitmaps. This can be used to achieve backup checkpoints, or in ++# simpler usages, to copy bitmaps. ++# + # Returns: nothing on success + # If @node is not a valid block device, DeviceNotFound + # If any bitmap in @bitmaps or @target is not found, GenericError +@@ -2003,7 +2019,7 @@ + ## + # @x-debug-block-dirty-bitmap-sha256: + # +-# Get bitmap SHA256 ++# Get bitmap SHA256. + # + # Returns: BlockDirtyBitmapSha256 on success + # If @node is not a valid block device, DeviceNotFound +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-add-inconsistent-status.patch b/SOURCES/kvm-block-dirty-bitmap-add-inconsistent-status.patch new file mode 100644 index 0000000..618f7dd --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-add-inconsistent-status.patch @@ -0,0 +1,76 @@ +From 615fbb1d8b28619f0a6a00cdaaa57d223670bf92 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:50 +0200 +Subject: [PATCH 145/163] block/dirty-bitmap: add inconsistent status + +RH-Author: John Snow +Message-id: <20190403181857.9693-15-jsnow@redhat.com> +Patchwork-id: 85411 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 14/21] block/dirty-bitmap: add inconsistent status +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Even though the status field is deprecated, we still have to support +it for a few more releases. Since this is a very new kind of bitmap +state, it makes sense for it to have its own status field. + +Reviewed-by: Eric Blake +Signed-off-by: John Snow +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190301191545.8728-3-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 0064cfefa4e90c11e394befb7abe47602f2f30d7) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 7 ++++++- + qapi/block-core.json | 7 ++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 096c1b7..4a2349d 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -210,10 +210,15 @@ bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) + * or it can be Disabled and not recording writes. + * (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap + * in any way from the monitor. ++ * (5) Inconsistent: This is a persistent bitmap whose "in use" bit is set, and ++ * is unusable by QEMU. It can be deleted to remove it from ++ * the qcow2. + */ + DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) + { +- if (bdrv_dirty_bitmap_has_successor(bitmap)) { ++ if (bdrv_dirty_bitmap_inconsistent(bitmap)) { ++ return DIRTY_BITMAP_STATUS_INCONSISTENT; ++ } else if (bdrv_dirty_bitmap_has_successor(bitmap)) { + return DIRTY_BITMAP_STATUS_FROZEN; + } else if (bdrv_dirty_bitmap_busy(bitmap)) { + return DIRTY_BITMAP_STATUS_LOCKED; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 92a42ef..c84144d 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -443,10 +443,15 @@ + # recording new writes. If the bitmap was @disabled, it is not + # recording new writes. (Since 2.12) + # ++# @inconsistent: This is a persistent dirty bitmap that was marked in-use on ++# disk, and is unusable by QEMU. It can only be deleted. ++# Please rely on the inconsistent field in @BlockDirtyInfo ++# instead, as the status field is deprecated. (Since 4.0) ++# + # Since: 2.4 + ## + { 'enum': 'DirtyBitmapStatus', +- 'data': ['active', 'disabled', 'frozen', 'locked'] } ++ 'data': ['active', 'disabled', 'frozen', 'locked', 'inconsistent'] } + + ## + # @BlockDirtyInfo: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-add-recording-and-busy-properties.patch b/SOURCES/kvm-block-dirty-bitmap-add-recording-and-busy-properties.patch new file mode 100644 index 0000000..49656b4 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-add-recording-and-busy-properties.patch @@ -0,0 +1,268 @@ +From baab9fd178c51f5712acef9a54cd2848903f90e9 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:39 +0200 +Subject: [PATCH 134/163] block/dirty-bitmap: add recording and busy properties + +RH-Author: John Snow +Message-id: <20190403181857.9693-4-jsnow@redhat.com> +Patchwork-id: 85412 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/21] block/dirty-bitmap: add recording and busy properties +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +The current API allows us to report a single status, which we've defined as: + +Frozen: has a successor, treated as qmp_locked, may or may not be enabled. +Locked: no successor, qmp_locked. may or may not be enabled. +Disabled: Not frozen or locked, disabled. +Active: Not frozen, locked, or disabled. + +The problem is that both "Frozen" and "Locked" mean nearly the same thing, +and that both of them do not intuit whether they are recording guest writes +or not. + +This patch deprecates that status field and introduces two orthogonal +properties instead to replace it. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-2-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 4db6ceb0b594e179fcbd46a351b8cebaa840bf0d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 9 +++++++++ + qapi/block-core.json | 10 +++++++++- + qemu-doc.texi | 6 ++++++ + tests/qemu-iotests/236.out | 28 ++++++++++++++++++++++++++++ + 4 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index c6d4ace..101383b 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -226,6 +226,13 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) + } + } + ++/* Called with BQL taken. */ ++static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap) ++{ ++ return !bitmap->disabled || (bitmap->successor && ++ !bitmap->successor->disabled); ++} ++ + /** + * Create a successor bitmap destined to replace this bitmap after an operation. + * Requires that the bitmap is not frozen and has no successor. +@@ -448,6 +455,8 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) + info->has_name = !!bm->name; + info->name = g_strdup(bm->name); + info->status = bdrv_dirty_bitmap_status(bm); ++ info->recording = bdrv_dirty_bitmap_recording(bm); ++ info->busy = bdrv_dirty_bitmap_user_locked(bm); + info->persistent = bm->persistent; + entry->value = info; + *plist = entry; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 5fe7897..98bd3a8 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -459,7 +459,14 @@ + # + # @granularity: granularity of the dirty bitmap in bytes (since 1.4) + # +-# @status: current status of the dirty bitmap (since 2.4) ++# @status: Deprecated in favor of @recording and @locked. (since 2.4) ++# ++# @recording: true if the bitmap is recording new writes from the guest. ++# Replaces `active` and `disabled` statuses. (since 4.0) ++# ++# @busy: true if the bitmap is in-use by some operation (NBD or jobs) ++# and cannot be modified via QMP or used by another operation. ++# Replaces `locked` and `frozen` statuses. (since 4.0) + # + # @persistent: true if the bitmap will eventually be flushed to persistent + # storage (since 4.0) +@@ -468,6 +475,7 @@ + ## + { 'struct': 'BlockDirtyInfo', + 'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32', ++ 'recording': 'bool', 'busy': 'bool', + 'status': 'DirtyBitmapStatus', 'persistent': 'bool' } } + + ## +diff --git a/qemu-doc.texi b/qemu-doc.texi +index 2acbec5..d5060dd 100644 +--- a/qemu-doc.texi ++++ b/qemu-doc.texi +@@ -2951,6 +2951,12 @@ for these file types is 'host_cdrom' or 'host_device' as appropriate. + "autoload" parameter is now ignored. All bitmaps are automatically loaded + from qcow2 images. + ++@subsection query-block result field dirty-bitmaps[i].status (since 4.0) ++ ++The ``status'' field of the ``BlockDirtyInfo'' structure, returned by ++the query-block command is deprecated. Two new boolean fields, ++``recording'' and ``busy'' effectively replace it. ++ + @subsection query-cpus (since 2.12.0) + + The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command. +diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out +index 5006f7b..815cd05 100644 +--- a/tests/qemu-iotests/236.out ++++ b/tests/qemu-iotests/236.out +@@ -22,17 +22,21 @@ write -P0xcd 0x3ff0000 64k + "bitmaps": { + "drive0": [ + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapB", + "persistent": false, ++ "recording": true, + "status": "active" + }, + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapA", + "persistent": false, ++ "recording": true, + "status": "active" + } + ] +@@ -84,17 +88,21 @@ write -P0xcd 0x3ff0000 64k + "bitmaps": { + "drive0": [ + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapB", + "persistent": false, ++ "recording": true, + "status": "active" + }, + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapA", + "persistent": false, ++ "recording": true, + "status": "active" + } + ] +@@ -184,24 +192,30 @@ write -P0xea 0x3fe0000 64k + "bitmaps": { + "drive0": [ + { ++ "busy": false, + "count": 393216, + "granularity": 65536, + "name": "bitmapC", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapB", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 458752, + "granularity": 65536, + "name": "bitmapA", + "persistent": false, ++ "recording": false, + "status": "disabled" + } + ] +@@ -251,24 +265,30 @@ write -P0xea 0x3fe0000 64k + "bitmaps": { + "drive0": [ + { ++ "busy": false, + "count": 393216, + "granularity": 65536, + "name": "bitmapC", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapB", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 458752, + "granularity": 65536, + "name": "bitmapA", + "persistent": false, ++ "recording": false, + "status": "disabled" + } + ] +@@ -311,31 +331,39 @@ write -P0xea 0x3fe0000 64k + "bitmaps": { + "drive0": [ + { ++ "busy": false, + "count": 458752, + "granularity": 65536, + "name": "bitmapD", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 393216, + "granularity": 65536, + "name": "bitmapC", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 262144, + "granularity": 65536, + "name": "bitmapB", + "persistent": false, ++ "recording": false, + "status": "disabled" + }, + { ++ "busy": false, + "count": 458752, + "granularity": 65536, + "name": "bitmapA", + "persistent": false, ++ "recording": false, + "status": "disabled" + } + ] +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-change-semantics-of-enabled-predi.patch b/SOURCES/kvm-block-dirty-bitmap-change-semantics-of-enabled-predi.patch new file mode 100644 index 0000000..7ba1c31 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-change-semantics-of-enabled-predi.patch @@ -0,0 +1,114 @@ +From 7bcc4bb06fb8455874578fe3ad722600081e8d1c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:42 +0200 +Subject: [PATCH 137/163] block/dirty-bitmap: change semantics of enabled + predicate + +RH-Author: John Snow +Message-id: <20190403181857.9693-7-jsnow@redhat.com> +Patchwork-id: 85427 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/21] block/dirty-bitmap: change semantics of enabled predicate +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Currently, the enabled predicate means something like: +"the QAPI status of the bitmap is ACTIVE." +After this patch, it should mean exclusively: +"This bitmap is recording guest writes, and is allowed to do so." + +In many places, this is how this predicate was already used. +Internal usages of the bitmap QPI can call user_locked to find out if +the bitmap is in use by an operation. + +To accommodate this, modify the create_successor routine to now +explicitly disable the parent bitmap at creation time. + +Justifications: + +1. bdrv_dirty_bitmap_status suffers no change from the lack of + 1:1 parity with the new predicates because of the order in which + the predicates are checked. This is now only for compatibility. + +2. bdrv_set_dirty() is unchanged: pre-patch, it was skipping bitmaps that were + disabled or had a successor, while post-patch it is only skipping bitmaps + that are disabled. To accommodate this, create_successor now ensures that + any bitmap with a successor is explicitly disabled. + +3. qcow2_store_persistent_dirty_bitmaps: No functional change. This function + cares only about the literal enabled bit, and makes no effort to check if + the bitmap is in-use or not. After this patch there are still no ways to + produce an enabled bitmap with a successor. + +4. block_dirty_bitmap_enable_prepare + block_dirty_bitmap_disable_prepare + init_dirty_bitmap_migration + nbd_export_new + + These functions care about the literal enabled bit, + and already check user_locked separately. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-5-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 8b2e20f64f25a5bf9a7cd45b4babdf2d7416f7ad) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 7dc5b55..fa411f9 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -209,7 +209,7 @@ bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap) + /* Called with BQL taken. */ + bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) + { +- return !(bitmap->disabled || bitmap->successor); ++ return !bitmap->disabled; + } + + /* Called with BQL taken. */ +@@ -236,6 +236,7 @@ static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap) + /** + * Create a successor bitmap destined to replace this bitmap after an operation. + * Requires that the bitmap is not user_locked and has no successor. ++ * The successor will be enabled if the parent bitmap was. + * Called with BQL taken. + */ + int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, +@@ -264,6 +265,7 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + + /* Successor will be on or off based on our current state. */ + child->disabled = bitmap->disabled; ++ bitmap->disabled = true; + + /* Install the successor and freeze the parent */ + bitmap->successor = child; +@@ -329,7 +331,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, + /** + * In cases of failure where we can no longer safely delete the parent, + * we may wish to re-join the parent and child/successor. +- * The merged parent will not be user_locked, nor explicitly re-enabled. ++ * The merged parent will not be user_locked. ++ * The marged parent will be enabled if and only if the successor was enabled. + * Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken. + */ + BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, +@@ -347,6 +350,8 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + error_setg(errp, "Merging of parent and successor bitmap failed"); + return NULL; + } ++ ++ parent->disabled = successor->disabled; + bdrv_release_dirty_bitmap_locked(successor); + parent->successor = NULL; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-explicitly-lock-bitmaps-with-succ.patch b/SOURCES/kvm-block-dirty-bitmap-explicitly-lock-bitmaps-with-succ.patch new file mode 100644 index 0000000..2e7672e --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-explicitly-lock-bitmaps-with-succ.patch @@ -0,0 +1,86 @@ +From dec8a19c9a45f060a9f20556672edeb61ecb6685 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:44 +0200 +Subject: [PATCH 139/163] block/dirty-bitmap: explicitly lock bitmaps with + successors + +RH-Author: John Snow +Message-id: <20190403181857.9693-9-jsnow@redhat.com> +Patchwork-id: 85410 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/21] block/dirty-bitmap: explicitly lock bitmaps with successors +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Instead of implying a user_locked/busy status, make it explicit. +Now, bitmaps in use by migration, NBD or backup operations +are all treated the same way with the same code paths. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-7-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 21d2376f264bcaa1692bd71ab1f99b9b0ff5afbf) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index fa411f9..a495178 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -50,7 +50,7 @@ struct BdrvDirtyBitmap { + HBitmap *meta; /* Meta dirty bitmap */ + bool qmp_locked; /* Bitmap is locked, it can't be modified + through QMP */ +- BdrvDirtyBitmap *successor; /* Anonymous child; implies user_locked state */ ++ BdrvDirtyBitmap *successor; /* Anonymous child, if any. */ + char *name; /* Optional non-empty unique ID */ + int64_t size; /* Size of the bitmap, in bytes */ + bool disabled; /* Bitmap is disabled. It ignores all writes to +@@ -188,10 +188,8 @@ bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap) + return bitmap->successor; + } + +-/* Both conditions disallow user-modification via QMP. */ + bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap) { +- return bdrv_dirty_bitmap_has_successor(bitmap) || +- bdrv_dirty_bitmap_qmp_locked(bitmap); ++ return bdrv_dirty_bitmap_qmp_locked(bitmap); + } + + void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked) +@@ -267,8 +265,9 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + child->disabled = bitmap->disabled; + bitmap->disabled = true; + +- /* Install the successor and freeze the parent */ ++ /* Install the successor and lock the parent */ + bitmap->successor = child; ++ bitmap->qmp_locked = true; + return 0; + } + +@@ -323,6 +322,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, + bitmap->successor = NULL; + successor->persistent = bitmap->persistent; + bitmap->persistent = false; ++ bitmap->qmp_locked = false; + bdrv_release_dirty_bitmap(bs, bitmap); + + return successor; +@@ -352,6 +352,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + } + + parent->disabled = successor->disabled; ++ parent->qmp_locked = false; + bdrv_release_dirty_bitmap_locked(successor); + parent->successor = NULL; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-remove-assertion-from-restore.patch b/SOURCES/kvm-block-dirty-bitmap-remove-assertion-from-restore.patch new file mode 100644 index 0000000..237ea7f --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-remove-assertion-from-restore.patch @@ -0,0 +1,49 @@ +From 03544f6a149a35f62d97106fd5320f8b53cbc085 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Thu, 24 Jan 2019 00:55:11 +0100 +Subject: [PATCH 6/8] block/dirty-bitmap: remove assertion from restore + +RH-Author: John Snow +Message-id: <20190124005511.27662-3-jsnow@redhat.com> +Patchwork-id: 84104 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/2] block/dirty-bitmap: remove assertion from restore +Bugzilla: 1658426 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Eric Blake + +When making a backup of a dirty bitmap (for transactions), we want to +restore that backup whether or not the bitmap is enabled. + +It is perfectly valid to write into bitmaps that are disabled. It is +only illegitimate for the guest to have done so. + +Remove this assertion. + +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +Message-Id: <20181221093529.23855-3-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 07d5a8df6a0018d831baef6d50f53f31a06b5a60) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index f580c1a..bc662d3 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -610,7 +610,6 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) + void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in) + { + HBitmap *tmp = bitmap->bitmap; +- assert(bdrv_dirty_bitmap_enabled(bitmap)); + assert(!bdrv_dirty_bitmap_readonly(bitmap)); + bitmap->bitmap = in; + hbitmap_free(tmp); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-remove-set-reset-assertions-again.patch b/SOURCES/kvm-block-dirty-bitmap-remove-set-reset-assertions-again.patch new file mode 100644 index 0000000..cc3994a --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-remove-set-reset-assertions-again.patch @@ -0,0 +1,60 @@ +From f969846f7376f6e33b3af86c498a51cb29ca0cca Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:41 +0200 +Subject: [PATCH 136/163] block/dirty-bitmap: remove set/reset assertions + against enabled bit + +RH-Author: John Snow +Message-id: <20190403181857.9693-6-jsnow@redhat.com> +Patchwork-id: 85426 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/21] block/dirty-bitmap: remove set/reset assertions against enabled bit +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +bdrv_set_dirty_bitmap and bdrv_reset_dirty_bitmap are only used as an +internal API by the mirror and migration areas of our code. These +calls modify the bitmap, but do so at the behest of QEMU and not the +guest. + +Presently, these bitmaps are always "enabled" anyway, but there's no +reason they have to be. + +Modify these internal APIs to drop this assertion. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-4-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit c28ddbb07ef39d79a81941d97faa1a1bb1ce2249) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index f8984b8..7dc5b55 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -544,7 +544,6 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter) + void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t offset, int64_t bytes) + { +- assert(bdrv_dirty_bitmap_enabled(bitmap)); + assert(!bdrv_dirty_bitmap_readonly(bitmap)); + hbitmap_set(bitmap->bitmap, offset, bytes); + } +@@ -561,7 +560,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap, + void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, + int64_t offset, int64_t bytes) + { +- assert(bdrv_dirty_bitmap_enabled(bitmap)); + assert(!bdrv_dirty_bitmap_readonly(bitmap)); + hbitmap_reset(bitmap->bitmap, offset, bytes); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-add-block_dirty_bitmap_check-fun.patch b/SOURCES/kvm-block-dirty-bitmaps-add-block_dirty_bitmap_check-fun.patch new file mode 100644 index 0000000..647b3d1 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-add-block_dirty_bitmap_check-fun.patch @@ -0,0 +1,324 @@ +From ac4ba4bb4b2118dab2e7f0b7c7e3daec3698d060 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:51 +0200 +Subject: [PATCH 146/163] block/dirty-bitmaps: add block_dirty_bitmap_check + function + +RH-Author: John Snow +Message-id: <20190403181857.9693-16-jsnow@redhat.com> +Patchwork-id: 85429 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 15/21] block/dirty-bitmaps: add block_dirty_bitmap_check function +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Instead of checking against busy, inconsistent, or read only directly, +use a check function with permissions bits that let us streamline the +checks without reproducing them in many places. + +Included in this patch are permissions changes that simply add the +inconsistent check to existing permissions call spots, without +addressing existing bugs. + +In general, this means that busy+readonly checks become BDRV_BITMAP_DEFAULT, +which checks against all three conditions. busy-only checks become +BDRV_BITMAP_ALLOW_RO. + +Notably, remove allows inconsistent bitmaps, so it doesn't follow the pattern. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190301191545.8728-4-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 3ae96d66840f72ef54902d012dbdf87ef4e9fe0c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 42 +++++++++++++++++++++++++----------- + blockdev.c | 49 ++++++++---------------------------------- + include/block/dirty-bitmap.h | 13 ++++++++++- + migration/block-dirty-bitmap.c | 13 ++++------- + nbd/server.c | 3 +-- + 5 files changed, 56 insertions(+), 64 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 4a2349d..6170f3a 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -174,7 +174,7 @@ bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap) + return bitmap->successor; + } + +-bool bdrv_dirty_bitmap_busy(BdrvDirtyBitmap *bitmap) ++static bool bdrv_dirty_bitmap_busy(const BdrvDirtyBitmap *bitmap) + { + return bitmap->busy; + } +@@ -236,6 +236,33 @@ static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap) + !bitmap->successor->disabled); + } + ++int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags, ++ Error **errp) ++{ ++ if ((flags & BDRV_BITMAP_BUSY) && bdrv_dirty_bitmap_busy(bitmap)) { ++ error_setg(errp, "Bitmap '%s' is currently in use by another" ++ " operation and cannot be used", bitmap->name); ++ return -1; ++ } ++ ++ if ((flags & BDRV_BITMAP_RO) && bdrv_dirty_bitmap_readonly(bitmap)) { ++ error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", ++ bitmap->name); ++ return -1; ++ } ++ ++ if ((flags & BDRV_BITMAP_INCONSISTENT) && ++ bdrv_dirty_bitmap_inconsistent(bitmap)) { ++ error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used", ++ bitmap->name); ++ error_append_hint(errp, "Try block-dirty-bitmap-remove to delete" ++ " this bitmap from disk"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + /** + * Create a successor bitmap destined to replace this bitmap after an operation. + * Requires that the bitmap is not marked busy and has no successor. +@@ -248,9 +275,7 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + uint64_t granularity; + BdrvDirtyBitmap *child; + +- if (bdrv_dirty_bitmap_busy(bitmap)) { +- error_setg(errp, "Cannot create a successor for a bitmap that is " +- "in-use by an operation"); ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY, errp)) { + return -1; + } + if (bdrv_dirty_bitmap_has_successor(bitmap)) { +@@ -796,17 +821,10 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + + qemu_mutex_lock(dest->mutex); + +- if (bdrv_dirty_bitmap_busy(dest)) { +- error_setg(errp, "Bitmap '%s' is currently in use by another" +- " operation and cannot be modified", dest->name); ++ if (bdrv_dirty_bitmap_check(dest, BDRV_BITMAP_DEFAULT, errp)) { + goto out; + } + +- if (bdrv_dirty_bitmap_readonly(dest)) { +- error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", +- dest->name); +- goto out; +- } + + if (!hbitmap_can_merge(dest->bitmap, src->bitmap)) { + error_setg(errp, "Bitmaps are incompatible and can't be merged"); +diff --git a/blockdev.c b/blockdev.c +index a9e2e1d..860cea6 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2160,11 +2160,7 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_busy(state->bitmap)) { +- error_setg(errp, "Cannot modify a bitmap in use by another operation"); +- return; +- } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) { +- error_setg(errp, "Cannot clear a readonly bitmap"); ++ if (bdrv_dirty_bitmap_check(state->bitmap, BDRV_BITMAP_DEFAULT, errp)) { + return; + } + +@@ -2209,10 +2205,7 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_busy(state->bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be enabled", action->name); ++ if (bdrv_dirty_bitmap_check(state->bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } + +@@ -2250,10 +2243,7 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_busy(state->bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be disabled", action->name); ++ if (bdrv_dirty_bitmap_check(state->bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } + +@@ -3044,10 +3034,7 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_busy(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation and" +- " cannot be removed", name); ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY, errp)) { + return; + } + +@@ -3083,13 +3070,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_busy(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be cleared", name); +- return; +- } else if (bdrv_dirty_bitmap_readonly(bitmap)) { +- error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name); ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { + return; + } + +@@ -3107,10 +3088,7 @@ void qmp_block_dirty_bitmap_enable(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_busy(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be enabled", name); ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } + +@@ -3128,10 +3106,7 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_busy(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be disabled", name); ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { + return; + } + +@@ -3709,10 +3684,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + bdrv_unref(target_bs); + goto out; + } +- if (bdrv_dirty_bitmap_busy(bmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be used for backup", backup->bitmap); ++ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) { + goto out; + } + } +@@ -3816,10 +3788,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); + goto out; + } +- if (bdrv_dirty_bitmap_busy(bmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently in use by another operation" +- " and cannot be used for backup", backup->bitmap); ++ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) { + goto out; + } + } +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index bd1b647..2a78243 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -5,6 +5,16 @@ + #include "qapi/qapi-types-block-core.h" + #include "qemu/hbitmap.h" + ++typedef enum BitmapCheckFlags { ++ BDRV_BITMAP_BUSY = 1, ++ BDRV_BITMAP_RO = 2, ++ BDRV_BITMAP_INCONSISTENT = 4, ++} BitmapCheckFlags; ++ ++#define BDRV_BITMAP_DEFAULT (BDRV_BITMAP_BUSY | BDRV_BITMAP_RO | \ ++ BDRV_BITMAP_INCONSISTENT) ++#define BDRV_BITMAP_ALLOW_RO (BDRV_BITMAP_BUSY | BDRV_BITMAP_INCONSISTENT) ++ + BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, + uint32_t granularity, + const char *name, +@@ -24,6 +34,8 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs, + void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap); + BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, + const char *name); ++int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags, ++ Error **errp); + void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); + void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); + void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, +@@ -93,7 +105,6 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); + bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap); +-bool bdrv_dirty_bitmap_busy(BdrvDirtyBitmap *bitmap); + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); + BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 62f2806..06ab58d 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -274,6 +274,7 @@ static int init_dirty_bitmap_migration(void) + BdrvDirtyBitmap *bitmap; + DirtyBitmapMigBitmapState *dbms; + BdrvNextIterator it; ++ Error *local_err = NULL; + + dirty_bitmap_mig_state.bulk_completed = false; + dirty_bitmap_mig_state.prev_bs = NULL; +@@ -301,15 +302,9 @@ static int init_dirty_bitmap_migration(void) + goto fail; + } + +- if (bdrv_dirty_bitmap_busy(bitmap)) { +- error_report("Can't migrate a bitmap that is in use by another operation: '%s'", +- bdrv_dirty_bitmap_name(bitmap)); +- goto fail; +- } +- +- if (bdrv_dirty_bitmap_readonly(bitmap)) { +- error_report("Can't migrate read-only dirty bitmap: '%s", +- bdrv_dirty_bitmap_name(bitmap)); ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, ++ &local_err)) { ++ error_report_err(local_err); + goto fail; + } + +diff --git a/nbd/server.c b/nbd/server.c +index 02773e2..9b87c7f 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1510,8 +1510,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + goto fail; + } + +- if (bdrv_dirty_bitmap_busy(bm)) { +- error_setg(errp, "Bitmap '%s' is in use", bitmap); ++ if (bdrv_dirty_bitmap_check(bm, BDRV_BITMAP_ALLOW_RO, errp)) { + goto fail; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-add-inconsistent-bit.patch b/SOURCES/kvm-block-dirty-bitmaps-add-inconsistent-bit.patch new file mode 100644 index 0000000..1eababd --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-add-inconsistent-bit.patch @@ -0,0 +1,136 @@ +From a955ea9fa72ac1a0e21b66d0958e582fbbc3f716 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:49 +0200 +Subject: [PATCH 144/163] block/dirty-bitmaps: add inconsistent bit + +RH-Author: John Snow +Message-id: <20190403181857.9693-14-jsnow@redhat.com> +Patchwork-id: 85419 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/21] block/dirty-bitmaps: add inconsistent bit +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Add an inconsistent bit to dirty-bitmaps that allows us to report a bitmap as +persistent but potentially inconsistent, i.e. if we find bitmaps on a qcow2 +that have been marked as "in use". + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190301191545.8728-2-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit b0f455599d0f092abc11aa3daba693be1453d29a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 20 ++++++++++++++++++++ + include/block/dirty-bitmap.h | 2 ++ + qapi/block-core.json | 13 +++++++++---- + 3 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index e090237..096c1b7 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -46,6 +46,9 @@ struct BdrvDirtyBitmap { + and this bitmap must remain unchanged while + this flag is set. */ + bool persistent; /* bitmap must be saved to owner disk image */ ++ bool inconsistent; /* bitmap is persistent, but inconsistent. ++ It cannot be used at all in any way, except ++ a QMP user can remove it. */ + bool migration; /* Bitmap is selected for migration, it should + not be stored on the next inactivation + (persistent flag doesn't matter until next +@@ -465,6 +468,8 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) + info->recording = bdrv_dirty_bitmap_recording(bm); + info->busy = bdrv_dirty_bitmap_busy(bm); + info->persistent = bm->persistent; ++ info->has_inconsistent = bm->inconsistent; ++ info->inconsistent = bm->inconsistent; + entry->value = info; + *plist = entry; + plist = &entry->next; +@@ -713,6 +718,16 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent) + } + + /* Called with BQL taken. */ ++void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap) ++{ ++ qemu_mutex_lock(bitmap->mutex); ++ assert(bitmap->persistent == true); ++ bitmap->inconsistent = true; ++ bitmap->disabled = true; ++ qemu_mutex_unlock(bitmap->mutex); ++} ++ ++/* Called with BQL taken. */ + void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration) + { + qemu_mutex_lock(bitmap->mutex); +@@ -725,6 +740,11 @@ bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap) + return bitmap->persistent && !bitmap->migration; + } + ++bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap) ++{ ++ return bitmap->inconsistent; ++} ++ + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs) + { + BdrvDirtyBitmap *bm; +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index ba8477b..bd1b647 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -68,6 +68,7 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); + void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); + void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, + bool persistent); ++void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap); + void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy); + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + HBitmap **backup, Error **errp); +@@ -91,6 +92,7 @@ bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); + bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); + bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); ++bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_busy(BdrvDirtyBitmap *bitmap); + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); + BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 98bd3a8..92a42ef 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -468,15 +468,20 @@ + # and cannot be modified via QMP or used by another operation. + # Replaces `locked` and `frozen` statuses. (since 4.0) + # +-# @persistent: true if the bitmap will eventually be flushed to persistent +-# storage (since 4.0) ++# @persistent: true if the bitmap was stored on disk, is scheduled to be stored ++# on disk, or both. (since 4.0) ++# ++# @inconsistent: true if this is a persistent bitmap that was improperly ++# stored. Implies @persistent to be true; @recording and ++# @busy to be false. This bitmap cannot be used. To remove ++# it, use @block-dirty-bitmap-remove. (Since 4.0) + # + # Since: 1.3 + ## + { 'struct': 'BlockDirtyInfo', + 'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32', +- 'recording': 'bool', 'busy': 'bool', +- 'status': 'DirtyBitmapStatus', 'persistent': 'bool' } } ++ 'recording': 'bool', 'busy': 'bool', 'status': 'DirtyBitmapStatus', ++ 'persistent': 'bool', '*inconsistent': 'bool' } } + + ## + # @Qcow2BitmapInfoFlags: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-add-user_locked-status-checker.patch b/SOURCES/kvm-block-dirty-bitmaps-add-user_locked-status-checker.patch new file mode 100644 index 0000000..f9a9a4b --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-add-user_locked-status-checker.patch @@ -0,0 +1,148 @@ +From 489118db0f6952e55e05792d9ee53ecd80ef08ea Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:31 +0100 +Subject: [PATCH 21/33] block/dirty-bitmaps: add user_locked status checker + +RH-Author: John Snow +Message-id: <20190206221243.7407-12-jsnow@redhat.com> +Patchwork-id: 84272 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 11/23] block/dirty-bitmaps: add user_locked status checker +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +Instead of both frozen and qmp_locked checks, wrap it into one check. +frozen implies the bitmap is split in two (for backup), and shouldn't +be modified. qmp_locked implies it's being used by another operation, +like being exported over NBD. In both cases it means we shouldn't allow +the user to modify it in any meaningful way. + +Replace any usages where we check both frozen and qmp_locked with the +new check. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20181002230218.13949-2-jsnow@redhat.com +[w/edits Suggested-By: Vladimir Sementsov-Ogievskiy ] +Signed-off-by: John Snow +(cherry picked from commit 993edc0ce0c6f44deb8272a7a857e419417f5f84) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 6 ++++++ + blockdev.c | 29 ++++++++--------------------- + include/block/dirty-bitmap.h | 1 + + migration/block-dirty-bitmap.c | 10 ++-------- + 4 files changed, 17 insertions(+), 29 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index a9421cd..8cc7b71 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -176,6 +176,12 @@ bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap) + return bitmap->successor; + } + ++/* Both conditions disallow user-modification via QMP. */ ++bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap) { ++ return bdrv_dirty_bitmap_frozen(bitmap) || ++ bdrv_dirty_bitmap_qmp_locked(bitmap); ++} ++ + void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked) + { + qemu_mutex_lock(bitmap->mutex); +diff --git a/blockdev.c b/blockdev.c +index df0cbe2..6cf7654 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2161,11 +2161,8 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_frozen(state->bitmap)) { +- error_setg(errp, "Cannot modify a frozen bitmap"); +- return; +- } else if (bdrv_dirty_bitmap_qmp_locked(state->bitmap)) { +- error_setg(errp, "Cannot modify a locked bitmap"); ++ if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { ++ error_setg(errp, "Cannot modify a bitmap in use by another operation"); + return; + } else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) { + error_setg(errp, "Cannot clear a disabled bitmap"); +@@ -3034,15 +3031,10 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_frozen(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently frozen and cannot be removed", +- name); +- return; +- } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bitmap)) { + error_setg(errp, +- "Bitmap '%s' is currently locked and cannot be removed", +- name); ++ "Bitmap '%s' is currently in use by another operation and" ++ " cannot be removed", name); + return; + } + +@@ -3072,15 +3064,10 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bitmap)) { + error_setg(errp, +- "Bitmap '%s' is currently frozen and cannot be modified", +- name); +- return; +- } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently locked and cannot be modified", +- name); ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be cleared", name); + return; + } else if (!bdrv_dirty_bitmap_enabled(bitmap)) { + error_setg(errp, +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 201ff7f..1463943 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -94,6 +94,7 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); + bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap); ++bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap); + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); + BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index fefbc6a..47251af 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -301,14 +301,8 @@ static int init_dirty_bitmap_migration(void) + goto fail; + } + +- if (bdrv_dirty_bitmap_frozen(bitmap)) { +- error_report("Can't migrate frozen dirty bitmap: '%s", +- bdrv_dirty_bitmap_name(bitmap)); +- goto fail; +- } +- +- if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { +- error_report("Can't migrate locked dirty bitmap: '%s", ++ if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ error_report("Can't migrate a bitmap that is in use by another operation: '%s'", + bdrv_dirty_bitmap_name(bitmap)); + goto fail; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-allow-clear-on-disabled-bitmaps.patch b/SOURCES/kvm-block-dirty-bitmaps-allow-clear-on-disabled-bitmaps.patch new file mode 100644 index 0000000..9c196c8 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-allow-clear-on-disabled-bitmaps.patch @@ -0,0 +1,72 @@ +From 2f1acc04e2744651329f4c9bf2de480923f63a41 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:33 +0100 +Subject: [PATCH 23/33] block/dirty-bitmaps: allow clear on disabled bitmaps + +RH-Author: John Snow +Message-id: <20190206221243.7407-14-jsnow@redhat.com> +Patchwork-id: 84266 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 13/23] block/dirty-bitmaps: allow clear on disabled bitmaps +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +Similarly to merge, it's OK to allow clear operations on disabled +bitmaps, as this condition only means that they are not recording +new writes. We are free to clear it if the user requests it. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20181002230218.13949-4-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 0be37c9e19f541643ef407bdafe0282b667ec23c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 1 - + blockdev.c | 8 -------- + 2 files changed, 9 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 8c7dc60..db8021a 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -625,7 +625,6 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, + + void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) + { +- assert(bdrv_dirty_bitmap_enabled(bitmap)); + assert(!bdrv_dirty_bitmap_readonly(bitmap)); + bdrv_dirty_bitmap_lock(bitmap); + if (!out) { +diff --git a/blockdev.c b/blockdev.c +index 6cf7654..7300f01 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2164,9 +2164,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, + if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { + error_setg(errp, "Cannot modify a bitmap in use by another operation"); + return; +- } else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) { +- error_setg(errp, "Cannot clear a disabled bitmap"); +- return; + } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) { + error_setg(errp, "Cannot clear a readonly bitmap"); + return; +@@ -3069,11 +3066,6 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + "Bitmap '%s' is currently in use by another operation" + " and cannot be cleared", name); + return; +- } else if (!bdrv_dirty_bitmap_enabled(bitmap)) { +- error_setg(errp, +- "Bitmap '%s' is currently disabled and cannot be cleared", +- name); +- return; + } else if (bdrv_dirty_bitmap_readonly(bitmap)) { + error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name); + return; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-disallow-busy-bitmaps-as-merge-s.patch b/SOURCES/kvm-block-dirty-bitmaps-disallow-busy-bitmaps-as-merge-s.patch new file mode 100644 index 0000000..7ff29a9 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-disallow-busy-bitmaps-as-merge-s.patch @@ -0,0 +1,49 @@ +From 971a623b5bb048b3ecf079f4a761d423388ea59c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:54 +0200 +Subject: [PATCH 149/163] block/dirty-bitmaps: disallow busy bitmaps as merge + source + +RH-Author: John Snow +Message-id: <20190403181857.9693-19-jsnow@redhat.com> +Patchwork-id: 85422 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 18/21] block/dirty-bitmaps: disallow busy bitmaps as merge source +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +We didn't do any state checking on source bitmaps at all, +so this adds inconsistent and busy checks. readonly is +allowed, so you can still copy a readonly bitmap to a new +destination to use it for operations like drive-backup. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190301191545.8728-7-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit cb8e58e3de1a0f39c60de272faa0133b98b02cb5) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 6170f3a..2139354 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -825,6 +825,9 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + goto out; + } + ++ if (bdrv_dirty_bitmap_check(src, BDRV_BITMAP_ALLOW_RO, errp)) { ++ goto out; ++ } + + if (!hbitmap_can_merge(dest->bitmap, src->bitmap)) { + error_setg(errp, "Bitmaps are incompatible and can't be merged"); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-fix-merge-permissions.patch b/SOURCES/kvm-block-dirty-bitmaps-fix-merge-permissions.patch new file mode 100644 index 0000000..f8a04e7 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-fix-merge-permissions.patch @@ -0,0 +1,53 @@ +From c215981d4abf69a7aaac79dbeea3e5c1ad2ac115 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:32 +0100 +Subject: [PATCH 22/33] block/dirty-bitmaps: fix merge permissions + +RH-Author: John Snow +Message-id: <20190206221243.7407-13-jsnow@redhat.com> +Patchwork-id: 84275 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 12/23] block/dirty-bitmaps: fix merge permissions +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +In prior commits that made merge transactionable, we removed the +assertion that merge cannot operate on disabled bitmaps. In addition, +we want to make sure that we are prohibiting merges to "locked" bitmaps. + +Use the new user_locked function to check. + +Reported-by: Eric Blake +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20181002230218.13949-3-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 283d7a04f2addcc51468635300208b60c19a0db3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 8cc7b71..8c7dc60 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -805,9 +805,9 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + + qemu_mutex_lock(dest->mutex); + +- if (bdrv_dirty_bitmap_frozen(dest)) { +- error_setg(errp, "Bitmap '%s' is frozen and cannot be modified", +- dest->name); ++ if (bdrv_dirty_bitmap_user_locked(dest)) { ++ error_setg(errp, "Bitmap '%s' is currently in use by another" ++ " operation and cannot be modified", dest->name); + goto out; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-implement-inconsistent-bit.patch b/SOURCES/kvm-block-dirty-bitmaps-implement-inconsistent-bit.patch new file mode 100644 index 0000000..b49b265 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-implement-inconsistent-bit.patch @@ -0,0 +1,196 @@ +From 9f251abbe1e79a790aaf3a3ca48de60deb0c2a10 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:55 +0200 +Subject: [PATCH 150/163] block/dirty-bitmaps: implement inconsistent bit + +RH-Author: John Snow +Message-id: <20190403181857.9693-20-jsnow@redhat.com> +Patchwork-id: 85428 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 19/21] block/dirty-bitmaps: implement inconsistent bit +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Set the inconsistent bit on load instead of rejecting such bitmaps. +There is no way to un-set it; the only option is to delete the bitmap. + +Obvervations: +- bitmap loading does not need to update the header for in_use bitmaps. +- inconsistent bitmaps don't need to have their data loaded; they're + glorified corruption sentinels. +- bitmap saving does not need to save inconsistent bitmaps back to disk. +- bitmap reopening DOES need to drop the readonly flag from inconsistent + bitmaps to allow reopening of qcow2 files with non-qemu-owned bitmaps + being eventually flushed back to disk. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20190301191545.8728-8-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 74da6b943565c451d275de1b0253546c5e729d20) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-bitmap.c | 99 +++++++++++++++++++++++++++------------------------- + 1 file changed, 51 insertions(+), 48 deletions(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index 4899719..cbab0e5 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -345,11 +345,17 @@ static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs, + uint32_t granularity; + BdrvDirtyBitmap *bitmap = NULL; + +- if (bm->flags & BME_FLAG_IN_USE) { +- error_setg(errp, "Bitmap '%s' is in use", bm->name); ++ granularity = 1U << bm->granularity_bits; ++ bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp); ++ if (bitmap == NULL) { + goto fail; + } + ++ if (bm->flags & BME_FLAG_IN_USE) { ++ /* Data is unusable, skip loading it */ ++ return bitmap; ++ } ++ + ret = bitmap_table_load(bs, &bm->table, &bitmap_table); + if (ret < 0) { + error_setg_errno(errp, -ret, +@@ -358,12 +364,6 @@ static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs, + goto fail; + } + +- granularity = 1U << bm->granularity_bits; +- bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp); +- if (bitmap == NULL) { +- goto fail; +- } +- + ret = load_bitmap_data(bs, bitmap_table, bm->table.size, bitmap); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image", +@@ -951,6 +951,7 @@ bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp) + Qcow2Bitmap *bm; + GSList *created_dirty_bitmaps = NULL; + bool header_updated = false; ++ bool needs_update = false; + + if (s->nb_bitmaps == 0) { + /* No bitmaps - nothing to do */ +@@ -964,35 +965,39 @@ bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp) + } + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { +- if (!(bm->flags & BME_FLAG_IN_USE)) { +- BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp); +- if (bitmap == NULL) { +- goto fail; +- } ++ BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp); ++ if (bitmap == NULL) { ++ goto fail; ++ } + +- if (!(bm->flags & BME_FLAG_AUTO)) { +- bdrv_disable_dirty_bitmap(bitmap); +- } +- bdrv_dirty_bitmap_set_persistance(bitmap, true); ++ bdrv_dirty_bitmap_set_persistance(bitmap, true); ++ if (bm->flags & BME_FLAG_IN_USE) { ++ bdrv_dirty_bitmap_set_inconsistent(bitmap); ++ } else { ++ /* NB: updated flags only get written if can_write(bs) is true. */ + bm->flags |= BME_FLAG_IN_USE; +- created_dirty_bitmaps = +- g_slist_append(created_dirty_bitmaps, bitmap); ++ needs_update = true; + } ++ if (!(bm->flags & BME_FLAG_AUTO)) { ++ bdrv_disable_dirty_bitmap(bitmap); ++ } ++ created_dirty_bitmaps = ++ g_slist_append(created_dirty_bitmaps, bitmap); + } + +- if (created_dirty_bitmaps != NULL) { +- if (can_write(bs)) { +- /* in_use flags must be updated */ +- int ret = update_ext_header_and_dir_in_place(bs, bm_list); +- if (ret < 0) { +- error_setg_errno(errp, -ret, "Can't update bitmap directory"); +- goto fail; +- } +- header_updated = true; +- } else { +- g_slist_foreach(created_dirty_bitmaps, set_readonly_helper, +- (gpointer)true); ++ if (needs_update && can_write(bs)) { ++ /* in_use flags must be updated */ ++ int ret = update_ext_header_and_dir_in_place(bs, bm_list); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "Can't update bitmap directory"); ++ goto fail; + } ++ header_updated = true; ++ } ++ ++ if (!can_write(bs)) { ++ g_slist_foreach(created_dirty_bitmaps, set_readonly_helper, ++ (gpointer)true); + } + + g_slist_free(created_dirty_bitmaps); +@@ -1114,23 +1119,21 @@ int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + } + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { +- if (!(bm->flags & BME_FLAG_IN_USE)) { +- BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name); +- if (bitmap == NULL) { +- continue; +- } +- +- if (!bdrv_dirty_bitmap_readonly(bitmap)) { +- error_setg(errp, "Bitmap %s is not readonly but not marked" +- "'IN_USE' in the image. Something went wrong," +- "all the bitmaps may be corrupted", bm->name); +- ret = -EINVAL; +- goto out; +- } ++ BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name); ++ if (bitmap == NULL) { ++ continue; ++ } + +- bm->flags |= BME_FLAG_IN_USE; +- ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap); ++ if (!bdrv_dirty_bitmap_readonly(bitmap)) { ++ error_setg(errp, "Bitmap %s was loaded prior to rw-reopen, but was " ++ "not marked as readonly. This is a bug, something went " ++ "wrong. All of the bitmaps may be corrupted", bm->name); ++ ret = -EINVAL; ++ goto out; + } ++ ++ bm->flags |= BME_FLAG_IN_USE; ++ ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap); + } + + if (ro_dirty_bitmaps != NULL) { +@@ -1426,8 +1429,8 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) + Qcow2Bitmap *bm; + + if (!bdrv_dirty_bitmap_get_persistance(bitmap) || +- bdrv_dirty_bitmap_readonly(bitmap)) +- { ++ bdrv_dirty_bitmap_readonly(bitmap) || ++ bdrv_dirty_bitmap_inconsistent(bitmap)) { + continue; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-move-comment-block.patch b/SOURCES/kvm-block-dirty-bitmaps-move-comment-block.patch new file mode 100644 index 0000000..1077438 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-move-comment-block.patch @@ -0,0 +1,87 @@ +From 4123b978727d577491f84dde507f841c23b6caa4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:46 +0200 +Subject: [PATCH 141/163] block/dirty-bitmaps: move comment block + +RH-Author: John Snow +Message-id: <20190403181857.9693-11-jsnow@redhat.com> +Patchwork-id: 85415 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/21] block/dirty-bitmaps: move comment block +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Simply move the big status enum comment block to above the status +function, and document it as being deprecated. The whole confusing +block can get deleted in three releases time. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-9-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 1e6fddcd6f2d3b6b8c7584004763b376334a8457) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 36 +++++++++++++++++++----------------- + 1 file changed, 19 insertions(+), 17 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 89c9665..e090237 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -28,22 +28,6 @@ + #include "block/block_int.h" + #include "block/blockjob.h" + +-/** +- * A BdrvDirtyBitmap can be in four possible user-visible states: +- * (1) Active: successor is NULL, and disabled is false: full r/w mode +- * (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode, +- * guest writes are dropped, but monitor writes are possible, +- * through commands like merge and clear. +- * (3) Frozen: successor is not NULL. +- * A frozen bitmap cannot be renamed, deleted, cleared, set, +- * enabled, merged to, etc. A frozen bitmap can only abdicate() +- * or reclaim(). +- * In this state, the anonymous successor bitmap may be either +- * Active and recording writes from the guest (e.g. backup jobs), +- * but it can be Disabled and not recording writes. +- * (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap +- * in any way from the monitor. +- */ + struct BdrvDirtyBitmap { + QemuMutex *mutex; + HBitmap *bitmap; /* Dirty bitmap implementation */ +@@ -205,7 +189,25 @@ bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) + return !bitmap->disabled; + } + +-/* Called with BQL taken. */ ++/** ++ * bdrv_dirty_bitmap_status: This API is now deprecated. ++ * Called with BQL taken. ++ * ++ * A BdrvDirtyBitmap can be in four possible user-visible states: ++ * (1) Active: successor is NULL, and disabled is false: full r/w mode ++ * (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode, ++ * guest writes are dropped, but monitor writes are possible, ++ * through commands like merge and clear. ++ * (3) Frozen: successor is not NULL. ++ * A frozen bitmap cannot be renamed, deleted, cleared, set, ++ * enabled, merged to, etc. A frozen bitmap can only abdicate() ++ * or reclaim(). ++ * In this state, the anonymous successor bitmap may be either ++ * Active and recording writes from the guest (e.g. backup jobs), ++ * or it can be Disabled and not recording writes. ++ * (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap ++ * in any way from the monitor. ++ */ + DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) + { + if (bdrv_dirty_bitmap_has_successor(bitmap)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-prohibit-enable-disable-on-locke.patch b/SOURCES/kvm-block-dirty-bitmaps-prohibit-enable-disable-on-locke.patch new file mode 100644 index 0000000..767aa65 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-prohibit-enable-disable-on-locke.patch @@ -0,0 +1,93 @@ +From 6f65d2a9ee0258869d7420b2cf1b3890c7fcfef0 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:34 +0100 +Subject: [PATCH 24/33] block/dirty-bitmaps: prohibit enable/disable on + locked/frozen bitmaps + +RH-Author: John Snow +Message-id: <20190206221243.7407-15-jsnow@redhat.com> +Patchwork-id: 84264 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 14/23] block/dirty-bitmaps: prohibit enable/disable on locked/frozen bitmaps +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +We're not being consistent about this. If it's in use by an operation, +the user should not be able to change the behavior of that bitmap. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20181002230218.13949-5-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit b053bb55738f35832f3d6472b12277a75c32a038) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 7300f01..9921de6 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2210,6 +2210,13 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common, + return; + } + ++ if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { ++ error_setg(errp, ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be enabled", action->name); ++ return; ++ } ++ + state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); + bdrv_enable_dirty_bitmap(state->bitmap); + } +@@ -2244,6 +2251,13 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common, + return; + } + ++ if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { ++ error_setg(errp, ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be disabled", action->name); ++ return; ++ } ++ + state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); + bdrv_disable_dirty_bitmap(state->bitmap); + } +@@ -3085,10 +3099,10 @@ void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bitmap)) { + error_setg(errp, +- "Bitmap '%s' is currently frozen and cannot be enabled", +- name); ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be enabled", name); + return; + } + +@@ -3106,10 +3120,10 @@ void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bitmap)) { + error_setg(errp, +- "Bitmap '%s' is currently frozen and cannot be disabled", +- name); ++ "Bitmap '%s' is currently in use by another operation" ++ " and cannot be disabled", name); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-prohibit-readonly-bitmaps-for-ba.patch b/SOURCES/kvm-block-dirty-bitmaps-prohibit-readonly-bitmaps-for-ba.patch new file mode 100644 index 0000000..b0d7ff2 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-prohibit-readonly-bitmaps-for-ba.patch @@ -0,0 +1,57 @@ +From 259fa803d7b12cda535e1c115e3757bc58131acf Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:52 +0200 +Subject: [PATCH 147/163] block/dirty-bitmaps: prohibit readonly bitmaps for + backups + +RH-Author: John Snow +Message-id: <20190403181857.9693-17-jsnow@redhat.com> +Patchwork-id: 85418 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 16/21] block/dirty-bitmaps: prohibit readonly bitmaps for backups +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +drive and blockdev backup cannot use readonly bitmaps, because the +sync=incremental mechanism actually edits the bitmaps on success. + +If you really want to do this operation, use a copied bitmap. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190301191545.8728-5-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit a54a0c113b333aee49e484758fab7f1f1c593dd3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 860cea6..de8a2bf 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3684,7 +3684,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + bdrv_unref(target_bs); + goto out; + } +- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) { ++ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { + goto out; + } + } +@@ -3788,7 +3788,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); + goto out; + } +- if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_ALLOW_RO, errp)) { ++ if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { + goto out; + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-prohibit-removing-readonly-bitma.patch b/SOURCES/kvm-block-dirty-bitmaps-prohibit-removing-readonly-bitma.patch new file mode 100644 index 0000000..87b3abd --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-prohibit-removing-readonly-bitma.patch @@ -0,0 +1,47 @@ +From 87a49b51dcddd2f779fbc387d83f182870fdcaa8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:53 +0200 +Subject: [PATCH 148/163] block/dirty-bitmaps: prohibit removing readonly + bitmaps + +RH-Author: John Snow +Message-id: <20190403181857.9693-18-jsnow@redhat.com> +Patchwork-id: 85413 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 17/21] block/dirty-bitmaps: prohibit removing readonly bitmaps +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Remove is an inherently RW operation, so this will fail anyway, but +we can fail it very quickly instead of trying and failing, so do so. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190301191545.8728-6-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit c3edf13cd1efdb5a59e0ae4f15e63080ffb35525) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index de8a2bf..e497939 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3034,7 +3034,8 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY, errp)) { ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO, ++ errp)) { + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-rename-frozen-predicate-helper.patch b/SOURCES/kvm-block-dirty-bitmaps-rename-frozen-predicate-helper.patch new file mode 100644 index 0000000..f37ea88 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-rename-frozen-predicate-helper.patch @@ -0,0 +1,196 @@ +From 1e53f224150ad795131e8ea93605979de0e3c40c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:40 +0200 +Subject: [PATCH 135/163] block/dirty-bitmaps: rename frozen predicate helper + +RH-Author: John Snow +Message-id: <20190403181857.9693-5-jsnow@redhat.com> +Patchwork-id: 85421 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/21] block/dirty-bitmaps: rename frozen predicate helper +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +"Frozen" was a good description a long time ago, but it isn't adequate now. +Rename the frozen predicate to has_successor to make the semantics of the +predicate more clear to outside callers. + +In the process, remove some calls to frozen() that no longer semantically +make sense. For bdrv_enable_dirty_bitmap_locked and +bdrv_disable_dirty_bitmap_locked, it doesn't make sense to prohibit QEMU +internals from performing this action when we only wished to prohibit QMP +users from issuing these commands. All of the QMP API commands for bitmap +manipulation already check against user_locked() to prohibit these actions. + +Several other assertions really want to check that the bitmap isn't in-use +by another operation -- use the bitmap_user_locked function for this instead, +which presently also checks for has_successor. This leaves some redundant +checks of has_successor through different helpers that are addressed in +forthcoming patches. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-3-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 50a47257f8f1368ba08e4789bb63ca84c4306dde) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 32 ++++++++++++++++++-------------- + include/block/dirty-bitmap.h | 2 +- + migration/block-dirty-bitmap.c | 2 +- + 3 files changed, 20 insertions(+), 16 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 101383b..f8984b8 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -50,7 +50,7 @@ struct BdrvDirtyBitmap { + HBitmap *meta; /* Meta dirty bitmap */ + bool qmp_locked; /* Bitmap is locked, it can't be modified + through QMP */ +- BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */ ++ BdrvDirtyBitmap *successor; /* Anonymous child; implies user_locked state */ + char *name; /* Optional non-empty unique ID */ + int64_t size; /* Size of the bitmap, in bytes */ + bool disabled; /* Bitmap is disabled. It ignores all writes to +@@ -183,14 +183,14 @@ const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap) + } + + /* Called with BQL taken. */ +-bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap) ++bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap) + { + return bitmap->successor; + } + + /* Both conditions disallow user-modification via QMP. */ + bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap) { +- return bdrv_dirty_bitmap_frozen(bitmap) || ++ return bdrv_dirty_bitmap_has_successor(bitmap) || + bdrv_dirty_bitmap_qmp_locked(bitmap); + } + +@@ -215,7 +215,7 @@ bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) + /* Called with BQL taken. */ + DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) + { +- if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ if (bdrv_dirty_bitmap_has_successor(bitmap)) { + return DIRTY_BITMAP_STATUS_FROZEN; + } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { + return DIRTY_BITMAP_STATUS_LOCKED; +@@ -235,7 +235,7 @@ static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap) + + /** + * Create a successor bitmap destined to replace this bitmap after an operation. +- * Requires that the bitmap is not frozen and has no successor. ++ * Requires that the bitmap is not user_locked and has no successor. + * Called with BQL taken. + */ + int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, +@@ -244,12 +244,16 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + uint64_t granularity; + BdrvDirtyBitmap *child; + +- if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ if (bdrv_dirty_bitmap_user_locked(bitmap)) { + error_setg(errp, "Cannot create a successor for a bitmap that is " +- "currently frozen"); ++ "in-use by an operation"); ++ return -1; ++ } ++ if (bdrv_dirty_bitmap_has_successor(bitmap)) { ++ error_setg(errp, "Cannot create a successor for a bitmap that already " ++ "has one"); + return -1; + } +- assert(!bitmap->successor); + + /* Create an anonymous successor */ + granularity = bdrv_dirty_bitmap_granularity(bitmap); +@@ -268,7 +272,6 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + + void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) + { +- assert(!bdrv_dirty_bitmap_frozen(bitmap)); + bitmap->disabled = false; + } + +@@ -285,7 +288,8 @@ void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap) + static void bdrv_release_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) + { + assert(!bitmap->active_iterators); +- assert(!bdrv_dirty_bitmap_frozen(bitmap)); ++ assert(!bdrv_dirty_bitmap_user_locked(bitmap)); ++ assert(!bdrv_dirty_bitmap_has_successor(bitmap)); + assert(!bitmap->meta); + QLIST_REMOVE(bitmap, list); + hbitmap_free(bitmap->bitmap); +@@ -325,7 +329,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, + /** + * In cases of failure where we can no longer safely delete the parent, + * we may wish to re-join the parent and child/successor. +- * The merged parent will be un-frozen, but not explicitly re-enabled. ++ * The merged parent will not be user_locked, nor explicitly re-enabled. + * Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken. + */ + BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, +@@ -373,7 +377,8 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes) + + bdrv_dirty_bitmaps_lock(bs); + QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { +- assert(!bdrv_dirty_bitmap_frozen(bitmap)); ++ assert(!bdrv_dirty_bitmap_user_locked(bitmap)); ++ assert(!bdrv_dirty_bitmap_has_successor(bitmap)); + assert(!bitmap->active_iterators); + hbitmap_truncate(bitmap->bitmap, bytes); + bitmap->size = bytes; +@@ -391,7 +396,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) + + /** + * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()). +- * There must not be any frozen bitmaps attached. ++ * There must not be any user_locked bitmaps attached. + * This function does not remove persistent bitmaps from the storage. + * Called with BQL taken. + */ +@@ -428,7 +433,6 @@ void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, + void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) + { + bdrv_dirty_bitmap_lock(bitmap); +- assert(!bdrv_dirty_bitmap_frozen(bitmap)); + bitmap->disabled = true; + bdrv_dirty_bitmap_unlock(bitmap); + } +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 04a117f..cdbb4df 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -36,7 +36,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); + uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs); + uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap); +-bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap); ++bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap); + const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap); + int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap); + DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap); +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index ffe7aca..89b2a2f 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -542,7 +542,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DirtyBitmapLoadState *s) + } + } + +- if (bdrv_dirty_bitmap_frozen(s->bitmap)) { ++ if (bdrv_dirty_bitmap_has_successor(s->bitmap)) { + bdrv_dirty_bitmap_lock(s->bitmap); + if (enabled_bitmaps == NULL) { + /* in postcopy */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmaps-unify-qmp_locked-and-user_locked.patch b/SOURCES/kvm-block-dirty-bitmaps-unify-qmp_locked-and-user_locked.patch new file mode 100644 index 0000000..4191e41 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmaps-unify-qmp_locked-and-user_locked.patch @@ -0,0 +1,362 @@ +From dc1a43268c8f0859cce105a0025c3b7affc6d52c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:45 +0200 +Subject: [PATCH 140/163] block/dirty-bitmaps: unify qmp_locked and user_locked + calls + +RH-Author: John Snow +Message-id: <20190403181857.9693-10-jsnow@redhat.com> +Patchwork-id: 85417 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/21] block/dirty-bitmaps: unify qmp_locked and user_locked calls +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +These mean the same thing now. Unify them and rename the merged call +bdrv_dirty_bitmap_busy to indicate semantically what we are describing, +as well as help disambiguate from the various _locked and _unlocked +versions of bitmap helpers that refer to mutex locks. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-8-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 27a1b301a448a0426a96716484fc034b73c10c51) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 43 +++++++++++++++++++----------------------- + blockdev.c | 18 +++++++++--------- + include/block/dirty-bitmap.h | 5 ++--- + migration/block-dirty-bitmap.c | 6 +++--- + nbd/server.c | 6 +++--- + 5 files changed, 36 insertions(+), 42 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index a495178..89c9665 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -48,8 +48,7 @@ struct BdrvDirtyBitmap { + QemuMutex *mutex; + HBitmap *bitmap; /* Dirty bitmap implementation */ + HBitmap *meta; /* Meta dirty bitmap */ +- bool qmp_locked; /* Bitmap is locked, it can't be modified +- through QMP */ ++ bool busy; /* Bitmap is busy, it can't be used via QMP */ + BdrvDirtyBitmap *successor; /* Anonymous child, if any. */ + char *name; /* Optional non-empty unique ID */ + int64_t size; /* Size of the bitmap, in bytes */ +@@ -188,22 +187,18 @@ bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap) + return bitmap->successor; + } + +-bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap) { +- return bdrv_dirty_bitmap_qmp_locked(bitmap); ++bool bdrv_dirty_bitmap_busy(BdrvDirtyBitmap *bitmap) ++{ ++ return bitmap->busy; + } + +-void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked) ++void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy) + { + qemu_mutex_lock(bitmap->mutex); +- bitmap->qmp_locked = qmp_locked; ++ bitmap->busy = busy; + qemu_mutex_unlock(bitmap->mutex); + } + +-bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap) +-{ +- return bitmap->qmp_locked; +-} +- + /* Called with BQL taken. */ + bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) + { +@@ -215,7 +210,7 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) + { + if (bdrv_dirty_bitmap_has_successor(bitmap)) { + return DIRTY_BITMAP_STATUS_FROZEN; +- } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) { ++ } else if (bdrv_dirty_bitmap_busy(bitmap)) { + return DIRTY_BITMAP_STATUS_LOCKED; + } else if (!bdrv_dirty_bitmap_enabled(bitmap)) { + return DIRTY_BITMAP_STATUS_DISABLED; +@@ -233,7 +228,7 @@ static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap) + + /** + * Create a successor bitmap destined to replace this bitmap after an operation. +- * Requires that the bitmap is not user_locked and has no successor. ++ * Requires that the bitmap is not marked busy and has no successor. + * The successor will be enabled if the parent bitmap was. + * Called with BQL taken. + */ +@@ -243,7 +238,7 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + uint64_t granularity; + BdrvDirtyBitmap *child; + +- if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_busy(bitmap)) { + error_setg(errp, "Cannot create a successor for a bitmap that is " + "in-use by an operation"); + return -1; +@@ -265,9 +260,9 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + child->disabled = bitmap->disabled; + bitmap->disabled = true; + +- /* Install the successor and lock the parent */ ++ /* Install the successor and mark the parent as busy */ + bitmap->successor = child; +- bitmap->qmp_locked = true; ++ bitmap->busy = true; + return 0; + } + +@@ -289,7 +284,7 @@ void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap) + static void bdrv_release_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) + { + assert(!bitmap->active_iterators); +- assert(!bdrv_dirty_bitmap_user_locked(bitmap)); ++ assert(!bdrv_dirty_bitmap_busy(bitmap)); + assert(!bdrv_dirty_bitmap_has_successor(bitmap)); + assert(!bitmap->meta); + QLIST_REMOVE(bitmap, list); +@@ -322,7 +317,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, + bitmap->successor = NULL; + successor->persistent = bitmap->persistent; + bitmap->persistent = false; +- bitmap->qmp_locked = false; ++ bitmap->busy = false; + bdrv_release_dirty_bitmap(bs, bitmap); + + return successor; +@@ -331,7 +326,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, + /** + * In cases of failure where we can no longer safely delete the parent, + * we may wish to re-join the parent and child/successor. +- * The merged parent will not be user_locked. ++ * The merged parent will be marked as not busy. + * The marged parent will be enabled if and only if the successor was enabled. + * Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken. + */ +@@ -352,7 +347,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + } + + parent->disabled = successor->disabled; +- parent->qmp_locked = false; ++ parent->busy = false; + bdrv_release_dirty_bitmap_locked(successor); + parent->successor = NULL; + +@@ -383,7 +378,7 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes) + + bdrv_dirty_bitmaps_lock(bs); + QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { +- assert(!bdrv_dirty_bitmap_user_locked(bitmap)); ++ assert(!bdrv_dirty_bitmap_busy(bitmap)); + assert(!bdrv_dirty_bitmap_has_successor(bitmap)); + assert(!bitmap->active_iterators); + hbitmap_truncate(bitmap->bitmap, bytes); +@@ -402,7 +397,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) + + /** + * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()). +- * There must not be any user_locked bitmaps attached. ++ * There must not be any busy bitmaps attached. + * This function does not remove persistent bitmaps from the storage. + * Called with BQL taken. + */ +@@ -466,7 +461,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) + info->name = g_strdup(bm->name); + info->status = bdrv_dirty_bitmap_status(bm); + info->recording = bdrv_dirty_bitmap_recording(bm); +- info->busy = bdrv_dirty_bitmap_user_locked(bm); ++ info->busy = bdrv_dirty_bitmap_busy(bm); + info->persistent = bm->persistent; + entry->value = info; + *plist = entry; +@@ -774,7 +769,7 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + + qemu_mutex_lock(dest->mutex); + +- if (bdrv_dirty_bitmap_user_locked(dest)) { ++ if (bdrv_dirty_bitmap_busy(dest)) { + error_setg(errp, "Bitmap '%s' is currently in use by another" + " operation and cannot be modified", dest->name); + goto out; +diff --git a/blockdev.c b/blockdev.c +index f437896..c9ade12 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2161,7 +2161,7 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { ++ if (bdrv_dirty_bitmap_busy(state->bitmap)) { + error_setg(errp, "Cannot modify a bitmap in use by another operation"); + return; + } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) { +@@ -2210,7 +2210,7 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { ++ if (bdrv_dirty_bitmap_busy(state->bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be enabled", action->name); +@@ -2251,7 +2251,7 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(state->bitmap)) { ++ if (bdrv_dirty_bitmap_busy(state->bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be disabled", action->name); +@@ -3045,7 +3045,7 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_busy(bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation and" + " cannot be removed", name); +@@ -3084,7 +3084,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_busy(bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be cleared", name); +@@ -3108,7 +3108,7 @@ void qmp_block_dirty_bitmap_enable(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_busy(bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be enabled", name); +@@ -3129,7 +3129,7 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name, + return; + } + +- if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_busy(bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be disabled", name); +@@ -3710,7 +3710,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + bdrv_unref(target_bs); + goto out; + } +- if (bdrv_dirty_bitmap_user_locked(bmap)) { ++ if (bdrv_dirty_bitmap_busy(bmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be used for backup", backup->bitmap); +@@ -3817,7 +3817,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); + goto out; + } +- if (bdrv_dirty_bitmap_user_locked(bmap)) { ++ if (bdrv_dirty_bitmap_busy(bmap)) { + error_setg(errp, + "Bitmap '%s' is currently in use by another operation" + " and cannot be used for backup", backup->bitmap); +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index cdbb4df..ba8477b 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -68,7 +68,7 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); + void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); + void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, + bool persistent); +-void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked); ++void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy); + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + HBitmap **backup, Error **errp); + void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration); +@@ -91,8 +91,7 @@ bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap); + bool bdrv_has_readonly_bitmaps(BlockDriverState *bs); + bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap); + bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap); +-bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap); +-bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap); ++bool bdrv_dirty_bitmap_busy(BdrvDirtyBitmap *bitmap); + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); + BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 89b2a2f..62f2806 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -261,7 +261,7 @@ static void dirty_bitmap_mig_cleanup(void) + + while ((dbms = QSIMPLEQ_FIRST(&dirty_bitmap_mig_state.dbms_list)) != NULL) { + QSIMPLEQ_REMOVE_HEAD(&dirty_bitmap_mig_state.dbms_list, entry); +- bdrv_dirty_bitmap_set_qmp_locked(dbms->bitmap, false); ++ bdrv_dirty_bitmap_set_busy(dbms->bitmap, false); + bdrv_unref(dbms->bs); + g_free(dbms); + } +@@ -301,7 +301,7 @@ static int init_dirty_bitmap_migration(void) + goto fail; + } + +- if (bdrv_dirty_bitmap_user_locked(bitmap)) { ++ if (bdrv_dirty_bitmap_busy(bitmap)) { + error_report("Can't migrate a bitmap that is in use by another operation: '%s'", + bdrv_dirty_bitmap_name(bitmap)); + goto fail; +@@ -314,7 +314,7 @@ static int init_dirty_bitmap_migration(void) + } + + bdrv_ref(bs); +- bdrv_dirty_bitmap_set_qmp_locked(bitmap, true); ++ bdrv_dirty_bitmap_set_busy(bitmap, true); + + dbms = g_new0(DirtyBitmapMigBitmapState, 1); + dbms->bs = bs; +diff --git a/nbd/server.c b/nbd/server.c +index de21c64..02773e2 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1510,7 +1510,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + goto fail; + } + +- if (bdrv_dirty_bitmap_user_locked(bm)) { ++ if (bdrv_dirty_bitmap_busy(bm)) { + error_setg(errp, "Bitmap '%s' is in use", bitmap); + goto fail; + } +@@ -1523,7 +1523,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + goto fail; + } + +- bdrv_dirty_bitmap_set_qmp_locked(bm, true); ++ bdrv_dirty_bitmap_set_busy(bm, true); + exp->export_bitmap = bm; + exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s", + bitmap); +@@ -1641,7 +1641,7 @@ void nbd_export_put(NBDExport *exp) + } + + if (exp->export_bitmap) { +- bdrv_dirty_bitmap_set_qmp_locked(exp->export_bitmap, false); ++ bdrv_dirty_bitmap_set_busy(exp->export_bitmap, false); + g_free(exp->export_bitmap_context); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-file-posix-do-not-fail-on-unlock-bytes.patch b/SOURCES/kvm-block-file-posix-do-not-fail-on-unlock-bytes.patch new file mode 100644 index 0000000..11e181f --- /dev/null +++ b/SOURCES/kvm-block-file-posix-do-not-fail-on-unlock-bytes.patch @@ -0,0 +1,58 @@ +From 82d4a912b8b197d9d2f56ffc54ca89c535a0f47c Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Wed, 3 Apr 2019 18:43:30 +0200 +Subject: [PATCH 153/163] block/file-posix: do not fail on unlock bytes + +RH-Author: Max Reitz +Message-id: <20190403184330.1210-2-mreitz@redhat.com> +Patchwork-id: 85432 +O-Subject: [RHV-7.7 qemu-kvm-rhev PATCH 1/1] block/file-posix: do not fail on unlock bytes +Bugzilla: 1603104 +RH-Acked-by: John Snow +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +bdrv_replace_child() calls bdrv_check_perm() with error_abort on +loosening permissions. However file-locking operations may fail even +in this case, for example on NFS. And this leads to Qemu crash. + +Let's avoid such errors. Note, that we ignore such things anyway on +permission update commit and abort. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Kevin Wolf +(cherry picked from commit 696aaaed579ac5bf5fa336216909b46d3d8f07a8) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 0cf7261..518f16b 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -795,6 +795,18 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + + switch (op) { + case RAW_PL_PREPARE: ++ if ((s->perm | new_perm) == s->perm && ++ (s->shared_perm & new_shared) == s->shared_perm) ++ { ++ /* ++ * We are going to unlock bytes, it should not fail. If it fail due ++ * to some fs-dependent permission-unrelated reasons (which occurs ++ * sometimes on NFS and leads to abort in bdrv_replace_child) we ++ * can't prevent such errors by any check here. And we ignore them ++ * anyway in ABORT and COMMIT. ++ */ ++ return 0; ++ } + ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm, + ~s->shared_perm | ~new_shared, + false, errp); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-client-don-t-check-ioc.patch b/SOURCES/kvm-block-nbd-client-don-t-check-ioc.patch new file mode 100644 index 0000000..fcac981 --- /dev/null +++ b/SOURCES/kvm-block-nbd-client-don-t-check-ioc.patch @@ -0,0 +1,87 @@ +From 9cfc0299d10213160701c07ed5f4feb1c98d4f2a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:02 +0100 +Subject: [PATCH 124/163] block/nbd-client: don't check ioc + +RH-Author: John Snow +Message-id: <20190327172308.31077-50-jsnow@redhat.com> +Patchwork-id: 85214 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 49/55] block/nbd-client: don't check ioc +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +We have several paranoid checks for ioc != NULL. But ioc may become +NULL only on close, which should not happen during requests handling. +Also, we check ioc only sometimes, not after each yield, which is +inconsistent. Let's drop these checks. However, for safety, let's leave +asserts instead. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20190201130138.94525-6-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit 88ed4e1bf0c7017c04fac2166ec9a7687aa21f97) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 5d22f8b..5f3a67f 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -53,9 +53,7 @@ static void nbd_teardown_connection(BlockDriverState *bs) + { + NBDClientSession *client = nbd_get_client_session(bs); + +- if (!client->ioc) { /* Already closed */ +- return; +- } ++ assert(client->ioc); + + /* finish any pending coroutines */ + qio_channel_shutdown(client->ioc, +@@ -153,10 +151,7 @@ static int nbd_co_send_request(BlockDriverState *bs, + rc = -EIO; + goto err; + } +- if (!s->ioc) { +- rc = -EPIPE; +- goto err; +- } ++ assert(s->ioc); + + if (qiov) { + qio_channel_set_cork(s->ioc, true); +@@ -428,10 +423,11 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( + s->requests[i].receiving = true; + qemu_coroutine_yield(); + s->requests[i].receiving = false; +- if (!s->ioc || s->quit) { ++ if (s->quit) { + error_setg(errp, "Connection closed"); + return -EIO; + } ++ assert(s->ioc); + + assert(s->reply.handle == handle); + +@@ -981,9 +977,7 @@ void nbd_client_close(BlockDriverState *bs) + NBDClientSession *client = nbd_get_client_session(bs); + NBDRequest request = { .type = NBD_CMD_DISC }; + +- if (client->ioc == NULL) { +- return; +- } ++ assert(client->ioc); + + nbd_send_request(client->ioc, &request); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-client-fix-nbd_reply_chunk_iter_receive.patch b/SOURCES/kvm-block-nbd-client-fix-nbd_reply_chunk_iter_receive.patch new file mode 100644 index 0000000..eb75f0c --- /dev/null +++ b/SOURCES/kvm-block-nbd-client-fix-nbd_reply_chunk_iter_receive.patch @@ -0,0 +1,46 @@ +From 49725596691ccd778e0d9328b2ee2064ec35595f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:01 +0100 +Subject: [PATCH 123/163] block/nbd-client: fix nbd_reply_chunk_iter_receive + +RH-Author: John Snow +Message-id: <20190327172308.31077-49-jsnow@redhat.com> +Patchwork-id: 85209 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 48/55] block/nbd-client: fix nbd_reply_chunk_iter_receive +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Use exported report, not the variable to be reused (should not really +matter). + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20190201130138.94525-5-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit 65e01d47653eb127fa917bd9d2f1824a00ab2de6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 22e5042..5d22f8b 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -601,7 +601,7 @@ static bool nbd_reply_chunk_iter_receive(NBDClientSession *s, + } + + /* Do not execute the body of NBD_FOREACH_REPLY_CHUNK for simple reply. */ +- if (nbd_reply_is_simple(&s->reply) || s->quit) { ++ if (nbd_reply_is_simple(reply) || s->quit) { + goto break_loop; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-client-rename-read_reply_co-to-connection_.patch b/SOURCES/kvm-block-nbd-client-rename-read_reply_co-to-connection_.patch new file mode 100644 index 0000000..3ff15cf --- /dev/null +++ b/SOURCES/kvm-block-nbd-client-rename-read_reply_co-to-connection_.patch @@ -0,0 +1,160 @@ +From 309faf75d981afc47f5890bbf65e5251c01249ef Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:03 +0100 +Subject: [PATCH 125/163] block/nbd-client: rename read_reply_co to + connection_co + +RH-Author: John Snow +Message-id: <20190327172308.31077-51-jsnow@redhat.com> +Patchwork-id: 85221 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 50/55] block/nbd-client: rename read_reply_co to connection_co +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +This coroutine will serve nbd reconnects, so, rename it to be something +more generic. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20190201130138.94525-7-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit bc5a03350c220698229e7d6929dd242d5d358345) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 24 ++++++++++++------------ + block/nbd-client.h | 4 ++-- + 2 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 5f3a67f..1230850 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -59,7 +59,7 @@ static void nbd_teardown_connection(BlockDriverState *bs) + qio_channel_shutdown(client->ioc, + QIO_CHANNEL_SHUTDOWN_BOTH, + NULL); +- BDRV_POLL_WHILE(bs, client->read_reply_co); ++ BDRV_POLL_WHILE(bs, client->connection_co); + + nbd_client_detach_aio_context(bs); + object_unref(OBJECT(client->sioc)); +@@ -68,7 +68,7 @@ static void nbd_teardown_connection(BlockDriverState *bs) + client->ioc = NULL; + } + +-static coroutine_fn void nbd_read_reply_entry(void *opaque) ++static coroutine_fn void nbd_connection_entry(void *opaque) + { + NBDClientSession *s = opaque; + uint64_t i; +@@ -100,14 +100,14 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + } + + /* We're woken up again by the request itself. Note that there +- * is no race between yielding and reentering read_reply_co. This ++ * is no race between yielding and reentering connection_co. This + * is because: + * + * - if the request runs on the same AioContext, it is only + * entered after we yield + * + * - if the request runs on a different AioContext, reentering +- * read_reply_co happens through a bottom half, which can only ++ * connection_co happens through a bottom half, which can only + * run after we yield. + */ + aio_co_wake(s->requests[i].coroutine); +@@ -116,7 +116,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + + s->quit = true; + nbd_recv_coroutines_wake_all(s); +- s->read_reply_co = NULL; ++ s->connection_co = NULL; + } + + static int nbd_co_send_request(BlockDriverState *bs, +@@ -419,7 +419,7 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( + } + *request_ret = 0; + +- /* Wait until we're woken up by nbd_read_reply_entry. */ ++ /* Wait until we're woken up by nbd_connection_entry. */ + s->requests[i].receiving = true; + qemu_coroutine_yield(); + s->requests[i].receiving = false; +@@ -494,7 +494,7 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( + } + + /* nbd_co_receive_one_chunk +- * Read reply, wake up read_reply_co and set s->quit if needed. ++ * Read reply, wake up connection_co and set s->quit if needed. + * Return value is a fatal error code or normal nbd reply error code + */ + static coroutine_fn int nbd_co_receive_one_chunk( +@@ -508,15 +508,15 @@ static coroutine_fn int nbd_co_receive_one_chunk( + if (ret < 0) { + s->quit = true; + } else { +- /* For assert at loop start in nbd_read_reply_entry */ ++ /* For assert at loop start in nbd_connection_entry */ + if (reply) { + *reply = s->reply; + } + s->reply.handle = 0; + } + +- if (s->read_reply_co) { +- aio_co_wake(s->read_reply_co); ++ if (s->connection_co) { ++ aio_co_wake(s->connection_co); + } + + return ret; +@@ -969,7 +969,7 @@ void nbd_client_attach_aio_context(BlockDriverState *bs, + { + NBDClientSession *client = nbd_get_client_session(bs); + qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), new_context); +- aio_co_schedule(new_context, client->read_reply_co); ++ aio_co_schedule(new_context, client->connection_co); + } + + void nbd_client_close(BlockDriverState *bs) +@@ -1074,7 +1074,7 @@ static int nbd_client_connect(BlockDriverState *bs, + /* Now that we're connected, set the socket to be non-blocking and + * kick the reply mechanism. */ + qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); +- client->read_reply_co = qemu_coroutine_create(nbd_read_reply_entry, client); ++ client->connection_co = qemu_coroutine_create(nbd_connection_entry, client); + nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); + + logout("Established connection with NBD server\n"); +diff --git a/block/nbd-client.h b/block/nbd-client.h +index 2f047ba..d990207 100644 +--- a/block/nbd-client.h ++++ b/block/nbd-client.h +@@ -20,7 +20,7 @@ + typedef struct { + Coroutine *coroutine; + uint64_t offset; /* original offset of the request */ +- bool receiving; /* waiting for read_reply_co? */ ++ bool receiving; /* waiting for connection_co? */ + } NBDClientRequest; + + typedef struct NBDClientSession { +@@ -30,7 +30,7 @@ typedef struct NBDClientSession { + + CoMutex send_mutex; + CoQueue free_sema; +- Coroutine *read_reply_co; ++ Coroutine *connection_co; + int in_flight; + + NBDClientRequest requests[MAX_NBD_REQUESTS]; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-client-split-channel-errors-from-export-er.patch b/SOURCES/kvm-block-nbd-client-split-channel-errors-from-export-er.patch new file mode 100644 index 0000000..a164d77 --- /dev/null +++ b/SOURCES/kvm-block-nbd-client-split-channel-errors-from-export-er.patch @@ -0,0 +1,313 @@ +From 00ecc208207488fec5d793b13b1a967d8af2acfd Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:58 +0100 +Subject: [PATCH 120/163] block/nbd-client: split channel errors from export + errors + +RH-Author: John Snow +Message-id: <20190327172308.31077-46-jsnow@redhat.com> +Patchwork-id: 85208 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 45/55] block/nbd-client: split channel errors from export errors +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +To implement nbd reconnect in further patches, we need to distinguish +error codes, returned by nbd server, from channel errors, to reconnect +only in the latter case. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20190201130138.94525-2-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit 7f86068dc1aceec8f6151a3a713e57e680f73b45) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 83 +++++++++++++++++++++++++++++++----------------------- + 1 file changed, 47 insertions(+), 36 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 5c97052..f5b9aaa 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -503,11 +503,11 @@ static coroutine_fn int nbd_co_do_receive_one_chunk( + */ + static coroutine_fn int nbd_co_receive_one_chunk( + NBDClientSession *s, uint64_t handle, bool only_structured, +- QEMUIOVector *qiov, NBDReply *reply, void **payload, Error **errp) ++ int *request_ret, QEMUIOVector *qiov, NBDReply *reply, void **payload, ++ Error **errp) + { +- int request_ret; + int ret = nbd_co_do_receive_one_chunk(s, handle, only_structured, +- &request_ret, qiov, payload, errp); ++ request_ret, qiov, payload, errp); + + if (ret < 0) { + s->quit = true; +@@ -517,7 +517,6 @@ static coroutine_fn int nbd_co_receive_one_chunk( + *reply = s->reply; + } + s->reply.handle = 0; +- ret = request_ret; + } + + if (s->read_reply_co) { +@@ -529,22 +528,17 @@ static coroutine_fn int nbd_co_receive_one_chunk( + + typedef struct NBDReplyChunkIter { + int ret; +- bool fatal; ++ int request_ret; + Error *err; + bool done, only_structured; + } NBDReplyChunkIter; + +-static void nbd_iter_error(NBDReplyChunkIter *iter, bool fatal, +- int ret, Error **local_err) ++static void nbd_iter_channel_error(NBDReplyChunkIter *iter, ++ int ret, Error **local_err) + { + assert(ret < 0); + +- if ((fatal && !iter->fatal) || iter->ret == 0) { +- if (iter->ret != 0) { +- error_free(iter->err); +- iter->err = NULL; +- } +- iter->fatal = fatal; ++ if (!iter->ret) { + iter->ret = ret; + error_propagate(&iter->err, *local_err); + } else { +@@ -554,6 +548,15 @@ static void nbd_iter_error(NBDReplyChunkIter *iter, bool fatal, + *local_err = NULL; + } + ++static void nbd_iter_request_error(NBDReplyChunkIter *iter, int ret) ++{ ++ assert(ret < 0); ++ ++ if (!iter->request_ret) { ++ iter->request_ret = ret; ++ } ++} ++ + /* NBD_FOREACH_REPLY_CHUNK + */ + #define NBD_FOREACH_REPLY_CHUNK(s, iter, handle, structured, \ +@@ -569,13 +572,13 @@ static bool nbd_reply_chunk_iter_receive(NBDClientSession *s, + QEMUIOVector *qiov, NBDReply *reply, + void **payload) + { +- int ret; ++ int ret, request_ret; + NBDReply local_reply; + NBDStructuredReplyChunk *chunk; + Error *local_err = NULL; + if (s->quit) { + error_setg(&local_err, "Connection closed"); +- nbd_iter_error(iter, true, -EIO, &local_err); ++ nbd_iter_channel_error(iter, -EIO, &local_err); + goto break_loop; + } + +@@ -589,10 +592,12 @@ static bool nbd_reply_chunk_iter_receive(NBDClientSession *s, + } + + ret = nbd_co_receive_one_chunk(s, handle, iter->only_structured, +- qiov, reply, payload, &local_err); ++ &request_ret, qiov, reply, payload, ++ &local_err); + if (ret < 0) { +- /* If it is a fatal error s->quit is set by nbd_co_receive_one_chunk */ +- nbd_iter_error(iter, s->quit, ret, &local_err); ++ nbd_iter_channel_error(iter, ret, &local_err); ++ } else if (request_ret < 0) { ++ nbd_iter_request_error(iter, request_ret); + } + + /* Do not execute the body of NBD_FOREACH_REPLY_CHUNK for simple reply. */ +@@ -629,7 +634,7 @@ break_loop: + } + + static int nbd_co_receive_return_code(NBDClientSession *s, uint64_t handle, +- Error **errp) ++ int *request_ret, Error **errp) + { + NBDReplyChunkIter iter; + +@@ -638,12 +643,13 @@ static int nbd_co_receive_return_code(NBDClientSession *s, uint64_t handle, + } + + error_propagate(errp, iter.err); ++ *request_ret = iter.request_ret; + return iter.ret; + } + + static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t handle, + uint64_t offset, QEMUIOVector *qiov, +- Error **errp) ++ int *request_ret, Error **errp) + { + NBDReplyChunkIter iter; + NBDReply reply; +@@ -668,7 +674,7 @@ static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t handle, + offset, qiov, &local_err); + if (ret < 0) { + s->quit = true; +- nbd_iter_error(&iter, true, ret, &local_err); ++ nbd_iter_channel_error(&iter, ret, &local_err); + } + break; + default: +@@ -678,7 +684,7 @@ static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t handle, + error_setg(&local_err, + "Unexpected reply type: %d (%s) for CMD_READ", + chunk->type, nbd_reply_type_lookup(chunk->type)); +- nbd_iter_error(&iter, true, -EINVAL, &local_err); ++ nbd_iter_channel_error(&iter, -EINVAL, &local_err); + } + } + +@@ -687,12 +693,14 @@ static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t handle, + } + + error_propagate(errp, iter.err); ++ *request_ret = iter.request_ret; + return iter.ret; + } + + static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + uint64_t handle, uint64_t length, +- NBDExtent *extent, Error **errp) ++ NBDExtent *extent, ++ int *request_ret, Error **errp) + { + NBDReplyChunkIter iter; + NBDReply reply; +@@ -714,7 +722,7 @@ static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + if (received) { + s->quit = true; + error_setg(&local_err, "Several BLOCK_STATUS chunks in reply"); +- nbd_iter_error(&iter, true, -EINVAL, &local_err); ++ nbd_iter_channel_error(&iter, -EINVAL, &local_err); + } + received = true; + +@@ -723,7 +731,7 @@ static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + &local_err); + if (ret < 0) { + s->quit = true; +- nbd_iter_error(&iter, true, ret, &local_err); ++ nbd_iter_channel_error(&iter, ret, &local_err); + } + break; + default: +@@ -733,7 +741,7 @@ static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + "Unexpected reply type: %d (%s) " + "for CMD_BLOCK_STATUS", + chunk->type, nbd_reply_type_lookup(chunk->type)); +- nbd_iter_error(&iter, true, -EINVAL, &local_err); ++ nbd_iter_channel_error(&iter, -EINVAL, &local_err); + } + } + +@@ -748,14 +756,16 @@ static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + iter.ret = -EIO; + } + } ++ + error_propagate(errp, iter.err); ++ *request_ret = iter.request_ret; + return iter.ret; + } + + static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, + QEMUIOVector *write_qiov) + { +- int ret; ++ int ret, request_ret; + Error *local_err = NULL; + NBDClientSession *client = nbd_get_client_session(bs); + +@@ -771,7 +781,8 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, + return ret; + } + +- ret = nbd_co_receive_return_code(client, request->handle, &local_err); ++ ret = nbd_co_receive_return_code(client, request->handle, ++ &request_ret, &local_err); + if (local_err) { + trace_nbd_co_request_fail(request->from, request->len, request->handle, + request->flags, request->type, +@@ -779,13 +790,13 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, + ret, error_get_pretty(local_err)); + error_free(local_err); + } +- return ret; ++ return ret ? ret : request_ret; + } + + int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, int flags) + { +- int ret; ++ int ret, request_ret; + Error *local_err = NULL; + NBDClientSession *client = nbd_get_client_session(bs); + NBDRequest request = { +@@ -806,7 +817,7 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + } + + ret = nbd_co_receive_cmdread_reply(client, request.handle, offset, qiov, +- &local_err); ++ &request_ret, &local_err); + if (local_err) { + trace_nbd_co_request_fail(request.from, request.len, request.handle, + request.flags, request.type, +@@ -814,7 +825,7 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + ret, error_get_pretty(local_err)); + error_free(local_err); + } +- return ret; ++ return ret ? ret : request_ret; + } + + int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, +@@ -908,7 +919,7 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + int64_t *pnum, int64_t *map, + BlockDriverState **file) + { +- int64_t ret; ++ int ret, request_ret; + NBDExtent extent = { 0 }; + NBDClientSession *client = nbd_get_client_session(bs); + Error *local_err = NULL; +@@ -933,7 +944,7 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + } + + ret = nbd_co_receive_blockstatus_reply(client, request.handle, bytes, +- &extent, &local_err); ++ &extent, &request_ret, &local_err); + if (local_err) { + trace_nbd_co_request_fail(request.from, request.len, request.handle, + request.flags, request.type, +@@ -941,8 +952,8 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + ret, error_get_pretty(local_err)); + error_free(local_err); + } +- if (ret < 0) { +- return ret; ++ if (ret < 0 || request_ret < 0) { ++ return ret ? ret : request_ret; + } + + assert(extent.length); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-client-split-connection-from-initializatio.patch b/SOURCES/kvm-block-nbd-client-split-connection-from-initializatio.patch new file mode 100644 index 0000000..fab552f --- /dev/null +++ b/SOURCES/kvm-block-nbd-client-split-connection-from-initializatio.patch @@ -0,0 +1,88 @@ +From a5b79479ab6a364899c6a5c7444c86c00bf0e42d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:00 +0100 +Subject: [PATCH 122/163] block/nbd-client: split connection from + initialization + +RH-Author: John Snow +Message-id: <20190327172308.31077-48-jsnow@redhat.com> +Patchwork-id: 85206 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 47/55] block/nbd-client: split connection from initialization +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Split connection code to reuse it for reconnect. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20190201130138.94525-4-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit b0e4b5a58fde6c0ed9edb9b683cfbbd8ab45c35d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 33 ++++++++++++++++++++++++--------- + 1 file changed, 24 insertions(+), 9 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index d86c412..22e5042 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -1011,13 +1011,13 @@ static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, + return sioc; + } + +-int nbd_client_init(BlockDriverState *bs, +- SocketAddress *saddr, +- const char *export, +- QCryptoTLSCreds *tlscreds, +- const char *hostname, +- const char *x_dirty_bitmap, +- Error **errp) ++static int nbd_client_connect(BlockDriverState *bs, ++ SocketAddress *saddr, ++ const char *export, ++ QCryptoTLSCreds *tlscreds, ++ const char *hostname, ++ const char *x_dirty_bitmap, ++ Error **errp) + { + NBDClientSession *client = nbd_get_client_session(bs); + int ret; +@@ -1070,8 +1070,6 @@ int nbd_client_init(BlockDriverState *bs, + bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP; + } + +- qemu_co_mutex_init(&client->send_mutex); +- qemu_co_queue_init(&client->free_sema); + client->sioc = sioc; + + if (!client->ioc) { +@@ -1104,3 +1102,20 @@ int nbd_client_init(BlockDriverState *bs, + return ret; + } + } ++ ++int nbd_client_init(BlockDriverState *bs, ++ SocketAddress *saddr, ++ const char *export, ++ QCryptoTLSCreds *tlscreds, ++ const char *hostname, ++ const char *x_dirty_bitmap, ++ Error **errp) ++{ ++ NBDClientSession *client = nbd_get_client_session(bs); ++ ++ qemu_co_mutex_init(&client->send_mutex); ++ qemu_co_queue_init(&client->free_sema); ++ ++ return nbd_client_connect(bs, saddr, export, tlscreds, hostname, ++ x_dirty_bitmap, errp); ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-client-use-traces-instead-of-noisy-error_r.patch b/SOURCES/kvm-block-nbd-client-use-traces-instead-of-noisy-error_r.patch new file mode 100644 index 0000000..8c7cf77 --- /dev/null +++ b/SOURCES/kvm-block-nbd-client-use-traces-instead-of-noisy-error_r.patch @@ -0,0 +1,253 @@ +From 32850a2e3ed06394a0086acc19b484ddf4a2cef6 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:19 +0100 +Subject: [PATCH 080/163] block/nbd-client: use traces instead of noisy + error_report_err + +RH-Author: John Snow +Message-id: <20190327172308.31077-7-jsnow@redhat.com> +Patchwork-id: 85183 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/55] block/nbd-client: use traces instead of noisy error_report_err +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Reduce extra noise of nbd-client, change 083 correspondingly. + +In various commits (be41c100 in 2.10, f140e300 in 2.11, 78a33ab +in 2.12), we added spots where qemu as an NBD client would report +problems communicating with the server to stderr, because there +was no where else to send the error to. However, this is racy, +particularly since the most common source of these errors is when +either the client or the server abruptly hangs up, leaving one +coroutine to report the error only if it wins (or loses) the +race in attempting the read from the server before another +thread completes its cleanup of a protocol error that caused the +disconnect in the first place. The race is also apparent in the +fact that differences in the flush behavior of the server can +alter the frequency of encountering the race in the client (see +commit 6d39db96). + +Rather than polluting stderr, it's better to just trace these +situations, for use by developers debugging a flaky connection, +particularly since the real error that either triggers the abrupt +disconnection in the first place, or that results from the EIO +when a request can't receive a reply, DOES make it back to the +user in the normal Error propagation channels. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181102151152.288399-4-vsementsov@virtuozzo.com> +[eblake: drop depedence on error hint, enhance commit message] +Signed-off-by: Eric Blake +(cherry picked from commit d8b4bad846f08ff0f167b46dc156a5310b750484) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 23 +++++++++++++++++++---- + block/trace-events | 4 ++++ + tests/qemu-iotests/083.out | 28 ---------------------------- + 3 files changed, 23 insertions(+), 32 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index fc5b7ed..ef32075 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -28,6 +28,8 @@ + */ + + #include "qemu/osdep.h" ++ ++#include "trace.h" + #include "qapi/error.h" + #include "nbd-client.h" + +@@ -79,7 +81,8 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + assert(s->reply.handle == 0); + ret = nbd_receive_reply(s->ioc, &s->reply, &local_err); + if (local_err) { +- error_report_err(local_err); ++ trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err)); ++ error_free(local_err); + } + if (ret <= 0) { + break; +@@ -771,7 +774,11 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, + + ret = nbd_co_receive_return_code(client, request->handle, &local_err); + if (local_err) { +- error_report_err(local_err); ++ trace_nbd_co_request_fail(request->from, request->len, request->handle, ++ request->flags, request->type, ++ nbd_cmd_lookup(request->type), ++ ret, error_get_pretty(local_err)); ++ error_free(local_err); + } + return ret; + } +@@ -802,7 +809,11 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + ret = nbd_co_receive_cmdread_reply(client, request.handle, offset, qiov, + &local_err); + if (local_err) { +- error_report_err(local_err); ++ trace_nbd_co_request_fail(request.from, request.len, request.handle, ++ request.flags, request.type, ++ nbd_cmd_lookup(request.type), ++ ret, error_get_pretty(local_err)); ++ error_free(local_err); + } + return ret; + } +@@ -925,7 +936,11 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + ret = nbd_co_receive_blockstatus_reply(client, request.handle, bytes, + &extent, &local_err); + if (local_err) { +- error_report_err(local_err); ++ trace_nbd_co_request_fail(request.from, request.len, request.handle, ++ request.flags, request.type, ++ nbd_cmd_lookup(request.type), ++ ret, error_get_pretty(local_err)); ++ error_free(local_err); + } + if (ret < 0) { + return ret; +diff --git a/block/trace-events b/block/trace-events +index c35287b..6d4d399 100644 +--- a/block/trace-events ++++ b/block/trace-events +@@ -150,3 +150,7 @@ nvme_free_req_queue_wait(void *q) "q %p" + nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d" + nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64 + nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d" ++ ++# block/nbd-client.c ++nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" ++nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" +diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out +index f9af8bb..7419722 100644 +--- a/tests/qemu-iotests/083.out ++++ b/tests/qemu-iotests/083.out +@@ -41,8 +41,6 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect after neg2 === + +-Unable to read from socket: Connection reset by peer +-Connection closed + read failed: Input/output error + + === Check disconnect 8 neg2 === +@@ -55,40 +53,30 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect before request === + +-Unable to read from socket: Connection reset by peer +-Connection closed + read failed: Input/output error + + === Check disconnect after request === + +-Connection closed + read failed: Input/output error + + === Check disconnect before reply === + +-Connection closed + read failed: Input/output error + + === Check disconnect after reply === + +-Unexpected end-of-file before all bytes were read + read failed: Input/output error + + === Check disconnect 4 reply === + +-Unexpected end-of-file before all bytes were read +-Connection closed + read failed: Input/output error + + === Check disconnect 8 reply === + +-Unexpected end-of-file before all bytes were read +-Connection closed + read failed: Input/output error + + === Check disconnect before data === + +-Unexpected end-of-file before all bytes were read + read failed: Input/output error + + === Check disconnect after data === +@@ -118,8 +106,6 @@ can't open device nbd+tcp://127.0.0.1:PORT/ + + === Check disconnect after neg-classic === + +-Unable to read from socket: Connection reset by peer +-Connection closed + read failed: Input/output error + + === Check disconnect before neg1 === +@@ -164,8 +150,6 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock + + === Check disconnect after neg2 === + +-Unable to read from socket: Connection reset by peer +-Connection closed + read failed: Input/output error + + === Check disconnect 8 neg2 === +@@ -178,40 +162,30 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock + + === Check disconnect before request === + +-Unable to read from socket: Connection reset by peer +-Connection closed + read failed: Input/output error + + === Check disconnect after request === + +-Connection closed + read failed: Input/output error + + === Check disconnect before reply === + +-Connection closed + read failed: Input/output error + + === Check disconnect after reply === + +-Unexpected end-of-file before all bytes were read + read failed: Input/output error + + === Check disconnect 4 reply === + +-Unexpected end-of-file before all bytes were read +-Connection closed + read failed: Input/output error + + === Check disconnect 8 reply === + +-Unexpected end-of-file before all bytes were read +-Connection closed + read failed: Input/output error + + === Check disconnect before data === + +-Unexpected end-of-file before all bytes were read + read failed: Input/output error + + === Check disconnect after data === +@@ -241,8 +215,6 @@ can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock + + === Check disconnect after neg-classic === + +-Unable to read from socket: Connection reset by peer +-Connection closed + read failed: Input/output error + + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-nbd-move-connection-code-from-block-nbd-to-blo.patch b/SOURCES/kvm-block-nbd-move-connection-code-from-block-nbd-to-blo.patch new file mode 100644 index 0000000..1515ea8 --- /dev/null +++ b/SOURCES/kvm-block-nbd-move-connection-code-from-block-nbd-to-blo.patch @@ -0,0 +1,197 @@ +From 44a47acaccb8455be42cb302885af0934c3360db Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:59 +0100 +Subject: [PATCH 121/163] block/nbd: move connection code from block/nbd to + block/nbd-client + +RH-Author: John Snow +Message-id: <20190327172308.31077-47-jsnow@redhat.com> +Patchwork-id: 85218 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 46/55] block/nbd: move connection code from block/nbd to block/nbd-client +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Keep all connection code in one file, to be able to implement reconnect +in further patches. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190201130138.94525-3-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: format tweak] +Signed-off-by: Eric Blake +(cherry picked from commit d42f78e9400c51f1ae30dadd52995e4d6b052d89) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 38 ++++++++++++++++++++++++++++++++++++-- + block/nbd-client.h | 2 +- + block/nbd.c | 40 ++-------------------------------------- + 3 files changed, 39 insertions(+), 41 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index f5b9aaa..d86c412 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -990,8 +990,29 @@ void nbd_client_close(BlockDriverState *bs) + nbd_teardown_connection(bs); + } + ++static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, ++ Error **errp) ++{ ++ QIOChannelSocket *sioc; ++ Error *local_err = NULL; ++ ++ sioc = qio_channel_socket_new(); ++ qio_channel_set_name(QIO_CHANNEL(sioc), "nbd-client"); ++ ++ qio_channel_socket_connect_sync(sioc, saddr, &local_err); ++ if (local_err) { ++ object_unref(OBJECT(sioc)); ++ error_propagate(errp, local_err); ++ return NULL; ++ } ++ ++ qio_channel_set_delay(QIO_CHANNEL(sioc), false); ++ ++ return sioc; ++} ++ + int nbd_client_init(BlockDriverState *bs, +- QIOChannelSocket *sioc, ++ SocketAddress *saddr, + const char *export, + QCryptoTLSCreds *tlscreds, + const char *hostname, +@@ -1001,6 +1022,16 @@ int nbd_client_init(BlockDriverState *bs, + NBDClientSession *client = nbd_get_client_session(bs); + int ret; + ++ /* ++ * establish TCP connection, return error if it fails ++ * TODO: Configurable retry-until-timeout behaviour. ++ */ ++ QIOChannelSocket *sioc = nbd_establish_connection(saddr, errp); ++ ++ if (!sioc) { ++ return -ECONNREFUSED; ++ } ++ + /* NBD handshake */ + logout("session init %s\n", export); + qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL); +@@ -1016,6 +1047,7 @@ int nbd_client_init(BlockDriverState *bs, + g_free(client->info.name); + if (ret < 0) { + logout("Failed to negotiate with the NBD server\n"); ++ object_unref(OBJECT(sioc)); + return ret; + } + if (x_dirty_bitmap && !client->info.base_allocation) { +@@ -1041,7 +1073,6 @@ int nbd_client_init(BlockDriverState *bs, + qemu_co_mutex_init(&client->send_mutex); + qemu_co_queue_init(&client->free_sema); + client->sioc = sioc; +- object_ref(OBJECT(client->sioc)); + + if (!client->ioc) { + client->ioc = QIO_CHANNEL(sioc); +@@ -1067,6 +1098,9 @@ int nbd_client_init(BlockDriverState *bs, + NBDRequest request = { .type = NBD_CMD_DISC }; + + nbd_send_request(client->ioc ?: QIO_CHANNEL(sioc), &request); ++ ++ object_unref(OBJECT(sioc)); ++ + return ret; + } + } +diff --git a/block/nbd-client.h b/block/nbd-client.h +index cfc9055..2f047ba 100644 +--- a/block/nbd-client.h ++++ b/block/nbd-client.h +@@ -41,7 +41,7 @@ typedef struct NBDClientSession { + NBDClientSession *nbd_get_client_session(BlockDriverState *bs); + + int nbd_client_init(BlockDriverState *bs, +- QIOChannelSocket *sock, ++ SocketAddress *saddr, + const char *export_name, + QCryptoTLSCreds *tlscreds, + const char *hostname, +diff --git a/block/nbd.c b/block/nbd.c +index f29c10f..838a8fe 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -295,30 +295,6 @@ NBDClientSession *nbd_get_client_session(BlockDriverState *bs) + return &s->client; + } + +-static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr, +- Error **errp) +-{ +- QIOChannelSocket *sioc; +- Error *local_err = NULL; +- +- sioc = qio_channel_socket_new(); +- qio_channel_set_name(QIO_CHANNEL(sioc), "nbd-client"); +- +- qio_channel_socket_connect_sync(sioc, +- saddr, +- &local_err); +- if (local_err) { +- object_unref(OBJECT(sioc)); +- error_propagate(errp, local_err); +- return NULL; +- } +- +- qio_channel_set_delay(QIO_CHANNEL(sioc), false); +- +- return sioc; +-} +- +- + static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) + { + Object *obj; +@@ -394,7 +370,6 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, + BDRVNBDState *s = bs->opaque; + QemuOpts *opts = NULL; + Error *local_err = NULL; +- QIOChannelSocket *sioc = NULL; + QCryptoTLSCreds *tlscreds = NULL; + const char *hostname = NULL; + int ret = -EINVAL; +@@ -434,22 +409,11 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, + hostname = s->saddr->u.inet.host; + } + +- /* establish TCP connection, return error if it fails +- * TODO: Configurable retry-until-timeout behaviour. +- */ +- sioc = nbd_establish_connection(s->saddr, errp); +- if (!sioc) { +- ret = -ECONNREFUSED; +- goto error; +- } +- + /* NBD handshake */ +- ret = nbd_client_init(bs, sioc, s->export, tlscreds, hostname, ++ ret = nbd_client_init(bs, s->saddr, s->export, tlscreds, hostname, + qemu_opt_get(opts, "x-dirty-bitmap"), errp); ++ + error: +- if (sioc) { +- object_unref(OBJECT(sioc)); +- } + if (tlscreds) { + object_unref(OBJECT(tlscreds)); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-pflash_cfi02-Fix-memory-leak-and-potential-use.patch b/SOURCES/kvm-block-pflash_cfi02-Fix-memory-leak-and-potential-use.patch new file mode 100644 index 0000000..8a1ab9a --- /dev/null +++ b/SOURCES/kvm-block-pflash_cfi02-Fix-memory-leak-and-potential-use.patch @@ -0,0 +1,97 @@ +From 689898009c6930b8a9ce598e85678bfc0f131594 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:51 +0200 +Subject: [PATCH 24/53] block/pflash_cfi02: Fix memory leak and potential + use-after-free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-3-armbru@redhat.com> +Patchwork-id: 87984 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 02/31] block/pflash_cfi02: Fix memory leak and potential use-after-free +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Stephen Checkoway + +Don't dynamically allocate the pflash's timer. But do use timer_del in +an unrealize function to make sure that the timer can't fire after the +pflash_t has been freed. + +Signed-off-by: Stephen Checkoway +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Wei Yang +Message-Id: <20190219153727.62279-1-stephen.checkoway@oberlin.edu> +Signed-off-by: Laurent Vivier +(cherry picked from commit d80cf1eb2e87df3a9bfb226bcc7fb3a1aa858817) +Signed-off-by: Miroslav Rezanina +--- + hw/block/pflash_cfi02.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index 75d1ae1..cbc3d4d 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -84,7 +84,7 @@ struct pflash_t { + uint16_t unlock_addr0; + uint16_t unlock_addr1; + uint8_t cfi_table[0x52]; +- QEMUTimer *timer; ++ QEMUTimer timer; + /* The device replicates the flash memory across its memory space. Emulate + * that by having a container (.mem) filled with an array of aliases + * (.mem_mappings) pointing to the flash memory (.orig_mem). +@@ -431,7 +431,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset, + } + pfl->status = 0x00; + /* Let's wait 5 seconds before chip erase is done */ +- timer_mod(pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ++ timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (NANOSECONDS_PER_SECOND * 5)); + break; + case 0x30: +@@ -446,7 +446,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset, + } + pfl->status = 0x00; + /* Let's wait 1/2 second before sector erase is done */ +- timer_mod(pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ++ timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (NANOSECONDS_PER_SECOND / 2)); + break; + default: +@@ -658,7 +658,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) + pfl->rom_mode = 1; + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + +- pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); ++ timer_init_ns(&pfl->timer, QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); + pfl->wcycle = 0; + pfl->cmd = 0; + pfl->status = 0; +@@ -757,11 +757,18 @@ static Property pflash_cfi02_properties[] = { + DEFINE_PROP_END_OF_LIST(), + }; + ++static void pflash_cfi02_unrealize(DeviceState *dev, Error **errp) ++{ ++ pflash_t *pfl = CFI_PFLASH02(dev); ++ timer_del(&pfl->timer); ++} ++ + static void pflash_cfi02_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pflash_cfi02_realize; ++ dc->unrealize = pflash_cfi02_unrealize; + dc->props = pflash_cfi02_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qcow2-bitmap-Allow-resizes-with-persistent-bit.patch b/SOURCES/kvm-block-qcow2-bitmap-Allow-resizes-with-persistent-bit.patch new file mode 100644 index 0000000..9a7d921 --- /dev/null +++ b/SOURCES/kvm-block-qcow2-bitmap-Allow-resizes-with-persistent-bit.patch @@ -0,0 +1,126 @@ +From ad64bca4d6cc7a258a546112b9494e6bfdf6cfbe Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 22:42:51 +0200 +Subject: [PATCH 156/163] block/qcow2-bitmap: Allow resizes with persistent + bitmaps + +RH-Author: John Snow +Message-id: <20190403224253.5251-4-jsnow@redhat.com> +Patchwork-id: 85433 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/5] block/qcow2-bitmap: Allow resizes with persistent bitmaps +Bugzilla: 1666884 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Sergio Lopez Pascual + +Since we now load all bitmaps into memory anyway, we can just truncate +them in-memory and then flush them back to disk. Just in case, we will +still check and enforce that this shortcut is valid -- i.e. that any +bitmap described on-disk is indeed in-memory and can be modified. + +If there are any inconsistent bitmaps, we refuse to allow the truncate +as we do not actually load these bitmaps into memory, and it isn't safe +or reasonable to attempt to truncate corrupted data. + +Signed-off-by: John Snow +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190311185147.52309-4-vsementsov@virtuozzo.com + [vsementsov: drop bitmap flushing, fix block comments style] +Signed-off-by: John Snow +(cherry picked from commit d19c6b36ffe09cec7ce7ac6a3e979bfe923ebba9) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-bitmap.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + block/qcow2.c | 4 +--- + block/qcow2.h | 1 + + 3 files changed, 48 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index fe4a6a2..3150855 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -1176,6 +1176,52 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) + return qcow2_reopen_bitmaps_rw_hint(bs, NULL, errp); + } + ++/* Checks to see if it's safe to resize bitmaps */ ++int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp) ++{ ++ BDRVQcow2State *s = bs->opaque; ++ Qcow2BitmapList *bm_list; ++ Qcow2Bitmap *bm; ++ int ret = 0; ++ ++ if (s->nb_bitmaps == 0) { ++ return 0; ++ } ++ ++ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, ++ s->bitmap_directory_size, errp); ++ if (bm_list == NULL) { ++ return -EINVAL; ++ } ++ ++ QSIMPLEQ_FOREACH(bm, bm_list, entry) { ++ BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name); ++ if (bitmap == NULL) { ++ /* ++ * We rely on all bitmaps being in-memory to be able to resize them, ++ * Otherwise, we'd need to resize them on disk explicitly ++ */ ++ error_setg(errp, "Cannot resize qcow2 with persistent bitmaps that " ++ "were not loaded into memory"); ++ ret = -ENOTSUP; ++ goto out; ++ } ++ ++ /* ++ * The checks against readonly and busy are redundant, but certainly ++ * do no harm. checks against inconsistent are crucial: ++ */ ++ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { ++ ret = -ENOTSUP; ++ goto out; ++ } ++ } ++ ++out: ++ bitmap_list_free(bm_list); ++ return ret; ++} ++ + /* store_bitmap_data() + * Store bitmap to image, filling bitmap table accordingly. + */ +diff --git a/block/qcow2.c b/block/qcow2.c +index 21f7556..b137480 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3487,9 +3487,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, + } + + /* cannot proceed if image has bitmaps */ +- if (s->nb_bitmaps) { +- /* TODO: resize bitmaps in the image */ +- error_setg(errp, "Can't resize an image which has bitmaps"); ++ if (qcow2_truncate_bitmaps_check(bs, errp)) { + ret = -ENOTSUP; + goto fail; + } +diff --git a/block/qcow2.h b/block/qcow2.h +index 2633e33..3b1b972 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -681,6 +681,7 @@ Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs, + int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp); + int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); ++int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); + void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp); + int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); + bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qcow2-bitmap-Don-t-check-size-for-IN_USE-bitma.patch b/SOURCES/kvm-block-qcow2-bitmap-Don-t-check-size-for-IN_USE-bitma.patch new file mode 100644 index 0000000..73bcdc9 --- /dev/null +++ b/SOURCES/kvm-block-qcow2-bitmap-Don-t-check-size-for-IN_USE-bitma.patch @@ -0,0 +1,67 @@ +From 09fa7fdc08f3edc26fd143bd7f3f6a863e6f1f17 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 22:42:50 +0200 +Subject: [PATCH 155/163] block/qcow2-bitmap: Don't check size for IN_USE + bitmap + +RH-Author: John Snow +Message-id: <20190403224253.5251-3-jsnow@redhat.com> +Patchwork-id: 85435 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/5] block/qcow2-bitmap: Don't check size for IN_USE bitmap +Bugzilla: 1666884 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Sergio Lopez Pascual + +From: Vladimir Sementsov-Ogievskiy + +We are going to allow image resize when there are persistent bitmaps. +It may lead to appearing of inconsistent bitmaps (IN_USE=1) with +inconsistent size. But we still want to load them as inconsistent. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190311185147.52309-3-vsementsov@virtuozzo.com +Signed-off-by: John Snow +(cherry picked from commit bf5f0cf5d819cce45dd578a19386d8b60022654f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-bitmap.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index 4d093da..fe4a6a2 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -464,10 +464,25 @@ static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry) + return len; + } + +- fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) || +- (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits)); ++ if (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) { ++ return -EINVAL; ++ } + +- return fail ? -EINVAL : 0; ++ if (!(entry->flags & BME_FLAG_IN_USE) && ++ (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits))) ++ { ++ /* ++ * We've loaded a valid bitmap (IN_USE not set) or we are going to ++ * store a valid bitmap, but the allocated bitmap table size is not ++ * enough to store this bitmap. ++ * ++ * Note, that it's OK to have an invalid bitmap with invalid size due ++ * to a bitmap that was not correctly saved after image resize. ++ */ ++ return -EINVAL; ++ } ++ ++ return 0; + } + + static inline void bitmap_directory_to_be(uint8_t *dir, size_t size) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qcow2-improve-error-message-in-qcow2_inactivat.patch b/SOURCES/kvm-block-qcow2-improve-error-message-in-qcow2_inactivat.patch new file mode 100644 index 0000000..7818f0b --- /dev/null +++ b/SOURCES/kvm-block-qcow2-improve-error-message-in-qcow2_inactivat.patch @@ -0,0 +1,48 @@ +From f2f3456bff9d30ce3850ff4d97b114714e4fe90d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:39 +0100 +Subject: [PATCH 29/33] block/qcow2: improve error message in qcow2_inactivate + +RH-Author: John Snow +Message-id: <20190206221243.7407-20-jsnow@redhat.com> +Patchwork-id: 84278 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 19/23] block/qcow2: improve error message in qcow2_inactivate +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +[Maintainer edit -- touched up error message. --js] +Reviewed-by: John Snow +Signed-off-by: John Snow +(cherry picked from commit 132adb682098e9af40a2132ec4feec6850fce8cd) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 1ea7203..5c5530d 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -2116,9 +2116,9 @@ static int qcow2_inactivate(BlockDriverState *bs) + qcow2_store_persistent_dirty_bitmaps(bs, &local_err); + if (local_err != NULL) { + result = -EINVAL; +- error_report_err(local_err); +- error_report("Persistent bitmaps are lost for node '%s'", +- bdrv_get_device_or_node_name(bs)); ++ error_reportf_err(local_err, "Lost persistent bitmaps during " ++ "inactivation of node '%s': ", ++ bdrv_get_device_or_node_name(bs)); + } + + ret = qcow2_cache_flush(bs, s->l2_table_cache); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-remove-bdrv_dirty_bitmap_make_anon.patch b/SOURCES/kvm-block-remove-bdrv_dirty_bitmap_make_anon.patch new file mode 100644 index 0000000..ea465d4 --- /dev/null +++ b/SOURCES/kvm-block-remove-bdrv_dirty_bitmap_make_anon.patch @@ -0,0 +1,82 @@ +From f803d3a0cda98654a4cf53ec64dcd179b4ccc6d4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:21 +0100 +Subject: [PATCH 11/33] block: remove bdrv_dirty_bitmap_make_anon + +RH-Author: John Snow +Message-id: <20190206221243.7407-2-jsnow@redhat.com> +Patchwork-id: 84261 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 01/23] block: remove bdrv_dirty_bitmap_make_anon +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Paolo Bonzini + +All this function is doing will be repeated by +bdrv_do_release_matching_dirty_bitmap_locked, except +resetting bm->persistent. But even that does not matter +because the bitmap will be freed. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Stefan Hajnoczi +Message-id: 20180323164254.26487-1-pbonzini@redhat.com +Signed-off-by: John Snow +(cherry picked from commit ab41fc4853cc0cf01ed4903ffe7c36e3768b538f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 9 --------- + blockdev.c | 1 - + include/block/dirty-bitmap.h | 1 - + 3 files changed, 11 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index bc662d3..50e855a 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -98,15 +98,6 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name) + } + + /* Called with BQL taken. */ +-void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) +-{ +- assert(!bdrv_dirty_bitmap_frozen(bitmap)); +- g_free(bitmap->name); +- bitmap->name = NULL; +- bitmap->persistent = false; +-} +- +-/* Called with BQL taken. */ + BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, + uint32_t granularity, + const char *name, +diff --git a/blockdev.c b/blockdev.c +index f25ab15..745ed08 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3019,7 +3019,6 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + } + } + +- bdrv_dirty_bitmap_make_anon(bitmap); + bdrv_release_dirty_bitmap(bs, bitmap); + } + +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index af9ba3c..bf68dd7 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -24,7 +24,6 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs, + void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap); + BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, + const char *name); +-void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap); + void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); + void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); + void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-remove-x-prefix-from-experimental-bitmap-APIs.patch b/SOURCES/kvm-block-remove-x-prefix-from-experimental-bitmap-APIs.patch new file mode 100644 index 0000000..062a4aa --- /dev/null +++ b/SOURCES/kvm-block-remove-x-prefix-from-experimental-bitmap-APIs.patch @@ -0,0 +1,286 @@ +From 73ad88009003572e654deca01a7c64655677bf39 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:17 +0100 +Subject: [PATCH 019/163] block: remove 'x' prefix from experimental bitmap + APIs + +RH-Author: John Snow +Message-id: <20190320161631.14841-6-jsnow@redhat.com> +Patchwork-id: 84949 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/19] block: remove 'x' prefix from experimental bitmap APIs +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +The 'x' prefix was added because I was uncertain of the direction we'd +take for the libvirt API. With the general approach solidified, I feel +comfortable committing to this API for 4.0. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-5-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 0e2b7f09837f1e2828d428af1e4ebb61e3b3ea5f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 22 +++++++++++----------- + qapi/block-core.json | 34 +++++++++++++++++----------------- + qapi/transaction.json | 12 ++++++------ + tests/qemu-iotests/223 | 4 ++-- + 4 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 3755936..47db9bb 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2116,7 +2116,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, + action->has_granularity, action->granularity, + action->has_persistent, action->persistent, + action->has_autoload, action->autoload, +- action->has_x_disabled, action->x_disabled, ++ action->has_disabled, action->disabled, + &local_err); + + if (!local_err) { +@@ -2201,7 +2201,7 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common, + return; + } + +- action = common->action->u.x_block_dirty_bitmap_enable.data; ++ action = common->action->u.block_dirty_bitmap_enable.data; + state->bitmap = block_dirty_bitmap_lookup(action->node, + action->name, + NULL, +@@ -2242,7 +2242,7 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common, + return; + } + +- action = common->action->u.x_block_dirty_bitmap_disable.data; ++ action = common->action->u.block_dirty_bitmap_disable.data; + state->bitmap = block_dirty_bitmap_lookup(action->node, + action->name, + NULL, +@@ -2289,7 +2289,7 @@ static void block_dirty_bitmap_merge_prepare(BlkActionState *common, + return; + } + +- action = common->action->u.x_block_dirty_bitmap_merge.data; ++ action = common->action->u.block_dirty_bitmap_merge.data; + + state->bitmap = do_block_dirty_bitmap_merge(action->node, action->target, + action->bitmaps, &state->backup, +@@ -2357,17 +2357,17 @@ static const BlkActionOps actions[] = { + .commit = block_dirty_bitmap_free_backup, + .abort = block_dirty_bitmap_restore, + }, +- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = { ++ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_enable_prepare, + .abort = block_dirty_bitmap_enable_abort, + }, +- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_DISABLE] = { ++ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_disable_prepare, + .abort = block_dirty_bitmap_disable_abort, + }, +- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_MERGE] = { ++ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_MERGE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_merge_prepare, + .commit = block_dirty_bitmap_free_backup, +@@ -3083,7 +3083,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + bdrv_clear_dirty_bitmap(bitmap, NULL); + } + +-void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name, ++void qmp_block_dirty_bitmap_enable(const char *node, const char *name, + Error **errp) + { + BlockDriverState *bs; +@@ -3104,7 +3104,7 @@ void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name, + bdrv_enable_dirty_bitmap(bitmap); + } + +-void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, ++void qmp_block_dirty_bitmap_disable(const char *node, const char *name, + Error **errp) + { + BlockDriverState *bs; +@@ -3171,8 +3171,8 @@ static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node, + return dst; + } + +-void qmp_x_block_dirty_bitmap_merge(const char *node, const char *target, +- strList *bitmaps, Error **errp) ++void qmp_block_dirty_bitmap_merge(const char *node, const char *target, ++ strList *bitmaps, Error **errp) + { + do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); + } +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 7e11392..176c04e 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1786,15 +1786,15 @@ + # Currently, all dirty tracking bitmaps are loaded from Qcow2 on + # open. + # +-# @x-disabled: the bitmap is created in the disabled state, which means that +-# it will not track drive changes. The bitmap may be enabled with +-# x-block-dirty-bitmap-enable. Default is false. (Since: 3.0) ++# @disabled: the bitmap is created in the disabled state, which means that ++# it will not track drive changes. The bitmap may be enabled with ++# block-dirty-bitmap-enable. Default is false. (Since: 4.0) + # + # Since: 2.4 + ## + { 'struct': 'BlockDirtyBitmapAdd', + 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32', +- '*persistent': 'bool', '*autoload': 'bool', '*x-disabled': 'bool' } } ++ '*persistent': 'bool', '*autoload': 'bool', '*disabled': 'bool' } } + + ## + # @BlockDirtyBitmapMerge: +@@ -1805,7 +1805,7 @@ + # + # @bitmaps: name(s) of the source dirty bitmap(s) + # +-# Since: 3.0 ++# Since: 4.0 + ## + { 'struct': 'BlockDirtyBitmapMerge', + 'data': { 'node': 'str', 'target': 'str', 'bitmaps': ['str'] } } +@@ -1879,7 +1879,7 @@ + 'data': 'BlockDirtyBitmap' } + + ## +-# @x-block-dirty-bitmap-enable: ++# @block-dirty-bitmap-enable: + # + # Enables a dirty bitmap so that it will begin tracking disk changes. + # +@@ -1887,20 +1887,20 @@ + # If @node is not a valid block device, DeviceNotFound + # If @name is not found, GenericError with an explanation + # +-# Since: 3.0 ++# Since: 4.0 + # + # Example: + # +-# -> { "execute": "x-block-dirty-bitmap-enable", ++# -> { "execute": "block-dirty-bitmap-enable", + # "arguments": { "node": "drive0", "name": "bitmap0" } } + # <- { "return": {} } + # + ## +- { 'command': 'x-block-dirty-bitmap-enable', ++ { 'command': 'block-dirty-bitmap-enable', + 'data': 'BlockDirtyBitmap' } + + ## +-# @x-block-dirty-bitmap-disable: ++# @block-dirty-bitmap-disable: + # + # Disables a dirty bitmap so that it will stop tracking disk changes. + # +@@ -1908,20 +1908,20 @@ + # If @node is not a valid block device, DeviceNotFound + # If @name is not found, GenericError with an explanation + # +-# Since: 3.0 ++# Since: 4.0 + # + # Example: + # +-# -> { "execute": "x-block-dirty-bitmap-disable", ++# -> { "execute": "block-dirty-bitmap-disable", + # "arguments": { "node": "drive0", "name": "bitmap0" } } + # <- { "return": {} } + # + ## +- { 'command': 'x-block-dirty-bitmap-disable', ++ { 'command': 'block-dirty-bitmap-disable', + 'data': 'BlockDirtyBitmap' } + + ## +-# @x-block-dirty-bitmap-merge: ++# @block-dirty-bitmap-merge: + # + # Merge dirty bitmaps listed in @bitmaps to the @target dirty bitmap. + # The @bitmaps dirty bitmaps are unchanged. +@@ -1933,17 +1933,17 @@ + # If any of the bitmaps have different sizes or granularities, + # GenericError + # +-# Since: 3.0 ++# Since: 4.0 + # + # Example: + # +-# -> { "execute": "x-block-dirty-bitmap-merge", ++# -> { "execute": "block-dirty-bitmap-merge", + # "arguments": { "node": "drive0", "target": "bitmap0", + # "bitmaps": ["bitmap1"] } } + # <- { "return": {} } + # + ## +- { 'command': 'x-block-dirty-bitmap-merge', ++ { 'command': 'block-dirty-bitmap-merge', + 'data': 'BlockDirtyBitmapMerge' } + + ## +diff --git a/qapi/transaction.json b/qapi/transaction.json +index 5875cdb..95edb78 100644 +--- a/qapi/transaction.json ++++ b/qapi/transaction.json +@@ -46,9 +46,9 @@ + # - @abort: since 1.6 + # - @block-dirty-bitmap-add: since 2.5 + # - @block-dirty-bitmap-clear: since 2.5 +-# - @x-block-dirty-bitmap-enable: since 3.0 +-# - @x-block-dirty-bitmap-disable: since 3.0 +-# - @x-block-dirty-bitmap-merge: since 3.1 ++# - @block-dirty-bitmap-enable: since 4.0 ++# - @block-dirty-bitmap-disable: since 4.0 ++# - @block-dirty-bitmap-merge: since 4.0 + # - @blockdev-backup: since 2.3 + # - @blockdev-snapshot: since 2.5 + # - @blockdev-snapshot-internal-sync: since 1.7 +@@ -62,9 +62,9 @@ + 'abort': 'Abort', + 'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd', + 'block-dirty-bitmap-clear': 'BlockDirtyBitmap', +- 'x-block-dirty-bitmap-enable': 'BlockDirtyBitmap', +- 'x-block-dirty-bitmap-disable': 'BlockDirtyBitmap', +- 'x-block-dirty-bitmap-merge': 'BlockDirtyBitmapMerge', ++ 'block-dirty-bitmap-enable': 'BlockDirtyBitmap', ++ 'block-dirty-bitmap-disable': 'BlockDirtyBitmap', ++ 'block-dirty-bitmap-merge': 'BlockDirtyBitmapMerge', + 'blockdev-backup': 'BlockdevBackup', + 'blockdev-snapshot': 'BlockdevSnapshot', + 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal', +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index a462f41..e59411e 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -111,9 +111,9 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", + "arguments":{"driver":"qcow2", "node-name":"n", + "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", + "arguments":{"node":"n", "name":"b"}}' "return" +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", + "arguments":{"node":"n", "name":"b2"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", + "arguments":{"addr":{"type":"unix", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-simplify-code-around-releasing-bitmaps.patch b/SOURCES/kvm-block-simplify-code-around-releasing-bitmaps.patch new file mode 100644 index 0000000..84367d5 --- /dev/null +++ b/SOURCES/kvm-block-simplify-code-around-releasing-bitmaps.patch @@ -0,0 +1,166 @@ +From 4cf452add8a2760d325b79efdd484c8d37cd2158 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:22 +0100 +Subject: [PATCH 12/33] block: simplify code around releasing bitmaps + +RH-Author: John Snow +Message-id: <20190206221243.7407-3-jsnow@redhat.com> +Patchwork-id: 84262 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 02/23] block: simplify code around releasing bitmaps +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Paolo Bonzini + +QLIST_REMOVE does not require walking the list, and once the "bitmap" +argument is removed from bdrv_do_release_matching_dirty_bitmap_locked +the code simplifies a lot and it is worth inlining everything in the +callers of bdrv_do_release_matching_dirty_bitmap. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +Message-id: 20180326104037.6894-1-pbonzini@redhat.com +Signed-off-by: John Snow +(cherry picked from commit b133c27f5dc59969574b0715e5837d32c99caa86) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 84 ++++++++++++++++++++-------------------------------- + 1 file changed, 32 insertions(+), 52 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 50e855a..cd39afd 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -256,49 +256,16 @@ void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap) + qemu_mutex_unlock(bitmap->mutex); + } + +-/* Called within bdrv_dirty_bitmap_lock..unlock */ +-static void bdrv_do_release_matching_dirty_bitmap_locked( +- BlockDriverState *bs, BdrvDirtyBitmap *bitmap, +- bool (*cond)(BdrvDirtyBitmap *bitmap)) ++/* Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken. */ ++static void bdrv_release_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) + { +- BdrvDirtyBitmap *bm, *next; +- +- QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { +- if ((!bitmap || bm == bitmap) && (!cond || cond(bm))) { +- assert(!bm->active_iterators); +- assert(!bdrv_dirty_bitmap_frozen(bm)); +- assert(!bm->meta); +- QLIST_REMOVE(bm, list); +- hbitmap_free(bm->bitmap); +- g_free(bm->name); +- g_free(bm); +- +- if (bitmap) { +- return; +- } +- } +- } +- +- if (bitmap) { +- abort(); +- } +-} +- +-/* Called with BQL taken. */ +-static void bdrv_do_release_matching_dirty_bitmap( +- BlockDriverState *bs, BdrvDirtyBitmap *bitmap, +- bool (*cond)(BdrvDirtyBitmap *bitmap)) +-{ +- bdrv_dirty_bitmaps_lock(bs); +- bdrv_do_release_matching_dirty_bitmap_locked(bs, bitmap, cond); +- bdrv_dirty_bitmaps_unlock(bs); +-} +- +-/* Called within bdrv_dirty_bitmap_lock..unlock */ +-static void bdrv_release_dirty_bitmap_locked(BlockDriverState *bs, +- BdrvDirtyBitmap *bitmap) +-{ +- bdrv_do_release_matching_dirty_bitmap_locked(bs, bitmap, NULL); ++ assert(!bitmap->active_iterators); ++ assert(!bdrv_dirty_bitmap_frozen(bitmap)); ++ assert(!bitmap->meta); ++ QLIST_REMOVE(bitmap, list); ++ hbitmap_free(bitmap->bitmap); ++ g_free(bitmap->name); ++ g_free(bitmap); + } + + /** +@@ -351,7 +318,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + error_setg(errp, "Merging of parent and successor bitmap failed"); + return NULL; + } +- bdrv_release_dirty_bitmap_locked(bs, successor); ++ bdrv_release_dirty_bitmap_locked(successor); + parent->successor = NULL; + + return parent; +@@ -389,15 +356,12 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes) + bdrv_dirty_bitmaps_unlock(bs); + } + +-static bool bdrv_dirty_bitmap_has_name(BdrvDirtyBitmap *bitmap) +-{ +- return !!bdrv_dirty_bitmap_name(bitmap); +-} +- + /* Called with BQL taken. */ + void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) + { +- bdrv_do_release_matching_dirty_bitmap(bs, bitmap, NULL); ++ bdrv_dirty_bitmaps_lock(bs); ++ bdrv_release_dirty_bitmap_locked(bitmap); ++ bdrv_dirty_bitmaps_unlock(bs); + } + + /** +@@ -408,7 +372,15 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) + */ + void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) + { +- bdrv_do_release_matching_dirty_bitmap(bs, NULL, bdrv_dirty_bitmap_has_name); ++ BdrvDirtyBitmap *bm, *next; ++ ++ bdrv_dirty_bitmaps_lock(bs); ++ QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { ++ if (bdrv_dirty_bitmap_name(bm)) { ++ bdrv_release_dirty_bitmap_locked(bm); ++ } ++ } ++ bdrv_dirty_bitmaps_unlock(bs); + } + + /** +@@ -416,11 +388,19 @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) + * bdrv_inactivate_recurse()). + * There must not be any frozen bitmaps attached. + * This function does not remove persistent bitmaps from the storage. ++ * Called with BQL taken. + */ + void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs) + { +- bdrv_do_release_matching_dirty_bitmap(bs, NULL, +- bdrv_dirty_bitmap_get_persistance); ++ BdrvDirtyBitmap *bm, *next; ++ ++ bdrv_dirty_bitmaps_lock(bs); ++ QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { ++ if (bdrv_dirty_bitmap_get_persistance(bm)) { ++ bdrv_release_dirty_bitmap_locked(bm); ++ } ++ } ++ bdrv_dirty_bitmaps_unlock(bs); + } + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-abort-transactions-in-reverse-order.patch b/SOURCES/kvm-blockdev-abort-transactions-in-reverse-order.patch new file mode 100644 index 0000000..685ffe4 --- /dev/null +++ b/SOURCES/kvm-blockdev-abort-transactions-in-reverse-order.patch @@ -0,0 +1,97 @@ +From 68dbabe0167538bcf3996692b3dc3dce01e34f74 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Thu, 24 Jan 2019 00:55:10 +0100 +Subject: [PATCH 5/8] blockdev: abort transactions in reverse order + +RH-Author: John Snow +Message-id: <20190124005511.27662-2-jsnow@redhat.com> +Patchwork-id: 84105 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/2] blockdev: abort transactions in reverse order +Bugzilla: 1658426 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Eric Blake + +Presently, we abort transactions in the same order they were processed in. +Bitmap commands, though, attempt to restore backup data structures on abort. + +That's not valid, they need to be aborted in reverse chronological order. + +Replace the QSIMPLEQ data structure with a QTAILQ one, so we can iterate +in reverse for the abort phase of the transaction. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-2-jsnow@redhat.com> +[eblake: rebase] +Signed-off-by: Eric Blake +(cherry picked from commit f4de0f8c40b70c4c9308b4670e0a6ad9faed0262) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 3eb1880..f25ab15 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1491,7 +1491,7 @@ struct BlkActionState { + const BlkActionOps *ops; + JobTxn *block_job_txn; + TransactionProperties *txn_props; +- QSIMPLEQ_ENTRY(BlkActionState) entry; ++ QTAILQ_ENTRY(BlkActionState) entry; + }; + + /* internal snapshot private data */ +@@ -2376,8 +2376,8 @@ void qmp_transaction(TransactionActionList *dev_list, + BlkActionState *state, *next; + Error *local_err = NULL; + +- QSIMPLEQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states; +- QSIMPLEQ_INIT(&snap_bdrv_states); ++ QTAILQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states; ++ QTAILQ_INIT(&snap_bdrv_states); + + /* Does this transaction get canceled as a group on failure? + * If not, we don't really need to make a JobTxn. +@@ -2408,7 +2408,7 @@ void qmp_transaction(TransactionActionList *dev_list, + state->action = dev_info; + state->block_job_txn = block_job_txn; + state->txn_props = props; +- QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry); ++ QTAILQ_INSERT_TAIL(&snap_bdrv_states, state, entry); + + state->ops->prepare(state, &local_err); + if (local_err) { +@@ -2417,7 +2417,7 @@ void qmp_transaction(TransactionActionList *dev_list, + } + } + +- QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) { ++ QTAILQ_FOREACH(state, &snap_bdrv_states, entry) { + if (state->ops->commit) { + state->ops->commit(state); + } +@@ -2428,13 +2428,13 @@ void qmp_transaction(TransactionActionList *dev_list, + + delete_and_fail: + /* failure, and it is all-or-none; roll back all operations */ +- QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) { ++ QTAILQ_FOREACH_REVERSE(state, &snap_bdrv_states, snap_bdrv_states, entry) { + if (state->ops->abort) { + state->ops->abort(state); + } + } + exit: +- QSIMPLEQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) { ++ QTAILQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) { + if (state->ops->clean) { + state->ops->clean(state); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-acquire-aio_context-for-bitmap-add-remove.patch b/SOURCES/kvm-blockdev-acquire-aio_context-for-bitmap-add-remove.patch new file mode 100644 index 0000000..7bae2e1 --- /dev/null +++ b/SOURCES/kvm-blockdev-acquire-aio_context-for-bitmap-add-remove.patch @@ -0,0 +1,115 @@ +From 04c5a9797c3bdf379ffad1f159eccfcdca12475f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 23:55:08 +0100 +Subject: [PATCH 046/163] blockdev: acquire aio_context for bitmap add/remove + +RH-Author: John Snow +Message-id: <20190320235508.17673-2-jsnow@redhat.com> +Patchwork-id: 85031 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] blockdev: acquire aio_context for bitmap add/remove +Bugzilla: 1672010 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz + +When bitmaps are persistent, they may incur a disk read or write when bitmaps +are added or removed. For configurations like virtio-dataplane, failing to +acquire this lock will abort QEMU when disk IO occurs. + +We used to acquire aio_context as part of the bitmap lookup, so re-introduce +the lock for just the cases that have an IO penalty. Commit 2119882c removed +these locks, and I failed to notice this when we committed fd5ae4cc, so this +has been broken since persistent bitmaps were introduced. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1672010 +Reported-By: Aihua Liang +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20190218233154.19303-1-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 0a6c86d024c52b1e66d4f7ec01a3bb8ea2600145) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 47db9bb..f437896 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2973,6 +2973,7 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + { + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; ++ AioContext *aio_context = NULL; + + if (!name || name[0] == '\0') { + error_setg(errp, "Bitmap name cannot be empty"); +@@ -3007,15 +3008,17 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + disabled = false; + } + +- if (persistent && +- !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) +- { +- return; ++ if (persistent) { ++ aio_context = bdrv_get_aio_context(bs); ++ aio_context_acquire(aio_context); ++ if (!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) { ++ goto out; ++ } + } + + bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); + if (bitmap == NULL) { +- return; ++ goto out; + } + + if (disabled) { +@@ -3023,6 +3026,10 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + } + + bdrv_dirty_bitmap_set_persistance(bitmap, persistent); ++ out: ++ if (aio_context) { ++ aio_context_release(aio_context); ++ } + } + + void qmp_block_dirty_bitmap_remove(const char *node, const char *name, +@@ -3031,6 +3038,7 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + Error *local_err = NULL; ++ AioContext *aio_context = NULL; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap || !bs) { +@@ -3045,14 +3053,20 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, + } + + if (bdrv_dirty_bitmap_get_persistance(bitmap)) { ++ aio_context = bdrv_get_aio_context(bs); ++ aio_context_acquire(aio_context); + bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); +- return; ++ goto out; + } + } + + bdrv_release_dirty_bitmap(bs, bitmap); ++ out: ++ if (aio_context) { ++ aio_context_release(aio_context); ++ } + } + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-fix-missed-target-unref-for-drive-backup.patch b/SOURCES/kvm-blockdev-fix-missed-target-unref-for-drive-backup.patch new file mode 100644 index 0000000..e16c424 --- /dev/null +++ b/SOURCES/kvm-blockdev-fix-missed-target-unref-for-drive-backup.patch @@ -0,0 +1,80 @@ +From 4f1adbc42c93d406d73e30243ddaa6cb11257a24 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 4 Jun 2019 17:47:22 +0200 +Subject: [PATCH 8/9] blockdev: fix missed target unref for drive-backup + +RH-Author: John Snow +Message-id: <20190604174722.30906-2-jsnow@redhat.com> +Patchwork-id: 88526 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] blockdev: fix missed target unref for drive-backup +Bugzilla: 1703916 +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefano Garzarella + +If the bitmap can't be used for whatever reason, we skip putting down +the reference. Fix that. + +In practice, this means that if you attempt to gracefully exit QEMU +after a backup command being rejected, bdrv_close_all will fail and +tell you some unpleasant things via assert(). + +Reported-by: aihua liang +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1703916 +Signed-off-by: John Snow +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 4da26f138db06c9c6d7199d42bd3c2be552cb956) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 61218b4..739441d 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3673,8 +3673,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + if (set_backing_hd) { + bdrv_set_backing_hd(target_bs, source, &local_err); + if (local_err) { +- bdrv_unref(target_bs); +- goto out; ++ goto unref; + } + } + +@@ -3682,11 +3681,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); + if (!bmap) { + error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); +- bdrv_unref(target_bs); +- goto out; ++ goto unref; + } + if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { +- goto out; ++ goto unref; + } + } + if (!backup->auto_finalize) { +@@ -3700,12 +3698,13 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + backup->sync, bmap, backup->compress, + backup->on_source_error, backup->on_target_error, + job_flags, NULL, NULL, txn, &local_err); +- bdrv_unref(target_bs); + if (local_err != NULL) { + error_propagate(errp, local_err); +- goto out; ++ goto unref; + } + ++unref: ++ bdrv_unref(target_bs); + out: + aio_context_release(aio_context); + return job; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-n-ary-bitmap-merge.patch b/SOURCES/kvm-blockdev-n-ary-bitmap-merge.patch new file mode 100644 index 0000000..ea7a8d6 --- /dev/null +++ b/SOURCES/kvm-blockdev-n-ary-bitmap-merge.patch @@ -0,0 +1,207 @@ +From 80ea6f080180cd5aea1603405948d164442dd8d1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:16 +0100 +Subject: [PATCH 018/163] blockdev: n-ary bitmap merge + +RH-Author: John Snow +Message-id: <20190320161631.14841-5-jsnow@redhat.com> +Patchwork-id: 84948 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/19] blockdev: n-ary bitmap merge +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Especially outside of transactions, it is helpful to provide +all-or-nothing semantics for bitmap merges. This facilitates +the coalescing of multiple bitmaps into a single target for +the "checkpoint" interpretation when assembling bitmaps that +represent arbitrary points in time from component bitmaps. + +This is an incompatible change from the preliminary version +of the API. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-4-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 360d4e4e9a501d92fb8866ac307d33a25f70c6d1) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 75 +++++++++++++++++++++++++++++++++++----------------- + qapi/block-core.json | 22 +++++++-------- + 2 files changed, 62 insertions(+), 35 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index c9bda43..3755936 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2272,33 +2272,28 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common) + } + } + ++static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node, ++ const char *target, ++ strList *bitmaps, ++ HBitmap **backup, ++ Error **errp); ++ + static void block_dirty_bitmap_merge_prepare(BlkActionState *common, + Error **errp) + { + BlockDirtyBitmapMerge *action; + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); +- BdrvDirtyBitmap *merge_source; + + if (action_check_completion_mode(common, errp) < 0) { + return; + } + + action = common->action->u.x_block_dirty_bitmap_merge.data; +- state->bitmap = block_dirty_bitmap_lookup(action->node, +- action->dst_name, +- &state->bs, +- errp); +- if (!state->bitmap) { +- return; +- } + +- merge_source = bdrv_find_dirty_bitmap(state->bs, action->src_name); +- if (!merge_source) { +- return; +- } +- +- bdrv_merge_dirty_bitmap(state->bitmap, merge_source, &state->backup, errp); ++ state->bitmap = do_block_dirty_bitmap_merge(action->node, action->target, ++ action->bitmaps, &state->backup, ++ errp); + } + + static void abort_prepare(BlkActionState *common, Error **errp) +@@ -3130,24 +3125,56 @@ void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, + bdrv_disable_dirty_bitmap(bitmap); + } + +-void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, +- const char *src_name, Error **errp) ++static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node, ++ const char *target, ++ strList *bitmaps, ++ HBitmap **backup, ++ Error **errp) + { + BlockDriverState *bs; +- BdrvDirtyBitmap *dst, *src; ++ BdrvDirtyBitmap *dst, *src, *anon; ++ strList *lst; ++ Error *local_err = NULL; + +- dst = block_dirty_bitmap_lookup(node, dst_name, &bs, errp); ++ dst = block_dirty_bitmap_lookup(node, target, &bs, errp); + if (!dst) { +- return; ++ return NULL; + } + +- src = bdrv_find_dirty_bitmap(bs, src_name); +- if (!src) { +- error_setg(errp, "Dirty bitmap '%s' not found", src_name); +- return; ++ anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst), ++ NULL, errp); ++ if (!anon) { ++ return NULL; ++ } ++ ++ for (lst = bitmaps; lst; lst = lst->next) { ++ src = bdrv_find_dirty_bitmap(bs, lst->value); ++ if (!src) { ++ error_setg(errp, "Dirty bitmap '%s' not found", lst->value); ++ dst = NULL; ++ goto out; ++ } ++ ++ bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ dst = NULL; ++ goto out; ++ } + } + +- bdrv_merge_dirty_bitmap(dst, src, NULL, errp); ++ /* Merge into dst; dst is unchanged on failure. */ ++ bdrv_merge_dirty_bitmap(dst, anon, backup, errp); ++ ++ out: ++ bdrv_release_dirty_bitmap(bs, anon); ++ return dst; ++} ++ ++void qmp_x_block_dirty_bitmap_merge(const char *node, const char *target, ++ strList *bitmaps, Error **errp) ++{ ++ do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp); + } + + BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 0960449..7e11392 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1801,14 +1801,14 @@ + # + # @node: name of device/node which the bitmap is tracking + # +-# @dst_name: name of the destination dirty bitmap ++# @target: name of the destination dirty bitmap + # +-# @src_name: name of the source dirty bitmap ++# @bitmaps: name(s) of the source dirty bitmap(s) + # + # Since: 3.0 + ## + { 'struct': 'BlockDirtyBitmapMerge', +- 'data': { 'node': 'str', 'dst_name': 'str', 'src_name': 'str' } } ++ 'data': { 'node': 'str', 'target': 'str', 'bitmaps': ['str'] } } + + ## + # @block-dirty-bitmap-add: +@@ -1923,23 +1923,23 @@ + ## + # @x-block-dirty-bitmap-merge: + # +-# FIXME: Rename @src_name and @dst_name to src-name and dst-name. +-# +-# Merge @src_name dirty bitmap to @dst_name dirty bitmap. @src_name dirty +-# bitmap is unchanged. On error, @dst_name is unchanged. ++# Merge dirty bitmaps listed in @bitmaps to the @target dirty bitmap. ++# The @bitmaps dirty bitmaps are unchanged. ++# On error, @target is unchanged. + # + # Returns: nothing on success + # If @node is not a valid block device, DeviceNotFound +-# If @dst_name or @src_name is not found, GenericError +-# If bitmaps has different sizes or granularities, GenericError ++# If any bitmap in @bitmaps or @target is not found, GenericError ++# If any of the bitmaps have different sizes or granularities, ++# GenericError + # + # Since: 3.0 + # + # Example: + # + # -> { "execute": "x-block-dirty-bitmap-merge", +-# "arguments": { "node": "drive0", "dst_name": "bitmap0", +-# "src_name": "bitmap1" } } ++# "arguments": { "node": "drive0", "target": "bitmap0", ++# "bitmaps": ["bitmap1"] } } + # <- { "return": {} } + # + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-remove-unused-paio-parameter-documentation.patch b/SOURCES/kvm-blockdev-remove-unused-paio-parameter-documentation.patch new file mode 100644 index 0000000..def8347 --- /dev/null +++ b/SOURCES/kvm-blockdev-remove-unused-paio-parameter-documentation.patch @@ -0,0 +1,43 @@ +From 7b60eac4fb7e3f0373381e148f963878e0325916 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:47 +0200 +Subject: [PATCH 142/163] blockdev: remove unused paio parameter documentation + +RH-Author: John Snow +Message-id: <20190403181857.9693-12-jsnow@redhat.com> +Patchwork-id: 85424 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/21] blockdev: remove unused paio parameter documentation +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +This field isn't present anymore. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-10-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 2f158ca7b63175c5f0ac9a65e933e23deac46caa) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index c9ade12..a9e2e1d 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1407,7 +1407,6 @@ out_aio_context: + * @node: The name of the BDS node to search for bitmaps + * @name: The name of the bitmap to search for + * @pbs: Output pointer for BDS lookup, if desired. Can be NULL. +- * @paio: Output pointer for aio_context acquisition, if desired. Can be NULL. + * @errp: Output pointer for error information. Can be NULL. + * + * @return: A bitmap object on success, or NULL on failure. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-rename-block-dirty-bitmap-clear-transaction.patch b/SOURCES/kvm-blockdev-rename-block-dirty-bitmap-clear-transaction.patch new file mode 100644 index 0000000..df90b06 --- /dev/null +++ b/SOURCES/kvm-blockdev-rename-block-dirty-bitmap-clear-transaction.patch @@ -0,0 +1,65 @@ +From 09fa15417e6c4778f50c8396004efd74077afa81 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:29 +0100 +Subject: [PATCH 19/33] blockdev: rename block-dirty-bitmap-clear transaction + handlers + +RH-Author: John Snow +Message-id: <20190206221243.7407-10-jsnow@redhat.com> +Patchwork-id: 84274 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 09/23] blockdev: rename block-dirty-bitmap-clear transaction handlers +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Rename block-dirty-bitmap-clear transaction handlers to reuse them for +x-block-dirty-bitmap-merge transaction in the following patch. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 5c4cf8b294ee65c049d6c40f5f6ff7c1befdb3d9) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 823a97f..853dd0e 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2178,7 +2178,7 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, + bdrv_clear_dirty_bitmap(state->bitmap, &state->backup); + } + +-static void block_dirty_bitmap_clear_abort(BlkActionState *common) ++static void block_dirty_bitmap_restore(BlkActionState *common) + { + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); +@@ -2188,7 +2188,7 @@ static void block_dirty_bitmap_clear_abort(BlkActionState *common) + } + } + +-static void block_dirty_bitmap_clear_commit(BlkActionState *common) ++static void block_dirty_bitmap_free_backup(BlkActionState *common) + { + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); +@@ -2322,8 +2322,8 @@ static const BlkActionOps actions[] = { + [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_CLEAR] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_clear_prepare, +- .commit = block_dirty_bitmap_clear_commit, +- .abort = block_dirty_bitmap_clear_abort, ++ .commit = block_dirty_bitmap_free_backup, ++ .abort = block_dirty_bitmap_restore, + }, + [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), +-- +1.8.3.1 + diff --git a/SOURCES/kvm-cpus-ignore-ESRCH-in-qemu_cpu_kick_thread.patch b/SOURCES/kvm-cpus-ignore-ESRCH-in-qemu_cpu_kick_thread.patch new file mode 100644 index 0000000..23a69c4 --- /dev/null +++ b/SOURCES/kvm-cpus-ignore-ESRCH-in-qemu_cpu_kick_thread.patch @@ -0,0 +1,55 @@ +From 9e6a36459015ac8ac3c8e550bd2242c127203370 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Wed, 23 Jan 2019 08:48:57 +0100 +Subject: [PATCH 4/8] cpus: ignore ESRCH in qemu_cpu_kick_thread() + +RH-Author: Laurent Vivier +Message-id: <20190123084857.16841-1-lvivier@redhat.com> +Patchwork-id: 84094 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH] cpus: ignore ESRCH in qemu_cpu_kick_thread() +Bugzilla: 1614610 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Serhii Popovych +RH-Acked-by: Thomas Huth + +We can have a race condition between qemu_cpu_kick_thread() and +qemu_kvm_cpu_thread_fn() when we hotunplug a CPU. In this case, +qemu_cpu_kick_thread() can try to kick a thread that is exiting. +pthread_kill() returns an error and qemu is stopped by an exit(1). + + qemu:qemu_cpu_kick_thread: No such process + +We can ignore safely this error. + +Signed-off-by: Laurent Vivier +Signed-off-by: Paolo Bonzini +(cherry picked from commit e9979ef245549b8e1fd240ec9937271c7fda0b57) + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1614610 +BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=19894361 +UPSTREAM: In maintainer pull request + git://github.com/bonzini/qemu.git tags/for-upstream + 3cf01054d896fa88ea0dd31c5abb605c2e68bb29 +TEST: Upstream version tested by QE + +Signed-off-by: Miroslav Rezanina +--- + cpus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cpus.c b/cpus.c +index be3a4eb..f9798e3 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -1700,7 +1700,7 @@ static void qemu_cpu_kick_thread(CPUState *cpu) + } + cpu->thread_kicked = true; + err = pthread_kill(cpu->thread->thread, SIG_IPI); +- if (err) { ++ if (err && err != ESRCH) { + fprintf(stderr, "qemu:%s: %s", __func__, strerror(err)); + exit(1); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-add-testing-for-unaligned-buffers-with-XTS-ci.patch b/SOURCES/kvm-crypto-add-testing-for-unaligned-buffers-with-XTS-ci.patch new file mode 100644 index 0000000..bd9a534 --- /dev/null +++ b/SOURCES/kvm-crypto-add-testing-for-unaligned-buffers-with-XTS-ci.patch @@ -0,0 +1,136 @@ +From 97c4305758431f95fb64841dfec1b589e42de11f Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:30 +0200 +Subject: [PATCH 11/12] crypto: add testing for unaligned buffers with XTS + cipher mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-10-berrange@redhat.com> +Patchwork-id: 85896 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 9/9] crypto: add testing for unaligned buffers with XTS cipher mode +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +Validate that the XTS cipher mode will correctly operate with plain +text, cipher text and IV buffers that are not 64-bit aligned. + +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 1e0fa32c6c952d2ce9c19d35717c609804dd55d5) +Signed-off-by: Miroslav Rezanina +--- + tests/test-crypto-xts.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 86 insertions(+) + +diff --git a/tests/test-crypto-xts.c b/tests/test-crypto-xts.c +index 81606d9..6fb61cf 100644 +--- a/tests/test-crypto-xts.c ++++ b/tests/test-crypto-xts.c +@@ -416,6 +416,88 @@ static void test_xts_split(const void *opaque) + } + + ++static void test_xts_unaligned(const void *opaque) ++{ ++#define BAD_ALIGN 3 ++ const QCryptoXTSTestData *data = opaque; ++ uint8_t in[512 + BAD_ALIGN], out[512 + BAD_ALIGN]; ++ uint8_t Torg[16], T[16 + BAD_ALIGN]; ++ uint64_t seq; ++ struct TestAES aesdata; ++ struct TestAES aestweak; ++ ++ AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc); ++ AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec); ++ AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc); ++ AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec); ++ ++ seq = data->seqnum; ++ STORE64L(seq, Torg); ++ memset(Torg + 8, 0, 8); ++ ++ /* IV not aligned */ ++ memcpy(T + BAD_ALIGN, Torg, 16); ++ memcpy(in, data->PTX, data->PTLEN); ++ xts_encrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T + BAD_ALIGN, data->PTLEN, out, in); ++ ++ g_assert(memcmp(out, data->CTX, data->PTLEN) == 0); ++ ++ /* plain text not aligned */ ++ memcpy(T, Torg, 16); ++ memcpy(in + BAD_ALIGN, data->PTX, data->PTLEN); ++ xts_encrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, data->PTLEN, out, in + BAD_ALIGN); ++ ++ g_assert(memcmp(out, data->CTX, data->PTLEN) == 0); ++ ++ /* cipher text not aligned */ ++ memcpy(T, Torg, 16); ++ memcpy(in, data->PTX, data->PTLEN); ++ xts_encrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, data->PTLEN, out + BAD_ALIGN, in); ++ ++ g_assert(memcmp(out + BAD_ALIGN, data->CTX, data->PTLEN) == 0); ++ ++ ++ /* IV not aligned */ ++ memcpy(T + BAD_ALIGN, Torg, 16); ++ memcpy(in, data->CTX, data->PTLEN); ++ xts_decrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T + BAD_ALIGN, data->PTLEN, out, in); ++ ++ g_assert(memcmp(out, data->PTX, data->PTLEN) == 0); ++ ++ /* cipher text not aligned */ ++ memcpy(T, Torg, 16); ++ memcpy(in + BAD_ALIGN, data->CTX, data->PTLEN); ++ xts_decrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, data->PTLEN, out, in + BAD_ALIGN); ++ ++ g_assert(memcmp(out, data->PTX, data->PTLEN) == 0); ++ ++ /* plain text not aligned */ ++ memcpy(T, Torg, 16); ++ memcpy(in, data->CTX, data->PTLEN); ++ xts_decrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, data->PTLEN, out + BAD_ALIGN, in); ++ ++ g_assert(memcmp(out + BAD_ALIGN, data->PTX, data->PTLEN) == 0); ++} ++ ++ + int main(int argc, char **argv) + { + size_t i; +@@ -437,6 +519,10 @@ int main(int argc, char **argv) + g_test_add_data_func(path, &test_data[i], test_xts_split); + g_free(path); + } ++ ++ path = g_strdup_printf("%s/unaligned", test_data[i].path); ++ g_test_add_data_func(path, &test_data[i], test_xts_unaligned); ++ g_free(path); + } + + return g_test_run(); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-annotate-xts_tweak_encdec-as-inlineable.patch b/SOURCES/kvm-crypto-annotate-xts_tweak_encdec-as-inlineable.patch new file mode 100644 index 0000000..29bd77c --- /dev/null +++ b/SOURCES/kvm-crypto-annotate-xts_tweak_encdec-as-inlineable.patch @@ -0,0 +1,55 @@ +From a728b4ea94c406513e3d3167ba74c7b3314df3ce Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:28 +0200 +Subject: [PATCH 09/12] crypto: annotate xts_tweak_encdec as inlineable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-8-berrange@redhat.com> +Patchwork-id: 85893 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 7/9] crypto: annotate xts_tweak_encdec as inlineable +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +Encouraging the compiler to inline xts_tweak_encdec increases the +performance for xts-aes-128 when built with gcrypt: + + Encrypt: 545 MB/s -> 580 MB/s + Decrypt: 568 MB/s -> 602 MB/s + +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit aa895bd439341a8f218d8f1a3d21359ba058c13f) +Signed-off-by: Miroslav Rezanina +--- + crypto/xts.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/crypto/xts.c b/crypto/xts.c +index 10ec83f..4277ad4 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -81,11 +81,11 @@ static void xts_mult_x(xts_uint128 *I) + * + * Encrypt/decrypt data with a tweak + */ +-static void xts_tweak_encdec(const void *ctx, +- xts_cipher_func *func, +- const xts_uint128 *src, +- xts_uint128 *dst, +- xts_uint128 *iv) ++static inline void xts_tweak_encdec(const void *ctx, ++ xts_cipher_func *func, ++ const xts_uint128 *src, ++ xts_uint128 *dst, ++ xts_uint128 *iv) + { + /* tweak encrypt block i */ + xts_uint128_xor(dst, src, iv); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-convert-xts_mult_x-to-use-xts_uint128-type.patch b/SOURCES/kvm-crypto-convert-xts_mult_x-to-use-xts_uint128-type.patch new file mode 100644 index 0000000..df3adf1 --- /dev/null +++ b/SOURCES/kvm-crypto-convert-xts_mult_x-to-use-xts_uint128-type.patch @@ -0,0 +1,109 @@ +From dfbbe38a74bec140652071dce9dad71514ec7091 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:27 +0200 +Subject: [PATCH 08/12] crypto: convert xts_mult_x to use xts_uint128 type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-7-berrange@redhat.com> +Patchwork-id: 85895 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 6/9] crypto: convert xts_mult_x to use xts_uint128 type +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +Using 64-bit arithmetic increases the performance for xts-aes-128 +when built with gcrypt: + + Encrypt: 355 MB/s -> 545 MB/s + Decrypt: 362 MB/s -> 568 MB/s + +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 7dac0dd67426753646df0c23c819609b9e704f59) +Signed-off-by: Miroslav Rezanina +--- + crypto/xts.c | 40 ++++++++++++++++++++++++++++------------ + 1 file changed, 28 insertions(+), 12 deletions(-) + +diff --git a/crypto/xts.c b/crypto/xts.c +index 0ad231f..10ec83f 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -24,6 +24,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/bswap.h" + #include "crypto/xts.h" + + typedef union { +@@ -39,19 +40,34 @@ static inline void xts_uint128_xor(xts_uint128 *D, + D->u[1] = S1->u[1] ^ S2->u[1]; + } + +-static void xts_mult_x(uint8_t *I) ++static inline void xts_uint128_cpu_to_les(xts_uint128 *v) + { +- int x; +- uint8_t t, tt; ++ cpu_to_le64s(&v->u[0]); ++ cpu_to_le64s(&v->u[1]); ++} + +- for (x = t = 0; x < 16; x++) { +- tt = I[x] >> 7; +- I[x] = ((I[x] << 1) | t) & 0xFF; +- t = tt; +- } +- if (tt) { +- I[0] ^= 0x87; ++static inline void xts_uint128_le_to_cpus(xts_uint128 *v) ++{ ++ le64_to_cpus(&v->u[0]); ++ le64_to_cpus(&v->u[1]); ++} ++ ++static void xts_mult_x(xts_uint128 *I) ++{ ++ uint64_t tt; ++ ++ xts_uint128_le_to_cpus(I); ++ ++ tt = I->u[0] >> 63; ++ I->u[0] <<= 1; ++ ++ if (I->u[1] >> 63) { ++ I->u[0] ^= 0x87; + } ++ I->u[1] <<= 1; ++ I->u[1] |= tt; ++ ++ xts_uint128_cpu_to_les(I); + } + + +@@ -79,7 +95,7 @@ static void xts_tweak_encdec(const void *ctx, + xts_uint128_xor(dst, dst, iv); + + /* LFSR the tweak */ +- xts_mult_x(iv->b); ++ xts_mult_x(iv); + } + + +@@ -134,7 +150,7 @@ void xts_decrypt(const void *datactx, + if (mo > 0) { + xts_uint128 S, D; + memcpy(&CC, &T, XTS_BLOCK_SIZE); +- xts_mult_x(CC.b); ++ xts_mult_x(&CC); + + /* PP = tweak decrypt block m-1 */ + memcpy(&S, src, XTS_BLOCK_SIZE); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-convert-xts_tweak_encdec-to-use-xts_uint128-t.patch b/SOURCES/kvm-crypto-convert-xts_tweak_encdec-to-use-xts_uint128-t.patch new file mode 100644 index 0000000..1c937b2 --- /dev/null +++ b/SOURCES/kvm-crypto-convert-xts_tweak_encdec-to-use-xts_uint128-t.patch @@ -0,0 +1,185 @@ +From 8c411fd4449466ba46b272d60b739015a6b47e19 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:26 +0200 +Subject: [PATCH 07/12] crypto: convert xts_tweak_encdec to use xts_uint128 + type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-6-berrange@redhat.com> +Patchwork-id: 85890 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 5/9] crypto: convert xts_tweak_encdec to use xts_uint128 type +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +Using 64-bit arithmetic increases the performance for xts-aes-128 +when built with gcrypt: + + Encrypt: 272 MB/s -> 355 MB/s + Decrypt: 275 MB/s -> 362 MB/s + +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit db217c69f0849add67cfa2cd6601c329398be12c) +Signed-off-by: Miroslav Rezanina +--- + crypto/xts.c | 84 +++++++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 58 insertions(+), 26 deletions(-) + +diff --git a/crypto/xts.c b/crypto/xts.c +index bee23f8..0ad231f 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -31,6 +31,13 @@ typedef union { + uint64_t u[2]; + } xts_uint128; + ++static inline void xts_uint128_xor(xts_uint128 *D, ++ const xts_uint128 *S1, ++ const xts_uint128 *S2) ++{ ++ D->u[0] = S1->u[0] ^ S2->u[0]; ++ D->u[1] = S1->u[1] ^ S2->u[1]; ++} + + static void xts_mult_x(uint8_t *I) + { +@@ -60,25 +67,19 @@ static void xts_mult_x(uint8_t *I) + */ + static void xts_tweak_encdec(const void *ctx, + xts_cipher_func *func, +- const uint8_t *src, +- uint8_t *dst, +- uint8_t *iv) ++ const xts_uint128 *src, ++ xts_uint128 *dst, ++ xts_uint128 *iv) + { +- unsigned long x; +- + /* tweak encrypt block i */ +- for (x = 0; x < XTS_BLOCK_SIZE; x++) { +- dst[x] = src[x] ^ iv[x]; +- } ++ xts_uint128_xor(dst, src, iv); + +- func(ctx, XTS_BLOCK_SIZE, dst, dst); ++ func(ctx, XTS_BLOCK_SIZE, dst->b, dst->b); + +- for (x = 0; x < XTS_BLOCK_SIZE; x++) { +- dst[x] = dst[x] ^ iv[x]; +- } ++ xts_uint128_xor(dst, dst, iv); + + /* LFSR the tweak */ +- xts_mult_x(iv); ++ xts_mult_x(iv->b); + } + + +@@ -110,20 +111,34 @@ void xts_decrypt(const void *datactx, + /* encrypt the iv */ + encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv); + +- for (i = 0; i < lim; i++) { +- xts_tweak_encdec(datactx, decfunc, src, dst, T.b); +- +- src += XTS_BLOCK_SIZE; +- dst += XTS_BLOCK_SIZE; ++ if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) && ++ QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) { ++ xts_uint128 *S = (xts_uint128 *)src; ++ xts_uint128 *D = (xts_uint128 *)dst; ++ for (i = 0; i < lim; i++, S++, D++) { ++ xts_tweak_encdec(datactx, decfunc, S, D, &T); ++ } ++ } else { ++ xts_uint128 D; ++ ++ for (i = 0; i < lim; i++) { ++ memcpy(&D, src, XTS_BLOCK_SIZE); ++ xts_tweak_encdec(datactx, decfunc, &D, &D, &T); ++ memcpy(dst, &D, XTS_BLOCK_SIZE); ++ src += XTS_BLOCK_SIZE; ++ dst += XTS_BLOCK_SIZE; ++ } + } + + /* if length is not a multiple of XTS_BLOCK_SIZE then */ + if (mo > 0) { ++ xts_uint128 S, D; + memcpy(&CC, &T, XTS_BLOCK_SIZE); + xts_mult_x(CC.b); + + /* PP = tweak decrypt block m-1 */ +- xts_tweak_encdec(datactx, decfunc, src, PP.b, CC.b); ++ memcpy(&S, src, XTS_BLOCK_SIZE); ++ xts_tweak_encdec(datactx, decfunc, &S, &PP, &CC); + + /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */ + for (i = 0; i < mo; i++) { +@@ -135,7 +150,8 @@ void xts_decrypt(const void *datactx, + } + + /* Pm-1 = Tweak uncrypt CC */ +- xts_tweak_encdec(datactx, decfunc, CC.b, dst, T.b); ++ xts_tweak_encdec(datactx, decfunc, &CC, &D, &T); ++ memcpy(dst, &D, XTS_BLOCK_SIZE); + } + + /* Decrypt the iv back */ +@@ -171,17 +187,32 @@ void xts_encrypt(const void *datactx, + /* encrypt the iv */ + encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv); + +- for (i = 0; i < lim; i++) { +- xts_tweak_encdec(datactx, encfunc, src, dst, T.b); ++ if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) && ++ QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) { ++ xts_uint128 *S = (xts_uint128 *)src; ++ xts_uint128 *D = (xts_uint128 *)dst; ++ for (i = 0; i < lim; i++, S++, D++) { ++ xts_tweak_encdec(datactx, encfunc, S, D, &T); ++ } ++ } else { ++ xts_uint128 D; ++ ++ for (i = 0; i < lim; i++) { ++ memcpy(&D, src, XTS_BLOCK_SIZE); ++ xts_tweak_encdec(datactx, encfunc, &D, &D, &T); ++ memcpy(dst, &D, XTS_BLOCK_SIZE); + +- dst += XTS_BLOCK_SIZE; +- src += XTS_BLOCK_SIZE; ++ dst += XTS_BLOCK_SIZE; ++ src += XTS_BLOCK_SIZE; ++ } + } + + /* if length is not a multiple of XTS_BLOCK_SIZE then */ + if (mo > 0) { ++ xts_uint128 S, D; + /* CC = tweak encrypt block m-1 */ +- xts_tweak_encdec(datactx, encfunc, src, CC.b, T.b); ++ memcpy(&S, src, XTS_BLOCK_SIZE); ++ xts_tweak_encdec(datactx, encfunc, &S, &CC, &T); + + /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */ + for (i = 0; i < mo; i++) { +@@ -194,7 +225,8 @@ void xts_encrypt(const void *datactx, + } + + /* Cm-1 = Tweak encrypt PP */ +- xts_tweak_encdec(datactx, encfunc, PP.b, dst, T.b); ++ xts_tweak_encdec(datactx, encfunc, &PP, &D, &T); ++ memcpy(dst, &D, XTS_BLOCK_SIZE); + } + + /* Decrypt the iv back */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-expand-algorithm-coverage-for-cipher-benchmar.patch b/SOURCES/kvm-crypto-expand-algorithm-coverage-for-cipher-benchmar.patch new file mode 100644 index 0000000..70828fc --- /dev/null +++ b/SOURCES/kvm-crypto-expand-algorithm-coverage-for-cipher-benchmar.patch @@ -0,0 +1,228 @@ +From f6c73edd44ee862b9b965cad1789a5dece3c5974 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:23 +0200 +Subject: [PATCH 04/12] crypto: expand algorithm coverage for cipher benchmark +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-3-berrange@redhat.com> +Patchwork-id: 85888 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/9] crypto: expand algorithm coverage for cipher benchmark +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +Add testing coverage for AES with XTS, ECB and CTR modes + +Reviewed-by: Marc-André Lureau +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit a9e08155bd4ae096688a8ff19669023ab0fbc170) +Signed-off-by: Miroslav Rezanina +--- + tests/benchmark-crypto-cipher.c | 149 +++++++++++++++++++++++++++++++++------- + 1 file changed, 126 insertions(+), 23 deletions(-) + +diff --git a/tests/benchmark-crypto-cipher.c b/tests/benchmark-crypto-cipher.c +index f5a0d0b..67fdf8c 100644 +--- a/tests/benchmark-crypto-cipher.c ++++ b/tests/benchmark-crypto-cipher.c +@@ -15,17 +15,27 @@ + #include "crypto/init.h" + #include "crypto/cipher.h" + +-static void test_cipher_speed(const void *opaque) ++static void test_cipher_speed(size_t chunk_size, ++ QCryptoCipherMode mode, ++ QCryptoCipherAlgorithm alg) + { + QCryptoCipher *cipher; + Error *err = NULL; + double total = 0.0; +- size_t chunk_size = (size_t)opaque; + uint8_t *key = NULL, *iv = NULL; + uint8_t *plaintext = NULL, *ciphertext = NULL; +- size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALG_AES_128); +- size_t niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128, +- QCRYPTO_CIPHER_MODE_CBC); ++ size_t nkey; ++ size_t niv; ++ ++ if (!qcrypto_cipher_supports(alg, mode)) { ++ return; ++ } ++ ++ nkey = qcrypto_cipher_get_key_len(alg); ++ niv = qcrypto_cipher_get_iv_len(alg, mode); ++ if (mode == QCRYPTO_CIPHER_MODE_XTS) { ++ nkey *= 2; ++ } + + key = g_new0(uint8_t, nkey); + memset(key, g_test_rand_int(), nkey); +@@ -38,14 +48,14 @@ static void test_cipher_speed(const void *opaque) + plaintext = g_new0(uint8_t, chunk_size); + memset(plaintext, g_test_rand_int(), chunk_size); + +- cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128, +- QCRYPTO_CIPHER_MODE_CBC, ++ cipher = qcrypto_cipher_new(alg, mode, + key, nkey, &err); + g_assert(cipher != NULL); + +- g_assert(qcrypto_cipher_setiv(cipher, +- iv, niv, +- &err) == 0); ++ if (mode != QCRYPTO_CIPHER_MODE_ECB) ++ g_assert(qcrypto_cipher_setiv(cipher, ++ iv, niv, ++ &err) == 0); + + g_test_timer_start(); + do { +@@ -55,13 +65,26 @@ static void test_cipher_speed(const void *opaque) + chunk_size, + &err) == 0); + total += chunk_size; +- } while (g_test_timer_elapsed() < 5.0); ++ } while (g_test_timer_elapsed() < 1.0); + + total /= MiB; +- g_print("cbc(aes128): "); +- g_print("Testing chunk_size %zu bytes ", chunk_size); +- g_print("done: %.2f MB in %.2f secs: ", total, g_test_timer_last()); +- g_print("%.2f MB/sec\n", total / g_test_timer_last()); ++ g_print("Enc chunk %zu bytes ", chunk_size); ++ g_print("%.2f MB/sec ", total / g_test_timer_last()); ++ ++ total = 0.0; ++ g_test_timer_start(); ++ do { ++ g_assert(qcrypto_cipher_decrypt(cipher, ++ plaintext, ++ ciphertext, ++ chunk_size, ++ &err) == 0); ++ total += chunk_size; ++ } while (g_test_timer_elapsed() < 1.0); ++ ++ total /= MiB; ++ g_print("Dec chunk %zu bytes ", chunk_size); ++ g_print("%.2f MB/sec ", total / g_test_timer_last()); + + qcrypto_cipher_free(cipher); + g_free(plaintext); +@@ -70,19 +93,99 @@ static void test_cipher_speed(const void *opaque) + g_free(key); + } + +-int main(int argc, char **argv) ++ ++static void test_cipher_speed_ecb_aes_128(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_ECB, ++ QCRYPTO_CIPHER_ALG_AES_128); ++} ++ ++static void test_cipher_speed_ecb_aes_256(const void *opaque) + { +- size_t i; +- char name[64]; ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_ECB, ++ QCRYPTO_CIPHER_ALG_AES_256); ++} ++ ++static void test_cipher_speed_cbc_aes_128(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_CBC, ++ QCRYPTO_CIPHER_ALG_AES_128); ++} + ++static void test_cipher_speed_cbc_aes_256(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_CBC, ++ QCRYPTO_CIPHER_ALG_AES_256); ++} ++ ++static void test_cipher_speed_ctr_aes_128(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_CTR, ++ QCRYPTO_CIPHER_ALG_AES_128); ++} ++ ++static void test_cipher_speed_ctr_aes_256(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_CTR, ++ QCRYPTO_CIPHER_ALG_AES_256); ++} ++ ++static void test_cipher_speed_xts_aes_128(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_XTS, ++ QCRYPTO_CIPHER_ALG_AES_128); ++} ++ ++static void test_cipher_speed_xts_aes_256(const void *opaque) ++{ ++ size_t chunk_size = (size_t)opaque; ++ test_cipher_speed(chunk_size, ++ QCRYPTO_CIPHER_MODE_XTS, ++ QCRYPTO_CIPHER_ALG_AES_256); ++} ++ ++ ++int main(int argc, char **argv) ++{ + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + +- for (i = 512; i <= 64 * KiB; i *= 2) { +- memset(name, 0 , sizeof(name)); +- snprintf(name, sizeof(name), "/crypto/cipher/speed-%zu", i); +- g_test_add_data_func(name, (void *)i, test_cipher_speed); +- } ++#define ADD_TEST(mode, cipher, keysize, chunk) \ ++ g_test_add_data_func( \ ++ "/crypto/cipher/" #mode "-" #cipher "-" #keysize "/chunk-" #chunk, \ ++ (void *)chunk, \ ++ test_cipher_speed_ ## mode ## _ ## cipher ## _ ## keysize) ++ ++#define ADD_TESTS(chunk) \ ++ do { \ ++ ADD_TEST(ecb, aes, 128, chunk); \ ++ ADD_TEST(ecb, aes, 256, chunk); \ ++ ADD_TEST(cbc, aes, 128, chunk); \ ++ ADD_TEST(cbc, aes, 256, chunk); \ ++ ADD_TEST(ctr, aes, 128, chunk); \ ++ ADD_TEST(ctr, aes, 256, chunk); \ ++ ADD_TEST(xts, aes, 128, chunk); \ ++ ADD_TEST(xts, aes, 256, chunk); \ ++ } while (0) ++ ++ ADD_TESTS(512); ++ ADD_TESTS(4096); ++ ADD_TESTS(16384); ++ ADD_TESTS(65536); + + return g_test_run(); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-introduce-a-xts_uint128-data-type.patch b/SOURCES/kvm-crypto-introduce-a-xts_uint128-data-type.patch new file mode 100644 index 0000000..6e91816 --- /dev/null +++ b/SOURCES/kvm-crypto-introduce-a-xts_uint128-data-type.patch @@ -0,0 +1,158 @@ +From 880c18a0bffadfda3197a18daab03881025eb37c Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:25 +0200 +Subject: [PATCH 06/12] crypto: introduce a xts_uint128 data type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-5-berrange@redhat.com> +Patchwork-id: 85894 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/9] crypto: introduce a xts_uint128 data type +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +The new type is designed to allow use of 64-bit arithmetic instead +of operating 1-byte at a time. The following patches will use this to +improve performance. + +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit cc36930e4077eb3dbee6cd30d2d826ec62b3490a) +Signed-off-by: Miroslav Rezanina +--- + crypto/xts.c | 46 ++++++++++++++++++++++++++-------------------- + 1 file changed, 26 insertions(+), 20 deletions(-) + +diff --git a/crypto/xts.c b/crypto/xts.c +index 3c1a92f..bee23f8 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -26,6 +26,12 @@ + #include "qemu/osdep.h" + #include "crypto/xts.h" + ++typedef union { ++ uint8_t b[XTS_BLOCK_SIZE]; ++ uint64_t u[2]; ++} xts_uint128; ++ ++ + static void xts_mult_x(uint8_t *I) + { + int x; +@@ -85,7 +91,7 @@ void xts_decrypt(const void *datactx, + uint8_t *dst, + const uint8_t *src) + { +- uint8_t PP[XTS_BLOCK_SIZE], CC[XTS_BLOCK_SIZE], T[XTS_BLOCK_SIZE]; ++ xts_uint128 PP, CC, T; + unsigned long i, m, mo, lim; + + /* get number of blocks */ +@@ -102,10 +108,10 @@ void xts_decrypt(const void *datactx, + } + + /* encrypt the iv */ +- encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv); ++ encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv); + + for (i = 0; i < lim; i++) { +- xts_tweak_encdec(datactx, decfunc, src, dst, T); ++ xts_tweak_encdec(datactx, decfunc, src, dst, T.b); + + src += XTS_BLOCK_SIZE; + dst += XTS_BLOCK_SIZE; +@@ -113,27 +119,27 @@ void xts_decrypt(const void *datactx, + + /* if length is not a multiple of XTS_BLOCK_SIZE then */ + if (mo > 0) { +- memcpy(CC, T, XTS_BLOCK_SIZE); +- xts_mult_x(CC); ++ memcpy(&CC, &T, XTS_BLOCK_SIZE); ++ xts_mult_x(CC.b); + + /* PP = tweak decrypt block m-1 */ +- xts_tweak_encdec(datactx, decfunc, src, PP, CC); ++ xts_tweak_encdec(datactx, decfunc, src, PP.b, CC.b); + + /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */ + for (i = 0; i < mo; i++) { +- CC[i] = src[XTS_BLOCK_SIZE + i]; +- dst[XTS_BLOCK_SIZE + i] = PP[i]; ++ CC.b[i] = src[XTS_BLOCK_SIZE + i]; ++ dst[XTS_BLOCK_SIZE + i] = PP.b[i]; + } + for (; i < XTS_BLOCK_SIZE; i++) { +- CC[i] = PP[i]; ++ CC.b[i] = PP.b[i]; + } + + /* Pm-1 = Tweak uncrypt CC */ +- xts_tweak_encdec(datactx, decfunc, CC, dst, T); ++ xts_tweak_encdec(datactx, decfunc, CC.b, dst, T.b); + } + + /* Decrypt the iv back */ +- decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T); ++ decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b); + } + + +@@ -146,7 +152,7 @@ void xts_encrypt(const void *datactx, + uint8_t *dst, + const uint8_t *src) + { +- uint8_t PP[XTS_BLOCK_SIZE], CC[XTS_BLOCK_SIZE], T[XTS_BLOCK_SIZE]; ++ xts_uint128 PP, CC, T; + unsigned long i, m, mo, lim; + + /* get number of blocks */ +@@ -163,10 +169,10 @@ void xts_encrypt(const void *datactx, + } + + /* encrypt the iv */ +- encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv); ++ encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv); + + for (i = 0; i < lim; i++) { +- xts_tweak_encdec(datactx, encfunc, src, dst, T); ++ xts_tweak_encdec(datactx, encfunc, src, dst, T.b); + + dst += XTS_BLOCK_SIZE; + src += XTS_BLOCK_SIZE; +@@ -175,22 +181,22 @@ void xts_encrypt(const void *datactx, + /* if length is not a multiple of XTS_BLOCK_SIZE then */ + if (mo > 0) { + /* CC = tweak encrypt block m-1 */ +- xts_tweak_encdec(datactx, encfunc, src, CC, T); ++ xts_tweak_encdec(datactx, encfunc, src, CC.b, T.b); + + /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */ + for (i = 0; i < mo; i++) { +- PP[i] = src[XTS_BLOCK_SIZE + i]; +- dst[XTS_BLOCK_SIZE + i] = CC[i]; ++ PP.b[i] = src[XTS_BLOCK_SIZE + i]; ++ dst[XTS_BLOCK_SIZE + i] = CC.b[i]; + } + + for (; i < XTS_BLOCK_SIZE; i++) { +- PP[i] = CC[i]; ++ PP.b[i] = CC.b[i]; + } + + /* Cm-1 = Tweak encrypt PP */ +- xts_tweak_encdec(datactx, encfunc, PP, dst, T); ++ xts_tweak_encdec(datactx, encfunc, PP.b, dst, T.b); + } + + /* Decrypt the iv back */ +- decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T); ++ decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-refactor-XTS-cipher-mode-test-suite.patch b/SOURCES/kvm-crypto-refactor-XTS-cipher-mode-test-suite.patch new file mode 100644 index 0000000..50102a3 --- /dev/null +++ b/SOURCES/kvm-crypto-refactor-XTS-cipher-mode-test-suite.patch @@ -0,0 +1,203 @@ +From 35952167bb355997dcc327d22b7868a25969c933 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:29 +0200 +Subject: [PATCH 10/12] crypto: refactor XTS cipher mode test suite +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-9-berrange@redhat.com> +Patchwork-id: 85889 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 8/9] crypto: refactor XTS cipher mode test suite +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +The current XTS test overloads two different tests in a single function +making the code a little hard to follow. Split it into distinct test +cases. + +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit a61f682fde664467c4b4dd498ea84338598c8cbd) +Signed-off-by: Miroslav Rezanina +--- + tests/test-crypto-xts.c | 140 +++++++++++++++++++++++++++--------------------- + 1 file changed, 80 insertions(+), 60 deletions(-) + +diff --git a/tests/test-crypto-xts.c b/tests/test-crypto-xts.c +index 1f1412c..81606d9 100644 +--- a/tests/test-crypto-xts.c ++++ b/tests/test-crypto-xts.c +@@ -1,7 +1,7 @@ + /* + * QEMU Crypto XTS cipher mode + * +- * Copyright (c) 2015-2016 Red Hat, Inc. ++ * Copyright (c) 2015-2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -340,70 +340,79 @@ static void test_xts_aes_decrypt(const void *ctx, + static void test_xts(const void *opaque) + { + const QCryptoXTSTestData *data = opaque; +- unsigned char out[512], Torg[16], T[16]; ++ uint8_t out[512], Torg[16], T[16]; + uint64_t seq; +- int j; +- unsigned long len; + struct TestAES aesdata; + struct TestAES aestweak; + +- for (j = 0; j < 2; j++) { +- /* skip the cases where +- * the length is smaller than 2*blocklen +- * or the length is not a multiple of 32 +- */ +- if ((j == 1) && ((data->PTLEN < 32) || (data->PTLEN % 32))) { +- continue; +- } +- len = data->PTLEN / 2; +- +- AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc); +- AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec); +- AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc); +- AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec); +- +- seq = data->seqnum; +- STORE64L(seq, Torg); +- memset(Torg + 8, 0, 8); +- +- memcpy(T, Torg, sizeof(T)); +- if (j == 0) { +- xts_encrypt(&aesdata, &aestweak, +- test_xts_aes_encrypt, +- test_xts_aes_decrypt, +- T, data->PTLEN, out, data->PTX); +- } else { +- xts_encrypt(&aesdata, &aestweak, +- test_xts_aes_encrypt, +- test_xts_aes_decrypt, +- T, len, out, data->PTX); +- xts_encrypt(&aesdata, &aestweak, +- test_xts_aes_encrypt, +- test_xts_aes_decrypt, +- T, len, &out[len], &data->PTX[len]); +- } ++ AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc); ++ AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec); ++ AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc); ++ AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec); + +- g_assert(memcmp(out, data->CTX, data->PTLEN) == 0); +- +- memcpy(T, Torg, sizeof(T)); +- if (j == 0) { +- xts_decrypt(&aesdata, &aestweak, +- test_xts_aes_encrypt, +- test_xts_aes_decrypt, +- T, data->PTLEN, out, data->CTX); +- } else { +- xts_decrypt(&aesdata, &aestweak, +- test_xts_aes_encrypt, +- test_xts_aes_decrypt, +- T, len, out, data->CTX); +- xts_decrypt(&aesdata, &aestweak, +- test_xts_aes_encrypt, +- test_xts_aes_decrypt, +- T, len, &out[len], &data->CTX[len]); +- } ++ seq = data->seqnum; ++ STORE64L(seq, Torg); ++ memset(Torg + 8, 0, 8); + +- g_assert(memcmp(out, data->PTX, data->PTLEN) == 0); +- } ++ memcpy(T, Torg, sizeof(T)); ++ xts_encrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, data->PTLEN, out, data->PTX); ++ ++ g_assert(memcmp(out, data->CTX, data->PTLEN) == 0); ++ ++ memcpy(T, Torg, sizeof(T)); ++ xts_decrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, data->PTLEN, out, data->CTX); ++ ++ g_assert(memcmp(out, data->PTX, data->PTLEN) == 0); ++} ++ ++ ++static void test_xts_split(const void *opaque) ++{ ++ const QCryptoXTSTestData *data = opaque; ++ uint8_t out[512], Torg[16], T[16]; ++ uint64_t seq; ++ unsigned long len = data->PTLEN / 2; ++ struct TestAES aesdata; ++ struct TestAES aestweak; ++ ++ AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc); ++ AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec); ++ AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc); ++ AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec); ++ ++ seq = data->seqnum; ++ STORE64L(seq, Torg); ++ memset(Torg + 8, 0, 8); ++ ++ memcpy(T, Torg, sizeof(T)); ++ xts_encrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, len, out, data->PTX); ++ xts_encrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, len, &out[len], &data->PTX[len]); ++ ++ g_assert(memcmp(out, data->CTX, data->PTLEN) == 0); ++ ++ memcpy(T, Torg, sizeof(T)); ++ xts_decrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, len, out, data->CTX); ++ xts_decrypt(&aesdata, &aestweak, ++ test_xts_aes_encrypt, ++ test_xts_aes_decrypt, ++ T, len, &out[len], &data->CTX[len]); ++ ++ g_assert(memcmp(out, data->PTX, data->PTLEN) == 0); + } + + +@@ -416,7 +425,18 @@ int main(int argc, char **argv) + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { +- g_test_add_data_func(test_data[i].path, &test_data[i], test_xts); ++ gchar *path = g_strdup_printf("%s/basic", test_data[i].path); ++ g_test_add_data_func(path, &test_data[i], test_xts); ++ g_free(path); ++ ++ /* skip the cases where the length is smaller than 2*blocklen ++ * or the length is not a multiple of 32 ++ */ ++ if ((test_data[i].PTLEN >= 32) && !(test_data[i].PTLEN % 32)) { ++ path = g_strdup_printf("%s/split", test_data[i].path); ++ g_test_add_data_func(path, &test_data[i], test_xts_split); ++ g_free(path); ++ } + } + + return g_test_run(); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-crypto-remove-code-duplication-in-tweak-encrypt-decr.patch b/SOURCES/kvm-crypto-remove-code-duplication-in-tweak-encrypt-decr.patch new file mode 100644 index 0000000..43d36b6 --- /dev/null +++ b/SOURCES/kvm-crypto-remove-code-duplication-in-tweak-encrypt-decr.patch @@ -0,0 +1,163 @@ +From 272c652c38c9f9bcce2eb8e4e32ab68d48c3531a Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:24 +0200 +Subject: [PATCH 05/12] crypto: remove code duplication in tweak + encrypt/decrypt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-4-berrange@redhat.com> +Patchwork-id: 85891 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/9] crypto: remove code duplication in tweak encrypt/decrypt +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +The tweak encrypt/decrypt functions are identical except for the +comments, so can be merged. Profiling data shows that the compiler is +in fact already merging the two merges in the object files. + +Reviewed-by: Marc-André Lureau +Reviewed-by: Alberto Garcia +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 299ec87838babdf38be618cf2d81aef2500758bd) +Signed-off-by: Miroslav Rezanina +--- + crypto/xts.c | 64 ++++++++++++++---------------------------------------------- + 1 file changed, 15 insertions(+), 49 deletions(-) + +diff --git a/crypto/xts.c b/crypto/xts.c +index 9521234..3c1a92f 100644 +--- a/crypto/xts.c ++++ b/crypto/xts.c +@@ -43,20 +43,20 @@ static void xts_mult_x(uint8_t *I) + + + /** +- * xts_tweak_uncrypt: ++ * xts_tweak_encdec: + * @param ctxt: the cipher context + * @param func: the cipher function +- * @src: buffer providing the cipher text of XTS_BLOCK_SIZE bytes +- * @dst: buffer to output the plain text of XTS_BLOCK_SIZE bytes ++ * @src: buffer providing the input text of XTS_BLOCK_SIZE bytes ++ * @dst: buffer to output the output text of XTS_BLOCK_SIZE bytes + * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes + * +- * Decrypt data with a tweak ++ * Encrypt/decrypt data with a tweak + */ +-static void xts_tweak_decrypt(const void *ctx, +- xts_cipher_func *func, +- const uint8_t *src, +- uint8_t *dst, +- uint8_t *iv) ++static void xts_tweak_encdec(const void *ctx, ++ xts_cipher_func *func, ++ const uint8_t *src, ++ uint8_t *dst, ++ uint8_t *iv) + { + unsigned long x; + +@@ -105,7 +105,7 @@ void xts_decrypt(const void *datactx, + encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv); + + for (i = 0; i < lim; i++) { +- xts_tweak_decrypt(datactx, decfunc, src, dst, T); ++ xts_tweak_encdec(datactx, decfunc, src, dst, T); + + src += XTS_BLOCK_SIZE; + dst += XTS_BLOCK_SIZE; +@@ -117,7 +117,7 @@ void xts_decrypt(const void *datactx, + xts_mult_x(CC); + + /* PP = tweak decrypt block m-1 */ +- xts_tweak_decrypt(datactx, decfunc, src, PP, CC); ++ xts_tweak_encdec(datactx, decfunc, src, PP, CC); + + /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */ + for (i = 0; i < mo; i++) { +@@ -129,7 +129,7 @@ void xts_decrypt(const void *datactx, + } + + /* Pm-1 = Tweak uncrypt CC */ +- xts_tweak_decrypt(datactx, decfunc, CC, dst, T); ++ xts_tweak_encdec(datactx, decfunc, CC, dst, T); + } + + /* Decrypt the iv back */ +@@ -137,40 +137,6 @@ void xts_decrypt(const void *datactx, + } + + +-/** +- * xts_tweak_crypt: +- * @param ctxt: the cipher context +- * @param func: the cipher function +- * @src: buffer providing the plain text of XTS_BLOCK_SIZE bytes +- * @dst: buffer to output the cipher text of XTS_BLOCK_SIZE bytes +- * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes +- * +- * Encrypt data with a tweak +- */ +-static void xts_tweak_encrypt(const void *ctx, +- xts_cipher_func *func, +- const uint8_t *src, +- uint8_t *dst, +- uint8_t *iv) +-{ +- unsigned long x; +- +- /* tweak encrypt block i */ +- for (x = 0; x < XTS_BLOCK_SIZE; x++) { +- dst[x] = src[x] ^ iv[x]; +- } +- +- func(ctx, XTS_BLOCK_SIZE, dst, dst); +- +- for (x = 0; x < XTS_BLOCK_SIZE; x++) { +- dst[x] = dst[x] ^ iv[x]; +- } +- +- /* LFSR the tweak */ +- xts_mult_x(iv); +-} +- +- + void xts_encrypt(const void *datactx, + const void *tweakctx, + xts_cipher_func *encfunc, +@@ -200,7 +166,7 @@ void xts_encrypt(const void *datactx, + encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv); + + for (i = 0; i < lim; i++) { +- xts_tweak_encrypt(datactx, encfunc, src, dst, T); ++ xts_tweak_encdec(datactx, encfunc, src, dst, T); + + dst += XTS_BLOCK_SIZE; + src += XTS_BLOCK_SIZE; +@@ -209,7 +175,7 @@ void xts_encrypt(const void *datactx, + /* if length is not a multiple of XTS_BLOCK_SIZE then */ + if (mo > 0) { + /* CC = tweak encrypt block m-1 */ +- xts_tweak_encrypt(datactx, encfunc, src, CC, T); ++ xts_tweak_encdec(datactx, encfunc, src, CC, T); + + /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */ + for (i = 0; i < mo; i++) { +@@ -222,7 +188,7 @@ void xts_encrypt(const void *datactx, + } + + /* Cm-1 = Tweak encrypt PP */ +- xts_tweak_encrypt(datactx, encfunc, PP, dst, T); ++ xts_tweak_encdec(datactx, encfunc, PP, dst, T); + } + + /* Decrypt the iv back */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-curl-Support-auto-read-only-option.patch b/SOURCES/kvm-curl-Support-auto-read-only-option.patch new file mode 100644 index 0000000..d14a997 --- /dev/null +++ b/SOURCES/kvm-curl-Support-auto-read-only-option.patch @@ -0,0 +1,49 @@ +From a09f5141da57a969a5f7eb89adbf1429680e8ab2 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:49 +0100 +Subject: [PATCH 08/34] curl: Support auto-read-only option + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-8-kwolf@redhat.com> +Patchwork-id: 83117 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 07/12] curl: Support auto-read-only option +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +If read-only=off, but auto-read-only=on is given, just degrade to +read-only. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 6ceef36acb11819b255732b1de0ca62885da04bd) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/curl.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/block/curl.c b/block/curl.c +index aa42535..402f21e 100644 +--- a/block/curl.c ++++ b/block/curl.c +@@ -682,10 +682,10 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, + const char *protocol_delimiter; + int ret; + +- +- if (flags & BDRV_O_RDWR) { +- error_setg(errp, "curl block device does not support writes"); +- return -EROFS; ++ ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes", ++ errp); ++ if (ret < 0) { ++ return ret; + } + + if (!libcurl_initialized) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch b/SOURCES/kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch index 1f4fdaf..32f5950 100644 --- a/SOURCES/kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch +++ b/SOURCES/kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch @@ -1,16 +1,17 @@ -From b18831e53e64414ebd35419fb8dffd51e8ec46f7 Mon Sep 17 00:00:00 2001 +From e530c18fd567718e38683d73354fb56d4d3eb6aa Mon Sep 17 00:00:00 2001 From: Sergio Lopez Pascual -Date: Mon, 15 Apr 2019 09:09:30 +0200 -Subject: [PATCH] device_tree: Fix integer overflowing in load_device_tree() +Date: Mon, 15 Apr 2019 10:50:01 +0200 +Subject: [PATCH 161/163] device_tree: Fix integer overflowing in + load_device_tree() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Sergio Lopez Pascual -Message-id: <20190415090930.27086-2-slp@redhat.com> -Patchwork-id: 85657 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 1/1] device_tree: Fix integer overflowing in load_device_tree() -Bugzilla: 1693112 +Message-id: <20190415105001.42933-2-slp@redhat.com> +Patchwork-id: 85665 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] device_tree: Fix integer overflowing in load_device_tree() +Bugzilla: 1693115 RH-Acked-by: Philippe Mathieu-Daudé RH-Acked-by: Stefan Hajnoczi RH-Acked-by: John Snow diff --git a/SOURCES/kvm-dirty-bitmap-Expose-persistent-flag-to-query-block.patch b/SOURCES/kvm-dirty-bitmap-Expose-persistent-flag-to-query-block.patch new file mode 100644 index 0000000..e6e04f9 --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-Expose-persistent-flag-to-query-block.patch @@ -0,0 +1,190 @@ +From 7fecc102918b8945abefa36ee01da3b707849b41 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:37 +0200 +Subject: [PATCH 132/163] dirty-bitmap: Expose persistent flag to 'query-block' + +RH-Author: John Snow +Message-id: <20190403181857.9693-2-jsnow@redhat.com> +Patchwork-id: 85420 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/21] dirty-bitmap: Expose persistent flag to 'query-block' +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +From: Eric Blake + +Since qemu currently doesn't flush persistent bitmaps to disk until +shutdown (which might be MUCH later), it's useful if 'query-block' +at least shows WHICH bitmaps will (eventually) make it to persistent +storage. Update affected iotests. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +Message-id: 20190204210512.27458-1-eblake@redhat.com +Signed-off-by: John Snow +(cherry picked from commit f67cf661f8b88afe8a5ea2f120583924cba9087f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 1 + + qapi/block-core.json | 5 ++++- + tests/qemu-iotests/124 | 1 + + tests/qemu-iotests/236.out | 14 ++++++++++++++ + 4 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 00ea36f..e46f72b 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -440,6 +440,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) + info->has_name = !!bm->name; + info->name = g_strdup(bm->name); + info->status = bdrv_dirty_bitmap_status(bm); ++ info->persistent = bm->persistent; + entry->value = info; + *plist = entry; + plist = &entry->next; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 5d6bb14..23c9462 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -451,11 +451,14 @@ + # + # @status: current status of the dirty bitmap (since 2.4) + # ++# @persistent: true if the bitmap will eventually be flushed to persistent ++# storage (since 4.0) ++# + # Since: 1.3 + ## + { 'struct': 'BlockDirtyInfo', + 'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32', +- 'status': 'DirtyBitmapStatus'} } ++ 'status': 'DirtyBitmapStatus', 'persistent': 'bool' } } + + ## + # @Qcow2BitmapInfoFlags: +diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 +index 3ea4ac5..439a86a 100755 +--- a/tests/qemu-iotests/124 ++++ b/tests/qemu-iotests/124 +@@ -350,6 +350,7 @@ class TestIncrementalBackup(TestIncrementalBackupBase): + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/count', 458752) + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/granularity', 65536) + self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/status', 'active') ++ self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/persistent', False) + + # Prepare a cluster_size=128k backup target without a backing file. + (target, _) = bitmap0.new_target() +diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out +index bb2d71e..5006f7b 100644 +--- a/tests/qemu-iotests/236.out ++++ b/tests/qemu-iotests/236.out +@@ -25,12 +25,14 @@ write -P0xcd 0x3ff0000 64k + "count": 262144, + "granularity": 65536, + "name": "bitmapB", ++ "persistent": false, + "status": "active" + }, + { + "count": 262144, + "granularity": 65536, + "name": "bitmapA", ++ "persistent": false, + "status": "active" + } + ] +@@ -85,12 +87,14 @@ write -P0xcd 0x3ff0000 64k + "count": 262144, + "granularity": 65536, + "name": "bitmapB", ++ "persistent": false, + "status": "active" + }, + { + "count": 262144, + "granularity": 65536, + "name": "bitmapA", ++ "persistent": false, + "status": "active" + } + ] +@@ -183,18 +187,21 @@ write -P0xea 0x3fe0000 64k + "count": 393216, + "granularity": 65536, + "name": "bitmapC", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 262144, + "granularity": 65536, + "name": "bitmapB", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 458752, + "granularity": 65536, + "name": "bitmapA", ++ "persistent": false, + "status": "disabled" + } + ] +@@ -247,18 +254,21 @@ write -P0xea 0x3fe0000 64k + "count": 393216, + "granularity": 65536, + "name": "bitmapC", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 262144, + "granularity": 65536, + "name": "bitmapB", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 458752, + "granularity": 65536, + "name": "bitmapA", ++ "persistent": false, + "status": "disabled" + } + ] +@@ -304,24 +314,28 @@ write -P0xea 0x3fe0000 64k + "count": 458752, + "granularity": 65536, + "name": "bitmapD", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 393216, + "granularity": 65536, + "name": "bitmapC", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 262144, + "granularity": 65536, + "name": "bitmapB", ++ "persistent": false, + "status": "disabled" + }, + { + "count": 458752, + "granularity": 65536, + "name": "bitmapA", ++ "persistent": false, + "status": "disabled" + } + ] +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmap-add-bdrv_dirty_bitmap_next_dirty_area.patch b/SOURCES/kvm-dirty-bitmap-add-bdrv_dirty_bitmap_next_dirty_area.patch new file mode 100644 index 0000000..61dbad4 --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-add-bdrv_dirty_bitmap_next_dirty_area.patch @@ -0,0 +1,141 @@ +From afaa0a6c9269fc840a8a48b2ca2693c1c09f78ed Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:31 +0100 +Subject: [PATCH 038/163] dirty-bitmap: add bdrv_dirty_bitmap_next_dirty_area + +RH-Author: John Snow +Message-id: <20190320214838.22027-4-jsnow@redhat.com> +Patchwork-id: 84998 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/10] dirty-bitmap: add bdrv_dirty_bitmap_next_dirty_area +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +The function alters bdrv_dirty_iter_next_area(), which is wrong and +less efficient (see further commit +"block/mirror: fix and improve do_sync_target_write" for description). + +Signed-off-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit a78a1a48cd1a2e86f23f113bb05e2d3dd8ae0bf6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 6 ++++++ + include/block/dirty-bitmap.h | 2 ++ + include/qemu/hbitmap.h | 16 ++++++++++++++++ + util/hbitmap.c | 39 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 63 insertions(+) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index b162f4a..c151837 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -787,6 +787,12 @@ int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset, + return hbitmap_next_zero(bitmap->bitmap, offset, bytes); + } + ++bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap, ++ uint64_t *offset, uint64_t *bytes) ++{ ++ return hbitmap_next_dirty_area(bitmap->bitmap, offset, bytes); ++} ++ + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + HBitmap **backup, Error **errp) + { +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 102ccdd..4ef00ca 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -101,6 +101,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, + char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp); + int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset, + uint64_t bytes); ++bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap, ++ uint64_t *offset, uint64_t *bytes); + BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, + Error **errp); +diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h +index 1359755..097dce3 100644 +--- a/include/qemu/hbitmap.h ++++ b/include/qemu/hbitmap.h +@@ -311,6 +311,22 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi); + */ + int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start, uint64_t count); + ++/* hbitmap_next_dirty_area: ++ * @hb: The HBitmap to operate on ++ * @start: in-out parameter. ++ * in: the offset to start from ++ * out: (if area found) start of found area ++ * @count: in-out parameter. ++ * in: length of requested region ++ * out: length of found area ++ * ++ * If dirty area found within [@start, @start + @count), returns true and sets ++ * @offset and @bytes appropriately. Otherwise returns false and leaves @offset ++ * and @bytes unchanged. ++ */ ++bool hbitmap_next_dirty_area(const HBitmap *hb, uint64_t *start, ++ uint64_t *count); ++ + /* hbitmap_create_meta: + * Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap. + * The caller owns the created bitmap and must call hbitmap_free_meta(hb) to +diff --git a/util/hbitmap.c b/util/hbitmap.c +index 09b3719..fa35652 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -246,6 +246,45 @@ int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start, uint64_t count) + return res; + } + ++bool hbitmap_next_dirty_area(const HBitmap *hb, uint64_t *start, ++ uint64_t *count) ++{ ++ HBitmapIter hbi; ++ int64_t firt_dirty_off, area_end; ++ uint32_t granularity = 1UL << hb->granularity; ++ uint64_t end; ++ ++ if (*start >= hb->orig_size || *count == 0) { ++ return false; ++ } ++ ++ end = *count > hb->orig_size - *start ? hb->orig_size : *start + *count; ++ ++ hbitmap_iter_init(&hbi, hb, *start); ++ firt_dirty_off = hbitmap_iter_next(&hbi, false); ++ ++ if (firt_dirty_off < 0 || firt_dirty_off >= end) { ++ return false; ++ } ++ ++ if (firt_dirty_off + granularity >= end) { ++ area_end = end; ++ } else { ++ area_end = hbitmap_next_zero(hb, firt_dirty_off + granularity, ++ end - firt_dirty_off - granularity); ++ if (area_end < 0) { ++ area_end = end; ++ } ++ } ++ ++ if (firt_dirty_off > *start) { ++ *start = firt_dirty_off; ++ } ++ *count = area_end - *start; ++ ++ return true; ++} ++ + bool hbitmap_empty(const HBitmap *hb) + { + return hb->count == 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmap-improve-bdrv_dirty_bitmap_next_zero.patch b/SOURCES/kvm-dirty-bitmap-improve-bdrv_dirty_bitmap_next_zero.patch new file mode 100644 index 0000000..c21d5c5 --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-improve-bdrv_dirty_bitmap_next_zero.patch @@ -0,0 +1,195 @@ +From 31e5ab1930795584338fe2769a002b31c89c04b6 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:29 +0100 +Subject: [PATCH 036/163] dirty-bitmap: improve bdrv_dirty_bitmap_next_zero + +RH-Author: John Snow +Message-id: <20190320214838.22027-2-jsnow@redhat.com> +Patchwork-id: 84993 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/10] dirty-bitmap: improve bdrv_dirty_bitmap_next_zero +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Add bytes parameter to the function, to limit searched range. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 76d570dc495c56bbdcc4574bfc6d512dcb8e9aa9) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 3 ++- + block/dirty-bitmap.c | 5 +++-- + include/block/dirty-bitmap.h | 3 ++- + include/qemu/hbitmap.h | 10 +++++++--- + nbd/server.c | 2 +- + tests/test-hbitmap.c | 2 +- + util/hbitmap.c | 27 ++++++++++++++++++++++----- + 7 files changed, 38 insertions(+), 14 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index ac17db6..6a66b1c 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -446,7 +446,8 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) + break; + } + +- offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset); ++ offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset, ++ UINT64_MAX); + if (offset == -1) { + hbitmap_set(job->copy_bitmap, cluster, end - cluster); + break; +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 6b68839..b162f4a 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -781,9 +781,10 @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp) + return hbitmap_sha256(bitmap->bitmap, errp); + } + +-int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset) ++int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset, ++ uint64_t bytes) + { +- return hbitmap_next_zero(bitmap->bitmap, offset); ++ return hbitmap_next_zero(bitmap->bitmap, offset, bytes); + } + + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 8f38a3d..102ccdd 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -99,7 +99,8 @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); + BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); + char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp); +-int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t start); ++int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset, ++ uint64_t bytes); + BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, + Error **errp); +diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h +index a7cb780..1359755 100644 +--- a/include/qemu/hbitmap.h ++++ b/include/qemu/hbitmap.h +@@ -300,12 +300,16 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first); + unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi); + + /* hbitmap_next_zero: ++ * ++ * Find next not dirty bit within selected range. If not found, return -1. ++ * + * @hb: The HBitmap to operate on + * @start: The bit to start from. +- * +- * Find next not dirty bit. ++ * @count: Number of bits to proceed. If @start+@count > bitmap size, the whole ++ * bitmap is looked through. You can use UINT64_MAX as @count to search up to ++ * the bitmap end. + */ +-int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start); ++int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start, uint64_t count); + + /* hbitmap_create_meta: + * Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap. +diff --git a/nbd/server.c b/nbd/server.c +index e094300..0ab0dbd 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1952,7 +1952,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + assert(begin < overall_end && nb_extents); + while (begin < overall_end && i < nb_extents) { + if (dirty) { +- end = bdrv_dirty_bitmap_next_zero(bitmap, begin); ++ end = bdrv_dirty_bitmap_next_zero(bitmap, begin, UINT64_MAX); + } else { + bdrv_set_dirty_iter(it, begin); + end = bdrv_dirty_iter_next(it); +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index 5e67ac1..b04a45a 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -939,7 +939,7 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + + static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start) + { +- int64_t ret1 = hbitmap_next_zero(data->hb, start); ++ int64_t ret1 = hbitmap_next_zero(data->hb, start, UINT64_MAX); + int64_t ret2 = start; + for ( ; ret2 < data->size && hbitmap_get(data->hb, ret2); ret2++) { + ; +diff --git a/util/hbitmap.c b/util/hbitmap.c +index 8d402c5..09b3719 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -53,6 +53,9 @@ + */ + + struct HBitmap { ++ /* Size of the bitmap, as requested in hbitmap_alloc. */ ++ uint64_t orig_size; ++ + /* Number of total bits in the bottom level. */ + uint64_t size; + +@@ -192,16 +195,28 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) + } + } + +-int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start) ++int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start, uint64_t count) + { + size_t pos = (start >> hb->granularity) >> BITS_PER_LEVEL; + unsigned long *last_lev = hb->levels[HBITMAP_LEVELS - 1]; +- uint64_t sz = hb->sizes[HBITMAP_LEVELS - 1]; + unsigned long cur = last_lev[pos]; +- unsigned start_bit_offset = +- (start >> hb->granularity) & (BITS_PER_LONG - 1); ++ unsigned start_bit_offset; ++ uint64_t end_bit, sz; + int64_t res; + ++ if (start >= hb->orig_size || count == 0) { ++ return -1; ++ } ++ ++ end_bit = count > hb->orig_size - start ? ++ hb->size : ++ ((start + count - 1) >> hb->granularity) + 1; ++ sz = (end_bit + BITS_PER_LONG - 1) >> BITS_PER_LEVEL; ++ ++ /* There may be some zero bits in @cur before @start. We are not interested ++ * in them, let's set them. ++ */ ++ start_bit_offset = (start >> hb->granularity) & (BITS_PER_LONG - 1); + cur |= (1UL << start_bit_offset) - 1; + assert((start >> hb->granularity) < hb->size); + +@@ -218,7 +233,7 @@ int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start) + } + + res = (pos << BITS_PER_LEVEL) + ctol(cur); +- if (res >= hb->size) { ++ if (res >= end_bit) { + return -1; + } + +@@ -652,6 +667,8 @@ HBitmap *hbitmap_alloc(uint64_t size, int granularity) + HBitmap *hb = g_new0(struct HBitmap, 1); + unsigned i; + ++ hb->orig_size = size; ++ + assert(granularity >= 0 && granularity < 64); + size = (size + (1ULL << granularity) - 1) >> granularity; + assert(size <= ((uint64_t)1 << HBITMAP_LOG_MAX_SIZE)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmap-make-it-possible-to-restore-bitmap-afte.patch b/SOURCES/kvm-dirty-bitmap-make-it-possible-to-restore-bitmap-afte.patch new file mode 100644 index 0000000..1603ed0 --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-make-it-possible-to-restore-bitmap-afte.patch @@ -0,0 +1,192 @@ +From 8767d53aa1dd2df28d3093bb1c6d99e54916eb4a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:28 +0100 +Subject: [PATCH 18/33] dirty-bitmap: make it possible to restore bitmap after + merge + +RH-Author: John Snow +Message-id: <20190206221243.7407-9-jsnow@redhat.com> +Patchwork-id: 84267 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 08/23] dirty-bitmap: make it possible to restore bitmap after merge +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Add backup parameter to bdrv_merge_dirty_bitmap() to be used then with +bdrv_restore_dirty_bitmap() if it needed to restore the bitmap after +merge operation. + +This is needed to implement bitmap merge transaction action in further +commit. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit fa000f2f9fd96a75a0a33d50ead247fce11da92a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 17 ++++++++++++++--- + blockdev.c | 2 +- + include/block/dirty-bitmap.h | 2 +- + include/qemu/hbitmap.h | 25 ++++++++++++++++--------- + util/hbitmap.c | 11 ++++++++--- + 5 files changed, 40 insertions(+), 17 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index cadde5c..a9421cd 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -314,7 +314,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, + return NULL; + } + +- if (!hbitmap_merge(parent->bitmap, successor->bitmap)) { ++ if (!hbitmap_merge(parent->bitmap, successor->bitmap, parent->bitmap)) { + error_setg(errp, "Merging of parent and successor bitmap failed"); + return NULL; + } +@@ -790,8 +790,10 @@ int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset) + } + + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, +- Error **errp) ++ HBitmap **backup, Error **errp) + { ++ bool ret; ++ + /* only bitmaps from one bds are supported */ + assert(dest->mutex == src->mutex); + +@@ -809,11 +811,20 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + goto out; + } + +- if (!hbitmap_merge(dest->bitmap, src->bitmap)) { ++ if (!hbitmap_can_merge(dest->bitmap, src->bitmap)) { + error_setg(errp, "Bitmaps are incompatible and can't be merged"); + goto out; + } + ++ if (backup) { ++ *backup = dest->bitmap; ++ dest->bitmap = hbitmap_alloc(dest->size, hbitmap_granularity(*backup)); ++ ret = hbitmap_merge(*backup, src->bitmap, dest->bitmap); ++ } else { ++ ret = hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap); ++ } ++ assert(ret); ++ + out: + qemu_mutex_unlock(dest->mutex); + } +diff --git a/blockdev.c b/blockdev.c +index 5d9508c..823a97f 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3119,7 +3119,7 @@ void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, + return; + } + +- bdrv_merge_dirty_bitmap(dst, src, errp); ++ bdrv_merge_dirty_bitmap(dst, src, NULL, errp); + } + + BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 259bd27..201ff7f 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -71,7 +71,7 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, + bool persistent); + void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked); + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, +- Error **errp); ++ HBitmap **backup, Error **errp); + + /* Functions that require manual locking. */ + void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); +diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h +index ddca52c..a7cb780 100644 +--- a/include/qemu/hbitmap.h ++++ b/include/qemu/hbitmap.h +@@ -73,16 +73,23 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size); + + /** + * hbitmap_merge: +- * @a: The bitmap to store the result in. +- * @b: The bitmap to merge into @a. +- * @return true if the merge was successful, +- * false if it was not attempted. +- * +- * Merge two bitmaps together. +- * A := A (BITOR) B. +- * B is left unmodified. ++ * ++ * Store result of merging @a and @b into @result. ++ * @result is allowed to be equal to @a or @b. ++ * ++ * Return true if the merge was successful, ++ * false if it was not attempted. ++ */ ++bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result); ++ ++/** ++ * hbitmap_can_merge: ++ * ++ * hbitmap_can_merge(a, b) && hbitmap_can_merge(a, result) is sufficient and ++ * necessary for hbitmap_merge will not fail. ++ * + */ +-bool hbitmap_merge(HBitmap *a, const HBitmap *b); ++bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b); + + /** + * hbitmap_empty: +diff --git a/util/hbitmap.c b/util/hbitmap.c +index bcd3040..d5aca51 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -723,6 +723,10 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) + } + } + ++bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b) ++{ ++ return (a->size == b->size) && (a->granularity == b->granularity); ++} + + /** + * Given HBitmaps A and B, let A := A (BITOR) B. +@@ -731,14 +735,15 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) + * @return true if the merge was successful, + * false if it was not attempted. + */ +-bool hbitmap_merge(HBitmap *a, const HBitmap *b) ++bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) + { + int i; + uint64_t j; + +- if ((a->size != b->size) || (a->granularity != b->granularity)) { ++ if (!hbitmap_can_merge(a, b) || !hbitmap_can_merge(a, result)) { + return false; + } ++ assert(hbitmap_can_merge(b, result)); + + if (hbitmap_count(b) == 0) { + return true; +@@ -750,7 +755,7 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b) + */ + for (i = HBITMAP_LEVELS - 1; i >= 0; i--) { + for (j = 0; j < a->sizes[i]; j++) { +- a->levels[i][j] |= b->levels[i][j]; ++ result->levels[i][j] = a->levels[i][j] | b->levels[i][j]; + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmap-rename-bdrv_undo_clear_dirty_bitmap.patch b/SOURCES/kvm-dirty-bitmap-rename-bdrv_undo_clear_dirty_bitmap.patch new file mode 100644 index 0000000..9bf262e --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-rename-bdrv_undo_clear_dirty_bitmap.patch @@ -0,0 +1,77 @@ +From 3cccc41aae7526469ca941d12857ed3d6195b782 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:27 +0100 +Subject: [PATCH 17/33] dirty-bitmap: rename bdrv_undo_clear_dirty_bitmap + +RH-Author: John Snow +Message-id: <20190206221243.7407-8-jsnow@redhat.com> +Patchwork-id: 84271 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 07/23] dirty-bitmap: rename bdrv_undo_clear_dirty_bitmap +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Use more generic names to reuse the function for bitmap merge in the +following commit. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 56bd662497259400b7c9f155aaebaddde4450028) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 4 ++-- + blockdev.c | 2 +- + include/block/block_int.h | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 999a40c..cadde5c 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -633,11 +633,11 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out) + bdrv_dirty_bitmap_unlock(bitmap); + } + +-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in) ++void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup) + { + HBitmap *tmp = bitmap->bitmap; + assert(!bdrv_dirty_bitmap_readonly(bitmap)); +- bitmap->bitmap = in; ++ bitmap->bitmap = backup; + hbitmap_free(tmp); + } + +diff --git a/blockdev.c b/blockdev.c +index cef1bfe..5d9508c 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2184,7 +2184,7 @@ static void block_dirty_bitmap_clear_abort(BlkActionState *common) + common, common); + + if (state->backup) { +- bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup); ++ bdrv_restore_dirty_bitmap(state->bitmap, state->backup); + } + } + +diff --git a/include/block/block_int.h b/include/block/block_int.h +index ff923b7..f457acb 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -1141,7 +1141,7 @@ bool blk_dev_is_medium_locked(BlockBackend *blk); + void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes); + + void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out); +-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in); ++void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup); + + void bdrv_inc_in_flight(BlockDriverState *bs); + void bdrv_dec_in_flight(BlockDriverState *bs); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmap-switch-assert-fails-to-errors-in-bdrv_m.patch b/SOURCES/kvm-dirty-bitmap-switch-assert-fails-to-errors-in-bdrv_m.patch new file mode 100644 index 0000000..b3bf5b8 --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-switch-assert-fails-to-errors-in-bdrv_m.patch @@ -0,0 +1,88 @@ +From 33de34ca77050003d06f36c9228c6408312f4be0 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:26 +0100 +Subject: [PATCH 16/33] dirty-bitmap: switch assert-fails to errors in + bdrv_merge_dirty_bitmap + +RH-Author: John Snow +Message-id: <20190206221243.7407-7-jsnow@redhat.com> +Patchwork-id: 84263 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 06/23] dirty-bitmap: switch assert-fails to errors in bdrv_merge_dirty_bitmap +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Move checks from qmp_x_block_dirty_bitmap_merge() to +bdrv_merge_dirty_bitmap(), to share them with dirty bitmap merge +transaction action in future commit. + +Note: for now, only qmp_x_block_dirty_bitmap_merge() calls +bdrv_merge_dirty_bitmap(). + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 06bf50068a7e952afff8c4f6470ec54a712570f7) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 15 +++++++++++++-- + blockdev.c | 10 ---------- + 2 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 59027d4..999a40c 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -797,12 +797,23 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + + qemu_mutex_lock(dest->mutex); + +- assert(bdrv_dirty_bitmap_enabled(dest)); +- assert(!bdrv_dirty_bitmap_readonly(dest)); ++ if (bdrv_dirty_bitmap_frozen(dest)) { ++ error_setg(errp, "Bitmap '%s' is frozen and cannot be modified", ++ dest->name); ++ goto out; ++ } ++ ++ if (bdrv_dirty_bitmap_readonly(dest)) { ++ error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", ++ dest->name); ++ goto out; ++ } + + if (!hbitmap_merge(dest->bitmap, src->bitmap)) { + error_setg(errp, "Bitmaps are incompatible and can't be merged"); ++ goto out; + } + ++out: + qemu_mutex_unlock(dest->mutex); + } +diff --git a/blockdev.c b/blockdev.c +index 745ed08..cef1bfe 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3113,16 +3113,6 @@ void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, + return; + } + +- if (bdrv_dirty_bitmap_frozen(dst)) { +- error_setg(errp, "Bitmap '%s' is frozen and cannot be modified", +- dst_name); +- return; +- } else if (bdrv_dirty_bitmap_readonly(dst)) { +- error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", +- dst_name); +- return; +- } +- + src = bdrv_find_dirty_bitmap(bs, src_name); + if (!src) { + error_setg(errp, "Dirty bitmap '%s' not found", src_name); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmaps-clean-up-bitmaps-loading-and-migration.patch b/SOURCES/kvm-dirty-bitmaps-clean-up-bitmaps-loading-and-migration.patch new file mode 100644 index 0000000..e150188 --- /dev/null +++ b/SOURCES/kvm-dirty-bitmaps-clean-up-bitmaps-loading-and-migration.patch @@ -0,0 +1,323 @@ +From 5e3d8cd537a1742fcca824bca2e49e6c9b2db080 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:41 +0100 +Subject: [PATCH 31/33] dirty-bitmaps: clean-up bitmaps loading and migration + logic + +RH-Author: John Snow +Message-id: <20190206221243.7407-22-jsnow@redhat.com> +Patchwork-id: 84280 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 21/23] dirty-bitmaps: clean-up bitmaps loading and migration logic +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +This patch aims to bring the following behavior: + +1. We don't load bitmaps, when started in inactive mode. It's the case +of incoming migration. In this case we wait for bitmaps migration +through migration channel (if 'dirty-bitmaps' capability is enabled) or +for invalidation (to load bitmaps from the image). + +2. We don't remove persistent bitmaps on inactivation. Instead, we only +remove bitmaps after storing. This is the only way to restore bitmaps, +if we decided to resume source after [failed] migration with +'dirty-bitmaps' capability enabled (which means, that bitmaps were not +stored). + +3. We load bitmaps on open and any invalidation, it's ok for all cases: + - normal open + - migration target invalidation with dirty-bitmaps capability + (bitmaps are migrating through migration channel, the are not + stored, so they should have IN_USE flag set and will be skipped + when loading. However, it would fail if bitmaps are read-only[1]) + - migration target invalidation without dirty-bitmaps capability + (normal load of the bitmaps, if migrated with shared storage) + - source invalidation with dirty-bitmaps capability + (skip because IN_USE) + - source invalidation without dirty-bitmaps capability + (bitmaps were dropped, reload them) + +[1]: to accurately handle this, migration of read-only bitmaps is + explicitly forbidden in this patch. + +New mechanism for not storing bitmaps when migrate with dirty-bitmaps +capability is introduced: migration filed in BdrvDirtyBitmap. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +(cherry picked from commit 9c98f145dfb994e1e9d68a4d606ee5693891280d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block.c | 11 ++++--- + block/dirty-bitmap.c | 36 +++++++++-------------- + block/qcow2-bitmap.c | 16 +++++++++++ + block/qcow2.c | 65 ++++++++++++++++++++++++++++++++++++++++-- + include/block/dirty-bitmap.h | 2 +- + migration/block-dirty-bitmap.c | 10 +++++-- + 6 files changed, 109 insertions(+), 31 deletions(-) + +diff --git a/block.c b/block.c +index ce85c65..82b16df 100644 +--- a/block.c ++++ b/block.c +@@ -4350,6 +4350,7 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, + uint64_t perm, shared_perm; + Error *local_err = NULL; + int ret; ++ BdrvDirtyBitmap *bm; + + if (!bs->drv) { + return; +@@ -4399,6 +4400,12 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, + } + } + ++ for (bm = bdrv_dirty_bitmap_next(bs, NULL); bm; ++ bm = bdrv_dirty_bitmap_next(bs, bm)) ++ { ++ bdrv_dirty_bitmap_set_migration(bm, false); ++ } ++ + ret = refresh_total_sectors(bs, bs->total_sectors); + if (ret < 0) { + bs->open_flags |= BDRV_O_INACTIVE; +@@ -4537,10 +4544,6 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) + } + } + +- /* At this point persistent bitmaps should be already stored by the format +- * driver */ +- bdrv_release_persistent_dirty_bitmaps(bs); +- + return 0; + } + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index db8021a..6b68839 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -55,6 +55,10 @@ struct BdrvDirtyBitmap { + and this bitmap must remain unchanged while + this flag is set. */ + bool persistent; /* bitmap must be saved to owner disk image */ ++ bool migration; /* Bitmap is selected for migration, it should ++ not be stored on the next inactivation ++ (persistent flag doesn't matter until next ++ invalidation).*/ + QLIST_ENTRY(BdrvDirtyBitmap) list; + }; + +@@ -390,26 +394,6 @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) + } + + /** +- * Release all persistent dirty bitmaps attached to a BDS (for use in +- * bdrv_inactivate_recurse()). +- * There must not be any frozen bitmaps attached. +- * This function does not remove persistent bitmaps from the storage. +- * Called with BQL taken. +- */ +-void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs) +-{ +- BdrvDirtyBitmap *bm, *next; +- +- bdrv_dirty_bitmaps_lock(bs); +- QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) { +- if (bdrv_dirty_bitmap_get_persistance(bm)) { +- bdrv_release_dirty_bitmap_locked(bm); +- } +- } +- bdrv_dirty_bitmaps_unlock(bs); +-} +- +-/** + * Remove persistent dirty bitmap from the storage if it exists. + * Absence of bitmap is not an error, because we have the following scenario: + * BdrvDirtyBitmap can have .persistent = true but not yet saved and have no +@@ -760,16 +744,24 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent) + qemu_mutex_unlock(bitmap->mutex); + } + ++/* Called with BQL taken. */ ++void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration) ++{ ++ qemu_mutex_lock(bitmap->mutex); ++ bitmap->migration = migration; ++ qemu_mutex_unlock(bitmap->mutex); ++} ++ + bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap) + { +- return bitmap->persistent; ++ return bitmap->persistent && !bitmap->migration; + } + + bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs) + { + BdrvDirtyBitmap *bm; + QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) { +- if (bm->persistent && !bm->readonly) { ++ if (bm->persistent && !bm->readonly && !bm->migration) { + return true; + } + } +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index 14050eb..a36773c 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -1418,6 +1418,22 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) + g_free(tb); + } + ++ QSIMPLEQ_FOREACH(bm, bm_list, entry) { ++ /* For safety, we remove bitmap after storing. ++ * We may be here in two cases: ++ * 1. bdrv_close. It's ok to drop bitmap. ++ * 2. inactivation. It means migration without 'dirty-bitmaps' ++ * capability, so bitmaps are not marked with ++ * BdrvDirtyBitmap.migration flags. It's not bad to drop them too, ++ * and reload on invalidation. ++ */ ++ if (bm->dirty_bitmap == NULL) { ++ continue; ++ } ++ ++ bdrv_release_dirty_bitmap(bs, bm->dirty_bitmap); ++ } ++ + bitmap_list_free(bm_list); + return; + +diff --git a/block/qcow2.c b/block/qcow2.c +index d260cd6..36d1152 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1487,8 +1487,69 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, + s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; + } + +- if (qcow2_load_dirty_bitmaps(bs, &local_err)) { +- update_header = false; ++ /* == Handle persistent dirty bitmaps == ++ * ++ * We want load dirty bitmaps in three cases: ++ * ++ * 1. Normal open of the disk in active mode, not related to invalidation ++ * after migration. ++ * ++ * 2. Invalidation of the target vm after pre-copy phase of migration, if ++ * bitmaps are _not_ migrating through migration channel, i.e. ++ * 'dirty-bitmaps' capability is disabled. ++ * ++ * 3. Invalidation of source vm after failed or canceled migration. ++ * This is a very interesting case. There are two possible types of ++ * bitmaps: ++ * ++ * A. Stored on inactivation and removed. They should be loaded from the ++ * image. ++ * ++ * B. Not stored: not-persistent bitmaps and bitmaps, migrated through ++ * the migration channel (with dirty-bitmaps capability). ++ * ++ * On the other hand, there are two possible sub-cases: ++ * ++ * 3.1 disk was changed by somebody else while were inactive. In this ++ * case all in-RAM dirty bitmaps (both persistent and not) are ++ * definitely invalid. And we don't have any method to determine ++ * this. ++ * ++ * Simple and safe thing is to just drop all the bitmaps of type B on ++ * inactivation. But in this case we lose bitmaps in valid 4.2 case. ++ * ++ * On the other hand, resuming source vm, if disk was already changed ++ * is a bad thing anyway: not only bitmaps, the whole vm state is ++ * out of sync with disk. ++ * ++ * This means, that user or management tool, who for some reason ++ * decided to resume source vm, after disk was already changed by ++ * target vm, should at least drop all dirty bitmaps by hand. ++ * ++ * So, we can ignore this case for now, but TODO: "generation" ++ * extension for qcow2, to determine, that image was changed after ++ * last inactivation. And if it is changed, we will drop (or at least ++ * mark as 'invalid' all the bitmaps of type B, both persistent ++ * and not). ++ * ++ * 3.2 disk was _not_ changed while were inactive. Bitmaps may be saved ++ * to disk ('dirty-bitmaps' capability disabled), or not saved ++ * ('dirty-bitmaps' capability enabled), but we don't need to care ++ * of: let's load bitmaps as always: stored bitmaps will be loaded, ++ * and not stored has flag IN_USE=1 in the image and will be skipped ++ * on loading. ++ * ++ * One remaining possible case when we don't want load bitmaps: ++ * ++ * 4. Open disk in inactive mode in target vm (bitmaps are migrating or ++ * will be loaded on invalidation, no needs try loading them before) ++ */ ++ ++ if (!(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) { ++ /* It's case 1, 2 or 3.2. Or 3.1 which is BUG in management layer. */ ++ bool header_updated = qcow2_load_dirty_bitmaps(bs, &local_err); ++ ++ update_header = update_header && !header_updated; + } + if (local_err != NULL) { + error_propagate(errp, local_err); +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 1463943..8f38a3d 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -26,7 +26,6 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, + const char *name); + void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); + void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); +-void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs); + void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, + const char *name, + Error **errp); +@@ -72,6 +71,7 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, + void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked); + void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, + HBitmap **backup, Error **errp); ++void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration); + + /* Functions that require manual locking. */ + void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 47251af..ffe7aca 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -307,6 +307,12 @@ static int init_dirty_bitmap_migration(void) + goto fail; + } + ++ if (bdrv_dirty_bitmap_readonly(bitmap)) { ++ error_report("Can't migrate read-only dirty bitmap: '%s", ++ bdrv_dirty_bitmap_name(bitmap)); ++ goto fail; ++ } ++ + bdrv_ref(bs); + bdrv_dirty_bitmap_set_qmp_locked(bitmap, true); + +@@ -329,9 +335,9 @@ static int init_dirty_bitmap_migration(void) + } + } + +- /* unset persistance here, to not roll back it */ ++ /* unset migration flags here, to not roll back it */ + QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) { +- bdrv_dirty_bitmap_set_persistance(dbms->bitmap, false); ++ bdrv_dirty_bitmap_set_migration(dbms->bitmap, true); + } + + if (QSIMPLEQ_EMPTY(&dirty_bitmap_mig_state.dbms_list)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-docs-Document-the-new-default-sizes-of-the-qcow2-cac.patch b/SOURCES/kvm-docs-Document-the-new-default-sizes-of-the-qcow2-cac.patch new file mode 100644 index 0000000..33a6eec --- /dev/null +++ b/SOURCES/kvm-docs-Document-the-new-default-sizes-of-the-qcow2-cac.patch @@ -0,0 +1,87 @@ +From f05cd76313a9d1e461eb66ee85f9f45fdb235f85 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:12 +0100 +Subject: [PATCH 11/23] docs: Document the new default sizes of the qcow2 + caches + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-3-kwolf@redhat.com> +Patchwork-id: 84542 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/13] docs: Document the new default sizes of the qcow2 caches +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Alberto Garcia + +We have just reduced the refcount cache size to the minimum unless +the user explicitly requests a larger one, so we have to update the +documentation to reflect this change. + +Signed-off-by: Alberto Garcia +Message-id: c5f0bde23558dd9d33b21fffc76ac9953cc19c56.1523968389.git.berto@igalia.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 603790ef3aec6a19b1c095188a1d2171934a27de) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + docs/qcow2-cache.txt | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt +index 170191a..8a09a5c 100644 +--- a/docs/qcow2-cache.txt ++++ b/docs/qcow2-cache.txt +@@ -116,31 +116,30 @@ There are three options available, and all of them take bytes: + "refcount-cache-size": maximum size of the refcount block cache + "cache-size": maximum size of both caches combined + +-There are two things that need to be taken into account: ++There are a few things that need to be taken into account: + + - Both caches must have a size that is a multiple of the cluster size + (or the cache entry size: see "Using smaller cache sizes" below). + +- - If you only set one of the options above, QEMU will automatically +- adjust the others so that the L2 cache is 4 times bigger than the +- refcount cache. ++ - The default L2 cache size is 8 clusters or 1MB (whichever is more), ++ and the minimum is 2 clusters (or 2 cache entries, see below). + +-This means that these options are equivalent: ++ - The default (and minimum) refcount cache size is 4 clusters. + +- -drive file=hd.qcow2,l2-cache-size=2097152 +- -drive file=hd.qcow2,refcount-cache-size=524288 +- -drive file=hd.qcow2,cache-size=2621440 ++ - If only "cache-size" is specified then QEMU will assign as much ++ memory as possible to the L2 cache before increasing the refcount ++ cache size. + +-The reason for this 1/4 ratio is to ensure that both caches cover the +-same amount of disk space. Note however that this is only valid with +-the default value of refcount_bits (16). If you are using a different +-value you might want to calculate both cache sizes yourself since QEMU +-will always use the same 1/4 ratio. ++Unlike L2 tables, refcount blocks are not used during normal I/O but ++only during allocations and internal snapshots. In most cases they are ++accessed sequentially (even during random guest I/O) so increasing the ++refcount cache size won't have any measurable effect in performance ++(this can change if you are using internal snapshots, so you may want ++to think about increasing the cache size if you use them heavily). + +-It's also worth mentioning that there's no strict need for both caches +-to cover the same amount of disk space. The refcount cache is used +-much less often than the L2 cache, so it's perfectly reasonable to +-keep it small. ++Before QEMU 2.12 the refcount cache had a default size of 1/4 of the ++L2 cache size. This resulted in unnecessarily large caches, so now the ++refcount cache is as small as possible unless overridden by the user. + + + Using smaller cache entries +-- +1.8.3.1 + diff --git a/SOURCES/kvm-docs-interop-add-firmware.json.patch b/SOURCES/kvm-docs-interop-add-firmware.json.patch new file mode 100644 index 0000000..d65785d --- /dev/null +++ b/SOURCES/kvm-docs-interop-add-firmware.json.patch @@ -0,0 +1,598 @@ +From ec98b4315beedbb1c61277d47a11dccaecfa3fb1 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 13 Nov 2018 18:16:39 +0100 +Subject: [PATCH 20/22] docs/interop: add "firmware.json" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laszlo Ersek +Message-id: <20181113181639.4999-7-lersek@redhat.com> +Patchwork-id: 83009 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 6/6] docs/interop: add "firmware.json" +Bugzilla: 1607406 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Markus Armbruster + +Add a schema that describes the different uses and properties of virtual +machine firmware. + +Each firmware executable installed on a host system should come with at +least one JSON file that conforms to this schema. Each file informs the +management applications about +- the firmware's properties and one possible use case / feature set, +- configuration bits that are required to run the firmware binary. + +In addition, define rules for management apps for picking the highest +priority firmware JSON file when multiple such files match the search +criteria. + +Cc: "Daniel P. Berrange" +Cc: David Gibson +Cc: Eric Blake +Cc: Gerd Hoffmann +Cc: Kashyap Chamarthy +Cc: Markus Armbruster +Cc: Paolo Bonzini +Cc: Thomas Huth +Reviewed-by: Gerd Hoffmann +Signed-off-by: Laszlo Ersek +Message-Id: <20180509152608.9343-1-lersek@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 3a0adfc9bfcf217017bfc49d00c9a9b845e7118d) +Signed-off-by: Miroslav Rezanina +--- + docs/interop/firmware.json | 540 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 540 insertions(+) + create mode 100644 docs/interop/firmware.json + +diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json +new file mode 100644 +index 0000000..28f9bc1 +--- /dev/null ++++ b/docs/interop/firmware.json +@@ -0,0 +1,540 @@ ++# -*- Mode: Python -*- ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# Authors: ++# Daniel P. Berrange ++# Laszlo Ersek ++# ++# This work is licensed under the terms of the GNU GPL, version 2 or ++# later. See the COPYING file in the top-level directory. ++ ++## ++# = Firmware ++## ++ ++{ 'include' : 'common.json' } ++{ 'include' : 'block-core.json' } ++ ++## ++# @FirmwareOSInterface: ++# ++# Lists the firmware-OS interface types provided by various firmware ++# that is commonly used with QEMU virtual machines. ++# ++# @bios: Traditional x86 BIOS interface. For example, firmware built ++# from the SeaBIOS project usually provides this interface. ++# ++# @openfirmware: The interface is defined by the (historical) IEEE ++# 1275-1994 standard. Examples for firmware projects that ++# provide this interface are: OpenBIOS, OpenHackWare, ++# SLOF. ++# ++# @uboot: Firmware interface defined by the U-Boot project. ++# ++# @uefi: Firmware interface defined by the UEFI specification. For ++# example, firmware built from the edk2 (EFI Development Kit II) ++# project usually provides this interface. ++# ++# Since: 3.0 ++## ++{ 'enum' : 'FirmwareOSInterface', ++ 'data' : [ 'bios', 'openfirmware', 'uboot', 'uefi' ] } ++ ++## ++# @FirmwareDevice: ++# ++# Defines the device types that firmware can be mapped into. ++# ++# @flash: The firmware executable and its accompanying NVRAM file are to ++# be mapped into a pflash chip each. ++# ++# @kernel: The firmware is to be loaded like a Linux kernel. This is ++# similar to @memory but may imply additional processing that ++# is specific to the target architecture and machine type. ++# ++# @memory: The firmware is to be mapped into memory. ++# ++# Since: 3.0 ++## ++{ 'enum' : 'FirmwareDevice', ++ 'data' : [ 'flash', 'kernel', 'memory' ] } ++ ++## ++# @FirmwareTarget: ++# ++# Defines the machine types that firmware may execute on. ++# ++# @architecture: Determines the emulation target (the QEMU system ++# emulator) that can execute the firmware. ++# ++# @machines: Lists the machine types (known by the emulator that is ++# specified through @architecture) that can execute the ++# firmware. Elements of @machines are supposed to be concrete ++# machine types, not aliases. Glob patterns are understood, ++# which is especially useful for versioned machine types. ++# (For example, the glob pattern "pc-i440fx-*" matches ++# "pc-i440fx-2.12".) On the QEMU command line, "-machine ++# type=..." specifies the requested machine type (but that ++# option does not accept glob patterns). ++# ++# Since: 3.0 ++## ++{ 'struct' : 'FirmwareTarget', ++ 'data' : { 'architecture' : 'SysEmuTarget', ++ 'machines' : [ 'str' ] } } ++ ++## ++# @FirmwareFeature: ++# ++# Defines the features that firmware may support, and the platform ++# requirements that firmware may present. ++# ++# @acpi-s3: The firmware supports S3 sleep (suspend to RAM), as defined ++# in the ACPI specification. On the "pc-i440fx-*" machine ++# types of the @i386 and @x86_64 emulation targets, S3 can be ++# enabled with "-global PIIX4_PM.disable_s3=0" and disabled ++# with "-global PIIX4_PM.disable_s3=1". On the "pc-q35-*" ++# machine types of the @i386 and @x86_64 emulation targets, S3 ++# can be enabled with "-global ICH9-LPC.disable_s3=0" and ++# disabled with "-global ICH9-LPC.disable_s3=1". ++# ++# @acpi-s4: The firmware supports S4 hibernation (suspend to disk), as ++# defined in the ACPI specification. On the "pc-i440fx-*" ++# machine types of the @i386 and @x86_64 emulation targets, S4 ++# can be enabled with "-global PIIX4_PM.disable_s4=0" and ++# disabled with "-global PIIX4_PM.disable_s4=1". On the ++# "pc-q35-*" machine types of the @i386 and @x86_64 emulation ++# targets, S4 can be enabled with "-global ++# ICH9-LPC.disable_s4=0" and disabled with "-global ++# ICH9-LPC.disable_s4=1". ++# ++# @amd-sev: The firmware supports running under AMD Secure Encrypted ++# Virtualization, as specified in the AMD64 Architecture ++# Programmer's Manual. QEMU command line options related to ++# this feature are documented in ++# "docs/amd-memory-encryption.txt". ++# ++# @enrolled-keys: The variable store (NVRAM) template associated with ++# the firmware binary has the UEFI Secure Boot ++# operational mode turned on, with certificates ++# enrolled. ++# ++# @requires-smm: The firmware requires the platform to emulate SMM ++# (System Management Mode), as defined in the AMD64 ++# Architecture Programmer's Manual, and in the Intel(R)64 ++# and IA-32 Architectures Software Developer's Manual. On ++# the "pc-q35-*" machine types of the @i386 and @x86_64 ++# emulation targets, SMM emulation can be enabled with ++# "-machine smm=on". (On the "pc-q35-*" machine types of ++# the @i386 emulation target, @requires-smm presents ++# further CPU requirements; one combination known to work ++# is "-cpu coreduo,-nx".) If the firmware is marked as ++# both @secure-boot and @requires-smm, then write ++# accesses to the pflash chip (NVRAM) that holds the UEFI ++# variable store must be restricted to code that executes ++# in SMM, using the additional option "-global ++# driver=cfi.pflash01,property=secure,value=on". ++# Furthermore, a large guest-physical address space ++# (comprising guest RAM, memory hotplug range, and 64-bit ++# PCI MMIO aperture), and/or a high VCPU count, may ++# present high SMRAM requirements from the firmware. On ++# the "pc-q35-*" machine types of the @i386 and @x86_64 ++# emulation targets, the SMRAM size may be increased ++# above the default 16MB with the "-global ++# mch.extended-tseg-mbytes=uint16" option. As a rule of ++# thumb, the default 16MB size suffices for 1TB of ++# guest-phys address space and a few tens of VCPUs; for ++# every further TB of guest-phys address space, add 8MB ++# of SMRAM. 48MB should suffice for 4TB of guest-phys ++# address space and 2-3 hundred VCPUs. ++# ++# @secure-boot: The firmware implements the software interfaces for UEFI ++# Secure Boot, as defined in the UEFI specification. Note ++# that without @requires-smm, guest code running with ++# kernel privileges can undermine the security of Secure ++# Boot. ++# ++# @verbose-dynamic: When firmware log capture is enabled, the firmware ++# logs a large amount of debug messages, which may ++# impact boot performance. With log capture disabled, ++# there is no boot performance impact. On the ++# "pc-i440fx-*" and "pc-q35-*" machine types of the ++# @i386 and @x86_64 emulation targets, firmware log ++# capture can be enabled with the QEMU command line ++# options "-chardev file,id=fwdebug,path=LOGFILEPATH ++# -device isa-debugcon,iobase=0x402,chardev=fwdebug". ++# @verbose-dynamic is mutually exclusive with ++# @verbose-static. ++# ++# @verbose-static: The firmware unconditionally produces a large amount ++# of debug messages, which may impact boot performance. ++# This feature may typically be carried by certain UEFI ++# firmware for the "virt-*" machine types of the @arm ++# and @aarch64 emulation targets, where the debug ++# messages are written to the first (always present) ++# PL011 UART. @verbose-static is mutually exclusive ++# with @verbose-dynamic. ++# ++# Since: 3.0 ++## ++{ 'enum' : 'FirmwareFeature', ++ 'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'enrolled-keys', ++ 'requires-smm', 'secure-boot', 'verbose-dynamic', ++ 'verbose-static' ] } ++ ++## ++# @FirmwareFlashFile: ++# ++# Defines common properties that are necessary for loading a firmware ++# file into a pflash chip. The corresponding QEMU command line option is ++# "-drive file=@filename,format=@format". Note however that the ++# option-argument shown here is incomplete; it is completed under ++# @FirmwareMappingFlash. ++# ++# @filename: Specifies the filename on the host filesystem where the ++# firmware file can be found. ++# ++# @format: Specifies the block format of the file pointed-to by ++# @filename, such as @raw or @qcow2. ++# ++# Since: 3.0 ++## ++{ 'struct' : 'FirmwareFlashFile', ++ 'data' : { 'filename' : 'str', ++ 'format' : 'BlockdevDriver' } } ++ ++## ++# @FirmwareMappingFlash: ++# ++# Describes loading and mapping properties for the firmware executable ++# and its accompanying NVRAM file, when @FirmwareDevice is @flash. ++# ++# @executable: Identifies the firmware executable. The firmware ++# executable may be shared by multiple virtual machine ++# definitions. The corresponding QEMU command line option ++# is "-drive ++# if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format". ++# ++# @nvram-template: Identifies the NVRAM template compatible with ++# @executable. Management software instantiates an ++# individual copy -- a specific NVRAM file -- from ++# @nvram-template.@filename for each new virtual ++# machine definition created. @nvram-template.@filename ++# itself is never mapped into virtual machines, only ++# individual copies of it are. An NVRAM file is ++# typically used for persistently storing the ++# non-volatile UEFI variables of a virtual machine ++# definition. The corresponding QEMU command line ++# option is "-drive ++# if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format". ++# ++# Since: 3.0 ++## ++{ 'struct' : 'FirmwareMappingFlash', ++ 'data' : { 'executable' : 'FirmwareFlashFile', ++ 'nvram-template' : 'FirmwareFlashFile' } } ++ ++## ++# @FirmwareMappingKernel: ++# ++# Describes loading and mapping properties for the firmware executable, ++# when @FirmwareDevice is @kernel. ++# ++# @filename: Identifies the firmware executable. The firmware executable ++# may be shared by multiple virtual machine definitions. The ++# corresponding QEMU command line option is "-kernel ++# @filename". ++# ++# Since: 3.0 ++## ++{ 'struct' : 'FirmwareMappingKernel', ++ 'data' : { 'filename' : 'str' } } ++ ++## ++# @FirmwareMappingMemory: ++# ++# Describes loading and mapping properties for the firmware executable, ++# when @FirmwareDevice is @memory. ++# ++# @filename: Identifies the firmware executable. The firmware executable ++# may be shared by multiple virtual machine definitions. The ++# corresponding QEMU command line option is "-bios ++# @filename". ++# ++# Since: 3.0 ++## ++{ 'struct' : 'FirmwareMappingMemory', ++ 'data' : { 'filename' : 'str' } } ++ ++## ++# @FirmwareMapping: ++# ++# Provides a discriminated structure for firmware to describe its ++# loading / mapping properties. ++# ++# @device: Selects the device type that the firmware must be mapped ++# into. ++# ++# Since: 3.0 ++## ++{ 'union' : 'FirmwareMapping', ++ 'base' : { 'device' : 'FirmwareDevice' }, ++ 'discriminator' : 'device', ++ 'data' : { 'flash' : 'FirmwareMappingFlash', ++ 'kernel' : 'FirmwareMappingKernel', ++ 'memory' : 'FirmwareMappingMemory' } } ++ ++## ++# @Firmware: ++# ++# Describes a firmware (or a firmware use case) to management software. ++# ++# It is possible for multiple @Firmware elements to match the search ++# criteria of management software. Applications thus need rules to pick ++# one of the many matches, and users need the ability to override distro ++# defaults. ++# ++# It is recommended to create firmware JSON files (each containing a ++# single @Firmware root element) with a double-digit prefix, for example ++# "50-ovmf.json", "50-seabios-256k.json", etc, so they can be sorted in ++# predictable order. The firmware JSON files should be searched for in ++# three directories: ++# ++# - /usr/share/qemu/firmware -- populated by distro-provided firmware ++# packages (XDG_DATA_DIRS covers ++# /usr/share by default), ++# ++# - /etc/qemu/firmware -- exclusively for sysadmins' local additions, ++# ++# - $XDG_CONFIG_HOME/qemu/firmware -- exclusively for per-user local ++# additions (XDG_CONFIG_HOME ++# defaults to $HOME/.config). ++# ++# Top-down, the list of directories goes from general to specific. ++# ++# Management software should build a list of files from all three ++# locations, then sort the list by filename (i.e., last pathname ++# component). Management software should choose the first JSON file on ++# the sorted list that matches the search criteria. If a more specific ++# directory has a file with same name as a less specific directory, then ++# the file in the more specific directory takes effect. If the more ++# specific file is zero length, it hides the less specific one. ++# ++# For example, if a distro ships ++# ++# - /usr/share/qemu/firmware/50-ovmf.json ++# ++# - /usr/share/qemu/firmware/50-seabios-256k.json ++# ++# then the sysadmin can prevent the default OVMF being used at all with ++# ++# $ touch /etc/qemu/firmware/50-ovmf.json ++# ++# The sysadmin can replace/alter the distro default OVMF with ++# ++# $ vim /etc/qemu/firmware/50-ovmf.json ++# ++# or they can provide a parallel OVMF with higher priority ++# ++# $ vim /etc/qemu/firmware/10-ovmf.json ++# ++# or they can provide a parallel OVMF with lower priority ++# ++# $ vim /etc/qemu/firmware/99-ovmf.json ++# ++# @description: Provides a human-readable description of the firmware. ++# Management software may or may not display @description. ++# ++# @interface-types: Lists the types of interfaces that the firmware can ++# expose to the guest OS. This is a non-empty, ordered ++# list; entries near the beginning of @interface-types ++# are considered more native to the firmware, and/or ++# to have a higher quality implementation in the ++# firmware, than entries near the end of ++# @interface-types. ++# ++# @mapping: Describes the loading / mapping properties of the firmware. ++# ++# @targets: Collects the target architectures (QEMU system emulators) ++# and their machine types that may execute the firmware. ++# ++# @features: Lists the features that the firmware supports, and the ++# platform requirements it presents. ++# ++# @tags: A list of auxiliary strings associated with the firmware for ++# which @description is not appropriate, due to the latter's ++# possible exposure to the end-user. @tags serves development and ++# debugging purposes only, and management software shall ++# explicitly ignore it. ++# ++# Since: 3.0 ++# ++# Examples: ++# ++# { ++# "description": "SeaBIOS", ++# "interface-types": [ ++# "bios" ++# ], ++# "mapping": { ++# "device": "memory", ++# "filename": "/usr/share/seabios/bios-256k.bin" ++# }, ++# "targets": [ ++# { ++# "architecture": "i386", ++# "machines": [ ++# "pc-i440fx-*", ++# "pc-q35-*" ++# ] ++# }, ++# { ++# "architecture": "x86_64", ++# "machines": [ ++# "pc-i440fx-*", ++# "pc-q35-*" ++# ] ++# } ++# ], ++# "features": [ ++# "acpi-s3", ++# "acpi-s4" ++# ], ++# "tags": [ ++# "CONFIG_BOOTSPLASH=n", ++# "CONFIG_ROM_SIZE=256", ++# "CONFIG_USE_SMM=n" ++# ] ++# } ++# ++# { ++# "description": "OVMF with SB+SMM, empty varstore", ++# "interface-types": [ ++# "uefi" ++# ], ++# "mapping": { ++# "device": "flash", ++# "executable": { ++# "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd", ++# "format": "raw" ++# }, ++# "nvram-template": { ++# "filename": "/usr/share/OVMF/OVMF_VARS.fd", ++# "format": "raw" ++# } ++# }, ++# "targets": [ ++# { ++# "architecture": "x86_64", ++# "machines": [ ++# "pc-q35-*" ++# ] ++# } ++# ], ++# "features": [ ++# "acpi-s3", ++# "amd-sev", ++# "requires-smm", ++# "secure-boot", ++# "verbose-dynamic" ++# ], ++# "tags": [ ++# "-a IA32", ++# "-a X64", ++# "-p OvmfPkg/OvmfPkgIa32X64.dsc", ++# "-t GCC48", ++# "-b DEBUG", ++# "-D SMM_REQUIRE", ++# "-D SECURE_BOOT_ENABLE", ++# "-D FD_SIZE_4MB" ++# ] ++# } ++# ++# { ++# "description": "OVMF with SB+SMM, SB enabled, MS certs enrolled", ++# "interface-types": [ ++# "uefi" ++# ], ++# "mapping": { ++# "device": "flash", ++# "executable": { ++# "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd", ++# "format": "raw" ++# }, ++# "nvram-template": { ++# "filename": "/usr/share/OVMF/OVMF_VARS.secboot.fd", ++# "format": "raw" ++# } ++# }, ++# "targets": [ ++# { ++# "architecture": "x86_64", ++# "machines": [ ++# "pc-q35-*" ++# ] ++# } ++# ], ++# "features": [ ++# "acpi-s3", ++# "amd-sev", ++# "enrolled-keys", ++# "requires-smm", ++# "secure-boot", ++# "verbose-dynamic" ++# ], ++# "tags": [ ++# "-a IA32", ++# "-a X64", ++# "-p OvmfPkg/OvmfPkgIa32X64.dsc", ++# "-t GCC48", ++# "-b DEBUG", ++# "-D SMM_REQUIRE", ++# "-D SECURE_BOOT_ENABLE", ++# "-D FD_SIZE_4MB" ++# ] ++# } ++# ++# { ++# "description": "UEFI firmware for ARM64 virtual machines", ++# "interface-types": [ ++# "uefi" ++# ], ++# "mapping": { ++# "device": "flash", ++# "executable": { ++# "filename": "/usr/share/AAVMF/AAVMF_CODE.fd", ++# "format": "raw" ++# }, ++# "nvram-template": { ++# "filename": "/usr/share/AAVMF/AAVMF_VARS.fd", ++# "format": "raw" ++# } ++# }, ++# "targets": [ ++# { ++# "architecture": "aarch64", ++# "machines": [ ++# "virt-*" ++# ] ++# } ++# ], ++# "features": [ ++# ++# ], ++# "tags": [ ++# "-a AARCH64", ++# "-p ArmVirtPkg/ArmVirtQemu.dsc", ++# "-t GCC48", ++# "-b DEBUG", ++# "-D DEBUG_PRINT_ERROR_LEVEL=0x80000000" ++# ] ++# } ++## ++{ 'struct' : 'Firmware', ++ 'data' : { 'description' : 'str', ++ 'interface-types' : [ 'FirmwareOSInterface' ], ++ 'mapping' : 'FirmwareMapping', ++ 'targets' : [ 'FirmwareTarget' ], ++ 'features' : [ 'FirmwareFeature' ], ++ 'tags' : [ 'str' ] } } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-docs-interop-firmware.json-Prefer-machine-to-if-pfla.patch b/SOURCES/kvm-docs-interop-firmware.json-Prefer-machine-to-if-pfla.patch new file mode 100644 index 0000000..584b115 --- /dev/null +++ b/SOURCES/kvm-docs-interop-firmware.json-Prefer-machine-to-if-pfla.patch @@ -0,0 +1,72 @@ +From 11a0638c7c56d8653e99b8eab194d1adc70a35f3 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:18 +0200 +Subject: [PATCH 51/53] docs/interop/firmware.json: Prefer -machine to + if=pflash +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-30-armbru@redhat.com> +Patchwork-id: 87994 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 29/31] docs/interop/firmware.json: Prefer -machine to if=pflash +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +The previous commit added a way to configure firmware with -blockdev +rather than -drive if=pflash. Document it as the preferred way. + +Signed-off-by: Markus Armbruster +Message-Id: <20190308131445.17502-13-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Laszlo Ersek +(cherry picked from commit e33763be7cd3769c9ae48e67d775348863fdabdb) +Signed-off-by: Miroslav Rezanina +--- + docs/interop/firmware.json | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json +index 28f9bc1..ff8c2ce 100644 +--- a/docs/interop/firmware.json ++++ b/docs/interop/firmware.json +@@ -212,9 +212,13 @@ + # + # @executable: Identifies the firmware executable. The firmware + # executable may be shared by multiple virtual machine +-# definitions. The corresponding QEMU command line option +-# is "-drive +-# if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format". ++# definitions. The preferred corresponding QEMU command ++# line options are ++# -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format ++# -machine pflash0=pflash0 ++# or equivalent -blockdev instead of -drive. ++# With QEMU versions older than 4.0, you have to use ++# -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format + # + # @nvram-template: Identifies the NVRAM template compatible with + # @executable. Management software instantiates an +@@ -225,9 +229,13 @@ + # individual copies of it are. An NVRAM file is + # typically used for persistently storing the + # non-volatile UEFI variables of a virtual machine +-# definition. The corresponding QEMU command line +-# option is "-drive +-# if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format". ++# definition. The preferred corresponding QEMU ++# command line options are ++# -drive if=none,id=pflash1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format ++# -machine pflash1=pflash1 ++# or equivalent -blockdev instead of -drive. ++# With QEMU versions older than 4.0, you have to use ++# -drive if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format + # + # Since: 3.0 + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-docs-interop-qcow2-Improve-bitmap-flag-in_use-specif.patch b/SOURCES/kvm-docs-interop-qcow2-Improve-bitmap-flag-in_use-specif.patch new file mode 100644 index 0000000..c65d0ff --- /dev/null +++ b/SOURCES/kvm-docs-interop-qcow2-Improve-bitmap-flag-in_use-specif.patch @@ -0,0 +1,62 @@ +From 0b5f477725d2652d671b42238ea58dbbdd4763a9 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 22:42:49 +0200 +Subject: [PATCH 154/163] docs/interop/qcow2: Improve bitmap flag in_use + specification + +RH-Author: John Snow +Message-id: <20190403224253.5251-2-jsnow@redhat.com> +Patchwork-id: 85437 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/5] docs/interop/qcow2: Improve bitmap flag in_use specification +Bugzilla: 1666884 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Sergio Lopez Pascual + +From: Vladimir Sementsov-Ogievskiy + +We already use (we didn't notice it) IN_USE flag for marking bitmap +metadata outdated, such as AUTO flag, which mirrors enabled/disabled +bitmaps. Now we are going to support bitmap resize, so it's good to +write IN_USE meaning with more details. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190311185147.52309-2-vsementsov@virtuozzo.com +Signed-off-by: John Snow +(cherry picked from commit 2fd490c614500fc669386eaf8710cd2d015f548e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + docs/interop/qcow2.txt | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt +index feb711f..cba1787 100644 +--- a/docs/interop/qcow2.txt ++++ b/docs/interop/qcow2.txt +@@ -555,7 +555,10 @@ Structure of a bitmap directory entry: + Bit + 0: in_use + The bitmap was not saved correctly and may be +- inconsistent. ++ inconsistent. Although the bitmap metadata is still ++ well-formed from a qcow2 perspective, the metadata ++ (such as the auto flag or bitmap size) or data ++ contents may be outdated. + + 1: auto + The bitmap must reflect all changes of the virtual +@@ -683,8 +686,8 @@ corresponding range of the virtual disk (see above) was written to while the + bitmap was 'enabled'. An unset bit means that this range was not written to. + + The software doesn't have to sync the bitmap in the image file with its +-representation in RAM after each write. Flag 'in_use' should be set while the +-bitmap is not synced. ++representation in RAM after each write or metadata change. Flag 'in_use' ++should be set while the bitmap is not synced. + + In the image file the 'enabled' state is reflected by the 'auto' flag. If this + flag is set, the software must consider the bitmap as 'enabled' and start +-- +1.8.3.1 + diff --git a/SOURCES/kvm-egl-headless-parse-rendernode.patch b/SOURCES/kvm-egl-headless-parse-rendernode.patch new file mode 100644 index 0000000..8c971ae --- /dev/null +++ b/SOURCES/kvm-egl-headless-parse-rendernode.patch @@ -0,0 +1,50 @@ +From a2832a5633f66f85843184c223517bdb124104c2 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 5 Mar 2019 08:26:17 +0100 +Subject: [PATCH 9/9] egl-headless: parse rendernode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190305082617.14614-5-kraxel@redhat.com> +Patchwork-id: 84797 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/4] egl-headless: parse rendernode +Bugzilla: 1648236 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Marc-André Lureau +RH-Acked-by: John Snow +RH-Acked-by: Erik Skultety + +RHEL-7 hasn't the qapi-based -display parser, so we need a +few lines of code to explicitly handle the new option. + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Miroslav Rezanina +--- + vl.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/vl.c b/vl.c +index 8b79eb9..dfe261d 100644 +--- a/vl.c ++++ b/vl.c +@@ -2202,6 +2202,15 @@ static void parse_display(const char *p) + } + } else if (strstart(p, "egl-headless", &opts)) { + dpy.type = DISPLAY_TYPE_EGL_HEADLESS; ++ if (*opts) { ++ const char *nextopt; ++ if (strstart(opts, ",rendernode=", &nextopt)) { ++ dpy.u.egl_headless.rendernode = strdup(nextopt); ++ } else { ++ error_report("invalid egl-headless option string"); ++ exit(1); ++ } ++ } + } else if (strstart(p, "curses", &opts)) { + dpy.type = DISPLAY_TYPE_CURSES; + } else if (strstart(p, "gtk", &opts)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-Fix-MAP_RAM-for-cached-access.patch b/SOURCES/kvm-exec-Fix-MAP_RAM-for-cached-access.patch new file mode 100644 index 0000000..f2df3cf --- /dev/null +++ b/SOURCES/kvm-exec-Fix-MAP_RAM-for-cached-access.patch @@ -0,0 +1,275 @@ +From 8bd172d00ceb35cd2a625f1a86fe50a786d8564a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 25 Jan 2019 22:50:06 +0100 +Subject: [PATCH 06/23] exec: Fix MAP_RAM for cached access +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190125225007.8197-7-jsnow@redhat.com> +Patchwork-id: 84123 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 6/7] exec: Fix MAP_RAM for cached access +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Eric Auger + +When an IOMMUMemoryRegion is in front of a virtio device, +address_space_cache_init does not set cache->ptr as the memory +region is not RAM. However when the device performs an access, +we end up in glue() which performs the translation and then uses +MAP_RAM. This latter uses the unset ptr and returns a wrong value +which leads to a SIGSEV in address_space_lduw_internal_cached_slow, +for instance. + +In slow path cache->ptr is NULL and MAP_RAM must redirect to +qemu_map_ram_ptr((mr)->ram_block, ofs). + +As MAP_RAM, IS_DIRECT and INVALIDATE are the same in _cached_slow +and non cached mode, let's remove those macros. + +This fixes the use cases featuring vIOMMU (Intel and ARM SMMU) +which lead to a SIGSEV. + +Fixes: 48564041a73a (exec: reintroduce MemoryRegion caching) +Signed-off-by: Eric Auger + +Message-Id: <1528895946-28677-1-git-send-email-eric.auger@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit a99761d3c85679da380c0f597468acd3dc1b53b3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + exec.c | 6 ------ + memory_ldst.inc.c | 47 ++++++++++++++++++++++------------------------- + 2 files changed, 22 insertions(+), 31 deletions(-) + +diff --git a/exec.c b/exec.c +index 805a2d4..d87a51a 100644 +--- a/exec.c ++++ b/exec.c +@@ -3643,9 +3643,6 @@ void cpu_physical_memory_unmap(void *buffer, hwaddr len, + #define ARG1 as + #define SUFFIX + #define TRANSLATE(...) address_space_translate(as, __VA_ARGS__) +-#define IS_DIRECT(mr, is_write) memory_access_is_direct(mr, is_write) +-#define MAP_RAM(mr, ofs) qemu_map_ram_ptr((mr)->ram_block, ofs) +-#define INVALIDATE(mr, ofs, len) invalidate_and_set_dirty(mr, ofs, len) + #define RCU_READ_LOCK(...) rcu_read_lock() + #define RCU_READ_UNLOCK(...) rcu_read_unlock() + #include "memory_ldst.inc.c" +@@ -3775,9 +3772,6 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr, + #define ARG1 cache + #define SUFFIX _cached_slow + #define TRANSLATE(...) address_space_translate_cached(cache, __VA_ARGS__) +-#define IS_DIRECT(mr, is_write) memory_access_is_direct(mr, is_write) +-#define MAP_RAM(mr, ofs) (cache->ptr + (ofs - cache->xlat)) +-#define INVALIDATE(mr, ofs, len) invalidate_and_set_dirty(mr, ofs, len) + #define RCU_READ_LOCK() ((void)0) + #define RCU_READ_UNLOCK() ((void)0) + #include "memory_ldst.inc.c" +diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c +index 25d6125..e09c2b5 100644 +--- a/memory_ldst.inc.c ++++ b/memory_ldst.inc.c +@@ -34,7 +34,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); +- if (l < 4 || !IS_DIRECT(mr, false)) { ++ if (l < 4 || !memory_access_is_direct(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ +@@ -50,7 +50,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL, + #endif + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = ldl_le_p(ptr); +@@ -110,7 +110,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); +- if (l < 8 || !IS_DIRECT(mr, false)) { ++ if (l < 8 || !memory_access_is_direct(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ +@@ -126,7 +126,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, + #endif + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = ldq_le_p(ptr); +@@ -184,14 +184,14 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); +- if (!IS_DIRECT(mr, false)) { ++ if (!memory_access_is_direct(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ + r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs); + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + val = ldub_p(ptr); + r = MEMTX_OK; + } +@@ -220,7 +220,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); +- if (l < 2 || !IS_DIRECT(mr, false)) { ++ if (l < 2 || !memory_access_is_direct(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ +@@ -236,7 +236,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, + #endif + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = lduw_le_p(ptr); +@@ -297,12 +297,12 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); +- if (l < 4 || !IS_DIRECT(mr, true)) { ++ if (l < 4 || !memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + + r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); + } else { +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + stl_p(ptr, val); + + dirty_log_mask = memory_region_get_dirty_log_mask(mr); +@@ -334,7 +334,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); +- if (l < 4 || !IS_DIRECT(mr, true)) { ++ if (l < 4 || !memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + + #if defined(TARGET_WORDS_BIGENDIAN) +@@ -349,7 +349,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, + r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stl_le_p(ptr, val); +@@ -361,7 +361,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, + stl_p(ptr, val); + break; + } +- INVALIDATE(mr, addr1, 4); ++ invalidate_and_set_dirty(mr, addr1, 4); + r = MEMTX_OK; + } + if (result) { +@@ -406,14 +406,14 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); +- if (!IS_DIRECT(mr, true)) { ++ if (!memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + r = memory_region_dispatch_write(mr, addr1, val, 1, attrs); + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + stb_p(ptr, val); +- INVALIDATE(mr, addr1, 1); ++ invalidate_and_set_dirty(mr, addr1, 1); + r = MEMTX_OK; + } + if (result) { +@@ -439,7 +439,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); +- if (l < 2 || !IS_DIRECT(mr, true)) { ++ if (l < 2 || !memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + + #if defined(TARGET_WORDS_BIGENDIAN) +@@ -454,7 +454,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, + r = memory_region_dispatch_write(mr, addr1, val, 2, attrs); + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stw_le_p(ptr, val); +@@ -466,7 +466,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, + stw_p(ptr, val); + break; + } +- INVALIDATE(mr, addr1, 2); ++ invalidate_and_set_dirty(mr, addr1, 2); + r = MEMTX_OK; + } + if (result) { +@@ -512,7 +512,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); +- if (l < 8 || !IS_DIRECT(mr, true)) { ++ if (l < 8 || !memory_access_is_direct(mr, true)) { + release_lock |= prepare_mmio_access(mr); + + #if defined(TARGET_WORDS_BIGENDIAN) +@@ -527,7 +527,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, + r = memory_region_dispatch_write(mr, addr1, val, 8, attrs); + } else { + /* RAM case */ +- ptr = MAP_RAM(mr, addr1); ++ ptr = qemu_map_ram_ptr(mr->ram_block, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stq_le_p(ptr, val); +@@ -539,7 +539,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, + stq_p(ptr, val); + break; + } +- INVALIDATE(mr, addr1, 8); ++ invalidate_and_set_dirty(mr, addr1, 8); + r = MEMTX_OK; + } + if (result) { +@@ -576,8 +576,5 @@ void glue(address_space_stq_be, SUFFIX)(ARG1_DECL, + #undef ARG1 + #undef SUFFIX + #undef TRANSLATE +-#undef IS_DIRECT +-#undef MAP_RAM +-#undef INVALIDATE + #undef RCU_READ_LOCK + #undef RCU_READ_UNLOCK +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-check-that-alignment-is-a-power-of-two.patch b/SOURCES/kvm-exec-check-that-alignment-is-a-power-of-two.patch new file mode 100644 index 0000000..83ba857 --- /dev/null +++ b/SOURCES/kvm-exec-check-that-alignment-is-a-power-of-two.patch @@ -0,0 +1,60 @@ +From 16f855a65838c81a35ac65a8a8b1084fa0b39689 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Fri, 21 Sep 2018 09:43:58 +0200 +Subject: [PATCH 04/22] exec: check that alignment is a power of two + +RH-Author: David Hildenbrand +Message-id: <20180921094358.12256-1-david@redhat.com> +Patchwork-id: 82228 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] exec: check that alignment is a power of two +Bugzilla: 1629717 +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Igor Mammedov +RH-Acked-by: Paolo Bonzini + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1629717 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=18439720 +Upstream: 61362b71c105ccb151ca16897a7d56534423f390 + +Right now we can crash QEMU using e.g. + +qemu-system-x86_64 -m 256M,maxmem=20G,slots=2 \ + -object memory-backend-file,id=mem0,size=12288,mem-path=/dev/zero,align=12288 \ + -device pc-dimm,id=dimm1,memdev=mem0 + +qemu-system-x86_64: util/mmap-alloc.c:115: + qemu_ram_mmap: Assertion `is_power_of_2(align)' failed + +Fix this by adding a proper check. + +Signed-off-by: David Hildenbrand +Message-Id: <20180607154705.6316-3-david@redhat.com> +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Igor Mammedov +Signed-off-by: Paolo Bonzini +(cherry picked from commit 61362b71c105ccb151ca16897a7d56534423f390) +Signed-off-by: David Hildenbrand +Signed-off-by: Miroslav Rezanina +--- + exec.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/exec.c b/exec.c +index c670185..9028700 100644 +--- a/exec.c ++++ b/exec.c +@@ -1629,6 +1629,10 @@ static void *file_ram_alloc(RAMBlock *block, + " must be multiples of page size 0x%zx", + block->mr->align, block->page_size); + return NULL; ++ } else if (block->mr->align && !is_power_of_2(block->mr->align)) { ++ error_setg(errp, "alignment 0x%" PRIx64 ++ " must be a power of two", block->mr->align); ++ return NULL; + } + block->mr->align = MAX(block->page_size, block->mr->align); + #if defined(__s390x__) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-extract-address_space_translate_iommu-fix-page_.patch b/SOURCES/kvm-exec-extract-address_space_translate_iommu-fix-page_.patch new file mode 100644 index 0000000..04b6804 --- /dev/null +++ b/SOURCES/kvm-exec-extract-address_space_translate_iommu-fix-page_.patch @@ -0,0 +1,177 @@ +From 2a1d22e7758fe0ae11050d24f489ce2d76b6e5dc Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 25 Jan 2019 22:50:03 +0100 +Subject: [PATCH 03/23] exec: extract address_space_translate_iommu, fix + page_mask corner case + +RH-Author: John Snow +Message-id: <20190125225007.8197-4-jsnow@redhat.com> +Patchwork-id: 84116 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 3/7] exec: extract address_space_translate_iommu, fix page_mask corner case +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Paolo Bonzini + +This will be used to process IOMMUs in a MemoryRegionCache. This +includes a small bugfix, in that the returned page_mask is now +correctly -1 if the IOMMU memory region maps the entire address +space directly. Previously, address_space_get_iotlb_entry would +return ~TARGET_PAGE_MASK. + +Reviewed-by: Peter Xu +Signed-off-by: Paolo Bonzini +(cherry picked from commit a411c84b561baa94b28165c52f21c33517ee8f59) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + exec.c | 110 ++++++++++++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 75 insertions(+), 35 deletions(-) + +diff --git a/exec.c b/exec.c +index c6aeded..1bd0e6c 100644 +--- a/exec.c ++++ b/exec.c +@@ -445,6 +445,70 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x + } + + /** ++ * address_space_translate_iommu - translate an address through an IOMMU ++ * memory region and then through the target address space. ++ * ++ * @iommu_mr: the IOMMU memory region that we start the translation from ++ * @addr: the address to be translated through the MMU ++ * @xlat: the translated address offset within the destination memory region. ++ * It cannot be %NULL. ++ * @plen_out: valid read/write length of the translated address. It ++ * cannot be %NULL. ++ * @page_mask_out: page mask for the translated address. This ++ * should only be meaningful for IOMMU translated ++ * addresses, since there may be huge pages that this bit ++ * would tell. It can be %NULL if we don't care about it. ++ * @is_write: whether the translation operation is for write ++ * @is_mmio: whether this can be MMIO, set true if it can ++ * @target_as: the address space targeted by the IOMMU ++ * ++ * This function is called from RCU critical section. It is the common ++ * part of flatview_do_translate and address_space_translate_cached. ++ */ ++static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iommu_mr, ++ hwaddr *xlat, ++ hwaddr *plen_out, ++ hwaddr *page_mask_out, ++ bool is_write, ++ bool is_mmio, ++ AddressSpace **target_as) ++{ ++ MemoryRegionSection *section; ++ hwaddr page_mask = (hwaddr)-1; ++ ++ do { ++ hwaddr addr = *xlat; ++ IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr); ++ IOMMUTLBEntry iotlb = imrc->translate(iommu_mr, addr, is_write ? ++ IOMMU_WO : IOMMU_RO); ++ ++ if (!(iotlb.perm & (1 << is_write))) { ++ goto unassigned; ++ } ++ ++ addr = ((iotlb.translated_addr & ~iotlb.addr_mask) ++ | (addr & iotlb.addr_mask)); ++ page_mask &= iotlb.addr_mask; ++ *plen_out = MIN(*plen_out, (addr | iotlb.addr_mask) - addr + 1); ++ *target_as = iotlb.target_as; ++ ++ section = address_space_translate_internal( ++ address_space_to_dispatch(iotlb.target_as), addr, xlat, ++ plen_out, is_mmio); ++ ++ iommu_mr = memory_region_get_iommu(section->mr); ++ } while (unlikely(iommu_mr)); ++ ++ if (page_mask_out) { ++ *page_mask_out = page_mask; ++ } ++ return *section; ++ ++unassigned: ++ return (MemoryRegionSection) { .mr = &io_mem_unassigned }; ++} ++ ++/** + * flatview_do_translate - translate an address in FlatView + * + * @fv: the flat view that we want to translate on +@@ -472,55 +536,31 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv, + bool is_mmio, + AddressSpace **target_as) + { +- IOMMUTLBEntry iotlb; + MemoryRegionSection *section; + IOMMUMemoryRegion *iommu_mr; +- IOMMUMemoryRegionClass *imrc; +- hwaddr page_mask = (hwaddr)(-1); + hwaddr plen = (hwaddr)(-1); + + if (!plen_out) { + plen_out = &plen; + } + +- for (;;) { +- section = address_space_translate_internal( +- flatview_to_dispatch(fv), addr, xlat, +- plen_out, is_mmio); +- +- iommu_mr = memory_region_get_iommu(section->mr); +- if (!iommu_mr) { +- break; +- } +- imrc = memory_region_get_iommu_class_nocheck(iommu_mr); +- +- addr = *xlat; +- iotlb = imrc->translate(iommu_mr, addr, is_write ? +- IOMMU_WO : IOMMU_RO); +- if (!(iotlb.perm & (1 << is_write))) { +- goto translate_fail; +- } ++ section = address_space_translate_internal( ++ flatview_to_dispatch(fv), addr, xlat, ++ plen_out, is_mmio); + +- addr = ((iotlb.translated_addr & ~iotlb.addr_mask) +- | (addr & iotlb.addr_mask)); +- page_mask &= iotlb.addr_mask; +- *plen_out = MIN(*plen_out, (addr | iotlb.addr_mask) - addr + 1); +- fv = address_space_to_flatview(iotlb.target_as); +- *target_as = iotlb.target_as; ++ iommu_mr = memory_region_get_iommu(section->mr); ++ if (unlikely(iommu_mr)) { ++ return address_space_translate_iommu(iommu_mr, xlat, ++ plen_out, page_mask_out, ++ is_write, is_mmio, ++ target_as); + } +- + if (page_mask_out) { +- if (page_mask == (hwaddr)(-1)) { +- /* Not behind an IOMMU, use default page size. */ +- page_mask = ~TARGET_PAGE_MASK; +- } +- *page_mask_out = page_mask; ++ /* Not behind an IOMMU, use default page size. */ ++ *page_mask_out = ~TARGET_PAGE_MASK; + } + + return *section; +- +-translate_fail: +- return (MemoryRegionSection) { .mr = &io_mem_unassigned }; + } + + /* Called from RCU critical section */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-move-memory-access-declarations-to-a-common-hea.patch b/SOURCES/kvm-exec-move-memory-access-declarations-to-a-common-hea.patch new file mode 100644 index 0000000..b318a1d --- /dev/null +++ b/SOURCES/kvm-exec-move-memory-access-declarations-to-a-common-hea.patch @@ -0,0 +1,734 @@ +From f710b114f0f1d3e742dddd93158a7592b5fa01a1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 25 Jan 2019 22:50:01 +0100 +Subject: [PATCH 01/23] exec: move memory access declarations to a common + header, inline *_phys functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190125225007.8197-2-jsnow@redhat.com> +Patchwork-id: 84119 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 1/7] exec: move memory access declarations to a common header, inline *_phys functions +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Paolo Bonzini + +For now, this reduces the text size very slightly due to the newly-added +inlining: + + text size before: 9301965 + text size after: 9300645 + +Later, however, the declarations in include/exec/memory_ldst.inc.h will be +reused for the MemoryRegionCache slow path functions. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 4269c82bf72f7e171a03a09b9264b0db76ae0050) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/exec/cpu-all.h | 75 +++++++----------- + include/exec/memory.h | 153 +++++++++++------------------------- + include/exec/memory_ldst.inc.h | 71 +++++++++++++++++ + include/exec/memory_ldst_phys.inc.h | 147 ++++++++++++++++++++++++++++++++++ + memory_ldst.inc.c | 126 ----------------------------- + 5 files changed, 292 insertions(+), 280 deletions(-) + create mode 100644 include/exec/memory_ldst.inc.h + create mode 100644 include/exec/memory_ldst_phys.inc.h + +diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h +index f4fa94e..173edd1 100644 +--- a/include/exec/cpu-all.h ++++ b/include/exec/cpu-all.h +@@ -168,51 +168,36 @@ extern unsigned long reserved_va; + #else + + #include "exec/hwaddr.h" +-uint32_t lduw_phys(AddressSpace *as, hwaddr addr); +-uint32_t ldl_phys(AddressSpace *as, hwaddr addr); +-uint64_t ldq_phys(AddressSpace *as, hwaddr addr); +-void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val); +-void stw_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stl_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stq_phys(AddressSpace *as, hwaddr addr, uint64_t val); +- +-uint32_t address_space_lduw(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_ldl(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint64_t address_space_ldq(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val, +- MemTxAttrs attrs, MemTxResult *result); +- +-uint32_t lduw_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint32_t ldl_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint64_t ldq_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-void stl_phys_notdirty_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stw_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stl_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stq_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); +- +-uint32_t address_space_lduw_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_ldl_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint64_t address_space_ldq_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_notdirty_cached(MemoryRegionCache *cache, hwaddr addr, +- uint32_t val, MemTxAttrs attrs, MemTxResult *result); +-void address_space_stw_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stq_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val, +- MemTxAttrs attrs, MemTxResult *result); ++ ++#define SUFFIX ++#define ARG1 as ++#define ARG1_DECL AddressSpace *as ++#define TARGET_ENDIANNESS ++#include "exec/memory_ldst.inc.h" ++ ++#define SUFFIX _cached ++#define ARG1 cache ++#define ARG1_DECL MemoryRegionCache *cache ++#define TARGET_ENDIANNESS ++#include "exec/memory_ldst.inc.h" ++ ++static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val) ++{ ++ address_space_stl_notdirty(as, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++#define SUFFIX ++#define ARG1 as ++#define ARG1_DECL AddressSpace *as ++#define TARGET_ENDIANNESS ++#include "exec/memory_ldst_phys.inc.h" ++ ++#define SUFFIX _cached ++#define ARG1 cache ++#define ARG1_DECL MemoryRegionCache *cache ++#define TARGET_ENDIANNESS ++#include "exec/memory_ldst_phys.inc.h" + #endif + + /* page related stuff */ +diff --git a/include/exec/memory.h b/include/exec/memory.h +index fd2c574..84de0d4 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -1703,49 +1703,16 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr, + * @result: location to write the success/failure of the transaction; + * if NULL, this information is discarded + */ +-uint32_t address_space_ldub(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_lduw_le(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_lduw_be(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_ldl_le(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_ldl_be(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint64_t address_space_ldq_le(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint64_t address_space_ldq_be(AddressSpace *as, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stb(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stw_le(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stw_be(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_le(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_be(AddressSpace *as, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stq_le(AddressSpace *as, hwaddr addr, uint64_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stq_be(AddressSpace *as, hwaddr addr, uint64_t val, +- MemTxAttrs attrs, MemTxResult *result); +- +-uint32_t ldub_phys(AddressSpace *as, hwaddr addr); +-uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr); +-uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr); +-uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr); +-uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr); +-uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr); +-uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr); +-void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val); +-void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val); +-void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val); ++ ++#define SUFFIX ++#define ARG1 as ++#define ARG1_DECL AddressSpace *as ++#include "exec/memory_ldst.inc.h" ++ ++#define SUFFIX ++#define ARG1 as ++#define ARG1_DECL AddressSpace *as ++#include "exec/memory_ldst_phys.inc.h" + + struct MemoryRegionCache { + hwaddr xlat; +@@ -1755,6 +1722,40 @@ struct MemoryRegionCache { + + #define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .as = NULL }) + ++/* address_space_ld*_cached: load from a cached #MemoryRegion ++ * address_space_st*_cached: store into a cached #MemoryRegion ++ * ++ * These functions perform a load or store of the byte, word, ++ * longword or quad to the specified address. The address is ++ * a physical address in the AddressSpace, but it must lie within ++ * a #MemoryRegion that was mapped with address_space_cache_init. ++ * ++ * The _le suffixed functions treat the data as little endian; ++ * _be indicates big endian; no suffix indicates "same endianness ++ * as guest CPU". ++ * ++ * The "guest CPU endianness" accessors are deprecated for use outside ++ * target-* code; devices should be CPU-agnostic and use either the LE ++ * or the BE accessors. ++ * ++ * @cache: previously initialized #MemoryRegionCache to be accessed ++ * @addr: address within the address space ++ * @val: data value, for stores ++ * @attrs: memory transaction attributes ++ * @result: location to write the success/failure of the transaction; ++ * if NULL, this information is discarded ++ */ ++ ++#define SUFFIX _cached ++#define ARG1 cache ++#define ARG1_DECL MemoryRegionCache *cache ++#include "exec/memory_ldst.inc.h" ++ ++#define SUFFIX _cached ++#define ARG1 cache ++#define ARG1_DECL MemoryRegionCache *cache ++#include "exec/memory_ldst_phys.inc.h" ++ + /* address_space_cache_init: prepare for repeated access to a physical + * memory region + * +@@ -1799,72 +1800,6 @@ void address_space_cache_invalidate(MemoryRegionCache *cache, + */ + void address_space_cache_destroy(MemoryRegionCache *cache); + +-/* address_space_ld*_cached: load from a cached #MemoryRegion +- * address_space_st*_cached: store into a cached #MemoryRegion +- * +- * These functions perform a load or store of the byte, word, +- * longword or quad to the specified address. The address is +- * a physical address in the AddressSpace, but it must lie within +- * a #MemoryRegion that was mapped with address_space_cache_init. +- * +- * The _le suffixed functions treat the data as little endian; +- * _be indicates big endian; no suffix indicates "same endianness +- * as guest CPU". +- * +- * The "guest CPU endianness" accessors are deprecated for use outside +- * target-* code; devices should be CPU-agnostic and use either the LE +- * or the BE accessors. +- * +- * @cache: previously initialized #MemoryRegionCache to be accessed +- * @addr: address within the address space +- * @val: data value, for stores +- * @attrs: memory transaction attributes +- * @result: location to write the success/failure of the transaction; +- * if NULL, this information is discarded +- */ +-uint32_t address_space_ldub_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_lduw_le_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_lduw_be_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_ldl_le_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint32_t address_space_ldl_be_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint64_t address_space_ldq_le_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-uint64_t address_space_ldq_be_cached(MemoryRegionCache *cache, hwaddr addr, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stb_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stw_le_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stw_be_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_le_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stl_be_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stq_le_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val, +- MemTxAttrs attrs, MemTxResult *result); +-void address_space_stq_be_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val, +- MemTxAttrs attrs, MemTxResult *result); +- +-uint32_t ldub_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint32_t lduw_le_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint32_t lduw_be_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint32_t ldl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint32_t ldl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint64_t ldq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-uint64_t ldq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr); +-void stb_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stw_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stw_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +-void stq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); +-void stq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); + /* address_space_get_iotlb_entry: translate an address into an IOTLB + * entry. Should be called from an RCU critical section. + */ +diff --git a/include/exec/memory_ldst.inc.h b/include/exec/memory_ldst.inc.h +new file mode 100644 +index 0000000..272c20f +--- /dev/null ++++ b/include/exec/memory_ldst.inc.h +@@ -0,0 +1,71 @@ ++/* ++ * Physical memory access templates ++ * ++ * Copyright (c) 2003 Fabrice Bellard ++ * Copyright (c) 2015 Linaro, Inc. ++ * Copyright (c) 2016 Red Hat, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#ifdef TARGET_ENDIANNESS ++extern uint32_t glue(address_space_lduw, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint32_t glue(address_space_ldl, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint64_t glue(address_space_ldq, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stw, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stl, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stq, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); ++#else ++extern uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint32_t glue(address_space_lduw_le, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint32_t glue(address_space_lduw_be, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint32_t glue(address_space_ldl_le, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint32_t glue(address_space_ldl_be, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint64_t glue(address_space_ldq_le, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern uint64_t glue(address_space_ldq_be, SUFFIX)(ARG1_DECL, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stb, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stw_le, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stw_be, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stl_le, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stl_be, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stq_le, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); ++extern void glue(address_space_stq_be, SUFFIX)(ARG1_DECL, ++ hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); ++#endif ++ ++#undef ARG1_DECL ++#undef ARG1 ++#undef SUFFIX ++#undef TARGET_ENDIANNESS +diff --git a/include/exec/memory_ldst_phys.inc.h b/include/exec/memory_ldst_phys.inc.h +new file mode 100644 +index 0000000..91f7297 +--- /dev/null ++++ b/include/exec/memory_ldst_phys.inc.h +@@ -0,0 +1,147 @@ ++/* ++ * Physical memory access templates ++ * ++ * Copyright (c) 2003 Fabrice Bellard ++ * Copyright (c) 2015 Linaro, Inc. ++ * Copyright (c) 2016 Red Hat, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#ifdef TARGET_ENDIANNESS ++static inline uint32_t glue(ldl_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldl, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint64_t glue(ldq_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldq, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint32_t glue(lduw_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_lduw, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stl_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stl, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stw_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stw, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stq_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) ++{ ++ glue(address_space_stq, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++#else ++static inline uint32_t glue(ldl_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldl_le, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint32_t glue(ldl_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldl_be, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint64_t glue(ldq_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldq_le, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint64_t glue(ldq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldq_be, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint32_t glue(ldub_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_ldub, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint32_t glue(lduw_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_lduw_le, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline uint32_t glue(lduw_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) ++{ ++ return glue(address_space_lduw_be, SUFFIX)(ARG1, addr, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stl_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stl_le, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stl_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stl_be, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stb_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stb, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stw_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stw_le, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stw_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) ++{ ++ glue(address_space_stw_be, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stq_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) ++{ ++ glue(address_space_stq_le, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++ ++static inline void glue(stq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) ++{ ++ glue(address_space_stq_be, SUFFIX)(ARG1, addr, val, ++ MEMTXATTRS_UNSPECIFIED, NULL); ++} ++#endif ++ ++#undef ARG1_DECL ++#undef ARG1 ++#undef SUFFIX ++#undef TARGET_ENDIANNESS +diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c +index 5dbff9c..25d6125 100644 +--- a/memory_ldst.inc.c ++++ b/memory_ldst.inc.c +@@ -95,24 +95,6 @@ uint32_t glue(address_space_ldl_be, SUFFIX)(ARG1_DECL, + DEVICE_BIG_ENDIAN); + } + +-uint32_t glue(ldl_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldl, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-uint32_t glue(ldl_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldl_le, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-uint32_t glue(ldl_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldl_be, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + /* warning: addr must be aligned */ + static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result, +@@ -189,24 +171,6 @@ uint64_t glue(address_space_ldq_be, SUFFIX)(ARG1_DECL, + DEVICE_BIG_ENDIAN); + } + +-uint64_t glue(ldq_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldq, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-uint64_t glue(ldq_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldq_le, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-uint64_t glue(ldq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldq_be, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) + { +@@ -241,12 +205,6 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, + return val; + } + +-uint32_t glue(ldub_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_ldub, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + /* warning: addr must be aligned */ + static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result, +@@ -323,24 +281,6 @@ uint32_t glue(address_space_lduw_be, SUFFIX)(ARG1_DECL, + DEVICE_BIG_ENDIAN); + } + +-uint32_t glue(lduw_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_lduw, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-uint32_t glue(lduw_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_lduw_le, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-uint32_t glue(lduw_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +-{ +- return glue(address_space_lduw_be, SUFFIX)(ARG1, addr, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + /* warning: addr must be aligned. The ram page is not masked as dirty + and the code inside is not invalidated. It is useful if the dirty + bits are used to track modified PTEs */ +@@ -380,12 +320,6 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, + RCU_READ_UNLOCK(); + } + +-void glue(stl_phys_notdirty, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stl_notdirty, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + /* warning: addr must be aligned */ + static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, +@@ -460,24 +394,6 @@ void glue(address_space_stl_be, SUFFIX)(ARG1_DECL, + result, DEVICE_BIG_ENDIAN); + } + +-void glue(stl_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stl, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-void glue(stl_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stl_le, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-void glue(stl_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stl_be, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + void glue(address_space_stb, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) + { +@@ -509,12 +425,6 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL, + RCU_READ_UNLOCK(); + } + +-void glue(stb_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stb, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + /* warning: addr must be aligned */ + static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, +@@ -589,24 +499,6 @@ void glue(address_space_stw_be, SUFFIX)(ARG1_DECL, + DEVICE_BIG_ENDIAN); + } + +-void glue(stw_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stw, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-void glue(stw_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stw_le, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-void glue(stw_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +-{ +- glue(address_space_stw_be, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, uint64_t val, MemTxAttrs attrs, + MemTxResult *result, enum device_endian endian) +@@ -680,24 +572,6 @@ void glue(address_space_stq_be, SUFFIX)(ARG1_DECL, + DEVICE_BIG_ENDIAN); + } + +-void glue(stq_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) +-{ +- glue(address_space_stq, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-void glue(stq_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) +-{ +- glue(address_space_stq_le, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- +-void glue(stq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) +-{ +- glue(address_space_stq_be, SUFFIX)(ARG1, addr, val, +- MEMTXATTRS_UNSPECIFIED, NULL); +-} +- + #undef ARG1_DECL + #undef ARG1 + #undef SUFFIX +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-reintroduce-MemoryRegion-caching.patch b/SOURCES/kvm-exec-reintroduce-MemoryRegion-caching.patch new file mode 100644 index 0000000..d108bb5 --- /dev/null +++ b/SOURCES/kvm-exec-reintroduce-MemoryRegion-caching.patch @@ -0,0 +1,473 @@ +From c879b300ff1852e5102a787372cd949f6755f5ce Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 25 Jan 2019 22:50:04 +0100 +Subject: [PATCH 04/23] exec: reintroduce MemoryRegion caching + +RH-Author: John Snow +Message-id: <20190125225007.8197-5-jsnow@redhat.com> +Patchwork-id: 84120 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 4/7] exec: reintroduce MemoryRegion caching +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Paolo Bonzini + +MemoryRegionCache was reverted to "normal" address_space_* operations +for 2.9, due to lack of support for IOMMUs. Reinstate the +optimizations, caching only the IOMMU translation at address_cache_init +but not the IOMMU lookup and target AddressSpace translation are not +cached; now that MemoryRegionCache supports IOMMUs, it becomes more widely +applicable too. + +The inlined fast path is defined in memory_ldst_cached.inc.h, while the +slow path uses memory_ldst.inc.c as before. The smaller fast path causes +a little code size reduction in MemoryRegionCache users: + + hw/virtio/virtio.o text size before: 32373 + hw/virtio/virtio.o text size after: 31941 + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 48564041a73adbbff52834f9edbe3806fceefab7) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + exec.c | 121 ++++++++++++++++++++++++++++++---- + include/exec/cpu-all.h | 6 +- + include/exec/memory-internal.h | 3 + + include/exec/memory.h | 58 ++++++++++++++-- + include/exec/memory_ldst_cached.inc.h | 108 ++++++++++++++++++++++++++++++ + memory.c | 4 +- + 6 files changed, 280 insertions(+), 20 deletions(-) + create mode 100644 include/exec/memory_ldst_cached.inc.h + +diff --git a/exec.c b/exec.c +index 1bd0e6c..805a2d4 100644 +--- a/exec.c ++++ b/exec.c +@@ -3656,33 +3656,130 @@ int64_t address_space_cache_init(MemoryRegionCache *cache, + hwaddr len, + bool is_write) + { +- cache->len = len; +- cache->as = as; +- cache->xlat = addr; +- return len; ++ AddressSpaceDispatch *d; ++ hwaddr l; ++ MemoryRegion *mr; ++ ++ assert(len > 0); ++ ++ l = len; ++ cache->fv = address_space_get_flatview(as); ++ d = flatview_to_dispatch(cache->fv); ++ cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true); ++ ++ mr = cache->mrs.mr; ++ memory_region_ref(mr); ++ if (memory_access_is_direct(mr, is_write)) { ++ l = flatview_extend_translation(cache->fv, addr, len, mr, ++ cache->xlat, l, is_write); ++ cache->ptr = qemu_ram_ptr_length(mr->ram_block, cache->xlat, &l, true); ++ } else { ++ cache->ptr = NULL; ++ } ++ ++ cache->len = l; ++ cache->is_write = is_write; ++ return l; + } + + void address_space_cache_invalidate(MemoryRegionCache *cache, + hwaddr addr, + hwaddr access_len) + { ++ assert(cache->is_write); ++ if (likely(cache->ptr)) { ++ invalidate_and_set_dirty(cache->mrs.mr, addr + cache->xlat, access_len); ++ } + } + + void address_space_cache_destroy(MemoryRegionCache *cache) + { +- cache->as = NULL; ++ if (!cache->mrs.mr) { ++ return; ++ } ++ ++ if (xen_enabled()) { ++ xen_invalidate_map_cache_entry(cache->ptr); ++ } ++ memory_region_unref(cache->mrs.mr); ++ flatview_unref(cache->fv); ++ cache->mrs.mr = NULL; ++ cache->fv = NULL; ++} ++ ++/* Called from RCU critical section. This function has the same ++ * semantics as address_space_translate, but it only works on a ++ * predefined range of a MemoryRegion that was mapped with ++ * address_space_cache_init. ++ */ ++static inline MemoryRegion *address_space_translate_cached( ++ MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat, ++ hwaddr *plen, bool is_write) ++{ ++ MemoryRegionSection section; ++ MemoryRegion *mr; ++ IOMMUMemoryRegion *iommu_mr; ++ AddressSpace *target_as; ++ ++ assert(!cache->ptr); ++ *xlat = addr + cache->xlat; ++ ++ mr = cache->mrs.mr; ++ iommu_mr = memory_region_get_iommu(mr); ++ if (!iommu_mr) { ++ /* MMIO region. */ ++ return mr; ++ } ++ ++ section = address_space_translate_iommu(iommu_mr, xlat, plen, ++ NULL, is_write, true, ++ &target_as); ++ return section.mr; ++} ++ ++/* Called from RCU critical section. address_space_read_cached uses this ++ * out of line function when the target is an MMIO or IOMMU region. ++ */ ++void ++address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr, ++ void *buf, int len) ++{ ++ hwaddr addr1, l; ++ MemoryRegion *mr; ++ ++ l = len; ++ mr = address_space_translate_cached(cache, addr, &addr1, &l, false); ++ flatview_read_continue(cache->fv, ++ addr, MEMTXATTRS_UNSPECIFIED, buf, len, ++ addr1, l, mr); ++} ++ ++/* Called from RCU critical section. address_space_write_cached uses this ++ * out of line function when the target is an MMIO or IOMMU region. ++ */ ++void ++address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr, ++ const void *buf, int len) ++{ ++ hwaddr addr1, l; ++ MemoryRegion *mr; ++ ++ l = len; ++ mr = address_space_translate_cached(cache, addr, &addr1, &l, true); ++ flatview_write_continue(cache->fv, ++ addr, MEMTXATTRS_UNSPECIFIED, buf, len, ++ addr1, l, mr); + } + + #define ARG1_DECL MemoryRegionCache *cache + #define ARG1 cache +-#define SUFFIX _cached +-#define TRANSLATE(addr, ...) \ +- address_space_translate(cache->as, cache->xlat + (addr), __VA_ARGS__) +-#define IS_DIRECT(mr, is_write) true +-#define MAP_RAM(mr, ofs) qemu_map_ram_ptr((mr)->ram_block, ofs) ++#define SUFFIX _cached_slow ++#define TRANSLATE(...) address_space_translate_cached(cache, __VA_ARGS__) ++#define IS_DIRECT(mr, is_write) memory_access_is_direct(mr, is_write) ++#define MAP_RAM(mr, ofs) (cache->ptr + (ofs - cache->xlat)) + #define INVALIDATE(mr, ofs, len) invalidate_and_set_dirty(mr, ofs, len) +-#define RCU_READ_LOCK() rcu_read_lock() +-#define RCU_READ_UNLOCK() rcu_read_unlock() ++#define RCU_READ_LOCK() ((void)0) ++#define RCU_READ_UNLOCK() ((void)0) + #include "memory_ldst.inc.c" + + /* virtual memory access for debug (includes writing to ROM) */ +diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h +index 173edd1..a635f53 100644 +--- a/include/exec/cpu-all.h ++++ b/include/exec/cpu-all.h +@@ -175,7 +175,7 @@ extern unsigned long reserved_va; + #define TARGET_ENDIANNESS + #include "exec/memory_ldst.inc.h" + +-#define SUFFIX _cached ++#define SUFFIX _cached_slow + #define ARG1 cache + #define ARG1_DECL MemoryRegionCache *cache + #define TARGET_ENDIANNESS +@@ -193,6 +193,10 @@ static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val + #define TARGET_ENDIANNESS + #include "exec/memory_ldst_phys.inc.h" + ++/* Inline fast path for direct RAM access. */ ++#define ENDIANNESS ++#include "exec/memory_ldst_cached.inc.h" ++ + #define SUFFIX _cached + #define ARG1 cache + #define ARG1_DECL MemoryRegionCache *cache +diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h +index 6a5ee42..58399b9 100644 +--- a/include/exec/memory-internal.h ++++ b/include/exec/memory-internal.h +@@ -31,6 +31,9 @@ static inline AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as) + return flatview_to_dispatch(address_space_to_flatview(as)); + } + ++FlatView *address_space_get_flatview(AddressSpace *as); ++void flatview_unref(FlatView *view); ++ + extern const MemoryRegionOps unassigned_mem_ops; + + bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 84de0d4..96f1fd8 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -1715,12 +1715,16 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr, + #include "exec/memory_ldst_phys.inc.h" + + struct MemoryRegionCache { ++ void *ptr; + hwaddr xlat; + hwaddr len; +- AddressSpace *as; ++ FlatView *fv; ++ MemoryRegionSection mrs; ++ bool is_write; + }; + +-#define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .as = NULL }) ++#define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .mrs.mr = NULL }) ++ + + /* address_space_ld*_cached: load from a cached #MemoryRegion + * address_space_st*_cached: store into a cached #MemoryRegion +@@ -1746,11 +1750,40 @@ struct MemoryRegionCache { + * if NULL, this information is discarded + */ + +-#define SUFFIX _cached ++#define SUFFIX _cached_slow + #define ARG1 cache + #define ARG1_DECL MemoryRegionCache *cache + #include "exec/memory_ldst.inc.h" + ++/* Inline fast path for direct RAM access. */ ++static inline uint8_t address_space_ldub_cached(MemoryRegionCache *cache, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len); ++ if (likely(cache->ptr)) { ++ return ldub_p(cache->ptr + addr); ++ } else { ++ return address_space_ldub_cached_slow(cache, addr, attrs, result); ++ } ++} ++ ++static inline void address_space_stb_cached(MemoryRegionCache *cache, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len); ++ if (likely(cache->ptr)) { ++ stb_p(cache->ptr + addr, val); ++ } else { ++ address_space_stb_cached_slow(cache, addr, val, attrs, result); ++ } ++} ++ ++#define ENDIANNESS _le ++#include "exec/memory_ldst_cached.inc.h" ++ ++#define ENDIANNESS _be ++#include "exec/memory_ldst_cached.inc.h" ++ + #define SUFFIX _cached + #define ARG1 cache + #define ARG1_DECL MemoryRegionCache *cache +@@ -1887,6 +1920,13 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, + MemoryRegion *mr); + void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr); + ++/* Internal functions, part of the implementation of address_space_read_cached ++ * and address_space_write_cached. */ ++void address_space_read_cached_slow(MemoryRegionCache *cache, ++ hwaddr addr, void *buf, int len); ++void address_space_write_cached_slow(MemoryRegionCache *cache, ++ hwaddr addr, const void *buf, int len); ++ + static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) + { + if (is_write) { +@@ -1955,7 +1995,11 @@ address_space_read_cached(MemoryRegionCache *cache, hwaddr addr, + void *buf, int len) + { + assert(addr < cache->len && len <= cache->len - addr); +- address_space_read(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len); ++ if (likely(cache->ptr)) { ++ memcpy(buf, cache->ptr + addr, len); ++ } else { ++ address_space_read_cached_slow(cache, addr, buf, len); ++ } + } + + /** +@@ -1971,7 +2015,11 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, + void *buf, int len) + { + assert(addr < cache->len && len <= cache->len - addr); +- address_space_write(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len); ++ if (likely(cache->ptr)) { ++ memcpy(cache->ptr + addr, buf, len); ++ } else { ++ address_space_write_cached_slow(cache, addr, buf, len); ++ } + } + + #endif +diff --git a/include/exec/memory_ldst_cached.inc.h b/include/exec/memory_ldst_cached.inc.h +new file mode 100644 +index 0000000..fd4bbb4 +--- /dev/null ++++ b/include/exec/memory_ldst_cached.inc.h +@@ -0,0 +1,108 @@ ++/* ++ * Memory access templates for MemoryRegionCache ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#define ADDRESS_SPACE_LD_CACHED(size) \ ++ glue(glue(address_space_ld, size), glue(ENDIANNESS, _cached)) ++#define ADDRESS_SPACE_LD_CACHED_SLOW(size) \ ++ glue(glue(address_space_ld, size), glue(ENDIANNESS, _cached_slow)) ++#define LD_P(size) \ ++ glue(glue(ld, size), glue(ENDIANNESS, _p)) ++ ++static inline uint32_t ADDRESS_SPACE_LD_CACHED(l)(MemoryRegionCache *cache, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len && 4 <= cache->len - addr); ++ if (likely(cache->ptr)) { ++ return LD_P(l)(cache->ptr + addr); ++ } else { ++ return ADDRESS_SPACE_LD_CACHED_SLOW(l)(cache, addr, attrs, result); ++ } ++} ++ ++static inline uint64_t ADDRESS_SPACE_LD_CACHED(q)(MemoryRegionCache *cache, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len && 8 <= cache->len - addr); ++ if (likely(cache->ptr)) { ++ return LD_P(q)(cache->ptr + addr); ++ } else { ++ return ADDRESS_SPACE_LD_CACHED_SLOW(q)(cache, addr, attrs, result); ++ } ++} ++ ++static inline uint32_t ADDRESS_SPACE_LD_CACHED(uw)(MemoryRegionCache *cache, ++ hwaddr addr, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len && 2 <= cache->len - addr); ++ if (likely(cache->ptr)) { ++ return LD_P(uw)(cache->ptr + addr); ++ } else { ++ return ADDRESS_SPACE_LD_CACHED_SLOW(uw)(cache, addr, attrs, result); ++ } ++} ++ ++#undef ADDRESS_SPACE_LD_CACHED ++#undef ADDRESS_SPACE_LD_CACHED_SLOW ++#undef LD_P ++ ++#define ADDRESS_SPACE_ST_CACHED(size) \ ++ glue(glue(address_space_st, size), glue(ENDIANNESS, _cached)) ++#define ADDRESS_SPACE_ST_CACHED_SLOW(size) \ ++ glue(glue(address_space_st, size), glue(ENDIANNESS, _cached_slow)) ++#define ST_P(size) \ ++ glue(glue(st, size), glue(ENDIANNESS, _p)) ++ ++static inline void ADDRESS_SPACE_ST_CACHED(l)(MemoryRegionCache *cache, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len && 4 <= cache->len - addr); ++ if (likely(cache->ptr)) { ++ ST_P(l)(cache->ptr + addr, val); ++ } else { ++ ADDRESS_SPACE_ST_CACHED_SLOW(l)(cache, addr, val, attrs, result); ++ } ++} ++ ++static inline void ADDRESS_SPACE_ST_CACHED(w)(MemoryRegionCache *cache, ++ hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len && 2 <= cache->len - addr); ++ if (likely(cache->ptr)) { ++ ST_P(w)(cache->ptr + addr, val); ++ } else { ++ ADDRESS_SPACE_ST_CACHED_SLOW(w)(cache, addr, val, attrs, result); ++ } ++} ++ ++static inline void ADDRESS_SPACE_ST_CACHED(q)(MemoryRegionCache *cache, ++ hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) ++{ ++ assert(addr < cache->len && 8 <= cache->len - addr); ++ if (likely(cache->ptr)) { ++ ST_P(q)(cache->ptr + addr, val); ++ } else { ++ ADDRESS_SPACE_ST_CACHED_SLOW(q)(cache, addr, val, attrs, result); ++ } ++} ++ ++#undef ADDRESS_SPACE_ST_CACHED ++#undef ADDRESS_SPACE_ST_CACHED_SLOW ++#undef ST_P ++ ++#undef ENDIANNESS +diff --git a/memory.c b/memory.c +index 4974f97..1e90912 100644 +--- a/memory.c ++++ b/memory.c +@@ -298,7 +298,7 @@ static bool flatview_ref(FlatView *view) + return atomic_fetch_inc_nonzero(&view->ref) > 0; + } + +-static void flatview_unref(FlatView *view) ++void flatview_unref(FlatView *view) + { + if (atomic_fetch_dec(&view->ref) == 1) { + trace_flatview_destroy_rcu(view, view->root); +@@ -822,7 +822,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, + } + } + +-static FlatView *address_space_get_flatview(AddressSpace *as) ++FlatView *address_space_get_flatview(AddressSpace *as) + { + FlatView *view; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-small-changes-to-flatview_do_translate.patch b/SOURCES/kvm-exec-small-changes-to-flatview_do_translate.patch new file mode 100644 index 0000000..e6eeeab --- /dev/null +++ b/SOURCES/kvm-exec-small-changes-to-flatview_do_translate.patch @@ -0,0 +1,113 @@ +From 035c7c0a1c88284d2628532a70f43c04aa0aba56 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 25 Jan 2019 22:50:02 +0100 +Subject: [PATCH 02/23] exec: small changes to flatview_do_translate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190125225007.8197-3-jsnow@redhat.com> +Patchwork-id: 84117 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 2/7] exec: small changes to flatview_do_translate +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Paolo Bonzini + +Prepare for extracting the IOMMU part to a separate function. Mostly +cosmetic; the only semantic change is that, if there is more than one +cascaded IOMMU and the second one fails to translate, *plen_out is now +adjusted according to the page mask of the first IOMMU. + +Reviewed-by: Peter Xu +Signed-off-by: Paolo Bonzini +(cherry picked from commit ad2804d9e47df2dab642a253502b5ceef233f450) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + exec.c | 33 ++++++++++++++------------------- + 1 file changed, 14 insertions(+), 19 deletions(-) + +diff --git a/exec.c b/exec.c +index 9028700..c6aeded 100644 +--- a/exec.c ++++ b/exec.c +@@ -459,6 +459,7 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x + * would tell. It can be @NULL if we don't care about it. + * @is_write: whether the translation operation is for write + * @is_mmio: whether this can be MMIO, set true if it can ++ * @target_as: the address space targeted by the IOMMU + * + * This function is called from RCU critical section + */ +@@ -478,14 +479,14 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv, + hwaddr page_mask = (hwaddr)(-1); + hwaddr plen = (hwaddr)(-1); + +- if (plen_out) { +- plen = *plen_out; ++ if (!plen_out) { ++ plen_out = &plen; + } + + for (;;) { + section = address_space_translate_internal( +- flatview_to_dispatch(fv), addr, &addr, +- &plen, is_mmio); ++ flatview_to_dispatch(fv), addr, xlat, ++ plen_out, is_mmio); + + iommu_mr = memory_region_get_iommu(section->mr); + if (!iommu_mr) { +@@ -493,35 +494,29 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv, + } + imrc = memory_region_get_iommu_class_nocheck(iommu_mr); + ++ addr = *xlat; + iotlb = imrc->translate(iommu_mr, addr, is_write ? + IOMMU_WO : IOMMU_RO); +- addr = ((iotlb.translated_addr & ~iotlb.addr_mask) +- | (addr & iotlb.addr_mask)); +- page_mask &= iotlb.addr_mask; +- plen = MIN(plen, (addr | iotlb.addr_mask) - addr + 1); + if (!(iotlb.perm & (1 << is_write))) { + goto translate_fail; + } + ++ addr = ((iotlb.translated_addr & ~iotlb.addr_mask) ++ | (addr & iotlb.addr_mask)); ++ page_mask &= iotlb.addr_mask; ++ *plen_out = MIN(*plen_out, (addr | iotlb.addr_mask) - addr + 1); + fv = address_space_to_flatview(iotlb.target_as); + *target_as = iotlb.target_as; + } + +- *xlat = addr; +- +- if (page_mask == (hwaddr)(-1)) { +- /* Not behind an IOMMU, use default page size. */ +- page_mask = ~TARGET_PAGE_MASK; +- } +- + if (page_mask_out) { ++ if (page_mask == (hwaddr)(-1)) { ++ /* Not behind an IOMMU, use default page size. */ ++ page_mask = ~TARGET_PAGE_MASK; ++ } + *page_mask_out = page_mask; + } + +- if (plen_out) { +- *plen_out = plen; +- } +- + return *section; + + translate_fail: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Drop-s-lock_fd.patch b/SOURCES/kvm-file-posix-Drop-s-lock_fd.patch new file mode 100644 index 0000000..4701c5c --- /dev/null +++ b/SOURCES/kvm-file-posix-Drop-s-lock_fd.patch @@ -0,0 +1,138 @@ +From e56693b6f482bf594b39f751d17f371301e280b5 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:04 +0100 +Subject: [PATCH 04/33] file-posix: Drop s->lock_fd + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-5-mreitz@redhat.com> +Patchwork-id: 84223 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/7] file-posix: Drop s->lock_fd +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +From: Fam Zheng + +The lock_fd field is not strictly necessary because transferring locked +bytes from old fd to the new one shouldn't fail anyway. This spares the +user one fd per image. + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit f2e3af29b70624659a50903bd075e1663b64c9da) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 37 +++++++++++++------------------------ + 1 file changed, 13 insertions(+), 24 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 2a05193..97e7ff2 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -142,7 +142,6 @@ do { \ + + typedef struct BDRVRawState { + int fd; +- int lock_fd; + bool use_lock; + int type; + int open_flags; +@@ -153,7 +152,7 @@ typedef struct BDRVRawState { + uint64_t shared_perm; + + /* The perms bits whose corresponding bytes are already locked in +- * s->lock_fd. */ ++ * s->fd. */ + uint64_t locked_perm; + uint64_t locked_shared_perm; + +@@ -545,18 +544,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + } + s->fd = fd; + +- s->lock_fd = -1; +- if (s->use_lock) { +- fd = qemu_open(filename, s->open_flags); +- if (fd < 0) { +- ret = -errno; +- error_setg_errno(errp, errno, "Could not open '%s' for locking", +- filename); +- qemu_close(s->fd); +- goto fail; +- } +- s->lock_fd = fd; +- } + s->perm = 0; + s->shared_perm = BLK_PERM_ALL; + +@@ -811,15 +798,13 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + return 0; + } + +- assert(s->lock_fd > 0); +- + switch (op) { + case RAW_PL_PREPARE: +- ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm, ++ ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm, + ~s->shared_perm | ~new_shared, + false, errp); + if (!ret) { +- ret = raw_check_lock_bytes(s->lock_fd, new_perm, new_shared, errp); ++ ret = raw_check_lock_bytes(s->fd, new_perm, new_shared, errp); + if (!ret) { + return 0; + } +@@ -830,7 +815,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + op = RAW_PL_ABORT; + /* fall through to unlock bytes. */ + case RAW_PL_ABORT: +- raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm, ++ raw_apply_lock_bytes(s, s->fd, s->perm, ~s->shared_perm, + true, &local_err); + if (local_err) { + /* Theoretically the above call only unlocks bytes and it cannot +@@ -840,7 +825,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + } + break; + case RAW_PL_COMMIT: +- raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared, ++ raw_apply_lock_bytes(s, s->fd, new_perm, ~new_shared, + true, &local_err); + if (local_err) { + /* Theoretically the above call only unlocks bytes and it cannot +@@ -938,9 +923,17 @@ static void raw_reopen_commit(BDRVReopenState *state) + { + BDRVRawReopenState *rs = state->opaque; + BDRVRawState *s = state->bs->opaque; ++ Error *local_err = NULL; + + s->open_flags = rs->open_flags; + ++ /* Copy locks to the new fd before closing the old one. */ ++ raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm, ++ ~s->locked_shared_perm, false, &local_err); ++ if (local_err) { ++ /* shouldn't fail in a sane host, but report it just in case. */ ++ error_report_err(local_err); ++ } + qemu_close(s->fd); + s->fd = rs->fd; + +@@ -1903,10 +1896,6 @@ static void raw_close(BlockDriverState *bs) + qemu_close(s->fd); + s->fd = -1; + } +- if (s->lock_fd >= 0) { +- qemu_close(s->lock_fd); +- s->lock_fd = -1; +- } + } + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Factor-out-raw_reconfigure_getfd.patch b/SOURCES/kvm-file-posix-Factor-out-raw_reconfigure_getfd.patch new file mode 100644 index 0000000..652fc88 --- /dev/null +++ b/SOURCES/kvm-file-posix-Factor-out-raw_reconfigure_getfd.patch @@ -0,0 +1,157 @@ +From 1787cd88f968426a3f8a447408ed03f7778dc18a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:06 +0100 +Subject: [PATCH 010/163] file-posix: Factor out raw_reconfigure_getfd() + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-11-kwolf@redhat.com> +Patchwork-id: 84887 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/14] file-posix: Factor out raw_reconfigure_getfd() +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Kevin Wolf +(cherry picked from commit 5cec28702587d8dc9792f8274bfc6bb91f07d672) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 87 ++++++++++++++++++++++++++++++++---------------------- + 1 file changed, 52 insertions(+), 35 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 419781c..e50eb0e 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -834,35 +834,24 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + return ret; + } + +-static int raw_reopen_prepare(BDRVReopenState *state, +- BlockReopenQueue *queue, Error **errp) ++static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, ++ int *open_flags, Error **errp) + { +- BDRVRawState *s; +- BDRVRawReopenState *rs; +- int ret = 0; +- Error *local_err = NULL; +- +- assert(state != NULL); +- assert(state->bs != NULL); +- +- s = state->bs->opaque; +- +- state->opaque = g_new0(BDRVRawReopenState, 1); +- rs = state->opaque; +- +- if (s->type == FTYPE_CD) { +- rs->open_flags |= O_NONBLOCK; +- } +- +- raw_parse_flags(state->flags, &rs->open_flags); +- +- rs->fd = -1; +- ++ BDRVRawState *s = bs->opaque; ++ int fd = -1; ++ int ret; + int fcntl_flags = O_APPEND | O_NONBLOCK; + #ifdef O_NOATIME + fcntl_flags |= O_NOATIME; + #endif + ++ *open_flags = 0; ++ if (s->type == FTYPE_CD) { ++ *open_flags |= O_NONBLOCK; ++ } ++ ++ raw_parse_flags(flags, open_flags); ++ + #ifdef O_ASYNC + /* Not all operating systems have O_ASYNC, and those that don't + * will not let us track the state into rs->open_flags (typically +@@ -872,32 +861,59 @@ static int raw_reopen_prepare(BDRVReopenState *state, + assert((s->open_flags & O_ASYNC) == 0); + #endif + +- if ((rs->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) { ++ if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) { + /* dup the original fd */ +- rs->fd = qemu_dup(s->fd); +- if (rs->fd >= 0) { +- ret = fcntl_setfl(rs->fd, rs->open_flags); ++ fd = qemu_dup(s->fd); ++ if (fd >= 0) { ++ ret = fcntl_setfl(fd, *open_flags); + if (ret) { +- qemu_close(rs->fd); +- rs->fd = -1; ++ qemu_close(fd); ++ fd = -1; + } + } + } + + /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */ +- if (rs->fd == -1) { +- const char *normalized_filename = state->bs->filename; ++ if (fd == -1) { ++ const char *normalized_filename = bs->filename; + ret = raw_normalize_devicepath(&normalized_filename, errp); + if (ret >= 0) { +- assert(!(rs->open_flags & O_CREAT)); +- rs->fd = qemu_open(normalized_filename, rs->open_flags); +- if (rs->fd == -1) { ++ assert(!(*open_flags & O_CREAT)); ++ fd = qemu_open(normalized_filename, *open_flags); ++ if (fd == -1) { + error_setg_errno(errp, errno, "Could not reopen file"); +- ret = -1; ++ return -1; + } + } + } + ++ return fd; ++} ++ ++static int raw_reopen_prepare(BDRVReopenState *state, ++ BlockReopenQueue *queue, Error **errp) ++{ ++ BDRVRawState *s; ++ BDRVRawReopenState *rs; ++ int ret = 0; ++ Error *local_err = NULL; ++ ++ assert(state != NULL); ++ assert(state->bs != NULL); ++ ++ s = state->bs->opaque; ++ ++ state->opaque = g_new0(BDRVRawReopenState, 1); ++ rs = state->opaque; ++ ++ rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags, ++ &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ ret = -1; ++ goto out; ++ } ++ + /* Fail already reopen_prepare() if we can't get a working O_DIRECT + * alignment with the new fd. */ + if (rs->fd != -1) { +@@ -910,6 +926,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, + } + } + ++out: + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Fix-bdrv_open_flags-for-snapshot-on.patch b/SOURCES/kvm-file-posix-Fix-bdrv_open_flags-for-snapshot-on.patch new file mode 100644 index 0000000..a1a3b71 --- /dev/null +++ b/SOURCES/kvm-file-posix-Fix-bdrv_open_flags-for-snapshot-on.patch @@ -0,0 +1,114 @@ +From 043d71d0340799feafee434f8eec0360840ec777 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:04 +0100 +Subject: [PATCH 008/163] file-posix: Fix bdrv_open_flags() for snapshot=on + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-9-kwolf@redhat.com> +Patchwork-id: 84885 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/14] file-posix: Fix bdrv_open_flags() for snapshot=on +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Using a different read-only setting for bs->open_flags than for the +flags to the driver's open function is just inconsistent and a bad idea. +After this patch, the temporary snapshot keeps being opened read-only if +read-only=on,snapshot=on is passed. + +If we wanted to change this behaviour to make only the orginal image +file read-only, but the temporary overlay read-write (as the comment in +the removed code suggests), that change would have to be made in +bdrv_temp_snapshot_options() (where the comment suggests otherwise). + +Addressing this inconsistency before introducing dynamic auto-read-only +is important because otherwise we would immediately try to reopen the +temporary overlay even though the file is already unlinked. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 30855137783c0c762007044821a6f11e14e6af33) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 7 ------- + tests/qemu-iotests/051 | 7 +++++++ + tests/qemu-iotests/051.out | 9 +++++++++ + tests/qemu-iotests/051.pc.out | 9 +++++++++ + 4 files changed, 25 insertions(+), 7 deletions(-) + +diff --git a/block.c b/block.c +index 25b3fe5..bcf277d 100644 +--- a/block.c ++++ b/block.c +@@ -1100,13 +1100,6 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) + */ + open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_PROTOCOL); + +- /* +- * Snapshots should be writable. +- */ +- if (flags & BDRV_O_TEMPORARY) { +- open_flags |= BDRV_O_RDWR; +- } +- + return open_flags; + } + +diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 +index 4899f84..23f9678 100755 +--- a/tests/qemu-iotests/051 ++++ b/tests/qemu-iotests/051 +@@ -357,6 +357,13 @@ $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io + # Using snapshot=on with a non-existent TMPDIR + TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on + ++# Using snapshot=on together with read-only=on ++echo "info block" | ++ run_qemu -drive file="$TEST_IMG",snapshot=on,read-only=on,if=none,id=$device_id | ++ _filter_qemu_io | ++ sed -e 's#/[^"]*/vl\.[A-Za-z0-9]\{6\}#SNAPSHOT_PATH#g' ++ ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out +index 793af2a..e2f91fc 100644 +--- a/tests/qemu-iotests/051.out ++++ b/tests/qemu-iotests/051.out +@@ -458,4 +458,13 @@ read 4096/4096 bytes at offset 0 + Testing: -drive driver=null-co,snapshot=on + QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory + ++Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0 ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) info block ++drive0 (NODE_NAME): SNAPSHOT_PATH (qcow2, read-only) ++ Removable device: not locked, tray closed ++ Cache mode: writeback, ignore flushes ++ Backing file: TEST_DIR/t.qcow2 (chain depth: 1) ++(qemu) quit ++ + *** done +diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out +index ca64eda..3f71f9e 100644 +--- a/tests/qemu-iotests/051.pc.out ++++ b/tests/qemu-iotests/051.pc.out +@@ -530,4 +530,13 @@ read 4096/4096 bytes at offset 0 + Testing: -drive driver=null-co,snapshot=on + QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory + ++Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0 ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) info block ++drive0 (NODE_NAME): SNAPSHOT_PATH (qcow2, read-only) ++ Removable device: not locked, tray closed ++ Cache mode: writeback, ignore flushes ++ Backing file: TEST_DIR/t.qcow2 (chain depth: 1) ++(qemu) quit ++ + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Fix-shared-locks-on-reopen-commit.patch b/SOURCES/kvm-file-posix-Fix-shared-locks-on-reopen-commit.patch new file mode 100644 index 0000000..2c1a9ac --- /dev/null +++ b/SOURCES/kvm-file-posix-Fix-shared-locks-on-reopen-commit.patch @@ -0,0 +1,45 @@ +From ef27c0164bee4e910d0f2e20928688f873d924a3 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:06 +0100 +Subject: [PATCH 06/33] file-posix: Fix shared locks on reopen commit + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-7-mreitz@redhat.com> +Patchwork-id: 84225 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 6/7] file-posix: Fix shared locks on reopen commit +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +s->locked_shared_perm is the set of bits locked in the file, which is +the inverse of the permissions actually shared. So we need to pass them +as they are to raw_apply_lock_bytes() instead of inverting them again. + +Reported-by: Alberto Garcia +Signed-off-by: Max Reitz +Reviewed-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 577a133988c76e4ebf01d050d0d758d207a1baf7) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 97e7ff2..deecf58 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -929,7 +929,7 @@ static void raw_reopen_commit(BDRVReopenState *state) + + /* Copy locks to the new fd before closing the old one. */ + raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm, +- ~s->locked_shared_perm, false, &local_err); ++ s->locked_shared_perm, false, &local_err); + if (local_err) { + /* shouldn't fail in a sane host, but report it just in case. */ + error_report_err(local_err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Include-filename-in-locking-error-message.patch b/SOURCES/kvm-file-posix-Include-filename-in-locking-error-message.patch new file mode 100644 index 0000000..8b29b08 --- /dev/null +++ b/SOURCES/kvm-file-posix-Include-filename-in-locking-error-message.patch @@ -0,0 +1,345 @@ +From 53e0ff897da0cac47f08e1cb49ab98823301fe3b Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:02 +0100 +Subject: [PATCH 02/33] file-posix: Include filename in locking error message + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-3-mreitz@redhat.com> +Patchwork-id: 84221 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/7] file-posix: Include filename in locking error message +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +From: Fam Zheng + +Image locking errors happening at device initialization time doesn't say +which file cannot be locked, for instance, + + -device scsi-disk,drive=drive-1: Failed to get shared "write" lock + Is another process using the image? + +could refer to either the overlay image or its backing image. + +Hoist the error_append_hint to the caller of raw_check_lock_bytes where +file name is known, and include it in the error hint. + +Signed-off-by: Fam Zheng +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit b857431d2abe3945b672b41f33690e9943a8752a) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 10 +++--- + tests/qemu-iotests/153.out | 76 +++++++++++++++++++++++----------------------- + tests/qemu-iotests/182.out | 2 +- + 3 files changed, 45 insertions(+), 43 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 7e6869d..c2403ba 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -738,8 +738,6 @@ static int raw_check_lock_bytes(int fd, uint64_t perm, uint64_t shared_perm, + "Failed to get \"%s\" lock", + perm_name); + g_free(perm_name); +- error_append_hint(errp, +- "Is another process using the image?\n"); + return ret; + } + } +@@ -755,8 +753,6 @@ static int raw_check_lock_bytes(int fd, uint64_t perm, uint64_t shared_perm, + "Failed to get shared \"%s\" lock", + perm_name); + g_free(perm_name); +- error_append_hint(errp, +- "Is another process using the image?\n"); + return ret; + } + } +@@ -793,6 +789,9 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + if (!ret) { + return 0; + } ++ error_append_hint(errp, ++ "Is another process using the image [%s]?\n", ++ bs->filename); + } + op = RAW_PL_ABORT; + /* fall through to unlock bytes. */ +@@ -2169,6 +2168,9 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + /* Step two: Check that nobody else has taken conflicting locks */ + result = raw_check_lock_bytes(fd, perm, shared, errp); + if (result < 0) { ++ error_append_hint(errp, ++ "Is another process using the image [%s]?\n", ++ file_opts->filename); + goto out_unlock; + } + +diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out +index 93eaf10..8842548 100644 +--- a/tests/qemu-iotests/153.out ++++ b/tests/qemu-iotests/153.out +@@ -12,11 +12,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t + + == Launching another QEMU, opts: '' == + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=none,: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Launching another QEMU, opts: 'read-only=on' == + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=none,read-only=on: Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Launching another QEMU, opts: 'read-only=on,force-share=on' == + +@@ -24,77 +24,77 @@ Is another process using the image? + + _qemu_io_wrapper -c read 0 512 TEST_DIR/t.qcow2 + can't open device TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_io_wrapper -r -c read 0 512 TEST_DIR/t.qcow2 + can't open device TEST_DIR/t.qcow2: Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_io_wrapper -c open TEST_DIR/t.qcow2 -c read 0 512 + can't open device TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + no file open, try 'help open' + + _qemu_io_wrapper -c open -r TEST_DIR/t.qcow2 -c read 0 512 + can't open device TEST_DIR/t.qcow2: Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + no file open, try 'help open' + + _qemu_img_wrapper info TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper check TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper compare TEST_DIR/t.qcow2 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper map TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper amend -o TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper commit TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper resize TEST_DIR/t.qcow2 32M + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper snapshot -l TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper convert TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.convert + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper dd if=TEST_DIR/t.qcow2 of=TEST_DIR/t.qcow2.convert bs=512 count=1 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper bench -c 1 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base + qemu-img: TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + file format: IMGFMT + + == Running utility commands -U == +@@ -132,7 +132,7 @@ Try 'qemu-img --help' for more information + + _qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper snapshot -l -U TEST_DIR/t.qcow2 + +@@ -157,7 +157,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t + + == Launching another QEMU, opts: '' == + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=none,: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Launching another QEMU, opts: 'read-only=on' == + +@@ -167,13 +167,13 @@ Is another process using the image? + + _qemu_io_wrapper -c read 0 512 TEST_DIR/t.qcow2 + can't open device TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_io_wrapper -r -c read 0 512 TEST_DIR/t.qcow2 + + _qemu_io_wrapper -c open TEST_DIR/t.qcow2 -c read 0 512 + can't open device TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + no file open, try 'help open' + + _qemu_io_wrapper -c open -r TEST_DIR/t.qcow2 -c read 0 512 +@@ -188,19 +188,19 @@ _qemu_img_wrapper map TEST_DIR/t.qcow2 + + _qemu_img_wrapper amend -o TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper commit TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper resize TEST_DIR/t.qcow2 32M + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper rebase TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper snapshot -l TEST_DIR/t.qcow2 + +@@ -212,11 +212,11 @@ _qemu_img_wrapper bench -c 1 TEST_DIR/t.qcow2 + + _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base + qemu-img: TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + file format: IMGFMT + + == Running utility commands -U == +@@ -254,7 +254,7 @@ Try 'qemu-img --help' for more information + + _qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + _qemu_img_wrapper snapshot -l -U TEST_DIR/t.qcow2 + +@@ -372,17 +372,17 @@ Round done + + == Two devices with the same image (read-only=off - read-only=off) == + QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,read-only=off: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Two devices with the same image (read-only=off - read-only=on) == + QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,read-only=on: Failed to get shared "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Two devices with the same image (read-only=off - read-only=on,force-share=on) == + + == Two devices with the same image (read-only=on - read-only=off) == + QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,read-only=off: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Two devices with the same image (read-only=on - read-only=on) == + +@@ -403,13 +403,13 @@ Formatting 'TEST_DIR/t.IMGFMT.c', fmt=IMGFMT size=33554432 backing_file=TEST_DIR + + == Backing image also as an active device == + QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Backing image also as an active device (ro) == + + == Symbolic link == + QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + + == Active commit to intermediate layer should work when base in use == + {"return": {}} +@@ -420,7 +420,7 @@ Adding drive + + _qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512 + can't open device TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + Creating overlay with qemu-img when the guest is running should be allowed + + _qemu_img_wrapper create -f qcow2 -b TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.overlay +@@ -433,7 +433,7 @@ _qemu_img_wrapper info TEST_DIR/t.qcow2 + + _qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512 + can't open device TEST_DIR/t.qcow2: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + Closing the other + + _qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512 +diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out +index 23a4dbf..f1463c8 100644 +--- a/tests/qemu-iotests/182.out ++++ b/tests/qemu-iotests/182.out +@@ -4,5 +4,5 @@ Starting QEMU + + Starting a second QEMU using the same image should fail + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0,file.locking=on: Failed to get "write" lock +-Is another process using the image? ++Is another process using the image [TEST_DIR/t.qcow2]? + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Lock-new-fd-in-raw_reopen_prepare.patch b/SOURCES/kvm-file-posix-Lock-new-fd-in-raw_reopen_prepare.patch new file mode 100644 index 0000000..bb54012 --- /dev/null +++ b/SOURCES/kvm-file-posix-Lock-new-fd-in-raw_reopen_prepare.patch @@ -0,0 +1,90 @@ +From ffe4f32d741439547577bc87e1f08df8f6f2a151 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:08 +0100 +Subject: [PATCH 012/163] file-posix: Lock new fd in raw_reopen_prepare() + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-13-kwolf@redhat.com> +Patchwork-id: 84889 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/14] file-posix: Lock new fd in raw_reopen_prepare() +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +There is no reason why we can take locks on the new file descriptor only +in raw_reopen_commit() where error handling isn't possible any more. +Instead, we can already do this in raw_reopen_prepare(). + +Signed-off-by: Kevin Wolf +(cherry picked from commit a6aeca0ca530f104b5a5dd6704fca22b2c5edefa) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 27 ++++++++++++++++----------- + 1 file changed, 16 insertions(+), 11 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index b577d88..ae16f2f 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -897,7 +897,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, + { + BDRVRawState *s; + BDRVRawReopenState *rs; +- int ret = 0; ++ int ret; + Error *local_err = NULL; + + assert(state != NULL); +@@ -921,14 +921,27 @@ static int raw_reopen_prepare(BDRVReopenState *state, + if (rs->fd != -1) { + raw_probe_alignment(state->bs, rs->fd, &local_err); + if (local_err) { +- qemu_close(rs->fd); +- rs->fd = -1; + error_propagate(errp, local_err); + ret = -EINVAL; ++ goto out_fd; ++ } ++ ++ /* Copy locks to the new fd */ ++ ret = raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm, ++ s->locked_shared_perm, false, errp); ++ if (ret < 0) { ++ ret = -EINVAL; ++ goto out_fd; + } + } + + s->reopen_state = state; ++ ret = 0; ++out_fd: ++ if (ret < 0) { ++ qemu_close(rs->fd); ++ rs->fd = -1; ++ } + out: + return ret; + } +@@ -937,17 +950,9 @@ static void raw_reopen_commit(BDRVReopenState *state) + { + BDRVRawReopenState *rs = state->opaque; + BDRVRawState *s = state->bs->opaque; +- Error *local_err = NULL; + + s->open_flags = rs->open_flags; + +- /* Copy locks to the new fd before closing the old one. */ +- raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm, +- s->locked_shared_perm, false, &local_err); +- if (local_err) { +- /* shouldn't fail in a sane host, but report it just in case. */ +- error_report_err(local_err); +- } + qemu_close(s->fd); + s->fd = rs->fd; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Make-auto-read-only-dynamic.patch b/SOURCES/kvm-file-posix-Make-auto-read-only-dynamic.patch new file mode 100644 index 0000000..4a4f0de --- /dev/null +++ b/SOURCES/kvm-file-posix-Make-auto-read-only-dynamic.patch @@ -0,0 +1,174 @@ +From ee549d8b1c8cd482bb84d49e7535e174fd89b9ea Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:10 +0100 +Subject: [PATCH 014/163] file-posix: Make auto-read-only dynamic + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-15-kwolf@redhat.com> +Patchwork-id: 84891 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 14/14] file-posix: Make auto-read-only dynamic +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Until now, with auto-read-only=on we tried to open the file read-write +first and if that failed, read-only was tried. This is actually not good +enough for libvirt, which gives QEMU SELinux permissions for read-write +only as soon as it actually intends to write to the image. So we need to +be able to switch between read-only and read-write at runtime. + +This patch makes auto-read-only dynamic, i.e. the file is opened +read-only as long as no user of the node has requested write +permissions, but it is automatically reopened read-write as soon as the +first writer is attached. Conversely, if the last writer goes away, the +file is reopened read-only again. + +bs->read_only is no longer set for auto-read-only=on files even if the +file descriptor is opened read-only because it will be transparently +upgraded as soon as a writer is attached. This changes the output of +qemu-iotests 232. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 23dece19da41724349809873923e20a48b619cb7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 36 +++++++++++++++++------------------- + tests/qemu-iotests/232.out | 12 ++++++------ + 2 files changed, 23 insertions(+), 25 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index f0f8eaf..0cf7261 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -382,13 +382,21 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) + } + } + +-static void raw_parse_flags(int bdrv_flags, int *open_flags) ++static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers) + { ++ bool read_write = false; + assert(open_flags != NULL); + + *open_flags |= O_BINARY; + *open_flags &= ~O_ACCMODE; +- if (bdrv_flags & BDRV_O_RDWR) { ++ ++ if (bdrv_flags & BDRV_O_AUTO_RDONLY) { ++ read_write = has_writers; ++ } else if (bdrv_flags & BDRV_O_RDWR) { ++ read_write = true; ++ } ++ ++ if (read_write) { + *open_flags |= O_RDWR; + } else { + *open_flags |= O_RDONLY; +@@ -516,24 +524,12 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + } + + s->open_flags = open_flags; +- raw_parse_flags(bdrv_flags, &s->open_flags); ++ raw_parse_flags(bdrv_flags, &s->open_flags, false); + + s->fd = -1; + fd = qemu_open(filename, s->open_flags, 0644); + ret = fd < 0 ? -errno : 0; + +- if (ret == -EACCES || ret == -EROFS) { +- /* Try to degrade to read-only, but if it doesn't work, still use the +- * normal error message. */ +- if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) { +- bdrv_flags &= ~BDRV_O_RDWR; +- raw_parse_flags(bdrv_flags, &s->open_flags); +- assert(!(s->open_flags & O_CREAT)); +- fd = qemu_open(filename, s->open_flags); +- ret = fd < 0 ? -errno : 0; +- } +- } +- + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not open '%s'", filename); + if (ret == -EROFS) { +@@ -838,12 +834,14 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + } + + static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, +- int *open_flags, bool force_dup, ++ int *open_flags, uint64_t perm, bool force_dup, + Error **errp) + { + BDRVRawState *s = bs->opaque; + int fd = -1; + int ret; ++ bool has_writers = perm & ++ (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_RESIZE); + int fcntl_flags = O_APPEND | O_NONBLOCK; + #ifdef O_NOATIME + fcntl_flags |= O_NOATIME; +@@ -854,7 +852,7 @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, + *open_flags |= O_NONBLOCK; + } + +- raw_parse_flags(flags, open_flags); ++ raw_parse_flags(flags, open_flags, has_writers); + + #ifdef O_ASYNC + /* Not all operating systems have O_ASYNC, and those that don't +@@ -916,7 +914,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, + rs = state->opaque; + + rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags, +- true, &local_err); ++ state->perm, true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -1; +@@ -2548,7 +2546,7 @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared, + s->perm_change_fd = rs->fd; + } else { + /* We may need a new fd if auto-read-only switches the mode */ +- ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, ++ ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm, + false, errp); + if (ret < 0) { + return ret; +diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out +index dcb683a..3bd1a92 100644 +--- a/tests/qemu-iotests/232.out ++++ b/tests/qemu-iotests/232.out +@@ -22,12 +22,12 @@ NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) + NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) + + QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied +-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) +-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) + + QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied +-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) +-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) + + === -blockdev with read-write image: read-only/auto-read-only combinations === + +@@ -50,10 +50,10 @@ node0: TEST_DIR/t.IMGFMT (file, read-only) + node0: TEST_DIR/t.IMGFMT (file, read-only) + + QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied +-node0: TEST_DIR/t.IMGFMT (file, read-only) ++node0: TEST_DIR/t.IMGFMT (file) + QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied + + QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied +-node0: TEST_DIR/t.IMGFMT (file, read-only) ++node0: TEST_DIR/t.IMGFMT (file) + QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Prepare-permission-code-for-fd-switching.patch b/SOURCES/kvm-file-posix-Prepare-permission-code-for-fd-switching.patch new file mode 100644 index 0000000..bca91ee --- /dev/null +++ b/SOURCES/kvm-file-posix-Prepare-permission-code-for-fd-switching.patch @@ -0,0 +1,191 @@ +From a1cc5d5a181559a6f68c459cbae8488303112660 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:09 +0100 +Subject: [PATCH 013/163] file-posix: Prepare permission code for fd switching + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-14-kwolf@redhat.com> +Patchwork-id: 84890 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/14] file-posix: Prepare permission code for fd switching +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +In order to be able to dynamically reopen the file read-only or +read-write, depending on the users that are attached, we need to be able +to switch to a different file descriptor during the permission change. + +This interacts with reopen, which also creates a new file descriptor and +performs permission changes internally. In this case, the permission +change code must reuse the reopen file descriptor instead of creating a +third one. + +In turn, reopen can drop its code to copy file locks to the new file +descriptor because that is now done when applying the new permissions. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 6ceabe6f77e4ae5ac2fa3d2ac1be11dc95021941) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 85 insertions(+), 11 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index ae16f2f..f0f8eaf 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -156,6 +156,7 @@ typedef struct BDRVRawState { + uint64_t locked_perm; + uint64_t locked_shared_perm; + ++ int perm_change_fd; + BDRVReopenState *reopen_state; + + #ifdef CONFIG_XFS +@@ -837,7 +838,8 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + } + + static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, +- int *open_flags, Error **errp) ++ int *open_flags, bool force_dup, ++ Error **errp) + { + BDRVRawState *s = bs->opaque; + int fd = -1; +@@ -863,6 +865,11 @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, + assert((s->open_flags & O_ASYNC) == 0); + #endif + ++ if (!force_dup && *open_flags == s->open_flags) { ++ /* We're lucky, the existing fd is fine */ ++ return s->fd; ++ } ++ + if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) { + /* dup the original fd */ + fd = qemu_dup(s->fd); +@@ -909,7 +916,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, + rs = state->opaque; + + rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags, +- &local_err); ++ true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -1; +@@ -925,14 +932,6 @@ static int raw_reopen_prepare(BDRVReopenState *state, + ret = -EINVAL; + goto out_fd; + } +- +- /* Copy locks to the new fd */ +- ret = raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm, +- s->locked_shared_perm, false, errp); +- if (ret < 0) { +- ret = -EINVAL; +- goto out_fd; +- } + } + + s->reopen_state = state; +@@ -2524,12 +2523,78 @@ static QemuOptsList raw_create_opts = { + static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared, + Error **errp) + { +- return raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp); ++ BDRVRawState *s = bs->opaque; ++ BDRVRawReopenState *rs = NULL; ++ int open_flags; ++ int ret; ++ ++ if (s->perm_change_fd) { ++ /* ++ * In the context of reopen, this function may be called several times ++ * (directly and recursively while change permissions of the parent). ++ * This is even true for children that don't inherit from the original ++ * reopen node, so s->reopen_state is not set. ++ * ++ * Ignore all but the first call. ++ */ ++ return 0; ++ } ++ ++ if (s->reopen_state) { ++ /* We already have a new file descriptor to set permissions for */ ++ assert(s->reopen_state->perm == perm); ++ assert(s->reopen_state->shared_perm == shared); ++ rs = s->reopen_state->opaque; ++ s->perm_change_fd = rs->fd; ++ } else { ++ /* We may need a new fd if auto-read-only switches the mode */ ++ ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, ++ false, errp); ++ if (ret < 0) { ++ return ret; ++ } else if (ret != s->fd) { ++ s->perm_change_fd = ret; ++ } ++ } ++ ++ /* Prepare permissions on old fd to avoid conflicts between old and new, ++ * but keep everything locked that new will need. */ ++ ret = raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp); ++ if (ret < 0) { ++ goto fail; ++ } ++ ++ /* Copy locks to the new fd */ ++ if (s->perm_change_fd) { ++ ret = raw_apply_lock_bytes(NULL, s->perm_change_fd, perm, ~shared, ++ false, errp); ++ if (ret < 0) { ++ raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); ++ goto fail; ++ } ++ } ++ return 0; ++ ++fail: ++ if (s->perm_change_fd && !s->reopen_state) { ++ qemu_close(s->perm_change_fd); ++ } ++ s->perm_change_fd = 0; ++ return ret; + } + + static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared) + { + BDRVRawState *s = bs->opaque; ++ ++ /* For reopen, we have already switched to the new fd (.bdrv_set_perm is ++ * called after .bdrv_reopen_commit) */ ++ if (s->perm_change_fd && s->fd != s->perm_change_fd) { ++ qemu_close(s->fd); ++ s->fd = s->perm_change_fd; ++ } ++ s->perm_change_fd = 0; ++ + raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL); + s->perm = perm; + s->shared_perm = shared; +@@ -2537,6 +2602,15 @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared) + + static void raw_abort_perm_update(BlockDriverState *bs) + { ++ BDRVRawState *s = bs->opaque; ++ ++ /* For reopen, .bdrv_reopen_abort is called afterwards and will close ++ * the file descriptor. */ ++ if (s->perm_change_fd && !s->reopen_state) { ++ qemu_close(s->perm_change_fd); ++ } ++ s->perm_change_fd = 0; ++ + raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Skip-effectiveless-OFD-lock-operations.patch b/SOURCES/kvm-file-posix-Skip-effectiveless-OFD-lock-operations.patch new file mode 100644 index 0000000..ecadc42 --- /dev/null +++ b/SOURCES/kvm-file-posix-Skip-effectiveless-OFD-lock-operations.patch @@ -0,0 +1,195 @@ +From 63ef1f91221aabc910fea57486ecc54b1958c7a8 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:03 +0100 +Subject: [PATCH 03/33] file-posix: Skip effectiveless OFD lock operations + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-4-mreitz@redhat.com> +Patchwork-id: 84220 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/7] file-posix: Skip effectiveless OFD lock operations +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +From: Fam Zheng + +If we know we've already locked the bytes, don't do it again; similarly +don't unlock a byte if we haven't locked it. This doesn't change the +behavior, but fixes a corner case explained below. + +Libvirt had an error handling bug that an image can get its (ownership, +file mode, SELinux) permissions changed (RHBZ 1584982) by mistake behind +QEMU. Specifically, an image in use by Libvirt VM has: + + $ ls -lhZ b.img + -rw-r--r--. qemu qemu system_u:object_r:svirt_image_t:s0:c600,c690 b.img + +Trying to attach it a second time won't work because of image locking. +And after the error, it becomes: + + $ ls -lhZ b.img + -rw-r--r--. root root system_u:object_r:virt_image_t:s0 b.img + +Then, we won't be able to do OFD lock operations with the existing fd. +In other words, the code such as in blk_detach_dev: + + blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort); + +can abort() QEMU, out of environmental changes. + +This patch is an easy fix to this and the change is regardlessly +reasonable, so do it. + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 2996ffad3acabe890fbb4f84a069cdc325a68108) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 44 insertions(+), 10 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index c2403ba..2a05193 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -152,6 +152,11 @@ typedef struct BDRVRawState { + uint64_t perm; + uint64_t shared_perm; + ++ /* The perms bits whose corresponding bytes are already locked in ++ * s->lock_fd. */ ++ uint64_t locked_perm; ++ uint64_t locked_shared_perm; ++ + #ifdef CONFIG_XFS + bool is_xfs:1; + #endif +@@ -677,43 +682,72 @@ typedef enum { + * file; if @unlock == true, also unlock the unneeded bytes. + * @shared_perm_lock_bits is the mask of all permissions that are NOT shared. + */ +-static int raw_apply_lock_bytes(int fd, ++static int raw_apply_lock_bytes(BDRVRawState *s, int fd, + uint64_t perm_lock_bits, + uint64_t shared_perm_lock_bits, + bool unlock, Error **errp) + { + int ret; + int i; ++ uint64_t locked_perm, locked_shared_perm; ++ ++ if (s) { ++ locked_perm = s->locked_perm; ++ locked_shared_perm = s->locked_shared_perm; ++ } else { ++ /* ++ * We don't have the previous bits, just lock/unlock for each of the ++ * requested bits. ++ */ ++ if (unlock) { ++ locked_perm = BLK_PERM_ALL; ++ locked_shared_perm = BLK_PERM_ALL; ++ } else { ++ locked_perm = 0; ++ locked_shared_perm = 0; ++ } ++ } + + PERM_FOREACH(i) { + int off = RAW_LOCK_PERM_BASE + i; +- if (perm_lock_bits & (1ULL << i)) { ++ uint64_t bit = (1ULL << i); ++ if ((perm_lock_bits & bit) && !(locked_perm & bit)) { + ret = qemu_lock_fd(fd, off, 1, false); + if (ret) { + error_setg(errp, "Failed to lock byte %d", off); + return ret; ++ } else if (s) { ++ s->locked_perm |= bit; + } +- } else if (unlock) { ++ } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) { + ret = qemu_unlock_fd(fd, off, 1); + if (ret) { + error_setg(errp, "Failed to unlock byte %d", off); + return ret; ++ } else if (s) { ++ s->locked_perm &= ~bit; + } + } + } + PERM_FOREACH(i) { + int off = RAW_LOCK_SHARED_BASE + i; +- if (shared_perm_lock_bits & (1ULL << i)) { ++ uint64_t bit = (1ULL << i); ++ if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) { + ret = qemu_lock_fd(fd, off, 1, false); + if (ret) { + error_setg(errp, "Failed to lock byte %d", off); + return ret; ++ } else if (s) { ++ s->locked_shared_perm |= bit; + } +- } else if (unlock) { ++ } else if (unlock && (locked_shared_perm & bit) && ++ !(shared_perm_lock_bits & bit)) { + ret = qemu_unlock_fd(fd, off, 1); + if (ret) { + error_setg(errp, "Failed to unlock byte %d", off); + return ret; ++ } else if (s) { ++ s->locked_shared_perm &= ~bit; + } + } + } +@@ -781,7 +815,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + + switch (op) { + case RAW_PL_PREPARE: +- ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm, ++ ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm, + ~s->shared_perm | ~new_shared, + false, errp); + if (!ret) { +@@ -796,7 +830,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + op = RAW_PL_ABORT; + /* fall through to unlock bytes. */ + case RAW_PL_ABORT: +- raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm, ++ raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm, + true, &local_err); + if (local_err) { + /* Theoretically the above call only unlocks bytes and it cannot +@@ -806,7 +840,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + } + break; + case RAW_PL_COMMIT: +- raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared, ++ raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared, + true, &local_err); + if (local_err) { + /* Theoretically the above call only unlocks bytes and it cannot +@@ -2160,7 +2194,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; + + /* Step one: Take locks */ +- result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp); ++ result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp); + if (result < 0) { + goto out_close; + } +@@ -2204,7 +2238,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) + } + + out_unlock: +- raw_apply_lock_bytes(fd, 0, 0, true, &local_err); ++ raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err); + if (local_err) { + /* The above call should not fail, and if it does, that does + * not mean the whole creation operation has failed. So +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Store-BDRVRawState.reopen_state-during-re.patch b/SOURCES/kvm-file-posix-Store-BDRVRawState.reopen_state-during-re.patch new file mode 100644 index 0000000..18233fa --- /dev/null +++ b/SOURCES/kvm-file-posix-Store-BDRVRawState.reopen_state-during-re.patch @@ -0,0 +1,77 @@ +From c5a20feec46deb3f25037f29e7ae4823fe46afdf Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:07 +0100 +Subject: [PATCH 011/163] file-posix: Store BDRVRawState.reopen_state during + reopen + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-12-kwolf@redhat.com> +Patchwork-id: 84888 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/14] file-posix: Store BDRVRawState.reopen_state during reopen +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +We'll want to access the file descriptor in the reopen_state while +processing permission changes in the context of the repoen. + +Signed-off-by: Kevin Wolf +(cherry picked from commit e0c9cf3a484beb746996c0cd63e5585fecb3fd25) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/block/file-posix.c b/block/file-posix.c +index e50eb0e..b577d88 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -156,6 +156,8 @@ typedef struct BDRVRawState { + uint64_t locked_perm; + uint64_t locked_shared_perm; + ++ BDRVReopenState *reopen_state; ++ + #ifdef CONFIG_XFS + bool is_xfs:1; + #endif +@@ -926,6 +928,7 @@ static int raw_reopen_prepare(BDRVReopenState *state, + } + } + ++ s->reopen_state = state; + out: + return ret; + } +@@ -950,12 +953,16 @@ static void raw_reopen_commit(BDRVReopenState *state) + + g_free(state->opaque); + state->opaque = NULL; ++ ++ assert(s->reopen_state == state); ++ s->reopen_state = NULL; + } + + + static void raw_reopen_abort(BDRVReopenState *state) + { + BDRVRawReopenState *rs = state->opaque; ++ BDRVRawState *s = state->bs->opaque; + + /* nothing to do if NULL, we didn't get far enough */ + if (rs == NULL) { +@@ -968,6 +975,9 @@ static void raw_reopen_abort(BDRVReopenState *state) + } + g_free(state->opaque); + state->opaque = NULL; ++ ++ assert(s->reopen_state == state); ++ s->reopen_state = NULL; + } + + static int hdev_get_max_transfer_length(BlockDriverState *bs, int fd) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Support-auto-read-only-option.patch b/SOURCES/kvm-file-posix-Support-auto-read-only-option.patch new file mode 100644 index 0000000..f7e4b5d --- /dev/null +++ b/SOURCES/kvm-file-posix-Support-auto-read-only-option.patch @@ -0,0 +1,61 @@ +From e342033247c37090e1b8e0f99abc849e36521701 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:48 +0100 +Subject: [PATCH 07/34] file-posix: Support auto-read-only option + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-7-kwolf@redhat.com> +Patchwork-id: 83116 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 06/12] file-posix: Support auto-read-only option +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +If read-only=off, but auto-read-only=on is given, open the file +read-write if we have the permissions, but instead of erroring out for +read-only files, just degrade to read-only. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 64107dc044a54ebe46348ac0fe87584be2eb3e81) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index c12cdb7..7e6869d 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -517,9 +517,22 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + + s->fd = -1; + fd = qemu_open(filename, s->open_flags, 0644); +- if (fd < 0) { +- ret = -errno; +- error_setg_errno(errp, errno, "Could not open '%s'", filename); ++ ret = fd < 0 ? -errno : 0; ++ ++ if (ret == -EACCES || ret == -EROFS) { ++ /* Try to degrade to read-only, but if it doesn't work, still use the ++ * normal error message. */ ++ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) { ++ bdrv_flags &= ~BDRV_O_RDWR; ++ raw_parse_flags(bdrv_flags, &s->open_flags); ++ assert(!(s->open_flags & O_CREAT)); ++ fd = qemu_open(filename, s->open_flags); ++ ret = fd < 0 ? -errno : 0; ++ } ++ } ++ ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "Could not open '%s'", filename); + if (ret == -EROFS) { + ret = -EACCES; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Use-error-API-properly.patch b/SOURCES/kvm-file-posix-Use-error-API-properly.patch new file mode 100644 index 0000000..1543afd --- /dev/null +++ b/SOURCES/kvm-file-posix-Use-error-API-properly.patch @@ -0,0 +1,163 @@ +From a36c6beb5f5a2a02f805bcbf6303e3c6ab908c95 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:05 +0100 +Subject: [PATCH 009/163] file-posix: Use error API properly + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-10-kwolf@redhat.com> +Patchwork-id: 84886 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/14] file-posix: Use error API properly +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Fam Zheng + +Use error_report for situations that affect user operation (i.e. we're +actually returning error), and warn_report/warn_report_err when some +less critical error happened but the user operation can still carry on. + +For raw_normalize_devicepath, add Error parameter to propagate to +its callers. + +Suggested-by: Markus Armbruster +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit db0754df88e3ca4797539c1edbde596d871b64b6) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 39 ++++++++++++++++----------------------- + 1 file changed, 16 insertions(+), 23 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index deecf58..419781c 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -207,7 +207,7 @@ static int cdrom_reopen(BlockDriverState *bs); + #endif + + #if defined(__NetBSD__) +-static int raw_normalize_devicepath(const char **filename) ++static int raw_normalize_devicepath(const char **filename, Error **errp) + { + static char namebuf[PATH_MAX]; + const char *dp, *fname; +@@ -216,8 +216,7 @@ static int raw_normalize_devicepath(const char **filename) + fname = *filename; + dp = strrchr(fname, '/'); + if (lstat(fname, &sb) < 0) { +- fprintf(stderr, "%s: stat failed: %s\n", +- fname, strerror(errno)); ++ error_setg_errno(errp, errno, "%s: stat failed", fname); + return -errno; + } + +@@ -231,14 +230,13 @@ static int raw_normalize_devicepath(const char **filename) + snprintf(namebuf, PATH_MAX, "%.*s/r%s", + (int)(dp - fname), fname, dp + 1); + } +- fprintf(stderr, "%s is a block device", fname); + *filename = namebuf; +- fprintf(stderr, ", using %s\n", *filename); ++ warn_report("%s is a block device, using %s", fname, *filename); + + return 0; + } + #else +-static int raw_normalize_devicepath(const char **filename) ++static int raw_normalize_devicepath(const char **filename, Error **errp) + { + return 0; + } +@@ -458,9 +456,8 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + + filename = qemu_opt_get(opts, "filename"); + +- ret = raw_normalize_devicepath(&filename); ++ ret = raw_normalize_devicepath(&filename, errp); + if (ret != 0) { +- error_setg_errno(errp, -ret, "Could not normalize device path"); + goto fail; + } + +@@ -489,11 +486,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + case ON_OFF_AUTO_ON: + s->use_lock = true; + if (!qemu_has_ofd_lock()) { +- fprintf(stderr, +- "File lock requested but OFD locking syscall is " +- "unavailable, falling back to POSIX file locks.\n" +- "Due to the implementation, locks can be lost " +- "unexpectedly.\n"); ++ warn_report("File lock requested but OFD locking syscall is " ++ "unavailable, falling back to POSIX file locks"); ++ error_printf("Due to the implementation, locks can be lost " ++ "unexpectedly.\n"); + } + break; + case ON_OFF_AUTO_OFF: +@@ -821,7 +817,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + /* Theoretically the above call only unlocks bytes and it cannot + * fail. Something weird happened, report it. + */ +- error_report_err(local_err); ++ warn_report_err(local_err); + } + break; + case RAW_PL_COMMIT: +@@ -831,7 +827,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + /* Theoretically the above call only unlocks bytes and it cannot + * fail. Something weird happened, report it. + */ +- error_report_err(local_err); ++ warn_report_err(local_err); + } + break; + } +@@ -891,10 +887,8 @@ static int raw_reopen_prepare(BDRVReopenState *state, + /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */ + if (rs->fd == -1) { + const char *normalized_filename = state->bs->filename; +- ret = raw_normalize_devicepath(&normalized_filename); +- if (ret < 0) { +- error_setg_errno(errp, -ret, "Could not normalize device path"); +- } else { ++ ret = raw_normalize_devicepath(&normalized_filename, errp); ++ if (ret >= 0) { + assert(!(rs->open_flags & O_CREAT)); + rs->fd = qemu_open(normalized_filename, rs->open_flags); + if (rs->fd == -1) { +@@ -1742,7 +1736,7 @@ static int aio_worker(void *arg) + ret = handle_aiocb_truncate(aiocb); + break; + default: +- fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); ++ error_report("invalid aio request (0x%x)", aiocb->aio_type); + ret = -EINVAL; + break; + } +@@ -2233,7 +2227,7 @@ out_unlock: + * not mean the whole creation operation has failed. So + * report it the user for their convenience, but do not report + * it to the caller. */ +- error_report_err(local_err); ++ warn_report_err(local_err); + } + + out_close: +@@ -2986,9 +2980,8 @@ static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts + + (void)has_prefix; + +- ret = raw_normalize_devicepath(&filename); ++ ret = raw_normalize_devicepath(&filename, errp); + if (ret < 0) { +- error_setg_errno(errp, -ret, "Could not normalize device path"); + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-gluster-Support-auto-read-only-option.patch b/SOURCES/kvm-gluster-Support-auto-read-only-option.patch new file mode 100644 index 0000000..b3b8a54 --- /dev/null +++ b/SOURCES/kvm-gluster-Support-auto-read-only-option.patch @@ -0,0 +1,54 @@ +From 8c49a93129fc9faf8cdb0eb7599f625a2069a0fd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:50 +0100 +Subject: [PATCH 09/34] gluster: Support auto-read-only option + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-9-kwolf@redhat.com> +Patchwork-id: 83118 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 08/12] gluster: Support auto-read-only option +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +If read-only=off, but auto-read-only=on is given, open the file +read-write if we have the permissions, but instead of erroring out for +read-only files, just degrade to read-only. + +Signed-off-by: Kevin Wolf +Reviewed-by: Niels de Vos +(cherry picked from commit 54ea21bd16202c4a3e43c67b573b5d1aa2ec1c0c) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/gluster.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/block/gluster.c b/block/gluster.c +index cecfe09..8c13002 100644 +--- a/block/gluster.c ++++ b/block/gluster.c +@@ -849,8 +849,16 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options, + qemu_gluster_parse_flags(bdrv_flags, &open_flags); + + s->fd = glfs_open(s->glfs, gconf->path, open_flags); +- if (!s->fd) { +- ret = -errno; ++ ret = s->fd ? 0 : -errno; ++ ++ if (ret == -EACCES || ret == -EROFS) { ++ /* Try to degrade to read-only, but if it doesn't work, still use the ++ * normal error message. */ ++ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) { ++ open_flags = (open_flags & ~O_RDWR) | O_RDONLY; ++ s->fd = glfs_open(s->glfs, gconf->path, open_flags); ++ ret = s->fd ? 0 : -errno; ++ } + } + + s->supports_seek_data = qemu_gluster_test_seek(s->fd); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hbitmap-Add-advance-param-to-hbitmap_iter_next.patch b/SOURCES/kvm-hbitmap-Add-advance-param-to-hbitmap_iter_next.patch new file mode 100644 index 0000000..8c01257 --- /dev/null +++ b/SOURCES/kvm-hbitmap-Add-advance-param-to-hbitmap_iter_next.patch @@ -0,0 +1,182 @@ +From 300ff68e30f51846d0a226ee33a5878364303158 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:23 +0100 +Subject: [PATCH 13/33] hbitmap: Add @advance param to hbitmap_iter_next() + +RH-Author: John Snow +Message-id: <20190206221243.7407-4-jsnow@redhat.com> +Patchwork-id: 84260 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 03/23] hbitmap: Add @advance param to hbitmap_iter_next() +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Max Reitz + +This new parameter allows the caller to just query the next dirty +position without moving the iterator. + +Signed-off-by: Max Reitz +Reviewed-by: Fam Zheng +Reviewed-by: John Snow +Message-id: 20180613181823.13618-8-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit a33fbb4f8b64226becf502a123733776ce319b24) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/dirty-bitmap.c | 2 +- + include/qemu/hbitmap.h | 5 ++++- + tests/test-hbitmap.c | 26 +++++++++++++------------- + util/hbitmap.c | 10 +++++++--- + 5 files changed, 26 insertions(+), 19 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 524e0ff..ac17db6 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -409,7 +409,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) + HBitmapIter hbi; + + hbitmap_iter_init(&hbi, job->copy_bitmap, 0); +- while ((cluster = hbitmap_iter_next(&hbi)) != -1) { ++ while ((cluster = hbitmap_iter_next(&hbi, true)) != -1) { + do { + if (yield_and_check(job)) { + return 0; +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index cd39afd..f4a4cb7 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -525,7 +525,7 @@ void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter) + + int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter) + { +- return hbitmap_iter_next(&iter->hbi); ++ return hbitmap_iter_next(&iter->hbi, true); + } + + /* Called within bdrv_dirty_bitmap_lock..unlock */ +diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h +index 6b6490e..ddca52c 100644 +--- a/include/qemu/hbitmap.h ++++ b/include/qemu/hbitmap.h +@@ -324,11 +324,14 @@ void hbitmap_free_meta(HBitmap *hb); + /** + * hbitmap_iter_next: + * @hbi: HBitmapIter to operate on. ++ * @advance: If true, advance the iterator. Otherwise, the next call ++ * of this function will return the same result (if that ++ * position is still dirty). + * + * Return the next bit that is set in @hbi's associated HBitmap, + * or -1 if all remaining bits are zero. + */ +-int64_t hbitmap_iter_next(HBitmapIter *hbi); ++int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance); + + /** + * hbitmap_iter_next_word: +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index f29631f..f2158f7 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -46,7 +46,7 @@ static void hbitmap_test_check(TestHBitmapData *data, + + i = first; + for (;;) { +- next = hbitmap_iter_next(&hbi); ++ next = hbitmap_iter_next(&hbi, true); + if (next < 0) { + next = data->size; + } +@@ -435,25 +435,25 @@ static void test_hbitmap_iter_granularity(TestHBitmapData *data, + /* Note that hbitmap_test_check has to be invoked manually in this test. */ + hbitmap_test_init(data, 131072 << 7, 7); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_test_set(data, (131072 << 7) - 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); ++ g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + } + + static void hbitmap_test_set_boundary_bits(TestHBitmapData *data, ssize_t diff) +@@ -893,7 +893,7 @@ static void test_hbitmap_serialize_zeroes(TestHBitmapData *data, + for (i = 0; i < num_positions; i++) { + hbitmap_deserialize_zeroes(data->hb, positions[i], min_l1, true); + hbitmap_iter_init(&iter, data->hb, 0); +- next = hbitmap_iter_next(&iter); ++ next = hbitmap_iter_next(&iter, true); + if (i == num_positions - 1) { + g_assert_cmpint(next, ==, -1); + } else { +@@ -919,10 +919,10 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + + hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); + +- hbitmap_iter_next(&hbi); ++ hbitmap_iter_next(&hbi, true); + + hbitmap_reset_all(data->hb); +- hbitmap_iter_next(&hbi); ++ hbitmap_iter_next(&hbi, true); + } + + static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start) +diff --git a/util/hbitmap.c b/util/hbitmap.c +index 58a2c93..bcd3040 100644 +--- a/util/hbitmap.c ++++ b/util/hbitmap.c +@@ -141,7 +141,7 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) + return cur; + } + +-int64_t hbitmap_iter_next(HBitmapIter *hbi) ++int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance) + { + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] & + hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos]; +@@ -154,8 +154,12 @@ int64_t hbitmap_iter_next(HBitmapIter *hbi) + } + } + +- /* The next call will resume work from the next bit. */ +- hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); ++ if (advance) { ++ /* The next call will resume work from the next bit. */ ++ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); ++ } else { ++ hbi->cur[HBITMAP_LEVELS - 1] = cur; ++ } + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur); + + return item << hbi->granularity; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hostmem-drop-error-variable-from-host_memory_backend.patch b/SOURCES/kvm-hostmem-drop-error-variable-from-host_memory_backend.patch new file mode 100644 index 0000000..ba00f3b --- /dev/null +++ b/SOURCES/kvm-hostmem-drop-error-variable-from-host_memory_backend.patch @@ -0,0 +1,139 @@ +From 09b663f38767ce0d84b2301c97efec2d37e71a49 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 29 Oct 2018 07:01:36 +0100 +Subject: [PATCH 06/22] hostmem: drop error variable from + host_memory_backend_get_memory() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20181029070137.21196-3-armbru@redhat.com> +Patchwork-id: 82902 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] hostmem: drop error variable from host_memory_backend_get_memory() +Bugzilla: 1620373 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Igor Mammedov +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau + +From: David Hildenbrand + +Unused, so let's remove it. + +Reviewed-by: David Gibson +Reviewed-by: Igor Mammedov +Signed-off-by: David Hildenbrand +Message-Id: <20180619134141.29478-8-david@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 7943e97b858e64eddf0f3395427e58c5cc00a7d9) +Signed-off-by: Miroslav Rezanina +--- + backends/hostmem.c | 3 +-- + hw/mem/nvdimm.c | 4 ++-- + hw/mem/pc-dimm.c | 4 ++-- + hw/misc/ivshmem.c | 3 +-- + include/sysemu/hostmem.h | 3 +-- + numa.c | 3 +-- + 6 files changed, 8 insertions(+), 12 deletions(-) + +diff --git a/backends/hostmem.c b/backends/hostmem.c +index f610936..799ec69 100644 +--- a/backends/hostmem.c ++++ b/backends/hostmem.c +@@ -246,8 +246,7 @@ bool host_memory_backend_mr_inited(HostMemoryBackend *backend) + return memory_region_size(&backend->mr) != 0; + } + +-MemoryRegion * +-host_memory_backend_get_memory(HostMemoryBackend *backend, Error **errp) ++MemoryRegion *host_memory_backend_get_memory(HostMemoryBackend *backend) + { + return host_memory_backend_mr_inited(backend) ? &backend->mr : NULL; + } +diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c +index 5f1813d..da2b989 100644 +--- a/hw/mem/nvdimm.c ++++ b/hw/mem/nvdimm.c +@@ -106,7 +106,7 @@ static MemoryRegion *nvdimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) + + static void nvdimm_realize(PCDIMMDevice *dimm, Error **errp) + { +- MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem, errp); ++ MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem); + NVDIMMDevice *nvdimm = NVDIMM(dimm); + uint64_t align, pmem_size, size = memory_region_size(mr); + +@@ -168,7 +168,7 @@ static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf, + pmem_memcpy_persist(nvdimm->label_data + offset, buf, size); + } + +- mr = host_memory_backend_get_memory(dimm->hostmem, &error_abort); ++ mr = host_memory_backend_get_memory(dimm->hostmem); + backend_offset = memory_region_size(mr) - nvdimm->label_size + offset; + memory_region_set_dirty(mr, backend_offset, size); + } +diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c +index a9d7c51..c4a6551 100644 +--- a/hw/mem/pc-dimm.c ++++ b/hw/mem/pc-dimm.c +@@ -442,12 +442,12 @@ static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) + return NULL; + } + +- return host_memory_backend_get_memory(dimm->hostmem, errp); ++ return host_memory_backend_get_memory(dimm->hostmem); + } + + static MemoryRegion *pc_dimm_get_vmstate_memory_region(PCDIMMDevice *dimm) + { +- return host_memory_backend_get_memory(dimm->hostmem, &error_abort); ++ return host_memory_backend_get_memory(dimm->hostmem); + } + + static void pc_dimm_class_init(ObjectClass *oc, void *data) +diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c +index bfbfc0e..47456b8 100644 +--- a/hw/misc/ivshmem.c ++++ b/hw/misc/ivshmem.c +@@ -916,8 +916,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) + if (s->hostmem != NULL) { + IVSHMEM_DPRINTF("using hostmem\n"); + +- s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem, +- &error_abort); ++ s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem); + } else { + Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr); + assert(chr); +diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h +index 47bc984..69ba393 100644 +--- a/include/sysemu/hostmem.h ++++ b/include/sysemu/hostmem.h +@@ -63,8 +63,7 @@ struct HostMemoryBackend { + }; + + bool host_memory_backend_mr_inited(HostMemoryBackend *backend); +-MemoryRegion *host_memory_backend_get_memory(HostMemoryBackend *backend, +- Error **errp); ++MemoryRegion *host_memory_backend_get_memory(HostMemoryBackend *backend); + + void host_memory_backend_set_mapped(HostMemoryBackend *backend, bool mapped); + bool host_memory_backend_is_mapped(HostMemoryBackend *backend); +diff --git a/numa.c b/numa.c +index e78fba5..6e3d679 100644 +--- a/numa.c ++++ b/numa.c +@@ -512,8 +512,7 @@ void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner, + if (!backend) { + continue; + } +- MemoryRegion *seg = host_memory_backend_get_memory(backend, +- &error_fatal); ++ MemoryRegion *seg = host_memory_backend_get_memory(backend); + + if (memory_region_is_mapped(seg)) { + char *path = object_get_canonical_path_component(OBJECT(backend)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hostmem-file-remove-object-id-from-pmem-error-messag.patch b/SOURCES/kvm-hostmem-file-remove-object-id-from-pmem-error-messag.patch new file mode 100644 index 0000000..3c66717 --- /dev/null +++ b/SOURCES/kvm-hostmem-file-remove-object-id-from-pmem-error-messag.patch @@ -0,0 +1,78 @@ +From 111769e4a152fdb52f2b10fb957cdfec2fe7d4d2 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Tue, 8 Jan 2019 21:33:09 +0100 +Subject: [PATCH 3/8] hostmem-file: remove object id from pmem error message + +RH-Author: plai@redhat.com +Message-id: <1546983189-26340-1-git-send-email-plai@redhat.com> +Patchwork-id: 83911 +O-Subject: [RHEL7.7 qemu-kvm-rhev PATCH v2] hostmem-file: remove object id from pmem error message +Bugzilla: 1628098 +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Eduardo Habkost + +From: Zhang Yi + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1628098 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=19688087 +Branch: rhv7/master-2.12.0 + +Tested by Intel OTC virtualization. + +--- +v2 + fixing subject line to use qemu-kvm-rhev instead of qemu-kvm +--- +We will never get the canonical path from the object +before object_property_add_child. + +Signed-off-by: Zhang Yi +Message-Id: +[ehabkost: reword commit message] +Signed-off-by: Eduardo Habkost + +(cherry picked from commit 87dc3ce60a8a16b47aeb6c5f4dbc14ee975563df) +Signed-off-by: Paul Lai + +Resolved Conflicts: + backends/hostmem-file.c + +Signed-off-by: Miroslav Rezanina +--- + backends/hostmem-file.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c +index 2476dcb..5b519c2 100644 +--- a/backends/hostmem-file.c ++++ b/backends/hostmem-file.c +@@ -145,20 +145,19 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp) + HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); + + if (host_memory_backend_mr_inited(backend)) { +- error_setg(errp, "cannot change property 'pmem' of %s '%s'", +- object_get_typename(o), +- object_get_canonical_path_component(o)); ++ error_setg(errp, "cannot change property 'pmem' of %s.", ++ object_get_typename(o)); + return; + } + + #ifndef CONFIG_LIBPMEM + if (value) { + Error *local_err = NULL; ++ + error_setg(&local_err, + "Lack of libpmem support while setting the 'pmem=on'" +- " of %s '%s'. We can't ensure data persistence.", +- object_get_typename(o), +- object_get_canonical_path_component(o)); ++ " of %s. We can't ensure data persistence.", ++ object_get_typename(o)); + error_propagate(errp, local_err); + return; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-Use-PFLASH_CFI0-1-2-and-TYPE_PFLASH_CFI0-1-2.patch b/SOURCES/kvm-hw-Use-PFLASH_CFI0-1-2-and-TYPE_PFLASH_CFI0-1-2.patch new file mode 100644 index 0000000..e2ff4b2 --- /dev/null +++ b/SOURCES/kvm-hw-Use-PFLASH_CFI0-1-2-and-TYPE_PFLASH_CFI0-1-2.patch @@ -0,0 +1,159 @@ +From 8bad602712aa9d875e1826b6cc17baba97deb4c8 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:56 +0200 +Subject: [PATCH 29/53] hw: Use PFLASH_CFI0{1, 2} and TYPE_PFLASH_CFI0{1, 2} +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-8-armbru@redhat.com> +Patchwork-id: 87997 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 07/31] hw: Use PFLASH_CFI0{1, 2} and TYPE_PFLASH_CFI0{1, 2} +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +We have two open-coded copies of macro PFLASH_CFI01(). Move the macro +to the header, so we can ditch the copies. Move PFLASH_CFI02() to the +header for symmetry. + +We define macros TYPE_PFLASH_CFI01 and TYPE_PFLASH_CFI02 for type name +strings, then mostly use the strings. If the macros are worth +defining, they are worth using. Replace the strings by the macros. + +Signed-off-by: Markus Armbruster +Reviewed-by: Laszlo Ersek +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-6-armbru@redhat.com> +(cherry picked from commit 81c7db723ebd0c677784a728020c7e8845868daf) +Signed-off-by: Miroslav Rezanina +--- + hw/arm/vexpress.c | 4 ++-- + hw/arm/virt.c | 3 ++- + hw/block/pflash_cfi01.c | 3 --- + hw/block/pflash_cfi02.c | 3 --- + hw/xtensa/xtfpga.c | 4 ++-- + include/hw/block/flash.h | 4 ++++ + 6 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c +index 5cca371..cf87379 100644 +--- a/hw/arm/vexpress.c ++++ b/hw/arm/vexpress.c +@@ -504,7 +504,7 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) + static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, + DriveInfo *di) + { +- DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); ++ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + + if (di) { + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di), +@@ -525,7 +525,7 @@ static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); +- return OBJECT_CHECK(PFlashCFI01, (dev), "cfi.pflash01"); ++ return PFLASH_CFI01(dev); + } + + static void vexpress_common_init(MachineState *machine) +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 751a93c..4c652de 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -34,6 +34,7 @@ + #include "hw/arm/arm.h" + #include "hw/arm/primecell.h" + #include "hw/arm/virt.h" ++#include "hw/block/flash.h" + #include "hw/vfio/vfio-calxeda-xgmac.h" + #include "hw/vfio/vfio-amd-xgbe.h" + #include "hw/devices.h" +@@ -812,7 +813,7 @@ static void create_one_flash(const char *name, hwaddr flashbase, + * parameters as the flash devices on the Versatile Express board. + */ + DriveInfo *dinfo = drive_get_next(IF_PFLASH); +- DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); ++ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + const uint64_t sectorlength = 256 * 1024; + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 1ff4d25..dbd3b9d 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -59,9 +59,6 @@ do { \ + #define DPRINTF(fmt, ...) do { } while (0) + #endif + +-#define PFLASH_CFI01(obj) \ +- OBJECT_CHECK(PFlashCFI01, (obj), TYPE_PFLASH_CFI01) +- + #define PFLASH_BE 0 + #define PFLASH_SECURE 1 + +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index 2c0cbde..b9e0448 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -57,9 +57,6 @@ do { \ + + #define PFLASH_LAZY_ROMD_THRESHOLD 42 + +-#define PFLASH_CFI02(obj) \ +- OBJECT_CHECK(PFlashCFI02, (obj), TYPE_PFLASH_CFI02) +- + struct PFlashCFI02 { + /*< private >*/ + SysBusDevice parent_obj; +diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c +index 8f8c0b9..56deadc 100644 +--- a/hw/xtensa/xtfpga.c ++++ b/hw/xtensa/xtfpga.c +@@ -164,7 +164,7 @@ static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, + DriveInfo *dinfo, int be) + { + SysBusDevice *s; +- DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); ++ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), + &error_abort); +@@ -178,7 +178,7 @@ static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, + s = SYS_BUS_DEVICE(dev); + memory_region_add_subregion(address_space, board->flash->base, + sysbus_mmio_get_region(s, 0)); +- return OBJECT_CHECK(PFlashCFI01, (dev), "cfi.pflash01"); ++ return PFLASH_CFI01(dev); + } + + static uint64_t translate_phys_addr(void *opaque, uint64_t addr) +diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h +index 333005d..aeea3ca 100644 +--- a/include/hw/block/flash.h ++++ b/include/hw/block/flash.h +@@ -8,6 +8,8 @@ + /* pflash_cfi01.c */ + + #define TYPE_PFLASH_CFI01 "cfi.pflash01" ++#define PFLASH_CFI01(obj) \ ++ OBJECT_CHECK(PFlashCFI01, (obj), TYPE_PFLASH_CFI01) + + typedef struct PFlashCFI01 PFlashCFI01; + +@@ -25,6 +27,8 @@ MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl); + /* pflash_cfi02.c */ + + #define TYPE_PFLASH_CFI02 "cfi.pflash02" ++#define PFLASH_CFI02(obj) \ ++ OBJECT_CHECK(PFlashCFI02, (obj), TYPE_PFLASH_CFI02) + + typedef struct PFlashCFI02 PFlashCFI02; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-mips-malta-Remove-fl_sectors-variable.patch b/SOURCES/kvm-hw-mips-malta-Remove-fl_sectors-variable.patch new file mode 100644 index 0000000..55ce03a --- /dev/null +++ b/SOURCES/kvm-hw-mips-malta-Remove-fl_sectors-variable.patch @@ -0,0 +1,57 @@ +From 1170f872af13f294082e33e172e3c6e3a8995895 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:02 +0200 +Subject: [PATCH 35/53] hw/mips/malta: Remove fl_sectors variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-14-armbru@redhat.com> +Patchwork-id: 87996 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 13/31] hw/mips/malta: Remove fl_sectors variable +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Philippe Mathieu-Daudé + +Variable fl_sectors is used just once. Since +fl_sectors = bios_size >> 16 and bios_size = FLASH_SIZE there, +we can simply use FLASH_SIZE >> 16, and eliminate variable. + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Markus Armbruster +Message-Id: <20190308094610.21210-12-armbru@redhat.com> +(cherry picked from commit 5207c595eb8910eee3d329214e65d64e348985d1) +Signed-off-by: Miroslav Rezanina +--- + hw/mips/mips_malta.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index 7f19bdc..0566d18 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -1003,7 +1003,6 @@ void mips_malta_init(MachineState *machine) + DriveInfo *dinfo; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + int fl_idx = 0; +- int fl_sectors = bios_size >> 16; + int be; + + DeviceState *dev = qdev_create(NULL, TYPE_MIPS_MALTA); +@@ -1067,7 +1066,7 @@ void mips_malta_init(MachineState *machine) + fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", + BIOS_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 65536, fl_sectors, ++ 65536, FLASH_SIZE >> 16, + 4, 0x0000, 0x0000, 0x0000, 0x0000, be); + bios = pflash_cfi01_get_memory(fl); + fl_idx++; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-mips-malta-Restrict-bios_size-variable-scope.patch b/SOURCES/kvm-hw-mips-malta-Restrict-bios_size-variable-scope.patch new file mode 100644 index 0000000..4a25736 --- /dev/null +++ b/SOURCES/kvm-hw-mips-malta-Restrict-bios_size-variable-scope.patch @@ -0,0 +1,60 @@ +From 874453e6bed4da39f9860236148efdb09d285203 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:03 +0200 +Subject: [PATCH 36/53] hw/mips/malta: Restrict 'bios_size' variable scope +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-15-armbru@redhat.com> +Patchwork-id: 88003 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 14/31] hw/mips/malta: Restrict 'bios_size' variable scope +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Philippe Mathieu-Daudé + +The 'bios_size' variable is only used in the 'if (!kernel_filename && +!dinfo)' clause. This is the case when we don't provide -pflash command +line option, and also don't provide a -kernel option. In this case we +will check for the -bios option, or use the default BIOS_FILENAME file. + +The 'bios' term is valid in this if statement, but is confuse in the +whole mips_malta_init() scope. Restrict his scope. + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Markus Armbruster +Message-Id: <20190308094610.21210-13-armbru@redhat.com> +(cherry picked from commit 74c02ebd80fa331361c431d8dbfcba45a2a36e85) +Signed-off-by: Miroslav Rezanina +--- + hw/mips/mips_malta.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index 0566d18..857bdb8 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -990,7 +990,6 @@ void mips_malta_init(MachineState *machine) + MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1); + MemoryRegion *ram_low_postio; + MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1); +- target_long bios_size = FLASH_SIZE; + const size_t smbus_eeprom_size = 8 * 256; + uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size); + int64_t kernel_entry, bootloader_run_addr; +@@ -1097,6 +1096,7 @@ void mips_malta_init(MachineState *machine) + bootloader_run_addr, kernel_entry); + } + } else { ++ target_long bios_size = FLASH_SIZE; + /* The flash region isn't executable from a KVM guest */ + if (kvm_enabled()) { + error_report("KVM enabled but no -kernel argument was specified. " +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-s390x-Fix-bad-mask-in-time2tod.patch b/SOURCES/kvm-hw-s390x-Fix-bad-mask-in-time2tod.patch deleted file mode 100644 index 9a175ad..0000000 --- a/SOURCES/kvm-hw-s390x-Fix-bad-mask-in-time2tod.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 6e5f084a9839a417aaea25371af9dfe9c108cf65 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:57 +0100 -Subject: [PATCH 13/14] hw/s390x: Fix bad mask in time2tod() - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-13-david@redhat.com> -Patchwork-id: 83766 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 12/12] hw/s390x: Fix bad mask in time2tod() -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -Since "s390x/tcg: avoid overflows in time2tod/tod2time", the -time2tod() function tries to deal with the 9 uppermost bits in the -time value, but uses the wrong mask for this: 0xff80000000000000 should -be used instead of 0xff10000000000000 here. - -Fixes: 14055ce53c2d901d826ffad7fb7d6bb8ab46bdfd -Cc: qemu-stable@nongnu.org -Signed-off-by: Thomas Huth -Message-Id: <1544792887-14575-1-git-send-email-thuth@redhat.com> -Reviewed-by: David Hildenbrand -[CH: tweaked commit message] -Signed-off-by: Cornelia Huck -(cherry picked from commit aba7a5a2de3dba5917024df25441f715b9249e31) -Signed-off-by: David Hildenbrand - -Signed-off-by: Miroslav Rezanina ---- - include/hw/s390x/tod.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h -index cbd7552..47ef9de 100644 ---- a/include/hw/s390x/tod.h -+++ b/include/hw/s390x/tod.h -@@ -56,7 +56,7 @@ typedef struct S390TODClass { - /* Converts ns to s390's clock format */ - static inline uint64_t time2tod(uint64_t ns) - { -- return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9); -+ return (ns << 9) / 125 + (((ns & 0xff80000000000000ull) / 125) << 9); - } - - /* Converts s390's clock format to ns */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-s390x-Include-the-tod-qemu-also-for-builds-with-d.patch b/SOURCES/kvm-hw-s390x-Include-the-tod-qemu-also-for-builds-with-d.patch deleted file mode 100644 index 54f1392..0000000 --- a/SOURCES/kvm-hw-s390x-Include-the-tod-qemu-also-for-builds-with-d.patch +++ /dev/null @@ -1,61 +0,0 @@ -From abe7d93a04b4291bdcd406d180271143b16f2896 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:55 +0100 -Subject: [PATCH 11/14] hw/s390x: Include the tod-qemu also for builds with - --disable-tcg - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-11-david@redhat.com> -Patchwork-id: 83764 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 10/12] hw/s390x: Include the tod-qemu also for builds with --disable-tcg -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -The device is required for running qtests, see hw/s390x/tod.c: - -void s390_init_tod(void) -{ - Object *obj; - - if (kvm_enabled()) { - obj = object_new(TYPE_KVM_S390_TOD); - } else { - obj = object_new(TYPE_QEMU_S390_TOD); - } - [...] - } - -During qtests, we're running without kvm, so TYPE_QEMU_S390_TOD is -required to avoid that QEMU aborts here. - -Fixes: 8046f374a6 ("s390x/tod: factor out TOD into separate device") -Signed-off-by: Thomas Huth -Message-Id: <1539264723-741-1-git-send-email-thuth@redhat.com> -Reviewed-by: David Hildenbrand -Signed-off-by: Cornelia Huck -(cherry picked from commit 0161215d435ef5680c4623bcbdfe89ce5b35cf42) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/Makefile.objs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs -index 93282f7..58b1866 100644 ---- a/hw/s390x/Makefile.objs -+++ b/hw/s390x/Makefile.objs -@@ -15,8 +15,8 @@ obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o - obj-y += s390-skeys.o - obj-y += s390-stattrib.o - obj-y += tod.o -+obj-y += tod-qemu.o - obj-$(CONFIG_KVM) += tod-kvm.o --obj-$(CONFIG_TCG) += tod-qemu.o - obj-$(CONFIG_KVM) += s390-skeys-kvm.o - obj-$(CONFIG_KVM) += s390-stattrib-kvm.o - obj-y += s390-ccw.o --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-scsi-add-VPD-Block-Limits-emulation.patch b/SOURCES/kvm-hw-scsi-add-VPD-Block-Limits-emulation.patch new file mode 100644 index 0000000..996176f --- /dev/null +++ b/SOURCES/kvm-hw-scsi-add-VPD-Block-Limits-emulation.patch @@ -0,0 +1,338 @@ +From 2f019168e70aa391d110a09dbae9ac937091ddc2 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:02 +0100 +Subject: [PATCH 28/34] hw/scsi: add VPD Block Limits emulation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-5-pbonzini@redhat.com> +Patchwork-id: 82943 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 4/9] hw/scsi: add VPD Block Limits emulation +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +From: Daniel Henrique Barboza + +The VPD Block Limits Inquiry page is optional, allowing SCSI devices +to not implement it. This is the case for devices like the MegaRAID +SAS 9361-8i and Microsemi PM8069. + +In case of SCSI passthrough, the response of this request is used by +the QEMU SCSI layer to set the max_io_sectors that the guest +device will support, based on the value of the max_sectors_kb that +the device has set in the host at that time. Without this response, +the guest kernel is free to assume any value of max_io_sectors +for the SCSI device. If this value is greater than the value from +the host, SCSI Sense errors will occur because the guest will send +read/write requests that are larger than the underlying host device +is configured to support. An example of this behavior can be seen +in [1]. + +A workaround is to set the max_sectors_kb host value back in the guest +kernel (a process that can be automated using rc.local startup scripts +and the like), but this has several drawbacks: + +- it can be troublesome if the guest has many passthrough devices that +needs this tuning; + +- if a change in max_sectors_kb is made in the host side, manual change +in the guests will also be required; + +- during an OS install it is difficult, and sometimes not possible, to +go to a terminal and change the max_sectors_kb prior to the installation. +This means that the disk can't be used during the install process. The +easiest alternative here is to roll back to scsi-hd, install the guest +and then go back to SCSI passthrough when the installation is done and +max_sectors_kb can be set. + +An easier way would be to QEMU handle the absence of the Block Limits +VPD device response, setting max_io_sectors accordingly and allowing +the guest to use the device without the hassle. + +This patch adds emulation of the Block Limits VPD response for +SCSI passthrough devices of type TYPE_DISK that doesn't support +it. The following changes were made: + +- scsi_handle_inquiry_reply will now check the available VPD +pages from the Inquiry EVPD reply. In case the device does not + +- a new function called scsi_generic_set_vpd_bl_emulation, +that is called during device realize, was created to set a +new flag 'needs_vpd_bl_emulation' of the device. This function +retrieves the Inquiry EVPD response of the device to check for +VPD BL support. + +- scsi_handle_inquiry_reply will now check the available VPD +pages from the Inquiry EVPD reply in case the device needs +VPD BL emulation, adding the Block Limits page (0xb0) to +the list. This will make the guest kernel aware of the +support that we're now providing by emulation. + +- a new function scsi_emulate_block_limits creates the +emulated Block Limits response. This function is called +inside scsi_read_complete in case the device requires +Block Limits VPD emulation and we detected a SCSI Sense +error in the VPD Block Limits reply that was issued +from the guest kernel to the device. This error is +expected: we're reporting support from our side, but +the device isn't aware of it. + +With this patch, the guest now queries the Block Limits +page during the device configuration because it is being +advertised in the Supported Pages response. It will either +receive the Block Limits page from the hardware, if it supports +it, or will receive an emulated response from QEMU. At any rate, +the guest now has the information to set the max_sectors_kb +parameter accordingly, sparing the user of SCSI sense errors +that would happen without the emulated response and in the +absence of Block Limits support from the hardware. + +[1] https://bugzilla.redhat.com/show_bug.cgi?id=1566195 + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1566195 +Reported-by: Dac Nguyen +Signed-off-by: Daniel Henrique Barboza +Message-Id: <20180627172432.11120-4-danielhb413@gmail.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit a71c775b24ebc664129eb1d9b4c360590353efd5) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 2 +- + hw/scsi/scsi-generic.c | 132 +++++++++++++++++++++++++++++++++++++++++++++---- + include/hw/scsi/scsi.h | 3 +- + 3 files changed, 125 insertions(+), 12 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index ea86849..b3d53ec 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -2646,7 +2646,7 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) + s->features |= (1 << SCSI_DISK_F_NO_REMOVABLE_DEVOPS); + + scsi_realize(&s->qdev, errp); +- scsi_generic_read_device_identification(&s->qdev); ++ scsi_generic_read_device_inquiry(&s->qdev); + } + + typedef struct SCSIBlockReq { +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index c6307a8..4266003 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -145,6 +145,8 @@ static int execute_command(BlockBackend *blk, + + static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + { ++ uint8_t page, page_len; ++ + /* + * EVPD set to zero returns the standard INQUIRY data. + * +@@ -168,22 +170,57 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + s->scsi_version = r->buf[2]; + } + } +- if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) { +- uint32_t max_transfer = +- blk_get_max_transfer(s->conf.blk) / s->blocksize; + +- assert(max_transfer); +- stl_be_p(&r->buf[8], max_transfer); +- /* Also take care of the opt xfer len. */ +- stl_be_p(&r->buf[12], +- MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); ++ if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) { ++ page = r->req.cmd.buf[2]; ++ if (page == 0xb0) { ++ uint32_t max_transfer = ++ blk_get_max_transfer(s->conf.blk) / s->blocksize; ++ ++ assert(max_transfer); ++ stl_be_p(&r->buf[8], max_transfer); ++ /* Also take care of the opt xfer len. */ ++ stl_be_p(&r->buf[12], ++ MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); ++ } else if (page == 0x00 && s->needs_vpd_bl_emulation) { ++ /* ++ * Now we're capable of supplying the VPD Block Limits ++ * response if the hardware can't. Add it in the INQUIRY ++ * Supported VPD pages response in case we are using the ++ * emulation for this device. ++ * ++ * This way, the guest kernel will be aware of the support ++ * and will use it to proper setup the SCSI device. ++ */ ++ page_len = r->buf[3]; ++ r->buf[page_len + 4] = 0xb0; ++ r->buf[3] = ++page_len; ++ } + } + } + ++static int scsi_emulate_block_limits(SCSIGenericReq *r) ++{ ++ r->buflen = scsi_disk_emulate_vpd_page(&r->req, r->buf); ++ r->io_header.sb_len_wr = 0; ++ ++ /* ++ * We have valid contents in the reply buffer but the ++ * io_header can report a sense error coming from ++ * the hardware in scsi_command_complete_noio. Clean ++ * up the io_header to avoid reporting it. ++ */ ++ r->io_header.driver_status = 0; ++ r->io_header.status = 0; ++ ++ return r->buflen; ++} ++ + static void scsi_read_complete(void * opaque, int ret) + { + SCSIGenericReq *r = (SCSIGenericReq *)opaque; + SCSIDevice *s = r->req.dev; ++ SCSISense sense; + int len; + + assert(r->req.aiocb != NULL); +@@ -200,6 +237,27 @@ static void scsi_read_complete(void * opaque, int ret) + DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); + + r->len = -1; ++ ++ /* ++ * Check if this is a VPD Block Limits request that ++ * resulted in sense error but would need emulation. ++ * In this case, emulate a valid VPD response. ++ */ ++ if (s->needs_vpd_bl_emulation) { ++ int is_vpd_bl = r->req.cmd.buf[0] == INQUIRY && ++ r->req.cmd.buf[1] & 0x01 && ++ r->req.cmd.buf[2] == 0xb0; ++ ++ if (is_vpd_bl && sg_io_sense_from_errno(-ret, &r->io_header, &sense)) { ++ len = scsi_emulate_block_limits(r); ++ /* ++ * No need to let scsi_read_complete go on and handle an ++ * INQUIRY VPD BL request we created manually. ++ */ ++ goto req_complete; ++ } ++ } ++ + if (len == 0) { + scsi_command_complete_noio(r, 0); + goto done; +@@ -234,6 +292,8 @@ static void scsi_read_complete(void * opaque, int ret) + if (r->req.cmd.buf[0] == INQUIRY) { + scsi_handle_inquiry_reply(r, s); + } ++ ++req_complete: + scsi_req_data(&r->req, len); + scsi_req_unref(&r->req); + +@@ -435,7 +495,49 @@ int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, + return 0; + } + +-void scsi_generic_read_device_identification(SCSIDevice *s) ++/* ++ * Executes an INQUIRY request with EVPD set to retrieve the ++ * available VPD pages of the device. If the device does ++ * not support the Block Limits page (page 0xb0), set ++ * the needs_vpd_bl_emulation flag for future use. ++ */ ++static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s) ++{ ++ uint8_t cmd[6]; ++ uint8_t buf[250]; ++ uint8_t page_len; ++ int ret, i; ++ ++ memset(cmd, 0, sizeof(cmd)); ++ memset(buf, 0, sizeof(buf)); ++ cmd[0] = INQUIRY; ++ cmd[1] = 1; ++ cmd[2] = 0x00; ++ cmd[4] = sizeof(buf); ++ ++ ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), ++ buf, sizeof(buf)); ++ if (ret < 0) { ++ /* ++ * Do not assume anything if we can't retrieve the ++ * INQUIRY response to assert the VPD Block Limits ++ * support. ++ */ ++ s->needs_vpd_bl_emulation = false; ++ return; ++ } ++ ++ page_len = buf[3]; ++ for (i = 4; i < page_len + 4; i++) { ++ if (buf[i] == 0xb0) { ++ s->needs_vpd_bl_emulation = false; ++ return; ++ } ++ } ++ s->needs_vpd_bl_emulation = true; ++} ++ ++static void scsi_generic_read_device_identification(SCSIDevice *s) + { + uint8_t cmd[6]; + uint8_t buf[250]; +@@ -480,6 +582,16 @@ void scsi_generic_read_device_identification(SCSIDevice *s) + } + } + ++void scsi_generic_read_device_inquiry(SCSIDevice *s) ++{ ++ scsi_generic_read_device_identification(s); ++ if (s->type == TYPE_DISK) { ++ scsi_generic_set_vpd_bl_emulation(s); ++ } else { ++ s->needs_vpd_bl_emulation = false; ++ } ++} ++ + static int get_stream_blocksize(BlockBackend *blk) + { + uint8_t cmd[6]; +@@ -581,7 +693,7 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) + + /* Only used by scsi-block, but initialize it nevertheless to be clean. */ + s->default_scsi_version = -1; +- scsi_generic_read_device_identification(s); ++ scsi_generic_read_device_inquiry(s); + } + + const SCSIReqOps scsi_generic_req_ops = { +diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h +index b6e05c4..ee3a411 100644 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -87,6 +87,7 @@ struct SCSIDevice + uint64_t port_wwn; + int scsi_version; + int default_scsi_version; ++ bool needs_vpd_bl_emulation; + }; + + extern const VMStateDescription vmstate_scsi_device; +@@ -186,7 +187,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); + void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); + void scsi_device_report_change(SCSIDevice *dev, SCSISense sense); + void scsi_device_unit_attention_reported(SCSIDevice *dev); +-void scsi_generic_read_device_identification(SCSIDevice *dev); ++void scsi_generic_read_device_inquiry(SCSIDevice *dev); + int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); + int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf); + int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-scsi-centralize-SG_IO-calls-into-single-function.patch b/SOURCES/kvm-hw-scsi-centralize-SG_IO-calls-into-single-function.patch new file mode 100644 index 0000000..0f623d9 --- /dev/null +++ b/SOURCES/kvm-hw-scsi-centralize-SG_IO-calls-into-single-function.patch @@ -0,0 +1,204 @@ +From bf544897c8e513b68b9262f6f9315b8a49421429 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:01 +0100 +Subject: [PATCH 27/34] hw/scsi: centralize SG_IO calls into single function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-4-pbonzini@redhat.com> +Patchwork-id: 82947 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 3/9] hw/scsi: centralize SG_IO calls into single function +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +From: Daniel Henrique Barboza + +For the VPD Block Limits emulation with SCSI passthrough, +we'll issue an Inquiry request with EVPD set to retrieve +the available VPD pages of the device. This would be done in +a way similar of what scsi_generic_read_device_identification +does: create a SCSI command and a reply buffer, fill in the +sg_io_hdr_t structure, call blk_ioctl, check if an error +occurred, process the response. + +This same process is done in other 2 functions, get_device_type +and get_stream_blocksize. They differ in the command/reply +buffer and post-processing, everything else is almost a +copy/paste. + +Instead of adding a forth copy/pasted-ish code when adding +the passthrough VPD BL emulation, this patch extirpates +this repetition of those 3 functions and put it into +a new one called scsi_SG_IO_FROM_DEV. Any future code that +wants to execute an SG_DXFER_FROM_DEV to the device can +use it, avoiding filling sg_io_hdr_t again and et cetera. + +Signed-off-by: Daniel Henrique Barboza +Message-Id: <20180627172432.11120-3-danielhb413@gmail.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit a0c7e35b17b3d2cade8a5fc8e57904e02fb91fe4) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 18 +++------------ + hw/scsi/scsi-generic.c | 61 +++++++++++++++++++++++++------------------------- + include/hw/scsi/scsi.h | 2 ++ + 3 files changed, 36 insertions(+), 45 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index ae5b4c0..ea86849 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -2579,8 +2579,6 @@ static int get_device_type(SCSIDiskState *s) + { + uint8_t cmd[16]; + uint8_t buf[36]; +- uint8_t sensebuf[8]; +- sg_io_hdr_t io_header; + int ret; + + memset(cmd, 0, sizeof(cmd)); +@@ -2588,19 +2586,9 @@ static int get_device_type(SCSIDiskState *s) + cmd[0] = INQUIRY; + cmd[4] = sizeof(buf); + +- memset(&io_header, 0, sizeof(io_header)); +- io_header.interface_id = 'S'; +- io_header.dxfer_direction = SG_DXFER_FROM_DEV; +- io_header.dxfer_len = sizeof(buf); +- io_header.dxferp = buf; +- io_header.cmdp = cmd; +- io_header.cmd_len = sizeof(cmd); +- io_header.mx_sb_len = sizeof(sensebuf); +- io_header.sbp = sensebuf; +- io_header.timeout = 6000; /* XXX */ +- +- ret = blk_ioctl(s->qdev.conf.blk, SG_IO, &io_header); +- if (ret < 0 || io_header.driver_status || io_header.host_status) { ++ ret = scsi_SG_IO_FROM_DEV(s->qdev.conf.blk, cmd, sizeof(cmd), ++ buf, sizeof(buf)); ++ if (ret < 0) { + return -1; + } + s->qdev.type = buf[0]; +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 796162c..c6307a8 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -410,35 +410,48 @@ static int read_naa_id(const uint8_t *p, uint64_t *p_wwn) + return -EINVAL; + } + +-void scsi_generic_read_device_identification(SCSIDevice *s) ++int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, ++ uint8_t *buf, uint8_t buf_size) + { +- uint8_t cmd[6]; +- uint8_t buf[250]; +- uint8_t sensebuf[8]; + sg_io_hdr_t io_header; ++ uint8_t sensebuf[8]; + int ret; +- int i, len; +- +- memset(cmd, 0, sizeof(cmd)); +- memset(buf, 0, sizeof(buf)); +- cmd[0] = INQUIRY; +- cmd[1] = 1; +- cmd[2] = 0x83; +- cmd[4] = sizeof(buf); + + memset(&io_header, 0, sizeof(io_header)); + io_header.interface_id = 'S'; + io_header.dxfer_direction = SG_DXFER_FROM_DEV; +- io_header.dxfer_len = sizeof(buf); ++ io_header.dxfer_len = buf_size; + io_header.dxferp = buf; + io_header.cmdp = cmd; +- io_header.cmd_len = sizeof(cmd); ++ io_header.cmd_len = cmd_size; + io_header.mx_sb_len = sizeof(sensebuf); + io_header.sbp = sensebuf; + io_header.timeout = 6000; /* XXX */ + +- ret = blk_ioctl(s->conf.blk, SG_IO, &io_header); ++ ret = blk_ioctl(blk, SG_IO, &io_header); + if (ret < 0 || io_header.driver_status || io_header.host_status) { ++ return -1; ++ } ++ return 0; ++} ++ ++void scsi_generic_read_device_identification(SCSIDevice *s) ++{ ++ uint8_t cmd[6]; ++ uint8_t buf[250]; ++ int ret; ++ int i, len; ++ ++ memset(cmd, 0, sizeof(cmd)); ++ memset(buf, 0, sizeof(buf)); ++ cmd[0] = INQUIRY; ++ cmd[1] = 1; ++ cmd[2] = 0x83; ++ cmd[4] = sizeof(buf); ++ ++ ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), ++ buf, sizeof(buf)); ++ if (ret < 0) { + return; + } + +@@ -471,8 +484,6 @@ static int get_stream_blocksize(BlockBackend *blk) + { + uint8_t cmd[6]; + uint8_t buf[12]; +- uint8_t sensebuf[8]; +- sg_io_hdr_t io_header; + int ret; + + memset(cmd, 0, sizeof(cmd)); +@@ -480,21 +491,11 @@ static int get_stream_blocksize(BlockBackend *blk) + cmd[0] = MODE_SENSE; + cmd[4] = sizeof(buf); + +- memset(&io_header, 0, sizeof(io_header)); +- io_header.interface_id = 'S'; +- io_header.dxfer_direction = SG_DXFER_FROM_DEV; +- io_header.dxfer_len = sizeof(buf); +- io_header.dxferp = buf; +- io_header.cmdp = cmd; +- io_header.cmd_len = sizeof(cmd); +- io_header.mx_sb_len = sizeof(sensebuf); +- io_header.sbp = sensebuf; +- io_header.timeout = 6000; /* XXX */ +- +- ret = blk_ioctl(blk, SG_IO, &io_header); +- if (ret < 0 || io_header.driver_status || io_header.host_status) { ++ ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf)); ++ if (ret < 0) { + return -1; + } ++ + return (buf[9] << 16) | (buf[10] << 8) | buf[11]; + } + +diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h +index 5930a43..b6e05c4 100644 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -189,6 +189,8 @@ void scsi_device_unit_attention_reported(SCSIDevice *dev); + void scsi_generic_read_device_identification(SCSIDevice *dev); + int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); + int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf); ++int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, ++ uint8_t *buf, uint8_t buf_size); + SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun); + + /* scsi-generic.c. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-scsi-cleanups-before-VPD-BL-emulation.patch b/SOURCES/kvm-hw-scsi-cleanups-before-VPD-BL-emulation.patch new file mode 100644 index 0000000..f2278f3 --- /dev/null +++ b/SOURCES/kvm-hw-scsi-cleanups-before-VPD-BL-emulation.patch @@ -0,0 +1,597 @@ +From 3597e0269b24fe17de30e1554f33b1770852211b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:00 +0100 +Subject: [PATCH 26/34] hw/scsi: cleanups before VPD BL emulation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-3-pbonzini@redhat.com> +Patchwork-id: 82948 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 2/9] hw/scsi: cleanups before VPD BL emulation +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +From: Daniel Henrique Barboza + +To add support for the emulation of Block Limits VPD page +for passthrough devices, a few adjustments in the current code +base is required to avoid repetition and improve clarity. + +In scsi-generic.c, detach the Inquiry handling from +scsi_read_complete and put it into a new function called +scsi_handle_inquiry_reply. This change aims to avoid +cluttering of scsi_read_complete when we more logic in the +Inquiry response handling is added in the next patches, +centralizing the changes in the new function. + +In scsi-disk.c, take the build of all emulated VPD pages +from scsi_disk_emulate_inquiry and make it available to +other files into a non-static function called +scsi_disk_emulate_vpd_page. Making it public will allow +the future VPD BL emulation code for passthrough devices +to use it from scsi-generic.c, avoiding copy/pasting this +code solely for that purpose. It also has the advantage of +providing emulation of all VPD pages in case we need to +emulate other pages in other scenarios. As a bonus, +scsi_disk_emulate_inquiry got tidier. + +Signed-off-by: Daniel Henrique Barboza +Message-Id: <20180627172432.11120-2-danielhb413@gmail.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 0a96ca2437646bad197b0108c5f4a93e7ead05a9) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 407 +++++++++++++++++++++++++------------------------ + hw/scsi/scsi-generic.c | 71 +++++---- + include/hw/scsi/scsi.h | 1 + + 3 files changed, 249 insertions(+), 230 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index ded23d3..ae5b4c0 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -585,219 +585,228 @@ static uint8_t *scsi_get_buf(SCSIRequest *req) + return (uint8_t *)r->iov.iov_base; + } + +-static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) ++int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); +- int buflen = 0; +- int start; +- +- if (req->cmd.buf[1] & 0x1) { +- /* Vital product data */ +- uint8_t page_code = req->cmd.buf[2]; +- +- outbuf[buflen++] = s->qdev.type & 0x1f; +- outbuf[buflen++] = page_code ; // this page +- outbuf[buflen++] = 0x00; +- outbuf[buflen++] = 0x00; +- start = buflen; +- +- switch (page_code) { +- case 0x00: /* Supported page codes, mandatory */ +- { +- DPRINTF("Inquiry EVPD[Supported pages] " +- "buffer size %zd\n", req->cmd.xfer); +- outbuf[buflen++] = 0x00; // list of supported pages (this page) +- if (s->serial) { +- outbuf[buflen++] = 0x80; // unit serial number +- } +- outbuf[buflen++] = 0x83; // device identification +- if (s->qdev.type == TYPE_DISK) { +- outbuf[buflen++] = 0xb0; // block limits +- outbuf[buflen++] = 0xb1; /* block device characteristics */ +- outbuf[buflen++] = 0xb2; // thin provisioning +- } +- break; +- } +- case 0x80: /* Device serial number, optional */ +- { +- int l; ++ uint8_t page_code = req->cmd.buf[2]; ++ int start, buflen = 0; + +- if (!s->serial) { +- DPRINTF("Inquiry (EVPD[Serial number] not supported\n"); +- return -1; +- } ++ outbuf[buflen++] = s->qdev.type & 0x1f; ++ outbuf[buflen++] = page_code; ++ outbuf[buflen++] = 0x00; ++ outbuf[buflen++] = 0x00; ++ start = buflen; + +- l = strlen(s->serial); +- if (l > 36) { +- l = 36; +- } ++ switch (page_code) { ++ case 0x00: /* Supported page codes, mandatory */ ++ { ++ DPRINTF("Inquiry EVPD[Supported pages] " ++ "buffer size %zd\n", req->cmd.xfer); ++ outbuf[buflen++] = 0x00; /* list of supported pages (this page) */ ++ if (s->serial) { ++ outbuf[buflen++] = 0x80; /* unit serial number */ ++ } ++ outbuf[buflen++] = 0x83; /* device identification */ ++ if (s->qdev.type == TYPE_DISK) { ++ outbuf[buflen++] = 0xb0; /* block limits */ ++ outbuf[buflen++] = 0xb1; /* block device characteristics */ ++ outbuf[buflen++] = 0xb2; /* thin provisioning */ ++ } ++ break; ++ } ++ case 0x80: /* Device serial number, optional */ ++ { ++ int l; + +- DPRINTF("Inquiry EVPD[Serial number] " +- "buffer size %zd\n", req->cmd.xfer); +- memcpy(outbuf+buflen, s->serial, l); +- buflen += l; +- break; ++ if (!s->serial) { ++ DPRINTF("Inquiry (EVPD[Serial number] not supported\n"); ++ return -1; + } + +- case 0x83: /* Device identification page, mandatory */ +- { +- const char *str = s->serial ?: blk_name(s->qdev.conf.blk); +- int max_len = s->serial ? 20 : 255 - 8; +- int id_len = strlen(str); ++ l = strlen(s->serial); ++ if (l > 36) { ++ l = 36; ++ } + +- if (id_len > max_len) { +- id_len = max_len; +- } +- DPRINTF("Inquiry EVPD[Device identification] " +- "buffer size %zd\n", req->cmd.xfer); +- +- outbuf[buflen++] = 0x2; // ASCII +- outbuf[buflen++] = 0; // not officially assigned +- outbuf[buflen++] = 0; // reserved +- outbuf[buflen++] = id_len; // length of data following +- memcpy(outbuf+buflen, str, id_len); +- buflen += id_len; +- +- if (s->qdev.wwn) { +- outbuf[buflen++] = 0x1; // Binary +- outbuf[buflen++] = 0x3; // NAA +- outbuf[buflen++] = 0; // reserved +- outbuf[buflen++] = 8; +- stq_be_p(&outbuf[buflen], s->qdev.wwn); +- buflen += 8; +- } ++ DPRINTF("Inquiry EVPD[Serial number] " ++ "buffer size %zd\n", req->cmd.xfer); ++ memcpy(outbuf + buflen, s->serial, l); ++ buflen += l; ++ break; ++ } + +- if (s->qdev.port_wwn) { +- outbuf[buflen++] = 0x61; // SAS / Binary +- outbuf[buflen++] = 0x93; // PIV / Target port / NAA +- outbuf[buflen++] = 0; // reserved +- outbuf[buflen++] = 8; +- stq_be_p(&outbuf[buflen], s->qdev.port_wwn); +- buflen += 8; +- } ++ case 0x83: /* Device identification page, mandatory */ ++ { ++ const char *str = s->serial ?: blk_name(s->qdev.conf.blk); ++ int max_len = s->serial ? 20 : 255 - 8; ++ int id_len = strlen(str); + +- if (s->port_index) { +- outbuf[buflen++] = 0x61; // SAS / Binary +- outbuf[buflen++] = 0x94; // PIV / Target port / relative target port +- outbuf[buflen++] = 0; // reserved +- outbuf[buflen++] = 4; +- stw_be_p(&outbuf[buflen + 2], s->port_index); +- buflen += 4; +- } +- break; ++ if (id_len > max_len) { ++ id_len = max_len; + } +- case 0xb0: /* block limits */ +- { +- unsigned int unmap_sectors = +- s->qdev.conf.discard_granularity / s->qdev.blocksize; +- unsigned int min_io_size = +- s->qdev.conf.min_io_size / s->qdev.blocksize; +- unsigned int opt_io_size = +- s->qdev.conf.opt_io_size / s->qdev.blocksize; +- unsigned int max_unmap_sectors = +- s->max_unmap_size / s->qdev.blocksize; +- unsigned int max_io_sectors = +- s->max_io_size / s->qdev.blocksize; +- +- if (s->qdev.type == TYPE_ROM) { +- DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n", +- page_code); +- return -1; +- } +- if (s->qdev.type == TYPE_DISK) { +- int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk); +- int max_io_sectors_blk = +- max_transfer_blk / s->qdev.blocksize; +- +- max_io_sectors = +- MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors); +- +- /* min_io_size and opt_io_size can't be greater than +- * max_io_sectors */ +- if (min_io_size) { +- min_io_size = MIN(min_io_size, max_io_sectors); +- } +- if (opt_io_size) { +- opt_io_size = MIN(opt_io_size, max_io_sectors); +- } +- } +- /* required VPD size with unmap support */ +- buflen = 0x40; +- memset(outbuf + 4, 0, buflen - 4); +- +- outbuf[4] = 0x1; /* wsnz */ +- +- /* optimal transfer length granularity */ +- outbuf[6] = (min_io_size >> 8) & 0xff; +- outbuf[7] = min_io_size & 0xff; +- +- /* maximum transfer length */ +- outbuf[8] = (max_io_sectors >> 24) & 0xff; +- outbuf[9] = (max_io_sectors >> 16) & 0xff; +- outbuf[10] = (max_io_sectors >> 8) & 0xff; +- outbuf[11] = max_io_sectors & 0xff; +- +- /* optimal transfer length */ +- outbuf[12] = (opt_io_size >> 24) & 0xff; +- outbuf[13] = (opt_io_size >> 16) & 0xff; +- outbuf[14] = (opt_io_size >> 8) & 0xff; +- outbuf[15] = opt_io_size & 0xff; +- +- /* max unmap LBA count, default is 1GB */ +- outbuf[20] = (max_unmap_sectors >> 24) & 0xff; +- outbuf[21] = (max_unmap_sectors >> 16) & 0xff; +- outbuf[22] = (max_unmap_sectors >> 8) & 0xff; +- outbuf[23] = max_unmap_sectors & 0xff; +- +- /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header. */ +- outbuf[24] = 0; +- outbuf[25] = 0; +- outbuf[26] = 0; +- outbuf[27] = 255; +- +- /* optimal unmap granularity */ +- outbuf[28] = (unmap_sectors >> 24) & 0xff; +- outbuf[29] = (unmap_sectors >> 16) & 0xff; +- outbuf[30] = (unmap_sectors >> 8) & 0xff; +- outbuf[31] = unmap_sectors & 0xff; +- +- /* max write same size */ +- outbuf[36] = 0; +- outbuf[37] = 0; +- outbuf[38] = 0; +- outbuf[39] = 0; +- +- outbuf[40] = (max_io_sectors >> 24) & 0xff; +- outbuf[41] = (max_io_sectors >> 16) & 0xff; +- outbuf[42] = (max_io_sectors >> 8) & 0xff; +- outbuf[43] = max_io_sectors & 0xff; +- break; ++ DPRINTF("Inquiry EVPD[Device identification] " ++ "buffer size %zd\n", req->cmd.xfer); ++ ++ outbuf[buflen++] = 0x2; /* ASCII */ ++ outbuf[buflen++] = 0; /* not officially assigned */ ++ outbuf[buflen++] = 0; /* reserved */ ++ outbuf[buflen++] = id_len; /* length of data following */ ++ memcpy(outbuf + buflen, str, id_len); ++ buflen += id_len; ++ ++ if (s->qdev.wwn) { ++ outbuf[buflen++] = 0x1; /* Binary */ ++ outbuf[buflen++] = 0x3; /* NAA */ ++ outbuf[buflen++] = 0; /* reserved */ ++ outbuf[buflen++] = 8; ++ stq_be_p(&outbuf[buflen], s->qdev.wwn); ++ buflen += 8; + } +- case 0xb1: /* block device characteristics */ +- { +- buflen = 8; +- outbuf[4] = (s->rotation_rate >> 8) & 0xff; +- outbuf[5] = s->rotation_rate & 0xff; +- outbuf[6] = 0; +- outbuf[7] = 0; +- break; ++ ++ if (s->qdev.port_wwn) { ++ outbuf[buflen++] = 0x61; /* SAS / Binary */ ++ outbuf[buflen++] = 0x93; /* PIV / Target port / NAA */ ++ outbuf[buflen++] = 0; /* reserved */ ++ outbuf[buflen++] = 8; ++ stq_be_p(&outbuf[buflen], s->qdev.port_wwn); ++ buflen += 8; + } +- case 0xb2: /* thin provisioning */ +- { +- buflen = 8; +- outbuf[4] = 0; +- outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */ +- outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1; +- outbuf[7] = 0; +- break; ++ ++ if (s->port_index) { ++ outbuf[buflen++] = 0x61; /* SAS / Binary */ ++ ++ /* PIV/Target port/relative target port */ ++ outbuf[buflen++] = 0x94; ++ ++ outbuf[buflen++] = 0; /* reserved */ ++ outbuf[buflen++] = 4; ++ stw_be_p(&outbuf[buflen + 2], s->port_index); ++ buflen += 4; + } +- default: ++ break; ++ } ++ case 0xb0: /* block limits */ ++ { ++ unsigned int unmap_sectors = ++ s->qdev.conf.discard_granularity / s->qdev.blocksize; ++ unsigned int min_io_size = ++ s->qdev.conf.min_io_size / s->qdev.blocksize; ++ unsigned int opt_io_size = ++ s->qdev.conf.opt_io_size / s->qdev.blocksize; ++ unsigned int max_unmap_sectors = ++ s->max_unmap_size / s->qdev.blocksize; ++ unsigned int max_io_sectors = ++ s->max_io_size / s->qdev.blocksize; ++ ++ if (s->qdev.type == TYPE_ROM) { ++ DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n", ++ page_code); + return -1; + } +- /* done with EVPD */ +- assert(buflen - start <= 255); +- outbuf[start - 1] = buflen - start; +- return buflen; ++ if (s->qdev.type == TYPE_DISK) { ++ int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk); ++ int max_io_sectors_blk = ++ max_transfer_blk / s->qdev.blocksize; ++ ++ max_io_sectors = ++ MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors); ++ ++ /* min_io_size and opt_io_size can't be greater than ++ * max_io_sectors */ ++ if (min_io_size) { ++ min_io_size = MIN(min_io_size, max_io_sectors); ++ } ++ if (opt_io_size) { ++ opt_io_size = MIN(opt_io_size, max_io_sectors); ++ } ++ } ++ /* required VPD size with unmap support */ ++ buflen = 0x40; ++ memset(outbuf + 4, 0, buflen - 4); ++ ++ outbuf[4] = 0x1; /* wsnz */ ++ ++ /* optimal transfer length granularity */ ++ outbuf[6] = (min_io_size >> 8) & 0xff; ++ outbuf[7] = min_io_size & 0xff; ++ ++ /* maximum transfer length */ ++ outbuf[8] = (max_io_sectors >> 24) & 0xff; ++ outbuf[9] = (max_io_sectors >> 16) & 0xff; ++ outbuf[10] = (max_io_sectors >> 8) & 0xff; ++ outbuf[11] = max_io_sectors & 0xff; ++ ++ /* optimal transfer length */ ++ outbuf[12] = (opt_io_size >> 24) & 0xff; ++ outbuf[13] = (opt_io_size >> 16) & 0xff; ++ outbuf[14] = (opt_io_size >> 8) & 0xff; ++ outbuf[15] = opt_io_size & 0xff; ++ ++ /* max unmap LBA count, default is 1GB */ ++ outbuf[20] = (max_unmap_sectors >> 24) & 0xff; ++ outbuf[21] = (max_unmap_sectors >> 16) & 0xff; ++ outbuf[22] = (max_unmap_sectors >> 8) & 0xff; ++ outbuf[23] = max_unmap_sectors & 0xff; ++ ++ /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header */ ++ outbuf[24] = 0; ++ outbuf[25] = 0; ++ outbuf[26] = 0; ++ outbuf[27] = 255; ++ ++ /* optimal unmap granularity */ ++ outbuf[28] = (unmap_sectors >> 24) & 0xff; ++ outbuf[29] = (unmap_sectors >> 16) & 0xff; ++ outbuf[30] = (unmap_sectors >> 8) & 0xff; ++ outbuf[31] = unmap_sectors & 0xff; ++ ++ /* max write same size */ ++ outbuf[36] = 0; ++ outbuf[37] = 0; ++ outbuf[38] = 0; ++ outbuf[39] = 0; ++ ++ outbuf[40] = (max_io_sectors >> 24) & 0xff; ++ outbuf[41] = (max_io_sectors >> 16) & 0xff; ++ outbuf[42] = (max_io_sectors >> 8) & 0xff; ++ outbuf[43] = max_io_sectors & 0xff; ++ break; ++ } ++ case 0xb1: /* block device characteristics */ ++ { ++ buflen = 8; ++ outbuf[4] = (s->rotation_rate >> 8) & 0xff; ++ outbuf[5] = s->rotation_rate & 0xff; ++ outbuf[6] = 0; ++ outbuf[7] = 0; ++ break; ++ } ++ case 0xb2: /* thin provisioning */ ++ { ++ buflen = 8; ++ outbuf[4] = 0; ++ outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */ ++ outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1; ++ outbuf[7] = 0; ++ break; ++ } ++ default: ++ return -1; ++ } ++ /* done with EVPD */ ++ assert(buflen - start <= 255); ++ outbuf[start - 1] = buflen - start; ++ return buflen; ++} ++ ++static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) ++{ ++ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); ++ int buflen = 0; ++ ++ if (req->cmd.buf[1] & 0x1) { ++ /* Vital product data */ ++ return scsi_disk_emulate_vpd_page(req, outbuf); + } + + /* Standard INQUIRY data */ +@@ -3040,6 +3049,10 @@ static Property scsi_block_properties[] = { + DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), + DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), + DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), ++ DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size, ++ DEFAULT_MAX_UNMAP_SIZE), ++ DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, ++ DEFAULT_MAX_IO_SIZE), + DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, + -1), + DEFINE_PROP_END_OF_LIST(), +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 381f04e..796162c 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -143,6 +143,43 @@ static int execute_command(BlockBackend *blk, + return 0; + } + ++static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) ++{ ++ /* ++ * EVPD set to zero returns the standard INQUIRY data. ++ * ++ * Check if scsi_version is unset (-1) to avoid re-defining it ++ * each time an INQUIRY with standard data is received. ++ * scsi_version is initialized with -1 in scsi_generic_reset ++ * and scsi_disk_reset, making sure that we'll set the ++ * scsi_version after a reset. If the version field of the ++ * INQUIRY response somehow changes after a guest reboot, ++ * we'll be able to keep track of it. ++ * ++ * On SCSI-2 and older, first 3 bits of byte 2 is the ++ * ANSI-approved version, while on later versions the ++ * whole byte 2 contains the version. Check if we're dealing ++ * with a newer version and, in that case, assign the ++ * whole byte. ++ */ ++ if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) { ++ s->scsi_version = r->buf[2] & 0x07; ++ if (s->scsi_version > 2) { ++ s->scsi_version = r->buf[2]; ++ } ++ } ++ if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) { ++ uint32_t max_transfer = ++ blk_get_max_transfer(s->conf.blk) / s->blocksize; ++ ++ assert(max_transfer); ++ stl_be_p(&r->buf[8], max_transfer); ++ /* Also take care of the opt xfer len. */ ++ stl_be_p(&r->buf[12], ++ MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); ++ } ++} ++ + static void scsi_read_complete(void * opaque, int ret) + { + SCSIGenericReq *r = (SCSIGenericReq *)opaque; +@@ -195,39 +232,7 @@ static void scsi_read_complete(void * opaque, int ret) + } + } + if (r->req.cmd.buf[0] == INQUIRY) { +- /* +- * EVPD set to zero returns the standard INQUIRY data. +- * +- * Check if scsi_version is unset (-1) to avoid re-defining it +- * each time an INQUIRY with standard data is received. +- * scsi_version is initialized with -1 in scsi_generic_reset +- * and scsi_disk_reset, making sure that we'll set the +- * scsi_version after a reset. If the version field of the +- * INQUIRY response somehow changes after a guest reboot, +- * we'll be able to keep track of it. +- * +- * On SCSI-2 and older, first 3 bits of byte 2 is the +- * ANSI-approved version, while on later versions the +- * whole byte 2 contains the version. Check if we're dealing +- * with a newer version and, in that case, assign the +- * whole byte. +- */ +- if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) { +- s->scsi_version = r->buf[2] & 0x07; +- if (s->scsi_version > 2) { +- s->scsi_version = r->buf[2]; +- } +- } +- if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) { +- uint32_t max_transfer = +- blk_get_max_transfer(s->conf.blk) / s->blocksize; +- +- assert(max_transfer); +- stl_be_p(&r->buf[8], max_transfer); +- /* Also take care of the opt xfer len. */ +- stl_be_p(&r->buf[12], +- MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); +- } ++ scsi_handle_inquiry_reply(r, s); + } + scsi_req_data(&r->req, len); + scsi_req_unref(&r->req); +diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h +index 1a7290d..5930a43 100644 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -188,6 +188,7 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense); + void scsi_device_unit_attention_reported(SCSIDevice *dev); + void scsi_generic_read_device_identification(SCSIDevice *dev); + int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); ++int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf); + SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun); + + /* scsi-generic.c. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-include-Add-IEC-binary-prefixes-in-qemu-units.h.patch b/SOURCES/kvm-include-Add-IEC-binary-prefixes-in-qemu-units.h.patch new file mode 100644 index 0000000..64691bb --- /dev/null +++ b/SOURCES/kvm-include-Add-IEC-binary-prefixes-in-qemu-units.h.patch @@ -0,0 +1,61 @@ +From 887a7e12d07315fe03f0b8efe7054d7c4f946bc2 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 17:59:59 +0100 +Subject: [PATCH 25/34] include: Add IEC binary prefixes in "qemu/units.h" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-2-pbonzini@redhat.com> +Patchwork-id: 82941 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 1/9] include: Add IEC binary prefixes in "qemu/units.h" +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +From: Philippe Mathieu-Daudé + +Loosely based on 076b35b5a56. + +Suggested-by: Stefan Weil +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20180625124238.25339-2-f4bug@amsat.org> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 7ecdc94c40f4958a66893c0eac423c6a80f376d4) +Signed-off-by: Miroslav Rezanina +--- + include/qemu/units.h | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + create mode 100644 include/qemu/units.h + +diff --git a/include/qemu/units.h b/include/qemu/units.h +new file mode 100644 +index 0000000..692db3f +--- /dev/null ++++ b/include/qemu/units.h +@@ -0,0 +1,20 @@ ++/* ++ * IEC binary prefixes definitions ++ * ++ * Copyright (C) 2015 Nikunj A Dadhania, IBM Corporation ++ * Copyright (C) 2018 Philippe Mathieu-Daudé ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef QEMU_UNITS_H ++#define QEMU_UNITS_H ++ ++#define KiB (INT64_C(1) << 10) ++#define MiB (INT64_C(1) << 20) ++#define GiB (INT64_C(1) << 30) ++#define TiB (INT64_C(1) << 40) ++#define PiB (INT64_C(1) << 50) ++#define EiB (INT64_C(1) << 60) ++ ++#endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-include-Add-a-lookup-table-of-sizes.patch b/SOURCES/kvm-include-Add-a-lookup-table-of-sizes.patch new file mode 100644 index 0000000..7f6849c --- /dev/null +++ b/SOURCES/kvm-include-Add-a-lookup-table-of-sizes.patch @@ -0,0 +1,113 @@ +From c2b9a080a8c98bb536ce97c47efda84538458bd0 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:15 +0100 +Subject: [PATCH 14/23] include: Add a lookup table of sizes + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-6-kwolf@redhat.com> +Patchwork-id: 84545 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/13] include: Add a lookup table of sizes +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +Adding a lookup table for the powers of two, with the appropriate size +prefixes. This is needed when a size has to be stringified, in which +case something like '(1 * KiB)' would become a literal '(1 * (1L << 10))' +string. Powers of two are used very often for sizes, so such a table +will also make it easier and more intuitive to write them. + +This table is generatred using the following AWK script: + +BEGIN { + suffix="KMGTPE"; + for(i=10; i<64; i++) { + val=2**i; + s=substr(suffix, int(i/10), 1); + n=2**(i%10); + pad=21-int(log(n)/log(10)); + printf("#define S_%d%siB %*d\n", n, s, pad, val); + } +} + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 540b8492618ebbe98e7462bd7d31361b8cb10a05) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + include/qemu/units.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/include/qemu/units.h b/include/qemu/units.h +index 692db3f..68a7758 100644 +--- a/include/qemu/units.h ++++ b/include/qemu/units.h +@@ -17,4 +17,59 @@ + #define PiB (INT64_C(1) << 50) + #define EiB (INT64_C(1) << 60) + ++#define S_1KiB 1024 ++#define S_2KiB 2048 ++#define S_4KiB 4096 ++#define S_8KiB 8192 ++#define S_16KiB 16384 ++#define S_32KiB 32768 ++#define S_64KiB 65536 ++#define S_128KiB 131072 ++#define S_256KiB 262144 ++#define S_512KiB 524288 ++#define S_1MiB 1048576 ++#define S_2MiB 2097152 ++#define S_4MiB 4194304 ++#define S_8MiB 8388608 ++#define S_16MiB 16777216 ++#define S_32MiB 33554432 ++#define S_64MiB 67108864 ++#define S_128MiB 134217728 ++#define S_256MiB 268435456 ++#define S_512MiB 536870912 ++#define S_1GiB 1073741824 ++#define S_2GiB 2147483648 ++#define S_4GiB 4294967296 ++#define S_8GiB 8589934592 ++#define S_16GiB 17179869184 ++#define S_32GiB 34359738368 ++#define S_64GiB 68719476736 ++#define S_128GiB 137438953472 ++#define S_256GiB 274877906944 ++#define S_512GiB 549755813888 ++#define S_1TiB 1099511627776 ++#define S_2TiB 2199023255552 ++#define S_4TiB 4398046511104 ++#define S_8TiB 8796093022208 ++#define S_16TiB 17592186044416 ++#define S_32TiB 35184372088832 ++#define S_64TiB 70368744177664 ++#define S_128TiB 140737488355328 ++#define S_256TiB 281474976710656 ++#define S_512TiB 562949953421312 ++#define S_1PiB 1125899906842624 ++#define S_2PiB 2251799813685248 ++#define S_4PiB 4503599627370496 ++#define S_8PiB 9007199254740992 ++#define S_16PiB 18014398509481984 ++#define S_32PiB 36028797018963968 ++#define S_64PiB 72057594037927936 ++#define S_128PiB 144115188075855872 ++#define S_256PiB 288230376151711744 ++#define S_512PiB 576460752303423488 ++#define S_1EiB 1152921504606846976 ++#define S_2EiB 2305843009213693952 ++#define S_4EiB 4611686018427387904 ++#define S_8EiB 9223372036854775808 ++ + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-replace-more-vtd_err_-traces.patch b/SOURCES/kvm-intel-iommu-replace-more-vtd_err_-traces.patch new file mode 100644 index 0000000..876c913 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-replace-more-vtd_err_-traces.patch @@ -0,0 +1,212 @@ +From 20c0317b7984c5264e80c909227e1a78e82cc45a Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:17 +0100 +Subject: [PATCH 10/22] intel-iommu: replace more vtd_err_* traces +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-4-peterx@redhat.com> +Patchwork-id: 82953 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/7] intel-iommu: replace more vtd_err_* traces +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +Replace all the trace_vtd_err_*() hooks with the new error_report_once() +since they are similar to trace_vtd_err() - dumping the first error +would be mostly enough, then we have them on by default too. + +Signed-off-by: Peter Xu +Message-Id: <20180815095328.32414-4-peterx@redhat.com> +[Use "%x" instead of "%" PRIx16 to print uint16_t, whitespace tidied up] +Signed-off-by: Markus Armbruster +(cherry picked from commit 4e4abd111a2af0179a4467368d695958844bf113) +Signed-off-by: Peter Xu + +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 64 ++++++++++++++++++++++++++++++++++++--------------- + hw/i386/trace-events | 12 ---------- + 2 files changed, 46 insertions(+), 30 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index ab11cc4..aab86e9 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -705,7 +705,8 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, + uint64_t access_right_check; + + if (!vtd_iova_range_check(iova, ce, aw_bits)) { +- trace_vtd_err_dmar_iova_overflow(iova); ++ error_report_once("%s: detected IOVA overflow (iova=0x%" PRIx64 ")", ++ __func__, iova); + return -VTD_FR_ADDR_BEYOND_MGAW; + } + +@@ -717,7 +718,8 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, + slpte = vtd_get_slpte(addr, offset); + + if (slpte == (uint64_t)-1) { +- trace_vtd_err_dmar_slpte_read_error(iova, level); ++ error_report_once("%s: detected read error on DMAR slpte " ++ "(iova=0x%" PRIx64 ")", __func__, iova); + if (level == vtd_ce_get_level(ce)) { + /* Invalid programming of context-entry */ + return -VTD_FR_CONTEXT_ENTRY_INV; +@@ -728,11 +730,17 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, + *reads = (*reads) && (slpte & VTD_SL_R); + *writes = (*writes) && (slpte & VTD_SL_W); + if (!(slpte & access_right_check)) { +- trace_vtd_err_dmar_slpte_perm_error(iova, level, slpte, is_write); ++ error_report_once("%s: detected slpte permission error " ++ "(iova=0x%" PRIx64 ", level=0x%" PRIx32 ", " ++ "slpte=0x%" PRIx64 ", write=%d)", __func__, ++ iova, level, slpte, is_write); + return is_write ? -VTD_FR_WRITE : -VTD_FR_READ; + } + if (vtd_slpte_nonzero_rsvd(slpte, level)) { +- trace_vtd_err_dmar_slpte_resv_error(iova, level, slpte); ++ error_report_once("%s: detected splte reserve non-zero " ++ "iova=0x%" PRIx64 ", level=0x%" PRIx32 ++ "slpte=0x%" PRIx64 ")", __func__, iova, ++ level, slpte); + return -VTD_FR_PAGING_ENTRY_RSVD; + } + +@@ -1697,7 +1705,10 @@ static void vtd_handle_gcmd_qie(IntelIOMMUState *s, bool en) + /* Ok - report back to driver */ + vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_QIES, 0); + } else { +- trace_vtd_err_qi_disable(s->iq_head, s->iq_tail, s->iq_last_desc_type); ++ error_report_once("%s: detected improper state when disable QI " ++ "(head=0x%x, tail=0x%x, last_type=%d)", ++ __func__, ++ s->iq_head, s->iq_tail, s->iq_last_desc_type); + } + } + } +@@ -2094,7 +2105,9 @@ static void vtd_fetch_inv_desc(IntelIOMMUState *s) + + if (s->iq_tail >= s->iq_size) { + /* Detects an invalid Tail pointer */ +- trace_vtd_err_qi_tail(s->iq_tail, s->iq_size); ++ error_report_once("%s: detected invalid QI tail " ++ "(tail=0x%x, size=0x%x)", ++ __func__, s->iq_tail, s->iq_size); + vtd_handle_inv_queue_error(s); + return; + } +@@ -2507,10 +2520,12 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr, + iotlb.iova, iotlb.translated_addr, + iotlb.addr_mask); + } else { +- trace_vtd_err_dmar_translate(pci_bus_num(vtd_as->bus), +- VTD_PCI_SLOT(vtd_as->devfn), +- VTD_PCI_FUNC(vtd_as->devfn), +- iotlb.iova); ++ error_report_once("%s: detected translation failure " ++ "(dev=%02x:%02x:%02x, iova=0x%" PRIx64 ")", ++ __func__, pci_bus_num(vtd_as->bus), ++ VTD_PCI_SLOT(vtd_as->devfn), ++ VTD_PCI_FUNC(vtd_as->devfn), ++ iotlb.iova); + } + + return iotlb; +@@ -2626,15 +2641,19 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, + le64_to_cpu(entry->data[0])); + + if (!entry->irte.present) { +- trace_vtd_err_irte(index, le64_to_cpu(entry->data[1]), +- le64_to_cpu(entry->data[0])); ++ error_report_once("%s: detected non-present IRTE " ++ "(index=%u, high=0x%" PRIx64 ", low=0x%" PRIx64 ")", ++ __func__, index, le64_to_cpu(entry->data[1]), ++ le64_to_cpu(entry->data[0])); + return -VTD_FR_IR_ENTRY_P; + } + + if (entry->irte.__reserved_0 || entry->irte.__reserved_1 || + entry->irte.__reserved_2) { +- trace_vtd_err_irte(index, le64_to_cpu(entry->data[1]), +- le64_to_cpu(entry->data[0])); ++ error_report_once("%s: detected non-zero reserved IRTE " ++ "(index=%u, high=0x%" PRIx64 ", low=0x%" PRIx64 ")", ++ __func__, index, le64_to_cpu(entry->data[1]), ++ le64_to_cpu(entry->data[0])); + return -VTD_FR_IR_IRTE_RSVD; + } + +@@ -2648,7 +2667,9 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, + case VTD_SVT_ALL: + mask = vtd_svt_mask[entry->irte.sid_q]; + if ((source_id & mask) != (sid & mask)) { +- trace_vtd_err_irte_sid(index, sid, source_id); ++ error_report_once("%s: invalid IRTE SID " ++ "(index=%u, sid=%u, source_id=%u)", ++ __func__, index, sid, source_id); + return -VTD_FR_IR_SID_ERR; + } + break; +@@ -2658,13 +2679,17 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, + bus_min = source_id & 0xff; + bus = sid >> 8; + if (bus > bus_max || bus < bus_min) { +- trace_vtd_err_irte_sid_bus(index, bus, bus_min, bus_max); ++ error_report_once("%s: invalid SVT_BUS " ++ "(index=%u, bus=%u, min=%u, max=%u)", ++ __func__, index, bus, bus_min, bus_max); + return -VTD_FR_IR_SID_ERR; + } + break; + + default: +- trace_vtd_err_irte_svt(index, entry->irte.sid_vtype); ++ error_report_once("%s: detected invalid IRTE SVT " ++ "(index=%u, type=%d)", __func__, ++ index, entry->irte.sid_vtype); + /* Take this as verification failure. */ + return -VTD_FR_IR_SID_ERR; + break; +@@ -2786,7 +2811,10 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, + if (addr.addr.sub_valid) { + trace_vtd_ir_remap_type("MSI"); + if (origin->data & VTD_IR_MSI_DATA_RESERVED) { +- trace_vtd_err_ir_msi_invalid(sid, origin->address, origin->data); ++ error_report_once("%s: invalid IR MSI " ++ "(sid=%u, address=0x%" PRIx64 ++ ", data=0x%" PRIx32 ")", ++ __func__, sid, origin->address, origin->data); + return -VTD_FR_IR_REQ_RSVD; + } + } else { +diff --git a/hw/i386/trace-events b/hw/i386/trace-events +index 922431b..9e6fc4d 100644 +--- a/hw/i386/trace-events ++++ b/hw/i386/trace-events +@@ -69,19 +69,7 @@ vtd_ir_remap_msi_req(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PR + vtd_fsts_ppf(bool set) "FSTS PPF bit set to %d" + vtd_fsts_clear_ip(void) "" + vtd_frr_new(int index, uint64_t hi, uint64_t lo) "index %d high 0x%"PRIx64" low 0x%"PRIx64 +-vtd_err_dmar_iova_overflow(uint64_t iova) "iova 0x%"PRIx64 +-vtd_err_dmar_slpte_read_error(uint64_t iova, int level) "iova 0x%"PRIx64" level %d" +-vtd_err_dmar_slpte_perm_error(uint64_t iova, int level, uint64_t slpte, bool is_write) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64" write %d" +-vtd_err_dmar_slpte_resv_error(uint64_t iova, int level, uint64_t slpte) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64 +-vtd_err_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova) "dev %02x:%02x.%02x iova 0x%"PRIx64 + vtd_warn_invalid_qi_tail(uint16_t tail) "tail 0x%"PRIx16 +-vtd_err_qi_disable(uint16_t head, uint16_t tail, int type) "head 0x%"PRIx16" tail 0x%"PRIx16" last_desc_type %d" +-vtd_err_qi_tail(uint16_t tail, uint16_t size) "tail 0x%"PRIx16" size 0x%"PRIx16 +-vtd_err_irte(int index, uint64_t lo, uint64_t hi) "index %d low 0x%"PRIx64" high 0x%"PRIx64 +-vtd_err_irte_sid(int index, uint16_t req, uint16_t target) "index %d SVT_ALL sid 0x%"PRIx16" (should be: 0x%"PRIx16")" +-vtd_err_irte_sid_bus(int index, uint8_t bus, uint8_t min, uint8_t max) "index %d SVT_BUS bus 0x%"PRIx8" (should be: 0x%"PRIx8"-0x%"PRIx8")" +-vtd_err_irte_svt(int index, int type) "index %d SVT type %d" +-vtd_err_ir_msi_invalid(uint16_t sid, uint64_t addr, uint64_t data) "sid 0x%"PRIx16" addr 0x%"PRIx64" data 0x%"PRIx64 + vtd_warn_ir_vector(uint16_t sid, int index, int vec, int target) "sid 0x%"PRIx16" index %d vec %d (should be: %d)" + vtd_warn_ir_trigger(uint16_t sid, int index, int trig, int target) "sid 0x%"PRIx16" index %d trigger %d (should be: %d)" + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-start-to-use-error_report_once.patch b/SOURCES/kvm-intel-iommu-start-to-use-error_report_once.patch new file mode 100644 index 0000000..9f44d7a --- /dev/null +++ b/SOURCES/kvm-intel-iommu-start-to-use-error_report_once.patch @@ -0,0 +1,236 @@ +From 6c5d8bb3a12e24bdd909beb2ed2c9d6adffdef36 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:16 +0100 +Subject: [PATCH 09/22] intel-iommu: start to use error_report_once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-3-peterx@redhat.com> +Patchwork-id: 82954 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/7] intel-iommu: start to use error_report_once +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +Replace existing trace_vtd_err() with error_report_once() then stderr +will capture something if any of the error happens, meanwhile we don't +suffer from any DDOS. Then remove the trace point. Since at it, +provide more information where proper (now we can pass parameters into +the report function). + +Signed-off-by: Peter Xu +Message-Id: <20180815095328.32414-3-peterx@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +[Two format strings fixed, whitespace tidied up] +Signed-off-by: Markus Armbruster +(cherry picked from commit 1376211f77bdcd84dc4acb877690f7399d8cf58a) +Signed-off-by: Peter Xu + +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 65 +++++++++++++++++++++++++++++---------------------- + hw/i386/trace-events | 1 - + 2 files changed, 37 insertions(+), 29 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index b5a09b7..ab11cc4 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -311,14 +311,14 @@ static void vtd_generate_fault_event(IntelIOMMUState *s, uint32_t pre_fsts) + { + if (pre_fsts & VTD_FSTS_PPF || pre_fsts & VTD_FSTS_PFO || + pre_fsts & VTD_FSTS_IQE) { +- trace_vtd_err("There are previous interrupt conditions " +- "to be serviced by software, fault event " +- "is not generated."); ++ error_report_once("There are previous interrupt conditions " ++ "to be serviced by software, fault event " ++ "is not generated"); + return; + } + vtd_set_clear_mask_long(s, DMAR_FECTL_REG, 0, VTD_FECTL_IP); + if (vtd_get_long_raw(s, DMAR_FECTL_REG) & VTD_FECTL_IM) { +- trace_vtd_err("Interrupt Mask set, irq is not generated."); ++ error_report_once("Interrupt Mask set, irq is not generated"); + } else { + vtd_generate_interrupt(s, DMAR_FEADDR_REG, DMAR_FEDATA_REG); + vtd_set_clear_mask_long(s, DMAR_FECTL_REG, VTD_FECTL_IP, 0); +@@ -426,20 +426,20 @@ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, + trace_vtd_dmar_fault(source_id, fault, addr, is_write); + + if (fsts_reg & VTD_FSTS_PFO) { +- trace_vtd_err("New fault is not recorded due to " +- "Primary Fault Overflow."); ++ error_report_once("New fault is not recorded due to " ++ "Primary Fault Overflow"); + return; + } + + if (vtd_try_collapse_fault(s, source_id)) { +- trace_vtd_err("New fault is not recorded due to " +- "compression of faults."); ++ error_report_once("New fault is not recorded due to " ++ "compression of faults"); + return; + } + + if (vtd_is_frcd_set(s, s->next_frcd_reg)) { +- trace_vtd_err("Next Fault Recording Reg is used, " +- "new fault is not recorded, set PFO field."); ++ error_report_once("Next Fault Recording Reg is used, " ++ "new fault is not recorded, set PFO field"); + vtd_set_clear_mask_long(s, DMAR_FSTS_REG, 0, VTD_FSTS_PFO); + return; + } +@@ -447,8 +447,8 @@ static void vtd_report_dmar_fault(IntelIOMMUState *s, uint16_t source_id, + vtd_record_frcd(s, s->next_frcd_reg, source_id, addr, fault, is_write); + + if (fsts_reg & VTD_FSTS_PPF) { +- trace_vtd_err("There are pending faults already, " +- "fault event is not generated."); ++ error_report_once("There are pending faults already, " ++ "fault event is not generated"); + vtd_set_frcd_and_update_ppf(s, s->next_frcd_reg); + s->next_frcd_reg++; + if (s->next_frcd_reg == DMAR_FRCD_REG_NR) { +@@ -1056,8 +1056,10 @@ static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, + * we just skip the sync for this time. After all we even + * don't have the root table pointer! + */ +- trace_vtd_err("Detected invalid context entry when " +- "trying to sync shadow page table"); ++ error_report_once("%s: invalid context entry for bus 0x%x" ++ " devfn 0x%x", ++ __func__, pci_bus_num(vtd_as->bus), ++ vtd_as->devfn); + return 0; + } + } +@@ -1514,7 +1516,8 @@ static uint64_t vtd_context_cache_invalidate(IntelIOMMUState *s, uint64_t val) + break; + + default: +- trace_vtd_err("Context cache invalidate type error."); ++ error_report_once("%s: invalid context: 0x%" PRIx64, ++ __func__, val); + caig = 0; + } + return caig; +@@ -1634,7 +1637,8 @@ static uint64_t vtd_iotlb_flush(IntelIOMMUState *s, uint64_t val) + am = VTD_IVA_AM(addr); + addr = VTD_IVA_ADDR(addr); + if (am > VTD_MAMV) { +- trace_vtd_err("IOTLB PSI flush: address mask overflow."); ++ error_report_once("%s: address mask overflow: 0x%" PRIx64, ++ __func__, vtd_get_quad_raw(s, DMAR_IVA_REG)); + iaig = 0; + break; + } +@@ -1643,7 +1647,8 @@ static uint64_t vtd_iotlb_flush(IntelIOMMUState *s, uint64_t val) + break; + + default: +- trace_vtd_err("IOTLB flush: invalid granularity."); ++ error_report_once("%s: invalid granularity: 0x%" PRIx64, ++ __func__, val); + iaig = 0; + } + return iaig; +@@ -1793,8 +1798,8 @@ static void vtd_handle_ccmd_write(IntelIOMMUState *s) + /* Context-cache invalidation request */ + if (val & VTD_CCMD_ICC) { + if (s->qi_enabled) { +- trace_vtd_err("Queued Invalidation enabled, " +- "should not use register-based invalidation"); ++ error_report_once("Queued Invalidation enabled, " ++ "should not use register-based invalidation"); + return; + } + ret = vtd_context_cache_invalidate(s, val); +@@ -1814,8 +1819,8 @@ static void vtd_handle_iotlb_write(IntelIOMMUState *s) + /* IOTLB invalidation request */ + if (val & VTD_TLB_IVT) { + if (s->qi_enabled) { +- trace_vtd_err("Queued Invalidation enabled, " +- "should not use register-based invalidation."); ++ error_report_once("Queued Invalidation enabled, " ++ "should not use register-based invalidation"); + return; + } + ret = vtd_iotlb_flush(s, val); +@@ -1833,7 +1838,7 @@ static bool vtd_get_inv_desc(dma_addr_t base_addr, uint32_t offset, + dma_addr_t addr = base_addr + offset * sizeof(*inv_desc); + if (dma_memory_read(&address_space_memory, addr, inv_desc, + sizeof(*inv_desc))) { +- trace_vtd_err("Read INV DESC failed."); ++ error_report_once("Read INV DESC failed"); + inv_desc->lo = 0; + inv_desc->hi = 0; + return false; +@@ -2188,7 +2193,8 @@ static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size) + trace_vtd_reg_read(addr, size); + + if (addr + size > DMAR_REG_SIZE) { +- trace_vtd_err("Read MMIO over range."); ++ error_report_once("%s: MMIO over range: addr=0x%" PRIx64 ++ " size=0x%u", __func__, addr, size); + return (uint64_t)-1; + } + +@@ -2239,7 +2245,8 @@ static void vtd_mem_write(void *opaque, hwaddr addr, + trace_vtd_reg_write(addr, size, val); + + if (addr + size > DMAR_REG_SIZE) { +- trace_vtd_err("Write MMIO over range."); ++ error_report_once("%s: MMIO over range: addr=0x%" PRIx64 ++ " size=0x%u", __func__, addr, size); + return; + } + +@@ -2610,7 +2617,8 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, + addr = iommu->intr_root + index * sizeof(*entry); + if (dma_memory_read(&address_space_memory, addr, entry, + sizeof(*entry))) { +- trace_vtd_err("Memory read failed for IRTE."); ++ error_report_once("%s: read failed: ind=0x%x addr=0x%" PRIx64, ++ __func__, index, addr); + return -VTD_FR_IR_ROOT_INVAL; + } + +@@ -2742,14 +2750,15 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, + } + + if (origin->address & VTD_MSI_ADDR_HI_MASK) { +- trace_vtd_err("MSI address high 32 bits non-zero when " +- "Interrupt Remapping enabled."); ++ error_report_once("%s: MSI address high 32 bits non-zero detected: " ++ "address=0x%" PRIx64, __func__, origin->address); + return -VTD_FR_IR_REQ_RSVD; + } + + addr.data = origin->address & VTD_MSI_ADDR_LO_MASK; + if (addr.addr.__head != 0xfee) { +- trace_vtd_err("MSI addr low 32 bit invalid."); ++ error_report_once("%s: MSI address low 32 bit invalid: 0x%" PRIx32, ++ __func__, addr.data); + return -VTD_FR_IR_REQ_RSVD; + } + +diff --git a/hw/i386/trace-events b/hw/i386/trace-events +index e14d06e..922431b 100644 +--- a/hw/i386/trace-events ++++ b/hw/i386/trace-events +@@ -69,7 +69,6 @@ vtd_ir_remap_msi_req(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PR + vtd_fsts_ppf(bool set) "FSTS PPF bit set to %d" + vtd_fsts_clear_ip(void) "" + vtd_frr_new(int index, uint64_t hi, uint64_t lo) "index %d high 0x%"PRIx64" low 0x%"PRIx64 +-vtd_err(const char *str) "%s" + vtd_err_dmar_iova_overflow(uint64_t iova) "iova 0x%"PRIx64 + vtd_err_dmar_slpte_read_error(uint64_t iova, int level) "iova 0x%"PRIx64" level %d" + vtd_err_dmar_slpte_perm_error(uint64_t iova, int level, uint64_t slpte, bool is_write) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64" write %d" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel_iommu-better-handling-of-dmar-state-switch.patch b/SOURCES/kvm-intel_iommu-better-handling-of-dmar-state-switch.patch new file mode 100644 index 0000000..734b44d --- /dev/null +++ b/SOURCES/kvm-intel_iommu-better-handling-of-dmar-state-switch.patch @@ -0,0 +1,150 @@ +From ad285b807f37f16571d03e7667ea7200fb9b25a7 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:19 +0100 +Subject: [PATCH 12/22] intel_iommu: better handling of dmar state switch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-6-peterx@redhat.com> +Patchwork-id: 82956 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 5/7] intel_iommu: better handling of dmar state switch +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +QEMU is not handling the global DMAR switch well, especially when from +"on" to "off". + +Let's first take the example of system reset. + +Assuming that a guest has IOMMU enabled. When it reboots, we will drop +all the existing DMAR mappings to handle the system reset, however we'll +still keep the existing memory layouts which has the IOMMU memory region +enabled. So after the reboot and before the kernel reloads again, there +will be no mapping at all for the host device. That's problematic since +any software (for example, SeaBIOS) that runs earlier than the kernel +after the reboot will assume the IOMMU is disabled, so any DMA from the +software will fail. + +For example, a guest that boots on an assigned NVMe device might fail to +find the boot device after a system reboot/reset and we'll be able to +observe SeaBIOS errors if we capture the debugging log: + + WARNING - Timeout at nvme_wait:144! + +Meanwhile, we should see DMAR errors on the host of that NVMe device. +It's the DMA fault that caused a NVMe driver timeout. + +The correct fix should be that we do proper switching of device DMA +address spaces when system resets, which will setup correct memory +regions and notify the backend of the devices. This might not affect +much on non-assigned devices since QEMU VT-d emulation will assume a +default passthrough mapping if DMAR is not enabled in the GCMD +register (please refer to vtd_iommu_translate). However that's required +for an assigned devices, since that'll rebuild the correct GPA to HPA +mapping that is needed for any DMA operation during guest bootstrap. + +Besides the system reset, we have some other places that might change +the global DMAR status and we'd better do the same thing there. For +example, when we change the state of GCMD register, or the DMAR root +pointer. Do the same refresh for all these places. For these two +places we'll also need to explicitly invalidate the context entry cache +and iotlb cache. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1625173 +CC: QEMU Stable +Reported-by: Cong Li +Signed-off-by: Peter Xu +-- +v2: +- do the same for GCMD write, or root pointer update [Alex] +- test is carried out by me this time, by observing the + vtd_switch_address_space tracepoint after system reboot +v3: +- rewrite commit message as suggested by Alex +Signed-off-by: Peter Xu +Reviewed-by: Eric Auger +Reviewed-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 2cc9ddccebcaa48b3debfc279a83761fcbb7616c) +Signed-off-by: Peter Xu + +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 48d0ba3..a6e87a9 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -37,6 +37,8 @@ + #include "kvm_i386.h" + #include "trace.h" + ++static void vtd_address_space_refresh_all(IntelIOMMUState *s); ++ + static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t wmask, uint64_t w1cmask) + { +@@ -1436,7 +1438,7 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s) + vtd_reset_context_cache_locked(s); + } + vtd_iommu_unlock(s); +- vtd_switch_address_space_all(s); ++ vtd_address_space_refresh_all(s); + /* + * From VT-d spec 6.5.2.1, a global context entry invalidation + * should be followed by a IOTLB global invalidation, so we should +@@ -1727,6 +1729,8 @@ static void vtd_handle_gcmd_srtp(IntelIOMMUState *s) + vtd_root_table_setup(s); + /* Ok - report back to driver */ + vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_RTPS); ++ vtd_reset_caches(s); ++ vtd_address_space_refresh_all(s); + } + + /* Set Interrupt Remap Table Pointer */ +@@ -1759,7 +1763,8 @@ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en) + vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_TES, 0); + } + +- vtd_switch_address_space_all(s); ++ vtd_reset_caches(s); ++ vtd_address_space_refresh_all(s); + } + + /* Handle Interrupt Remap Enable/Disable */ +@@ -3059,6 +3064,12 @@ static void vtd_address_space_unmap_all(IntelIOMMUState *s) + } + } + ++static void vtd_address_space_refresh_all(IntelIOMMUState *s) ++{ ++ vtd_address_space_unmap_all(s); ++ vtd_switch_address_space_all(s); ++} ++ + static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) + { + memory_region_notify_one((IOMMUNotifier *)private, entry); +@@ -3231,11 +3242,7 @@ static void vtd_reset(DeviceState *dev) + IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev); + + vtd_init(s); +- +- /* +- * When device reset, throw away all mappings and external caches +- */ +- vtd_address_space_unmap_all(s); ++ vtd_address_space_refresh_all(s); + } + + static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel_iommu-handle-invalid-ce-for-shadow-sync.patch b/SOURCES/kvm-intel_iommu-handle-invalid-ce-for-shadow-sync.patch new file mode 100644 index 0000000..64f8ee0 --- /dev/null +++ b/SOURCES/kvm-intel_iommu-handle-invalid-ce-for-shadow-sync.patch @@ -0,0 +1,89 @@ +From 80fe503d7c126fa2be6cc424593cae6c522f65e0 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:21 +0100 +Subject: [PATCH 14/22] intel_iommu: handle invalid ce for shadow sync +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-8-peterx@redhat.com> +Patchwork-id: 82958 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 7/7] intel_iommu: handle invalid ce for shadow sync +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +We should handle VTD_FR_CONTEXT_ENTRY_P properly when synchronizing +shadow page tables. Having invalid context entry there is perfectly +valid when we move a device out of an existing domain. When that +happens, instead of posting an error we invalidate the whole region. + +Without this patch, QEMU will crash if we do these steps: + +(1) start QEMU with VT-d IOMMU and two 10G NICs (ixgbe) +(2) bind the NICs with vfio-pci in the guest +(3) start testpmd with the NICs applied +(4) stop testpmd +(5) rebind the NIC back to ixgbe kernel driver + +The patch should fix it. + +Reported-by: Pei Zhang +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1627272 +Signed-off-by: Peter Xu +Reviewed-by: Eric Auger +Reviewed-by: Maxime Coquelin +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit c28b535d083d0a263d38d9ceeada83cdae8c64f0) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index c95128d..12af410 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -38,6 +38,7 @@ + #include "trace.h" + + static void vtd_address_space_refresh_all(IntelIOMMUState *s); ++static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n); + + static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val, + uint64_t wmask, uint64_t w1cmask) +@@ -1066,11 +1067,27 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) + { + int ret; + VTDContextEntry ce; ++ IOMMUNotifier *n; + + ret = vtd_dev_to_context_entry(vtd_as->iommu_state, + pci_bus_num(vtd_as->bus), + vtd_as->devfn, &ce); + if (ret) { ++ if (ret == -VTD_FR_CONTEXT_ENTRY_P) { ++ /* ++ * It's a valid scenario to have a context entry that is ++ * not present. For example, when a device is removed ++ * from an existing domain then the context entry will be ++ * zeroed by the guest before it was put into another ++ * domain. When this happens, instead of synchronizing ++ * the shadow pages we should invalidate all existing ++ * mappings and notify the backends. ++ */ ++ IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) { ++ vtd_address_space_unmap(vtd_as, n); ++ } ++ ret = 0; ++ } + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel_iommu-introduce-vtd_reset_caches.patch b/SOURCES/kvm-intel_iommu-introduce-vtd_reset_caches.patch new file mode 100644 index 0000000..4e6c1b2 --- /dev/null +++ b/SOURCES/kvm-intel_iommu-introduce-vtd_reset_caches.patch @@ -0,0 +1,66 @@ +From 7fc26da32e430d69df4ca9f74047310583c97e79 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:18 +0100 +Subject: [PATCH 11/22] intel_iommu: introduce vtd_reset_caches() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-5-peterx@redhat.com> +Patchwork-id: 82955 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/7] intel_iommu: introduce vtd_reset_caches() +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +Provide the function and use it in vtd_init(). Used to reset both +context entry cache and iotlb cache for the whole IOMMU unit. + +Signed-off-by: Peter Xu +Reviewed-by: Eric Auger +Reviewed-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 06aba4ca52fd2c8718b8ba486f22f0aa7c99ed55) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index aab86e9..48d0ba3 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -227,6 +227,14 @@ static void vtd_reset_iotlb(IntelIOMMUState *s) + vtd_iommu_unlock(s); + } + ++static void vtd_reset_caches(IntelIOMMUState *s) ++{ ++ vtd_iommu_lock(s); ++ vtd_reset_iotlb_locked(s); ++ vtd_reset_context_cache_locked(s); ++ vtd_iommu_unlock(s); ++} ++ + static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint16_t source_id, + uint32_t level) + { +@@ -3160,10 +3168,7 @@ static void vtd_init(IntelIOMMUState *s) + s->cap |= VTD_CAP_CM; + } + +- vtd_iommu_lock(s); +- vtd_reset_context_cache_locked(s); +- vtd_reset_iotlb_locked(s); +- vtd_iommu_unlock(s); ++ vtd_reset_caches(s); + + /* Define registers with default values and bit semantics */ + vtd_define_long(s, DMAR_VER_REG, 0x10UL, 0, 0); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel_iommu-move-ce-fetching-out-when-sync-shadow.patch b/SOURCES/kvm-intel_iommu-move-ce-fetching-out-when-sync-shadow.patch new file mode 100644 index 0000000..d19c107 --- /dev/null +++ b/SOURCES/kvm-intel_iommu-move-ce-fetching-out-when-sync-shadow.patch @@ -0,0 +1,110 @@ +From 5caab2b4c1876c564f8f9afee0a80a00e1a8880f Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:20 +0100 +Subject: [PATCH 13/22] intel_iommu: move ce fetching out when sync shadow +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-7-peterx@redhat.com> +Patchwork-id: 82957 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 6/7] intel_iommu: move ce fetching out when sync shadow +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +There are two callers for vtd_sync_shadow_page_table_range(): one +provided a valid context entry and one not. Move that fetching +operation into the caller vtd_sync_shadow_page_table() where we need to +fetch the context entry. + +Meanwhile, remove the error_report_once() directly since we're already +tracing all the error cases in the previous call. Instead, return error +number back to caller. This will not change anything functional since +callers are dropping it after all. + +We do this move majorly because we want to do something more later in +vtd_sync_shadow_page_table(). + +Signed-off-by: Peter Xu +Reviewed-by: Eric Auger +Reviewed-by: Maxime Coquelin +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 95ecd3df7815b4bc4f9a0f47e1c64d81434715aa) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 41 +++++++++++++---------------------------- + 1 file changed, 13 insertions(+), 28 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index a6e87a9..c95128d 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -1045,7 +1045,6 @@ static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry, + return 0; + } + +-/* If context entry is NULL, we'll try to fetch it on our own. */ + static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, + VTDContextEntry *ce, + hwaddr addr, hwaddr size) +@@ -1057,39 +1056,25 @@ static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, + .notify_unmap = true, + .aw = s->aw_bits, + .as = vtd_as, ++ .domain_id = VTD_CONTEXT_ENTRY_DID(ce->hi), + }; +- VTDContextEntry ce_cache; +- int ret; +- +- if (ce) { +- /* If the caller provided context entry, use it */ +- ce_cache = *ce; +- } else { +- /* If the caller didn't provide ce, try to fetch */ +- ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), +- vtd_as->devfn, &ce_cache); +- if (ret) { +- /* +- * This should not really happen, but in case it happens, +- * we just skip the sync for this time. After all we even +- * don't have the root table pointer! +- */ +- error_report_once("%s: invalid context entry for bus 0x%x" +- " devfn 0x%x", +- __func__, pci_bus_num(vtd_as->bus), +- vtd_as->devfn); +- return 0; +- } +- } + +- info.domain_id = VTD_CONTEXT_ENTRY_DID(ce_cache.hi); +- +- return vtd_page_walk(&ce_cache, addr, addr + size, &info); ++ return vtd_page_walk(ce, addr, addr + size, &info); + } + + static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) + { +- return vtd_sync_shadow_page_table_range(vtd_as, NULL, 0, UINT64_MAX); ++ int ret; ++ VTDContextEntry ce; ++ ++ ret = vtd_dev_to_context_entry(vtd_as->iommu_state, ++ pci_bus_num(vtd_as->bus), ++ vtd_as->devfn, &ce); ++ if (ret) { ++ return ret; ++ } ++ ++ return vtd_sync_shadow_page_table_range(vtd_as, &ce, 0, UINT64_MAX); + } + + /* +-- +1.8.3.1 + diff --git a/SOURCES/kvm-io-return-0-for-EOF-in-TLS-session-read-after-shutdo.patch b/SOURCES/kvm-io-return-0-for-EOF-in-TLS-session-read-after-shutdo.patch new file mode 100644 index 0000000..53781f6 --- /dev/null +++ b/SOURCES/kvm-io-return-0-for-EOF-in-TLS-session-read-after-shutdo.patch @@ -0,0 +1,127 @@ +From d3244c405b0968db4629855567c3a2c7729bea36 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:31 +0100 +Subject: [PATCH 064/163] io: return 0 for EOF in TLS session read after + shutdown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-19-jsnow@redhat.com> +Patchwork-id: 85099 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 18/28] io: return 0 for EOF in TLS session read after shutdown +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +GNUTLS takes a paranoid approach when seeing 0 bytes returned by the +underlying OS read() function. It will consider this an error and +return GNUTLS_E_PREMATURE_TERMINATION instead of propagating the 0 +return value. It expects apps to arrange for clean termination at +the protocol level and not rely on seeing EOF from a read call to +detect shutdown. This is to harden apps against a malicious 3rd party +causing termination of the sockets layer. + +This is unhelpful for the QEMU NBD code which does have a clean +protocol level shutdown, but still relies on seeing 0 from the I/O +channel read in the coroutine handling incoming replies. + +The upshot is that when using a plain NBD connection shutdown is +silent, but when using TLS, the client spams the console with + + Cannot read from TLS channel: Broken pipe + +The NBD connection has, however, called qio_channel_shutdown() +at this point to indicate that it is done with I/O. This gives +the opportunity to optimize the code such that when the channel +has been shutdown in the read direction, the error code +GNUTLS_E_PREMATURE_TERMINATION gets turned into a '0' return +instead of an error. + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20181119134228.11031-1-berrange@redhat.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +(cherry picked from commit a2458b6f6998c9a079f710ed7495d5c6f037e942) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + crypto/tlssession.c | 3 +++ + include/io/channel-tls.h | 1 + + include/io/channel.h | 6 +++--- + io/channel-tls.c | 5 +++++ + 4 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/crypto/tlssession.c b/crypto/tlssession.c +index 96a02de..68e0114 100644 +--- a/crypto/tlssession.c ++++ b/crypto/tlssession.c +@@ -427,6 +427,9 @@ qcrypto_tls_session_read(QCryptoTLSSession *session, + case GNUTLS_E_INTERRUPTED: + errno = EINTR; + break; ++ case GNUTLS_E_PREMATURE_TERMINATION: ++ errno = ECONNABORTED; ++ break; + default: + errno = EIO; + break; +diff --git a/include/io/channel-tls.h b/include/io/channel-tls.h +index 87fcaf9..fdbdf12 100644 +--- a/include/io/channel-tls.h ++++ b/include/io/channel-tls.h +@@ -48,6 +48,7 @@ struct QIOChannelTLS { + QIOChannel parent; + QIOChannel *master; + QCryptoTLSSession *session; ++ QIOChannelShutdown shutdown; + }; + + /** +diff --git a/include/io/channel.h b/include/io/channel.h +index e8cdadb..da2f138 100644 +--- a/include/io/channel.h ++++ b/include/io/channel.h +@@ -51,9 +51,9 @@ enum QIOChannelFeature { + typedef enum QIOChannelShutdown QIOChannelShutdown; + + enum QIOChannelShutdown { +- QIO_CHANNEL_SHUTDOWN_BOTH, +- QIO_CHANNEL_SHUTDOWN_READ, +- QIO_CHANNEL_SHUTDOWN_WRITE, ++ QIO_CHANNEL_SHUTDOWN_READ = 1, ++ QIO_CHANNEL_SHUTDOWN_WRITE = 2, ++ QIO_CHANNEL_SHUTDOWN_BOTH = 3, + }; + + typedef gboolean (*QIOChannelFunc)(QIOChannel *ioc, +diff --git a/io/channel-tls.c b/io/channel-tls.c +index 9628e6f..c98ead2 100644 +--- a/io/channel-tls.c ++++ b/io/channel-tls.c +@@ -275,6 +275,9 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc, + } else { + return QIO_CHANNEL_ERR_BLOCK; + } ++ } else if (errno == ECONNABORTED && ++ (tioc->shutdown & QIO_CHANNEL_SHUTDOWN_READ)) { ++ return 0; + } + + error_setg_errno(errp, errno, +@@ -357,6 +360,8 @@ static int qio_channel_tls_shutdown(QIOChannel *ioc, + { + QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); + ++ tioc->shutdown |= how; ++ + return qio_channel_shutdown(tioc->master, how, errp); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotest-Fix-241-to-run-in-generic-directory.patch b/SOURCES/kvm-iotest-Fix-241-to-run-in-generic-directory.patch new file mode 100644 index 0000000..85739ed --- /dev/null +++ b/SOURCES/kvm-iotest-Fix-241-to-run-in-generic-directory.patch @@ -0,0 +1,82 @@ +From 295b60369a025fd61f3abe3e6edbd2b298ba8314 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:29 +0200 +Subject: [PATCH 19/53] iotest: Fix 241 to run in generic directory + +RH-Author: John Snow +Message-id: <20190506175629.11079-20-jsnow@redhat.com> +Patchwork-id: 87200 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 19/19] iotest: Fix 241 to run in generic directory +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Filter the qemu-nbd server output to get rid of a direct reference +to my build directory. + +Fixes: e9dce9cb +Reported-by: Max Reitz +Signed-off-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit 9749636b005d118259810afb92482df2fe0ae2ad) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/241 | 4 +++- + tests/qemu-iotests/241.out | 6 +++--- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/tests/qemu-iotests/241 b/tests/qemu-iotests/241 +index 4b19685..017a736 100755 +--- a/tests/qemu-iotests/241 ++++ b/tests/qemu-iotests/241 +@@ -28,6 +28,7 @@ nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket + _cleanup() + { + _cleanup_test_img ++ rm -f "$TEST_DIR/server.log" + nbd_server_stop + } + trap "_cleanup; exit \$status" 0 1 2 3 15 +@@ -69,12 +70,13 @@ echo + + # Intentionally omit '-f' to force image probing, which in turn forces + # sector alignment, here at the server. +-nbd_server_start_unix_socket "$TEST_IMG_FILE" ++nbd_server_start_unix_socket "$TEST_IMG_FILE" 2> "$TEST_DIR/server.log" + + $QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)' + $QEMU_IMG map -f raw --output=json "$TEST_IMG" | _filter_qemu_img_map + $QEMU_IO -f raw -c map "$TEST_IMG" + nbd_server_stop ++cat "$TEST_DIR/server.log" | _filter_testdir + + echo + echo "=== Exporting unaligned raw image, forced client sector alignment ===" +diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out +index f481074..75f9f46 100644 +--- a/tests/qemu-iotests/241.out ++++ b/tests/qemu-iotests/241.out +@@ -10,13 +10,13 @@ QA output created by 241 + + === Exporting unaligned raw image, forced server sector alignment === + +-WARNING: Image format was not specified for '/home/eblake/qemu/tests/qemu-iotests/scratch/t.raw' and probing guessed raw. +- Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +- Specify the 'raw' format explicitly to remove the restrictions. + size: 1024 + min block: 512 + [{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] + 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) ++WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. + + === Exporting unaligned raw image, forced client sector alignment === + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotest-Fix-filtering-order-in-226.patch b/SOURCES/kvm-iotest-Fix-filtering-order-in-226.patch new file mode 100644 index 0000000..9574eac --- /dev/null +++ b/SOURCES/kvm-iotest-Fix-filtering-order-in-226.patch @@ -0,0 +1,55 @@ +From 97f1ac94b611b8e6c319696ac8a92aded5395ef5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 17:12:05 +0100 +Subject: [PATCH 034/163] iotest: Fix filtering order in 226 + +RH-Author: John Snow +Message-id: <20190320171206.19236-2-jsnow@redhat.com> +Patchwork-id: 84960 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/2] iotest: Fix filtering order in 226 +Bugzilla: 1691018 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Sergio Lopez Pascual + +From: Max Reitz + +The test directory should be filtered before the image format, otherwise +the test will fail if the image format is part of the test directory, +like so: + +[...] +-can't open: Could not open 'TEST_DIR/t.IMGFMT': Is a directory ++can't open: Could not open '/tmp/test-IMGFMT/t.IMGFMT': Is a directory +[...] + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit d6e4ca902148f33cfaf117396f57c7fff7c635f0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/226 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226 +index 460aea2..a5a1f67 100755 +--- a/tests/qemu-iotests/226 ++++ b/tests/qemu-iotests/226 +@@ -52,10 +52,10 @@ for PROTO in "file" "host_device" "host_cdrom"; do + echo "=== Testing with driver:$PROTO ===" + echo + echo "== Testing RO ==" +- $QEMU_IO -c "open -r -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_imgfmt | _filter_testdir ++ $QEMU_IO -c "open -r -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt + $QEMU_IO -c "open -r -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt + echo "== Testing RW ==" +- $QEMU_IO -c "open -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_imgfmt | _filter_testdir ++ $QEMU_IO -c "open -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt + $QEMU_IO -c "open -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt + done + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-153-Fix-dead-code.patch b/SOURCES/kvm-iotests-153-Fix-dead-code.patch new file mode 100644 index 0000000..87c7c34 --- /dev/null +++ b/SOURCES/kvm-iotests-153-Fix-dead-code.patch @@ -0,0 +1,90 @@ +From ddc6da501740a60c1e7356e60928845be6ca2cda Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:01 +0100 +Subject: [PATCH 01/33] iotests: 153: Fix dead code + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-2-mreitz@redhat.com> +Patchwork-id: 84219 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/7] iotests: 153: Fix dead code +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +From: Fam Zheng + +This step was left behind my mistake. As suggested by the echoed text, +the intention was to test two devices with the same image, with +different options. The behavior should be the same as two QEMU +processes. Complete it. + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 0e1a582750269d3dde0481ca034b08a5784e430c) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/153 | 2 ++ + tests/qemu-iotests/153.out | 25 +++++++++++++++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 +index 673813c..0daeb1b 100755 +--- a/tests/qemu-iotests/153 ++++ b/tests/qemu-iotests/153 +@@ -162,6 +162,7 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do + _cleanup_qemu + done + ++test_opts="read-only=off read-only=on read-only=on,force-share=on" + for opt1 in $test_opts; do + for opt2 in $test_opts; do + echo +@@ -170,6 +171,7 @@ for opt1 in $test_opts; do + done + done + ++echo + echo "== Creating ${TEST_IMG}.[abc] ==" | _filter_testdir + ( + $QEMU_IMG create -f qcow2 "${TEST_IMG}.a" -b "${TEST_IMG}" +diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out +index 3492ba7..93eaf10 100644 +--- a/tests/qemu-iotests/153.out ++++ b/tests/qemu-iotests/153.out +@@ -369,6 +369,31 @@ _qemu_img_wrapper bench -U -w -c 1 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': force-share=on can only be used with read-only images + + Round done ++ ++== Two devices with the same image (read-only=off - read-only=off) == ++QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,read-only=off: Failed to get "write" lock ++Is another process using the image? ++ ++== Two devices with the same image (read-only=off - read-only=on) == ++QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,read-only=on: Failed to get shared "write" lock ++Is another process using the image? ++ ++== Two devices with the same image (read-only=off - read-only=on,force-share=on) == ++ ++== Two devices with the same image (read-only=on - read-only=off) == ++QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,read-only=off: Failed to get "write" lock ++Is another process using the image? ++ ++== Two devices with the same image (read-only=on - read-only=on) == ++ ++== Two devices with the same image (read-only=on - read-only=on,force-share=on) == ++ ++== Two devices with the same image (read-only=on,force-share=on - read-only=off) == ++ ++== Two devices with the same image (read-only=on,force-share=on - read-only=on) == ++ ++== Two devices with the same image (read-only=on,force-share=on - read-only=on,force-share=on) == ++ + == Creating TEST_DIR/t.qcow2.[abc] == + Formatting 'TEST_DIR/t.IMGFMT.a', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT + Formatting 'TEST_DIR/t.IMGFMT.b', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-169-add-cases-for-source-vm-resuming.patch b/SOURCES/kvm-iotests-169-add-cases-for-source-vm-resuming.patch new file mode 100644 index 0000000..ff5bc13 --- /dev/null +++ b/SOURCES/kvm-iotests-169-add-cases-for-source-vm-resuming.patch @@ -0,0 +1,129 @@ +From b12adbb5e07d5c146f500e920a3dc1278dfebe53 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:43 +0100 +Subject: [PATCH 33/33] iotests: 169: add cases for source vm resuming + +RH-Author: John Snow +Message-id: <20190206221243.7407-24-jsnow@redhat.com> +Patchwork-id: 84277 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 23/23] iotests: 169: add cases for source vm resuming +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Test that we can resume source vm after [failed] migration, and bitmaps +are ok. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +(cherry picked from commit 3e6d88f280a53b5b399e73b1f80efe4c3db306f1) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/169 | 60 +++++++++++++++++++++++++++++++++++++++++++++- + tests/qemu-iotests/169.out | 4 ++-- + 2 files changed, 61 insertions(+), 3 deletions(-) + +diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169 +index 8b7947d..69850c4 100755 +--- a/tests/qemu-iotests/169 ++++ b/tests/qemu-iotests/169 +@@ -77,6 +77,58 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): + self.assert_qmp(result, 'error/desc', + "Dirty bitmap 'bitmap0' not found"); + ++ def do_test_migration_resume_source(self, persistent, migrate_bitmaps): ++ granularity = 512 ++ ++ # regions = ((start, count), ...) ++ regions = ((0, 0x10000), ++ (0xf0000, 0x10000), ++ (0xa0201, 0x1000)) ++ ++ mig_caps = [{'capability': 'events', 'state': True}] ++ if migrate_bitmaps: ++ mig_caps.append({'capability': 'dirty-bitmaps', 'state': True}) ++ ++ result = self.vm_a.qmp('migrate-set-capabilities', ++ capabilities=mig_caps) ++ self.assert_qmp(result, 'return', {}) ++ ++ self.add_bitmap(self.vm_a, granularity, persistent) ++ for r in regions: ++ self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % r) ++ sha256 = self.get_bitmap_hash(self.vm_a) ++ ++ result = self.vm_a.qmp('migrate', uri=mig_cmd) ++ while True: ++ event = self.vm_a.event_wait('MIGRATION') ++ if event['data']['status'] == 'completed': ++ break ++ ++ # test that bitmap is still here ++ removed = (not migrate_bitmaps) and persistent ++ self.check_bitmap(self.vm_a, False if removed else sha256) ++ ++ self.vm_a.qmp('cont') ++ ++ # test that bitmap is still here after invalidation ++ self.check_bitmap(self.vm_a, sha256) ++ ++ # shutdown and check that invalidation didn't fail ++ self.vm_a.shutdown() ++ ++ # catch 'Could not reopen qcow2 layer: Bitmap already exists' ++ # possible error ++ log = self.vm_a.get_log() ++ log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) ++ log = re.sub(r'^(wrote .* bytes at offset .*\n.*KiB.*ops.*sec.*\n){3}', ++ '', log) ++ log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) ++ self.assertEqual(log, '') ++ ++ # test that bitmap is still persistent ++ self.vm_a.launch() ++ self.check_bitmap(self.vm_a, sha256 if persistent else False) ++ + def do_test_migration(self, persistent, migrate_bitmaps, online, + shared_storage): + granularity = 512 +@@ -152,7 +204,7 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): + + def inject_test_case(klass, name, method, *args, **kwargs): + mc = operator.methodcaller(method, *args, **kwargs) +- setattr(klass, 'test_' + name, new.instancemethod(mc, None, klass)) ++ setattr(klass, 'test_' + method + name, new.instancemethod(mc, None, klass)) + + for cmb in list(itertools.product((True, False), repeat=4)): + name = ('_' if cmb[0] else '_not_') + 'persistent_' +@@ -163,6 +215,12 @@ for cmb in list(itertools.product((True, False), repeat=4)): + inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration', + *list(cmb)) + ++for cmb in list(itertools.product((True, False), repeat=2)): ++ name = ('_' if cmb[0] else '_not_') + 'persistent_' ++ name += ('_' if cmb[1] else '_not_') + 'migbitmap' ++ ++ inject_test_case(TestDirtyBitmapMigration, name, ++ 'do_test_migration_resume_source', *list(cmb)) + + if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) +diff --git a/tests/qemu-iotests/169.out b/tests/qemu-iotests/169.out +index b6f2576..3a89159 100644 +--- a/tests/qemu-iotests/169.out ++++ b/tests/qemu-iotests/169.out +@@ -1,5 +1,5 @@ +-................ ++.................... + ---------------------------------------------------------------------- +-Ran 16 tests ++Ran 20 tests + + OK +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-169-drop-deprecated-autoload-parameter.patch b/SOURCES/kvm-iotests-169-drop-deprecated-autoload-parameter.patch new file mode 100644 index 0000000..713a91c --- /dev/null +++ b/SOURCES/kvm-iotests-169-drop-deprecated-autoload-parameter.patch @@ -0,0 +1,41 @@ +From 4b6af7c190fb1366d5c7f43fdfe39fddc2465e89 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:38 +0100 +Subject: [PATCH 28/33] iotests: 169: drop deprecated 'autoload' parameter + +RH-Author: John Snow +Message-id: <20190206221243.7407-19-jsnow@redhat.com> +Patchwork-id: 84276 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 18/23] iotests: 169: drop deprecated 'autoload' parameter +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +Signed-off-by: John Snow +(cherry picked from commit 304cc429a07eb6601020212a478050ebbe87df88) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/169 | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169 +index f243db9..df408f8 100755 +--- a/tests/qemu-iotests/169 ++++ b/tests/qemu-iotests/169 +@@ -58,7 +58,6 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): + 'granularity': granularity} + if persistent: + params['persistent'] = True +- params['autoload'] = True + + result = vm.qmp('block-dirty-bitmap-add', **params) + self.assert_qmp(result, 'return', {}); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-236-fix-transaction-kwarg-order.patch b/SOURCES/kvm-iotests-236-fix-transaction-kwarg-order.patch new file mode 100644 index 0000000..0dd3cf6 --- /dev/null +++ b/SOURCES/kvm-iotests-236-fix-transaction-kwarg-order.patch @@ -0,0 +1,219 @@ +From 206d8696a89a1b4076f7afd46b6ae0dcc0f377f5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:25 +0100 +Subject: [PATCH 027/163] iotests/236: fix transaction kwarg order + +RH-Author: John Snow +Message-id: <20190320161631.14841-14-jsnow@redhat.com> +Patchwork-id: 84945 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/19] iotests/236: fix transaction kwarg order +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +It's not enough to order the kwargs for consistent QMP log output, +we must also sort any sub-dictionaries in lists that appear as values. + +Reported-by: Kevin Wolf +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Kevin Wolf +(cherry picked from commit 039be85c410bfb4b53cdee2083b4245e0d4e4181) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/236.out | 56 +++++++++++++++++++++---------------------- + tests/qemu-iotests/iotests.py | 21 ++++++++-------- + 2 files changed, 39 insertions(+), 38 deletions(-) + +diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out +index 1dad24d..bb2d71e 100644 +--- a/tests/qemu-iotests/236.out ++++ b/tests/qemu-iotests/236.out +@@ -45,23 +45,23 @@ write -P0xcd 0x3ff0000 64k + "actions": [ + { + "data": { +- "node": "drive0", +- "name": "bitmapB" ++ "name": "bitmapB", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-disable" + }, + { + "data": { +- "node": "drive0", ++ "granularity": 65536, + "name": "bitmapC", +- "granularity": 65536 ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-add" + }, + { + "data": { +- "node": "drive0", +- "name": "bitmapA" ++ "name": "bitmapA", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-clear" + }, +@@ -105,30 +105,30 @@ write -P0xcd 0x3ff0000 64k + "actions": [ + { + "data": { +- "node": "drive0", +- "name": "bitmapB" ++ "name": "bitmapB", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-disable" + }, + { + "data": { +- "node": "drive0", ++ "granularity": 65536, + "name": "bitmapC", +- "granularity": 65536 ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-add" + }, + { + "data": { +- "node": "drive0", +- "name": "bitmapC" ++ "name": "bitmapC", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-disable" + }, + { + "data": { +- "node": "drive0", +- "name": "bitmapC" ++ "name": "bitmapC", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-enable" + } +@@ -158,15 +158,15 @@ write -P0xea 0x3fe0000 64k + "actions": [ + { + "data": { +- "node": "drive0", +- "name": "bitmapA" ++ "name": "bitmapA", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-disable" + }, + { + "data": { +- "node": "drive0", +- "name": "bitmapC" ++ "name": "bitmapC", ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-disable" + } +@@ -209,21 +209,21 @@ write -P0xea 0x3fe0000 64k + "actions": [ + { + "data": { +- "node": "drive0", + "disabled": true, ++ "granularity": 65536, + "name": "bitmapD", +- "granularity": 65536 ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-add" + }, + { + "data": { +- "node": "drive0", +- "target": "bitmapD", + "bitmaps": [ + "bitmapB", + "bitmapC" +- ] ++ ], ++ "node": "drive0", ++ "target": "bitmapD" + }, + "type": "block-dirty-bitmap-merge" + }, +@@ -273,21 +273,21 @@ write -P0xea 0x3fe0000 64k + "actions": [ + { + "data": { +- "node": "drive0", + "disabled": true, ++ "granularity": 65536, + "name": "bitmapD", +- "granularity": 65536 ++ "node": "drive0" + }, + "type": "block-dirty-bitmap-add" + }, + { + "data": { +- "node": "drive0", +- "target": "bitmapD", + "bitmaps": [ + "bitmapB", + "bitmapC" +- ] ++ ], ++ "node": "drive0", ++ "target": "bitmapD" + }, + "type": "block-dirty-bitmap-merge" + } +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index d178469..4e9b2c4 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -74,15 +74,16 @@ def qemu_img(*args): + sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + return exitcode + +-def ordered_kwargs(kwargs): +- # kwargs prior to 3.6 are not ordered, so: +- od = OrderedDict() +- for k, v in sorted(kwargs.items()): +- if isinstance(v, dict): +- od[k] = ordered_kwargs(v) +- else: +- od[k] = v +- return od ++def ordered_qmp(qmsg): ++ # Dictionaries are not ordered prior to 3.6, therefore: ++ if isinstance(qmsg, list): ++ return [ordered_qmp(atom) for atom in qmsg] ++ if isinstance(qmsg, dict): ++ od = OrderedDict() ++ for k, v in sorted(qmsg.items()): ++ od[k] = ordered_qmp(v) ++ return od ++ return qmsg + + def qemu_img_create(*args): + args = list(args) +@@ -485,7 +486,7 @@ class VM(qtest.QEMUQtestMachine): + def qmp_log(self, cmd, filters=[], indent=None, **kwargs): + full_cmd = OrderedDict(( + ("execute", cmd), +- ("arguments", ordered_kwargs(kwargs)) ++ ("arguments", ordered_qmp(kwargs)) + )) + log(full_cmd, filters, indent=indent) + result = self.qmp(cmd, **kwargs) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-241-to-test-NBD-on-unaligned-images.patch b/SOURCES/kvm-iotests-Add-241-to-test-NBD-on-unaligned-images.patch new file mode 100644 index 0000000..6d6b353 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-241-to-test-NBD-on-unaligned-images.patch @@ -0,0 +1,202 @@ +From 8b23ebef39aa3e2817db7d42c8143139697e0adc Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:17 +0200 +Subject: [PATCH 07/53] iotests: Add 241 to test NBD on unaligned images + +RH-Author: John Snow +Message-id: <20190506175629.11079-8-jsnow@redhat.com> +Patchwork-id: 87182 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/19] iotests: Add 241 to test NBD on unaligned images +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Add a test for the NBD client workaround in the previous patch. It's +not really feasible for an iotest to assume a specific tracing engine, +so we can't really probe trace_nbd_parse_blockstatus_compliance to see +if the server was fixed vs. whether the client just worked around the +server (other than by rearranging order between code patches and this +test). But having a successful exchange sure beats the previous state +of an error message. Since format probing can change alignment, we can +use that as an easy way to test several configurations. + +Not tested yet, but worth adding to this test in future patches: an +NBD server that can advertise a non-sector-aligned size (such as +nbdkit) causes qemu as the NBD client to misbehave when it rounds the +size up and accesses beyond the advertised size. Qemu as NBD server +never advertises a non-sector-aligned size (since bdrv_getlength() +currently rounds up to sector boundaries); until qemu can act as such +a server, testing that flaw will have to rely on external binaries. + +Signed-off-by: Eric Blake +Message-Id: <20190329042750.14704-2-eblake@redhat.com> +Tested-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Vladimir Sementsov-Ogievskiy +[eblake: add forced-512 alignment, and nbdkit reproducer comment] +(cherry picked from commit e9dce9cb6eae57834cd80324ff43069299198bab) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/241 | 100 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/241.out | 26 ++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 127 insertions(+) + create mode 100755 tests/qemu-iotests/241 + create mode 100644 tests/qemu-iotests/241.out + +diff --git a/tests/qemu-iotests/241 b/tests/qemu-iotests/241 +new file mode 100755 +index 0000000..4b19685 +--- /dev/null ++++ b/tests/qemu-iotests/241 +@@ -0,0 +1,100 @@ ++#!/bin/bash ++# ++# Test qemu-nbd vs. unaligned images ++# ++# Copyright (C) 2018-2019 Red Hat, Inc. ++# ++# 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 . ++# ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket ++ ++_cleanup() ++{ ++ _cleanup_test_img ++ nbd_server_stop ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++. ./common.nbd ++ ++_supported_fmt raw ++_supported_proto nbd ++_supported_os Linux ++_require_command QEMU_NBD ++ ++# can't use _make_test_img, because qemu-img rounds image size up, ++# and because we want to use Unix socket rather than TCP port. Likewise, ++# we have to redirect TEST_IMG to our server. ++# This tests that we can deal with the hole at the end of an unaligned ++# raw file (either because the server doesn't advertise alignment too ++# large, or because the client ignores the server's noncompliance - even ++# though we can't actually wire iotests into checking trace messages). ++printf %01000d 0 > "$TEST_IMG_FILE" ++TEST_IMG="nbd:unix:$nbd_unix_socket" ++ ++echo ++echo "=== Exporting unaligned raw image, natural alignment ===" ++echo ++ ++nbd_server_start_unix_socket -f $IMGFMT "$TEST_IMG_FILE" ++ ++$QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)' ++$QEMU_IMG map -f raw --output=json "$TEST_IMG" | _filter_qemu_img_map ++$QEMU_IO -f raw -c map "$TEST_IMG" ++nbd_server_stop ++ ++echo ++echo "=== Exporting unaligned raw image, forced server sector alignment ===" ++echo ++ ++# Intentionally omit '-f' to force image probing, which in turn forces ++# sector alignment, here at the server. ++nbd_server_start_unix_socket "$TEST_IMG_FILE" ++ ++$QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)' ++$QEMU_IMG map -f raw --output=json "$TEST_IMG" | _filter_qemu_img_map ++$QEMU_IO -f raw -c map "$TEST_IMG" ++nbd_server_stop ++ ++echo ++echo "=== Exporting unaligned raw image, forced client sector alignment ===" ++echo ++ ++# Now force sector alignment at the client. ++nbd_server_start_unix_socket -f $IMGFMT "$TEST_IMG_FILE" ++ ++$QEMU_NBD_PROG --list -k $nbd_unix_socket | grep '\(size\|min\)' ++$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map ++$QEMU_IO -c map "$TEST_IMG" ++nbd_server_stop ++ ++# Not tested yet: we also want to ensure that qemu as NBD client does ++# not access beyond the end of a server's advertised unaligned size: ++# nbdkit -U - memory size=513 --run 'qemu-io -f raw -c "r 512 512" $nbd' ++# However, since qemu as server always rounds up to a sector alignment, ++# we would have to use nbdkit to provoke the current client failures. ++ ++# success, all done ++echo '*** done' ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out +new file mode 100644 +index 0000000..b76a623 +--- /dev/null ++++ b/tests/qemu-iotests/241.out +@@ -0,0 +1,26 @@ ++QA output created by 241 ++ ++=== Exporting unaligned raw image, natural alignment === ++ ++ size: 1024 ++ min block: 512 ++[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] ++1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) ++ ++=== Exporting unaligned raw image, forced server sector alignment === ++ ++WARNING: Image format was not specified for '/home/eblake/qemu/tests/qemu-iotests/scratch/t.raw' and probing guessed raw. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++ size: 1024 ++ min block: 512 ++[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] ++1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) ++ ++=== Exporting unaligned raw image, forced client sector alignment === ++ ++ size: 1024 ++ min block: 512 ++[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] ++1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 7da1334..882ff66 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -229,5 +229,6 @@ + 233 auto quick + 234 auto quick migration + 236 auto quick ++241 rw auto quick + 242 rw auto quick + 246 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Also-test-I-O-over-NBD-TLS.patch b/SOURCES/kvm-iotests-Also-test-I-O-over-NBD-TLS.patch new file mode 100644 index 0000000..4780d21 --- /dev/null +++ b/SOURCES/kvm-iotests-Also-test-I-O-over-NBD-TLS.patch @@ -0,0 +1,91 @@ +From 5074b9b995f708fe57995267b40d3fedc4368c3b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:36 +0100 +Subject: [PATCH 069/163] iotests: Also test I/O over NBD TLS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-24-jsnow@redhat.com> +Patchwork-id: 85113 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 23/28] iotests: Also test I/O over NBD TLS +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Enhance test 233 to also perform I/O beyond the initial handshake. + +Signed-off-by: Eric Blake +Message-Id: <20181118022403.2211483-1-eblake@redhat.com> +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit bb39c47d70e84acf5066f79eba27ae5945b837be) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/233 | 12 +++++++++++- + tests/qemu-iotests/233.out | 10 ++++++++++ + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 +index 46013ce..a4da60d 100755 +--- a/tests/qemu-iotests/233 ++++ b/tests/qemu-iotests/233 +@@ -62,7 +62,7 @@ tls_x509_create_client "ca2" "client2" + echo + echo "== preparing image ==" + _make_test_img 64M +- ++$QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io + + echo + echo "== check TLS client to plain server fails ==" +@@ -96,6 +96,16 @@ $QEMU_IMG info --image-opts \ + driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ + 2>&1 | sed "s/$nbd_tcp_port/PORT/g" + ++echo ++echo "== perform I/O over TLS ==" ++QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT ++$QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \ ++ --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ ++ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ ++ 2>&1 | _filter_qemu_io ++ ++$QEMU_IO -f qcow2 -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out +index 616e923..94acd9b 100644 +--- a/tests/qemu-iotests/233.out ++++ b/tests/qemu-iotests/233.out +@@ -9,6 +9,8 @@ Generating a signed certificate... + + == preparing image == + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++wrote 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + + == check TLS client to plain server fails == + qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls) +@@ -27,4 +29,12 @@ disk size: unavailable + == check TLS with different CA fails == + option negotiation failed: Verify failed: No certificate was found. + qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer ++ ++== perform I/O over TLS == ++read 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Disallow-compat-0.10-in-223.patch b/SOURCES/kvm-iotests-Disallow-compat-0.10-in-223.patch new file mode 100644 index 0000000..029419b --- /dev/null +++ b/SOURCES/kvm-iotests-Disallow-compat-0.10-in-223.patch @@ -0,0 +1,46 @@ +From 97ef4db37dea9ef4fd5e082cc45be1ee7915be1f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:19 +0100 +Subject: [PATCH 052/163] iotests: Disallow compat=0.10 in 223 + +RH-Author: John Snow +Message-id: <20190322032241.8111-7-jsnow@redhat.com> +Patchwork-id: 85089 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/28] iotests: Disallow compat=0.10 in 223 +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +223 tests persistent dirty bitmaps which are not supported in +compat=0.10, so that option is unsupported for this test. + +Signed-off-by: Max Reitz +Tested-by: John Snow +Reviewed-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit 092b9c408fb22010747f17e2fb19521cfafd45d6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/223 | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index e59411e..d011b3e 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -40,6 +40,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 + _supported_fmt qcow2 + _supported_proto file # uses NBD as well + _supported_os Linux ++# Persistent dirty bitmaps require compat=1.1 ++_unsupported_imgopts 'compat=0.10' + + function do_run_qemu() + { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Don-t-lock-dev-null-in-226.patch b/SOURCES/kvm-iotests-Don-t-lock-dev-null-in-226.patch new file mode 100644 index 0000000..656bd56 --- /dev/null +++ b/SOURCES/kvm-iotests-Don-t-lock-dev-null-in-226.patch @@ -0,0 +1,51 @@ +From 0290b82d90f8010677d46d3625fe5db50f25f763 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 17:12:06 +0100 +Subject: [PATCH 035/163] iotests: Don't lock /dev/null in 226 + +RH-Author: John Snow +Message-id: <20190320171206.19236-3-jsnow@redhat.com> +Patchwork-id: 84962 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/2] iotests: Don't lock /dev/null in 226 +Bugzilla: 1691018 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Sergio Lopez Pascual + +From: Fam Zheng + +On my system (Fedora 28), this script reports a 'failed to get +"consistent read" lock' error. Following docs/devel/testing.rst, it's +better to add locking=off here. + +Signed-off-by: Fam Zheng +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit ac49c189b4fd48251314a2b5d5a251bcc1687d66) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/226 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226 +index a5a1f67..0bc227f 100755 +--- a/tests/qemu-iotests/226 ++++ b/tests/qemu-iotests/226 +@@ -53,10 +53,10 @@ for PROTO in "file" "host_device" "host_cdrom"; do + echo + echo "== Testing RO ==" + $QEMU_IO -c "open -r -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt +- $QEMU_IO -c "open -r -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt ++ $QEMU_IO -c "open -r -o driver=$PROTO,filename=/dev/null,locking=off" 2>&1 | _filter_imgfmt + echo "== Testing RW ==" + $QEMU_IO -c "open -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt +- $QEMU_IO -c "open -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt ++ $QEMU_IO -c "open -o driver=$PROTO,filename=/dev/null,locking=off" 2>&1 | _filter_imgfmt + done + + # success, all done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Drop-use-of-bash-keyword-function.patch b/SOURCES/kvm-iotests-Drop-use-of-bash-keyword-function.patch new file mode 100644 index 0000000..e68fe53 --- /dev/null +++ b/SOURCES/kvm-iotests-Drop-use-of-bash-keyword-function.patch @@ -0,0 +1,962 @@ +From 65003ace540a37ec135d30020e2c0f829a0979ae Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:37 +0100 +Subject: [PATCH 070/163] iotests: Drop use of bash keyword 'function' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-25-jsnow@redhat.com> +Patchwork-id: 85112 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 24/28] iotests: Drop use of bash keyword 'function' +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Bash allows functions to be declared with or without the leading +keyword 'function'; but including the keyword does not comply with +POSIX syntax, and is confusing to ksh users where the use of the +keyword changes the scoping rules for functions. Stick to the +POSIX form through iotests. + +Done mechanically with: + sed -i 's/^function //' $(git ls-files tests/qemu-iotests) + +Signed-off-by: Eric Blake +Message-Id: <20181116215002.2124581-1-eblake@redhat.com> +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit 8cedcffdc195bc39aeb1373826ba0a45629741e0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/035 | 2 +- + tests/qemu-iotests/037 | 2 +- + tests/qemu-iotests/038 | 6 +++--- + tests/qemu-iotests/046 | 6 +++--- + tests/qemu-iotests/047 | 2 +- + tests/qemu-iotests/049 | 4 ++-- + tests/qemu-iotests/051 | 4 ++-- + tests/qemu-iotests/067 | 4 ++-- + tests/qemu-iotests/071 | 4 ++-- + tests/qemu-iotests/077 | 4 ++-- + tests/qemu-iotests/081 | 4 ++-- + tests/qemu-iotests/082 | 2 +- + tests/qemu-iotests/085 | 10 +++++----- + tests/qemu-iotests/086 | 2 +- + tests/qemu-iotests/087 | 6 +++--- + tests/qemu-iotests/099 | 6 +++--- + tests/qemu-iotests/109 | 2 +- + tests/qemu-iotests/112 | 2 +- + tests/qemu-iotests/142 | 8 ++++---- + tests/qemu-iotests/153 | 4 ++-- + tests/qemu-iotests/157 | 4 ++-- + tests/qemu-iotests/172 | 6 +++--- + tests/qemu-iotests/176 | 2 +- + tests/qemu-iotests/177 | 2 +- + tests/qemu-iotests/184 | 4 ++-- + tests/qemu-iotests/186 | 4 ++-- + tests/qemu-iotests/195 | 4 ++-- + tests/qemu-iotests/204 | 2 +- + tests/qemu-iotests/223 | 4 ++-- + tests/qemu-iotests/227 | 4 ++-- + tests/qemu-iotests/232 | 6 +++--- + tests/qemu-iotests/common.nbd | 12 ++++++------ + tests/qemu-iotests/common.pattern | 16 ++++++++-------- + tests/qemu-iotests/common.qemu | 8 ++++---- + tests/qemu-iotests/common.tls | 10 +++++----- + 35 files changed, 86 insertions(+), 86 deletions(-) + +diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035 +index a5716ca..85d9ef7 100755 +--- a/tests/qemu-iotests/035 ++++ b/tests/qemu-iotests/035 +@@ -49,7 +49,7 @@ echo + echo "creating image" + _make_test_img $size + +-function generate_requests() { ++generate_requests() { + for i in $(seq 0 63); do + echo "aio_write ${i}M 512" + echo "aio_write ${i}M 512" +diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 +index 2e43b19..a11992d 100755 +--- a/tests/qemu-iotests/037 ++++ b/tests/qemu-iotests/037 +@@ -54,7 +54,7 @@ TEST_IMG="$TEST_IMG.base" + + _make_test_img $size + +-function backing_io() ++backing_io() + { + local offset=$1 + local sectors=$2 +diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038 +index 4e03976..575093e 100755 +--- a/tests/qemu-iotests/038 ++++ b/tests/qemu-iotests/038 +@@ -51,7 +51,7 @@ TEST_IMG="$TEST_IMG.base" + + _make_test_img $size + +-function backing_io() ++backing_io() + { + local offset=$1 + local sectors=$2 +@@ -76,7 +76,7 @@ _make_test_img -b "$TEST_IMG.base" 6G + echo + echo "== Some concurrent requests touching the same cluster ==" + +-function overlay_io() ++overlay_io() + { + # Start with a request touching two clusters + echo aio_write -P 0x80 2020k 80k +@@ -102,7 +102,7 @@ overlay_io | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |\ + echo + echo "== Verify image content ==" + +-function verify_io() ++verify_io() + { + echo read -P 31 2016k 4k + echo read -P 0x80 2020k 80k +diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 +index 01c0de6..5e41d96 100755 +--- a/tests/qemu-iotests/046 ++++ b/tests/qemu-iotests/046 +@@ -48,7 +48,7 @@ echo "== creating backing file for COW tests ==" + + _make_test_img $size + +-function backing_io() ++backing_io() + { + local offset=$1 + local sectors=$2 +@@ -73,7 +73,7 @@ _make_test_img -b "$TEST_IMG.base" 6G + echo + echo "== Some concurrent requests touching the same cluster ==" + +-function overlay_io() ++overlay_io() + { + # Allocate middle of cluster 1, then write to somewhere before and after it + cat < /dev/null); then + # For v2 images, discarded clusters are read from the backing file +diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047 +index c168373..6e776d2 100755 +--- a/tests/qemu-iotests/047 ++++ b/tests/qemu-iotests/047 +@@ -45,7 +45,7 @@ size=128M + + _make_test_img $size + +-function qemu_io_cmds() ++qemu_io_cmds() + { + cat <&1 | filter_test_dir +diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 +index 4f20265..a73c73f 100755 +--- a/tests/qemu-iotests/051 ++++ b/tests/qemu-iotests/051 +@@ -43,7 +43,7 @@ _supported_os Linux + # other than refcount_bits=16 + _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + ( +@@ -57,7 +57,7 @@ function do_run_qemu() + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | + _filter_generated_node_ids | _filter_hmp +diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 +index f8d584f..342b2b0 100755 +--- a/tests/qemu-iotests/067 ++++ b/tests/qemu-iotests/067 +@@ -36,7 +36,7 @@ _supported_os Linux + # Because anything other than 16 would change the output of query-block + _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + $QEMU -nographic -qmp-pretty stdio -serial none "$@" +@@ -52,7 +52,7 @@ _filter_qmp_events() + | tr '\t' '\n' + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \ + | _filter_actual_image_size \ +diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 +index 6448e9e..6e467dc 100755 +--- a/tests/qemu-iotests/071 ++++ b/tests/qemu-iotests/071 +@@ -40,14 +40,14 @@ _supported_fmt qcow2 + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" | _filter_imgfmt + $QEMU -nographic -qmp stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp | _filter_qemu_io + } +diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 +index a40f319..58fe893 100755 +--- a/tests/qemu-iotests/077 ++++ b/tests/qemu-iotests/077 +@@ -48,7 +48,7 @@ _make_test_img $size + echo + echo "== Some concurrent requests involving RMW ==" + +-function test_io() ++test_io() + { + echo "open -o driver=$IMGFMT,file.align=4k blkdebug::$TEST_IMG" + # A simple RMW request +@@ -193,7 +193,7 @@ test_io | $QEMU_IO | _filter_qemu_io | \ + echo + echo "== Verify image content ==" + +-function verify_io() ++verify_io() + { + # A simple RMW request + echo read -P 0 0 0x200 +diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 +index c5d4616..4dc6b04 100755 +--- a/tests/qemu-iotests/081 ++++ b/tests/qemu-iotests/081 +@@ -42,14 +42,14 @@ _supported_fmt raw + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" | _filter_imgfmt + $QEMU -nographic -qmp stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\ + | _filter_qemu_io | _filter_generated_node_ids +diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 +index 14f6631..61eec63 100755 +--- a/tests/qemu-iotests/082 ++++ b/tests/qemu-iotests/082 +@@ -40,7 +40,7 @@ _supported_fmt qcow2 + _supported_proto file nfs + _supported_os Linux + +-function run_qemu_img() ++run_qemu_img() + { + echo + echo Testing: "$@" | _filter_testdir +diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 +index 2ef8407..ade68ef 100755 +--- a/tests/qemu-iotests/085 ++++ b/tests/qemu-iotests/085 +@@ -60,7 +60,7 @@ _supported_os Linux + + + # ${1}: unique identifier for the snapshot filename +-function create_single_snapshot() ++create_single_snapshot() + { + cmd="{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'device': 'virtio0', +@@ -70,7 +70,7 @@ function create_single_snapshot() + } + + # ${1}: unique identifier for the snapshot filename +-function create_group_snapshot() ++create_group_snapshot() + { + cmd="{ 'execute': 'transaction', 'arguments': + {'actions': [ +@@ -88,7 +88,7 @@ function create_group_snapshot() + # ${1}: unique identifier for the snapshot filename + # ${2}: extra_params to the blockdev-add command + # ${3}: filename +-function do_blockdev_add() ++do_blockdev_add() + { + cmd="{ 'execute': 'blockdev-add', 'arguments': + { 'driver': 'qcow2', 'node-name': 'snap_${1}', ${2} +@@ -99,7 +99,7 @@ function do_blockdev_add() + } + + # ${1}: unique identifier for the snapshot filename +-function add_snapshot_image() ++add_snapshot_image() + { + base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}" + snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}" +@@ -110,7 +110,7 @@ function add_snapshot_image() + + # ${1}: unique identifier for the snapshot filename + # ${2}: expected response, defaults to 'return' +-function blockdev_snapshot() ++blockdev_snapshot() + { + cmd="{ 'execute': 'blockdev-snapshot', + 'arguments': { 'node': 'virtio0', +diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086 +index f9e4722..06613fd 100755 +--- a/tests/qemu-iotests/086 ++++ b/tests/qemu-iotests/086 +@@ -40,7 +40,7 @@ _supported_fmt qcow2 raw + _supported_proto file nfs + _supported_os Linux + +-function run_qemu_img() ++run_qemu_img() + { + echo + echo Testing: "$@" | _filter_testdir +diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 +index 109cdf5..f625887 100755 +--- a/tests/qemu-iotests/087 ++++ b/tests/qemu-iotests/087 +@@ -34,14 +34,14 @@ _supported_fmt qcow2 + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + $QEMU -nographic -qmp stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ +@@ -102,7 +102,7 @@ echo === aio=native without O_DIRECT === + echo + + # Skip this test if AIO is not enabled in this build +-function run_qemu_filter_aio() ++run_qemu_filter_aio() + { + run_qemu "$@" | \ + sed -e 's/is not supported in this build/it requires cache.direct=on, which was not specified/' +diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099 +index 4a6275d..578808b 100755 +--- a/tests/qemu-iotests/099 ++++ b/tests/qemu-iotests/099 +@@ -45,12 +45,12 @@ _supported_os Linux + _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" + +-function do_run_qemu() ++do_run_qemu() + { + $QEMU -nographic -qmp stdio -serial none "$@" + } + +-function run_qemu() ++run_qemu() + { + # Get the "file": "foo" entry ($foo may only contain escaped double quotes, + # which is how we can extract it) +@@ -59,7 +59,7 @@ function run_qemu() + | sed -e 's/^.*"file": "\(\(\\"\|[^"]\)*\)".*$/\1/' -e 's/\\"/"/g' + } + +-function test_qemu() ++test_qemu() + { + run_qemu -drive "if=none,id=drv0,$1" <&1 | _filter_testdir | _filter_qemu | _filter_hmp + } +@@ -88,7 +88,7 @@ echo + files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base" + ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file" + +-function check_cache_all() ++check_cache_all() + { + # cache.direct is supposed to be inherited by both bs->file and + # bs->backing +@@ -231,7 +231,7 @@ drv_bk="if=none,file=json:{'driver':'$IMGFMT',,'file':'backing-file',,'node-name + drv_file="if=none,driver=file,filename=$TEST_IMG,node-name=file" + drv_img="if=none,id=blk,file=json:{'driver':'$IMGFMT',,'file':'file',,'backing':'backing',,'node-name':'image'}" + +-function check_cache_all_separate() ++check_cache_all_separate() + { + # Check cache.direct + +diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 +index 00092b8..3120a61 100755 +--- a/tests/qemu-iotests/153 ++++ b/tests/qemu-iotests/153 +@@ -70,7 +70,7 @@ _run_cmd() + (echo "$@"; "$@" 2>&1 1>/dev/null) | _filter_testdir + } + +-function _do_run_qemu() ++_do_run_qemu() + { + ( + if ! test -t 0; then +@@ -82,7 +82,7 @@ function _do_run_qemu() + ) | $QEMU -nographic -monitor stdio -serial none "$@" 1>/dev/null + } + +-function _run_qemu_with_images() ++_run_qemu_with_images() + { + _do_run_qemu \ + $(for i in $@; do echo "-drive if=none,file=$i"; done) 2>&1 \ +diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 +index c3231b7..6fb2659 100755 +--- a/tests/qemu-iotests/157 ++++ b/tests/qemu-iotests/157 +@@ -40,7 +40,7 @@ _supported_fmt generic + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + ( + if ! test -t 0; then +@@ -53,7 +53,7 @@ function do_run_qemu() + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt \ + | _filter_qemu | _filter_generated_node_ids +diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 +index c5ee33e..1e60a7e 100755 +--- a/tests/qemu-iotests/172 ++++ b/tests/qemu-iotests/172 +@@ -46,7 +46,7 @@ if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then + _notrun "Requires a PC machine" + fi + +-function do_run_qemu() ++do_run_qemu() + { + ( + if ! test -t 0; then +@@ -59,7 +59,7 @@ function do_run_qemu() + echo + } + +-function check_floppy_qtree() ++check_floppy_qtree() + { + echo + echo Testing: "$@" | _filter_testdir +@@ -75,7 +75,7 @@ function check_floppy_qtree() + _filter_win32 | _filter_qemu + } + +-function check_cache_mode() ++check_cache_mode() + { + echo "info block none0" | + QEMU_OPTIONS="" do_run_qemu -drive if=none,file="$TEST_IMG" "$@" | +diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176 +index c091d0b..4ecd589 100755 +--- a/tests/qemu-iotests/176 ++++ b/tests/qemu-iotests/176 +@@ -50,7 +50,7 @@ _supported_os Linux + # Persistent dirty bitmaps require compat=1.1 + _unsupported_imgopts 'compat=0.10' + +-function run_qemu() ++run_qemu() + { + $QEMU -nographic -qmp stdio -serial none "$@" 2>&1 \ + | _filter_testdir | _filter_qmp | _filter_qemu \ +diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 +index 7bf8e1d..f0c1155 100755 +--- a/tests/qemu-iotests/177 ++++ b/tests/qemu-iotests/177 +@@ -85,7 +85,7 @@ $QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \ + echo + echo "== verify image content ==" + +-function verify_io() ++verify_io() + { + if ($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | + grep "compat: 0.10" > /dev/null); then +diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184 +index 2f3259d..0af7a73 100755 +--- a/tests/qemu-iotests/184 ++++ b/tests/qemu-iotests/184 +@@ -34,14 +34,14 @@ trap "exit \$status" 0 1 2 3 15 + + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" | _filter_imgfmt + $QEMU -nographic -qmp-pretty stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\ + | _filter_qemu_io | _filter_generated_node_ids \ +diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 +index 29681bf..c27dc95 100755 +--- a/tests/qemu-iotests/186 ++++ b/tests/qemu-iotests/186 +@@ -44,7 +44,7 @@ if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then + _notrun "Requires a PC machine" + fi + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + +@@ -59,7 +59,7 @@ function do_run_qemu() + echo + } + +-function check_info_block() ++check_info_block() + { + echo "info block" | + do_run_qemu "$@" | _filter_win32 | _filter_hmp | _filter_qemu | +diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 +index f56f255..a977c97 100755 +--- a/tests/qemu-iotests/195 ++++ b/tests/qemu-iotests/195 +@@ -41,14 +41,14 @@ _supported_fmt qcow2 + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + $QEMU -nographic -qmp-pretty stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \ + | _filter_qmp | _filter_qemu_io \ +diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204 +index 57f3afe..30f0653 100755 +--- a/tests/qemu-iotests/204 ++++ b/tests/qemu-iotests/204 +@@ -93,7 +93,7 @@ $QEMU_IO -c "open -o $options,$limits blkdebug::$TEST_IMG" \ + echo + echo "== verify image content ==" + +-function verify_io() ++verify_io() + { + echo read -P 22 0 1000 + echo read -P 33 1000 128k +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index 29e1951..5513dc6 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -42,14 +42,14 @@ _supported_os Linux + # Persistent dirty bitmaps require compat=1.1 + _unsupported_imgopts 'compat=0.10' + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + $QEMU -nographic -qmp stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ +diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227 +index 43f2323..be1b636 100755 +--- a/tests/qemu-iotests/227 ++++ b/tests/qemu-iotests/227 +@@ -40,14 +40,14 @@ _supported_fmt generic + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + $QEMU -nographic -qmp-pretty stdio -serial none "$@" + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ +diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 +index ae63f13..e48bc8f 100755 +--- a/tests/qemu-iotests/232 ++++ b/tests/qemu-iotests/232 +@@ -40,7 +40,7 @@ _supported_fmt generic + _supported_proto file + _supported_os Linux + +-function do_run_qemu() ++do_run_qemu() + { + echo Testing: "$@" + ( +@@ -54,13 +54,13 @@ function do_run_qemu() + echo + } + +-function run_qemu() ++run_qemu() + { + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp | + _filter_generated_node_ids | _filter_imgfmt + } + +-function run_qemu_info_block() ++run_qemu_info_block() + { + echo "info block -n" | run_qemu "$@" | grep -e "(file" -e "QEMU_PROG" + } +diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd +index 0f4497a..233187a 100644 +--- a/tests/qemu-iotests/common.nbd ++++ b/tests/qemu-iotests/common.nbd +@@ -23,7 +23,7 @@ nbd_unix_socket="${TEST_DIR}/qemu-nbd.sock" + nbd_tcp_addr="127.0.0.1" + nbd_pid_file="${TEST_DIR}/qemu-nbd.pid" + +-function nbd_server_stop() ++nbd_server_stop() + { + local NBD_PID + if [ -f "$nbd_pid_file" ]; then +@@ -36,7 +36,7 @@ function nbd_server_stop() + rm -f "$nbd_unix_socket" + } + +-function nbd_server_wait_for_unix_socket() ++nbd_server_wait_for_unix_socket() + { + pid=$1 + +@@ -57,14 +57,14 @@ function nbd_server_wait_for_unix_socket() + exit 1 + } + +-function nbd_server_start_unix_socket() ++nbd_server_start_unix_socket() + { + nbd_server_stop + $QEMU_NBD -v -t -k "$nbd_unix_socket" "$@" & + nbd_server_wait_for_unix_socket $! + } + +-function nbd_server_set_tcp_port() ++nbd_server_set_tcp_port() + { + (ss --help) >/dev/null 2>&1 || _notrun "ss utility not found, skipping test" + +@@ -80,7 +80,7 @@ function nbd_server_set_tcp_port() + exit 1 + } + +-function nbd_server_wait_for_tcp_socket() ++nbd_server_wait_for_tcp_socket() + { + pid=$1 + +@@ -101,7 +101,7 @@ function nbd_server_wait_for_tcp_socket() + exit 1 + } + +-function nbd_server_start_tcp_socket() ++nbd_server_start_tcp_socket() + { + nbd_server_stop + $QEMU_NBD -v -t -b $nbd_tcp_addr -p $nbd_tcp_port "$@" & +diff --git a/tests/qemu-iotests/common.pattern b/tests/qemu-iotests/common.pattern +index 34f4a8d..b67bb34 100644 +--- a/tests/qemu-iotests/common.pattern ++++ b/tests/qemu-iotests/common.pattern +@@ -16,7 +16,7 @@ + # along with this program. If not, see . + # + +-function do_is_allocated() { ++do_is_allocated() { + local start=$1 + local size=$2 + local step=$3 +@@ -27,11 +27,11 @@ function do_is_allocated() { + done + } + +-function is_allocated() { ++is_allocated() { + do_is_allocated "$@" | $QEMU_IO "$TEST_IMG" | _filter_qemu_io + } + +-function do_io() { ++do_io() { + local op=$1 + local start=$2 + local size=$3 +@@ -45,22 +45,22 @@ function do_io() { + done + } + +-function io_pattern() { ++io_pattern() { + do_io "$@" | $QEMU_IO "$TEST_IMG" | _filter_qemu_io + } + +-function io() { ++io() { + local start=$2 + local pattern=$(( (start >> 9) % 256 )) + + do_io "$@" $pattern | $QEMU_IO "$TEST_IMG" | _filter_qemu_io + } + +-function io_zero() { ++io_zero() { + do_io "$@" 0 | $QEMU_IO "$TEST_IMG" | _filter_qemu_io + } + +-function io_test() { ++io_test() { + local op=$1 + local offset=$2 + local cluster_size=$3 +@@ -100,7 +100,7 @@ function io_test() { + offset=$((offset + num_large * ( l2_size + half_cluster ))) + } + +-function io_test2() { ++io_test2() { + local orig_offset=$1 + local cluster_size=$2 + local num=$3 +diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu +index f285484..6b8eb9b 100644 +--- a/tests/qemu-iotests/common.qemu ++++ b/tests/qemu-iotests/common.qemu +@@ -60,7 +60,7 @@ _in_fd=4 + # $3: A string to search for in the response; if found, this indicates + # failure and the test is either aborted (if $qemu_error_no_exit + # is not set) or ${QEMU_STATUS[$1]} is set to -1 (otherwise). +-function _timed_wait_for() ++_timed_wait_for() + { + local h=${1} + shift +@@ -131,7 +131,7 @@ function _timed_wait_for() + # strings the response will be scanned for. The first of the two + # indicates success, the latter indicates failure. Failure is handled + # like a timeout. +-function _send_qemu_cmd() ++_send_qemu_cmd() + { + local h=${1} + local count=1 +@@ -186,7 +186,7 @@ function _send_qemu_cmd() + # Returns: + # $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. + # +-function _launch_qemu() ++_launch_qemu() + { + local comm= + local fifo_out= +@@ -262,7 +262,7 @@ function _launch_qemu() + # If $wait is set to anything other than the empty string, the process will not + # be killed but only waited for, and any output will be forwarded to stdout. If + # $wait is empty, the process will be killed and all output will be suppressed. +-function _cleanup_qemu() ++_cleanup_qemu() + { + # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices + for i in "${!QEMU_OUT[@]}" +diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls +index cecab26..39f17c1 100644 +--- a/tests/qemu-iotests/common.tls ++++ b/tests/qemu-iotests/common.tls +@@ -20,7 +20,7 @@ + + tls_dir="${TEST_DIR}/tls" + +-function tls_x509_cleanup() ++tls_x509_cleanup() + { + rm -f "${tls_dir}"/*.pem + rm -f "${tls_dir}"/*/*.pem +@@ -29,7 +29,7 @@ function tls_x509_cleanup() + } + + +-function tls_x509_init() ++tls_x509_init() + { + mkdir -p "${tls_dir}" + +@@ -58,7 +58,7 @@ EOF + } + + +-function tls_x509_create_root_ca() ++tls_x509_create_root_ca() + { + name=${1:-ca-cert} + +@@ -77,7 +77,7 @@ EOF + } + + +-function tls_x509_create_server() ++tls_x509_create_server() + { + caname=$1 + name=$2 +@@ -108,7 +108,7 @@ EOF + } + + +-function tls_x509_create_client() ++tls_x509_create_client() + { + caname=$1 + name=$2 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Enhance-223-233-to-cover-qemu-nbd-list.patch b/SOURCES/kvm-iotests-Enhance-223-233-to-cover-qemu-nbd-list.patch new file mode 100644 index 0000000..41ab501 --- /dev/null +++ b/SOURCES/kvm-iotests-Enhance-223-233-to-cover-qemu-nbd-list.patch @@ -0,0 +1,191 @@ +From a4e0439bc039710f1c7f3133ea1cfd88ae38fda5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:55 +0100 +Subject: [PATCH 117/163] iotests: Enhance 223, 233 to cover 'qemu-nbd --list' + +RH-Author: John Snow +Message-id: <20190327172308.31077-43-jsnow@redhat.com> +Patchwork-id: 85215 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 42/55] iotests: Enhance 223, 233 to cover 'qemu-nbd --list' +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Any good new feature deserves some regression testing :) +Coverage includes: +- 223: what happens when there are 0 or more than 1 export, +proof that we can see multiple contexts including qemu:dirty-bitmap +- 233: proof that we can list over TLS, and that mix-and-match of +plain/TLS listings will behave sanely + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-22-eblake@redhat.com> +(cherry picked from commit ddd09448fd833d646952c769ae9ce3d39bee989f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/223 | 2 ++ + tests/qemu-iotests/223.out | 20 ++++++++++++++++++++ + tests/qemu-iotests/233 | 19 +++++++++++++------ + tests/qemu-iotests/233.out | 15 +++++++++++++++ + 4 files changed, 50 insertions(+), 6 deletions(-) + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index 773892d..f120a01 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -127,6 +127,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", + "arguments":{"addr":{"type":"unix", + "data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server ++$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n", "bitmap":"b"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", +@@ -142,6 +143,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n", "name":"n2", "writable":true, + "bitmap":"b2"}}' "return" ++$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd" + + echo + echo "=== Contrast normal status to large granularity dirty-bitmap ===" +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index 4012bb0..963ae28 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -30,12 +30,32 @@ wrote 2097152/2097152 bytes at offset 2097152 + {"error": {"class": "GenericError", "desc": "NBD server not running"}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "NBD server already running"}} ++exports available: 0 + {"return": {}} + {"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}} + {"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}} + {"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}} + {"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}} + {"return": {}} ++exports available: 2 ++ export: 'n' ++ size: 4194304 ++ flags: 0x4ef ( readonly flush fua trim zeroes df cache ) ++ min block: 512 ++ opt block: 4096 ++ max block: 33554432 ++ available meta contexts: 2 ++ base:allocation ++ qemu:dirty-bitmap:b ++ export: 'n2' ++ size: 4194304 ++ flags: 0x4ed ( flush fua trim zeroes df cache ) ++ min block: 512 ++ opt block: 4096 ++ max block: 33554432 ++ available meta contexts: 2 ++ base:allocation ++ qemu:dirty-bitmap:b2 + + === Contrast normal status to large granularity dirty-bitmap === + +diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 +index ab15c77..fc345a1 100755 +--- a/tests/qemu-iotests/233 ++++ b/tests/qemu-iotests/233 +@@ -69,10 +69,12 @@ echo + echo "== check TLS client to plain server fails ==" + nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" 2> "$TEST_DIR/server.log" + +-$QEMU_IMG info --image-opts \ +- --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ ++obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 ++$QEMU_IMG info --image-opts --object $obj \ + driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ + 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \ ++ --tls-creds=tls0 + + nbd_server_stop + +@@ -85,20 +87,25 @@ nbd_server_start_tcp_socket \ + -f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log" + + $QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port + + echo + echo "== check TLS works ==" +-$QEMU_IMG info --image-opts \ +- --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ ++obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 ++$QEMU_IMG info --image-opts --object $obj \ + driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ + 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \ ++ --tls-creds=tls0 + + echo + echo "== check TLS with different CA fails ==" +-$QEMU_IMG info --image-opts \ +- --object tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 \ ++obj=tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 ++$QEMU_IMG info --image-opts --object $obj \ + driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ + 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \ ++ --tls-creds=tls0 + + echo + echo "== perform I/O over TLS ==" +diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out +index 2199d8a..6d45f3b 100644 +--- a/tests/qemu-iotests/233.out ++++ b/tests/qemu-iotests/233.out +@@ -15,19 +15,33 @@ wrote 1048576/1048576 bytes at offset 1048576 + == check TLS client to plain server fails == + qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls) + server reported: TLS not configured ++qemu-nbd: Denied by server for option 5 (starttls) ++server reported: TLS not configured + + == check plain client to TLS server fails == + qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply) + server reported: Option 0x8 not permitted before TLS ++qemu-nbd: TLS negotiation required before option 8 (structured reply) ++server reported: Option 0x8 not permitted before TLS + + == check TLS works == + image: nbd://127.0.0.1:PORT + file format: nbd + virtual size: 64M (67108864 bytes) + disk size: unavailable ++exports available: 1 ++ export: '' ++ size: 67108864 ++ flags: 0x4ed ( flush fua trim zeroes df cache ) ++ min block: 512 ++ opt block: 4096 ++ max block: 33554432 ++ available meta contexts: 1 ++ base:allocation + + == check TLS with different CA fails == + qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer ++qemu-nbd: The certificate hasn't got a known issuer + + == perform I/O over TLS == + read 1048576/1048576 bytes at offset 1048576 +@@ -39,4 +53,5 @@ read 1048576/1048576 bytes at offset 1048576 + + == final server log == + qemu-nbd: option negotiation failed: Verify failed: No certificate was found. ++qemu-nbd: option negotiation failed: Verify failed: No certificate was found. + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Enhance-223-to-cover-multiple-bitmap-granula.patch b/SOURCES/kvm-iotests-Enhance-223-to-cover-multiple-bitmap-granula.patch new file mode 100644 index 0000000..76d0354 --- /dev/null +++ b/SOURCES/kvm-iotests-Enhance-223-to-cover-multiple-bitmap-granula.patch @@ -0,0 +1,216 @@ +From 4398dec3833e9a4c27c0394aaeee4329008d489a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:14 +0100 +Subject: [PATCH 016/163] iotests: Enhance 223 to cover multiple bitmap + granularities + +RH-Author: John Snow +Message-id: <20190320161631.14841-3-jsnow@redhat.com> +Patchwork-id: 84939 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/19] iotests: Enhance 223 to cover multiple bitmap granularities +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Testing granularity at the same size as the cluster isn't quite +as fun as what happens when it is larger or smaller. This +enhancement also shows that qemu's nbd server can serve the +same disk over multiple exports simultaneously. + +Signed-off-by: Eric Blake +Tested-by: John Snow +Reviewed-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit a237dea330a2be9a2cbe95056b9a8d67627d95c6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/223 | 43 +++++++++++++++++++++++++++++++++++-------- + tests/qemu-iotests/223.out | 32 +++++++++++++++++++++++++------- + 2 files changed, 60 insertions(+), 15 deletions(-) + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index b63b7a4..a462f41 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -56,10 +56,11 @@ function run_qemu() + } + + echo +-echo "=== Create partially sparse image, then add dirty bitmap ===" ++echo "=== Create partially sparse image, then add dirty bitmaps ===" + echo + +-_make_test_img 4M ++# Two bitmaps, to contrast granularity issues ++_make_test_img -o cluster_size=4k 4M + $QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io + run_qemu < >(_filter_nbd) +@@ -102,6 +113,8 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", + "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", + "arguments":{"node":"n", "name":"b"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", ++ "arguments":{"node":"n", "name":"b2"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", + "arguments":{"addr":{"type":"unix", + "data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return" +@@ -109,26 +122,40 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", + "arguments":{"name":"n", "bitmap":"b"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", ++ "arguments":{"device":"n", "name":"n2"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", ++ "arguments":{"name":"n2", "bitmap":"b2"}}' "return" + + echo +-echo "=== Contrast normal status with dirty-bitmap status ===" ++echo "=== Contrast normal status to large granularity dirty-bitmap ===" + echo + + QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT + IMG="driver=nbd,export=n,server.type=unix,server.path=$TEST_DIR/nbd" +-$QEMU_IO -r -c 'r -P 0 0 1m' -c 'r -P 0x11 1m 1m' \ +- -c 'r -P 0x22 2m 2m' --image-opts "$IMG" | _filter_qemu_io ++$QEMU_IO -r -c 'r -P 0x22 512 512' -c 'r -P 0 512k 512k' -c 'r -P 0x11 1m 1m' \ ++ -c 'r -P 0x33 2m 2m' --image-opts "$IMG" | _filter_qemu_io + $QEMU_IMG map --output=json --image-opts \ + "$IMG" | _filter_qemu_img_map + $QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map + + echo ++echo "=== Contrast to small granularity dirty-bitmap ===" ++echo ++ ++IMG="driver=nbd,export=n2,server.type=unix,server.path=$TEST_DIR/nbd" ++$QEMU_IMG map --output=json --image-opts \ ++ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map ++ ++echo + echo "=== End NBD server ===" + echo + + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + "arguments":{"name":"n"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", ++ "arguments":{"name":"n2"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" + +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index 33021c8..de41747 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -1,6 +1,6 @@ + QA output created by 223 + +-=== Create partially sparse image, then add dirty bitmap === ++=== Create partially sparse image, then add dirty bitmaps === + + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304 + wrote 2097152/2097152 bytes at offset 1048576 +@@ -11,15 +11,18 @@ QMP_VERSION + {"return": {}} + {"return": {}} + {"return": {}} ++{"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + + === Write part of the file under active bitmap === + ++wrote 512/512 bytes at offset 512 ++512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + wrote 2097152/2097152 bytes at offset 2097152 + 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +-=== End dirty bitmap, and start serving image over NBD === ++=== End dirty bitmaps, and start serving image over NBD === + + {"return": {}} + {"return": {}} +@@ -27,18 +30,32 @@ wrote 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"return": {}} + {"return": {}} ++{"return": {}} ++{"return": {}} ++{"return": {}} + +-=== Contrast normal status with dirty-bitmap status === ++=== Contrast normal status to large granularity dirty-bitmap === + +-read 1048576/1048576 bytes at offset 0 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 512/512 bytes at offset 512 ++512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 524288/524288 bytes at offset 524288 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + read 1048576/1048576 bytes at offset 1048576 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + read 2097152/2097152 bytes at offset 2097152 + 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true}, ++{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false}, + { "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true}] +-[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true}, ++[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, ++{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true}, ++{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] ++ ++=== Contrast to small granularity dirty-bitmap === ++ ++[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true}, ++{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, ++{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true}, + { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + + === End NBD server === +@@ -46,4 +63,5 @@ read 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"return": {}} + {"return": {}} ++{"return": {}} + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Fix-207-to-use-QMP-filters-for-qmp_log.patch b/SOURCES/kvm-iotests-Fix-207-to-use-QMP-filters-for-qmp_log.patch new file mode 100644 index 0000000..ad5b60f --- /dev/null +++ b/SOURCES/kvm-iotests-Fix-207-to-use-QMP-filters-for-qmp_log.patch @@ -0,0 +1,78 @@ +From c0db4cef886d62fa701b3c8000e1e6d5f4ac9ec5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:29 +0100 +Subject: [PATCH 031/163] iotests: Fix 207 to use QMP filters for qmp_log + +RH-Author: John Snow +Message-id: <20190320161631.14841-18-jsnow@redhat.com> +Patchwork-id: 84958 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 17/19] iotests: Fix 207 to use QMP filters for qmp_log +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +Fixes: 08fcd6111e1949f456e1b232ebeeb0cc17019a92 +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Message-id: 20190210145736.1486-6-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 9ac10f2e2c93e647ba6830c7083310aa04f65021) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/207 | 10 +++++++--- + tests/qemu-iotests/207.out | 4 ++-- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 +index 687b2ca..e0d2a2c 100755 +--- a/tests/qemu-iotests/207 ++++ b/tests/qemu-iotests/207 +@@ -27,12 +27,16 @@ import re + iotests.verify_image_format(supported_fmts=['raw']) + iotests.verify_protocol(supported=['ssh']) + +-def filter_hash(msg): +- return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg) ++def filter_hash(qmsg): ++ def _filter(key, value): ++ if key == 'hash' and re.match('[0-9a-f]+', value): ++ return 'HASH' ++ return value ++ return iotests.filter_qmp(qmsg, _filter) + + def blockdev_create(vm, options): + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, +- filters=[iotests.filter_testfiles, filter_hash]) ++ filters=[iotests.filter_qmp_testfiles, filter_hash]) + + if 'return' in result: + assert result['return'] == {} +diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out +index 45ac7c2..88d2240 100644 +--- a/tests/qemu-iotests/207.out ++++ b/tests/qemu-iotests/207.out +@@ -40,7 +40,7 @@ Job failed: remote host key does not match host_key_check 'wrong' + {"execute": "job-dismiss", "arguments": {"id": "job0"}} + {"return": {}} + +-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} + {"return": {}} + {"execute": "job-dismiss", "arguments": {"id": "job0"}} + {"return": {}} +@@ -55,7 +55,7 @@ Job failed: remote host key does not match host_key_check 'wrong' + {"execute": "job-dismiss", "arguments": {"id": "job0"}} + {"return": {}} + +-{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} + {"return": {}} + {"execute": "job-dismiss", "arguments": {"id": "job0"}} + {"return": {}} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Fix-232-for-LUKS.patch b/SOURCES/kvm-iotests-Fix-232-for-LUKS.patch new file mode 100644 index 0000000..ba812ca --- /dev/null +++ b/SOURCES/kvm-iotests-Fix-232-for-LUKS.patch @@ -0,0 +1,52 @@ +From 7ccfbb9865064e0b41b6acf9e451c6c1471fe86e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:28 +0100 +Subject: [PATCH 030/163] iotests: Fix 232 for LUKS + +RH-Author: John Snow +Message-id: <20190320161631.14841-17-jsnow@redhat.com> +Patchwork-id: 84955 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 16/19] iotests: Fix 232 for LUKS +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +With IMGOPTSSYNTAX, $TEST_IMG is useless for this test (it only tests +the file-posix protocol driver). Therefore, if $TEST_IMG_FILE is set, +use that instead. + +Because this test requires the file protocol, $TEST_IMG_FILE will always +be set if $IMGOPTSSYNTAX is true. + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Message-id: 20190210145736.1486-5-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit c48221aa91d9078b86e23b19484227dc35d71840) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/232 | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 +index de884cd..2ed39d2 100755 +--- a/tests/qemu-iotests/232 ++++ b/tests/qemu-iotests/232 +@@ -70,6 +70,10 @@ size=128M + + _make_test_img $size + ++if [ -n "$TEST_IMG_FILE" ]; then ++ TEST_IMG=$TEST_IMG_FILE ++fi ++ + echo + echo "=== -drive with read-write image: read-only/auto-read-only combinations ===" + echo +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Make-233-output-more-reliable.patch b/SOURCES/kvm-iotests-Make-233-output-more-reliable.patch new file mode 100644 index 0000000..356cee8 --- /dev/null +++ b/SOURCES/kvm-iotests-Make-233-output-more-reliable.patch @@ -0,0 +1,115 @@ +From 0269fa2be355b2885e90bd676f63ae5fe4e8de08 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:35 +0100 +Subject: [PATCH 097/163] iotests: Make 233 output more reliable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190327172308.31077-23-jsnow@redhat.com> +Patchwork-id: 85189 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 22/55] iotests: Make 233 output more reliable +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +We have a race between the nbd server and the client both trying +to report errors at once which can make the test sometimes fail +if the output lines swap order under load. Break the race by +collecting server messages into a file and then replaying that +at the end of the test. + +We may yet want to fix the server to not output ANYTHING for a +client action except when -v was used (to avoid malicious clients +from being able to DoS a server by filling up its logs), but that +is saved for a future patch. + +Signed-off-by: Eric Blake +CC: Daniel P. Berrangé +Message-Id: <20190117193658.16413-2-eblake@redhat.com> +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit d08980511d78480ffbbd9897b7fd050bd03d518d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/233 | 11 ++++++++--- + tests/qemu-iotests/233.out | 4 +++- + 2 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 +index 1814efe..ab15c77 100755 +--- a/tests/qemu-iotests/233 ++++ b/tests/qemu-iotests/233 +@@ -2,7 +2,7 @@ + # + # Test NBD TLS certificate / authorization integration + # +-# Copyright (C) 2018 Red Hat, Inc. ++# Copyright (C) 2018-2019 Red Hat, Inc. + # + # 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 +@@ -30,6 +30,7 @@ _cleanup() + { + nbd_server_stop + _cleanup_test_img ++ rm -f "$TEST_DIR/server.log" + tls_x509_cleanup + } + trap "_cleanup; exit \$status" 0 1 2 3 15 +@@ -66,7 +67,7 @@ $QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io + + echo + echo "== check TLS client to plain server fails ==" +-nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" ++nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" 2> "$TEST_DIR/server.log" + + $QEMU_IMG info --image-opts \ + --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ +@@ -81,7 +82,7 @@ echo "== check plain client to TLS server fails ==" + nbd_server_start_tcp_socket \ + --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \ + --tls-creds tls0 \ +- -f $IMGFMT "$TEST_IMG" ++ -f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log" + + $QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g" + +@@ -109,6 +110,10 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \ + + $QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io + ++echo ++echo "== final server log ==" ++cat "$TEST_DIR/server.log" ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out +index 5f41672..2199d8a 100644 +--- a/tests/qemu-iotests/233.out ++++ b/tests/qemu-iotests/233.out +@@ -27,7 +27,6 @@ virtual size: 64M (67108864 bytes) + disk size: unavailable + + == check TLS with different CA fails == +-qemu-nbd: option negotiation failed: Verify failed: No certificate was found. + qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer + + == perform I/O over TLS == +@@ -37,4 +36,7 @@ wrote 1048576/1048576 bytes at offset 1048576 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + read 1048576/1048576 bytes at offset 1048576 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++== final server log == ++qemu-nbd: option negotiation failed: Verify failed: No certificate was found. + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Make-nbd-fault-injector-flush.patch b/SOURCES/kvm-iotests-Make-nbd-fault-injector-flush.patch new file mode 100644 index 0000000..6c4285c --- /dev/null +++ b/SOURCES/kvm-iotests-Make-nbd-fault-injector-flush.patch @@ -0,0 +1,103 @@ +From 1006959f0d9606cc07fd6c7944228b8e1a8ffe98 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:15 +0100 +Subject: [PATCH 076/163] iotests: Make nbd-fault-injector flush + +RH-Author: John Snow +Message-id: <20190327172308.31077-3-jsnow@redhat.com> +Patchwork-id: 85177 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/55] iotests: Make nbd-fault-injector flush +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +When closing a connection, make the nbd-fault-injector flush the socket. +Without this, the output is a bit unreliable with Python 3. + +Signed-off-by: Max Reitz +Reviewed-by: Eduardo Habkost +Reviewed-by: Cleber Rosa +Reviewed-by: Eric Blake +Message-Id: <20181022135307.14398-2-mreitz@redhat.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit 6d39db96d23ebe0d4361d108fa202091aa9cbfc1) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/083.out | 9 +++++++++ + tests/qemu-iotests/nbd-fault-injector.py | 1 + + 2 files changed, 10 insertions(+) + +diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out +index be6079d..f9af8bb 100644 +--- a/tests/qemu-iotests/083.out ++++ b/tests/qemu-iotests/083.out +@@ -41,6 +41,7 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect after neg2 === + ++Unable to read from socket: Connection reset by peer + Connection closed + read failed: Input/output error + +@@ -54,6 +55,7 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect before request === + ++Unable to read from socket: Connection reset by peer + Connection closed + read failed: Input/output error + +@@ -116,6 +118,7 @@ can't open device nbd+tcp://127.0.0.1:PORT/ + + === Check disconnect after neg-classic === + ++Unable to read from socket: Connection reset by peer + Connection closed + read failed: Input/output error + +@@ -161,6 +164,8 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock + + === Check disconnect after neg2 === + ++Unable to read from socket: Connection reset by peer ++Connection closed + read failed: Input/output error + + === Check disconnect 8 neg2 === +@@ -173,6 +178,8 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock + + === Check disconnect before request === + ++Unable to read from socket: Connection reset by peer ++Connection closed + read failed: Input/output error + + === Check disconnect after request === +@@ -234,6 +241,8 @@ can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock + + === Check disconnect after neg-classic === + ++Unable to read from socket: Connection reset by peer ++Connection closed + read failed: Input/output error + + *** done +diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py +index 8a04d97..44823f4 100755 +--- a/tests/qemu-iotests/nbd-fault-injector.py ++++ b/tests/qemu-iotests/nbd-fault-injector.py +@@ -111,6 +111,7 @@ class FaultInjectionSocket(object): + if rule.match(event, io): + if rule.when == 0 or bufsize is None: + print 'Closing connection on rule match %s' % rule.name ++ self.sock.flush() + sys.exit(0) + if rule.when != -1: + return rule.when +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Re-add-filename-filters.patch b/SOURCES/kvm-iotests-Re-add-filename-filters.patch new file mode 100644 index 0000000..67ac98e --- /dev/null +++ b/SOURCES/kvm-iotests-Re-add-filename-filters.patch @@ -0,0 +1,134 @@ +From 04ee985760e2f82bf1a74ea0772116a2e2603a1e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:26 +0100 +Subject: [PATCH 028/163] iotests: Re-add filename filters + +RH-Author: John Snow +Message-id: <20190320161631.14841-15-jsnow@redhat.com> +Patchwork-id: 84951 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 14/19] iotests: Re-add filename filters +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +A previous commit removed the default filters for qmp_log with the +intention to make them explicit; but this happened only for test 206. +There are more tests (for more exotic image formats than qcow2) which +require the filename filter, though. + +Note that 237 is still broken for Python 2.x, which is fixed in the next +commit. + +Fixes: f8ca8609d8549def45b28e82ecac64adaeee9f12 +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Message-id: 20190210145736.1486-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 250c04f554a4a148eb3772af255e6a60450293b0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/210 | 5 +++-- + tests/qemu-iotests/211 | 5 +++-- + tests/qemu-iotests/212 | 5 +++-- + tests/qemu-iotests/213 | 5 +++-- + 4 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 +index d142841..565e3b7 100755 +--- a/tests/qemu-iotests/210 ++++ b/tests/qemu-iotests/210 +@@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['luks']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options, ++ filters=[iotests.filter_qmp_testfiles]) + + if 'return' in result: + assert result['return'] == {} +@@ -53,7 +54,7 @@ with iotests.FilePath('t.luks') as disk_path, \ + 'size': 0 }) + + vm.qmp_log('blockdev-add', driver='file', filename=disk_path, +- node_name='imgfile') ++ node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) + + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'imgfile', +diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 +index 7b7985d..5d28545 100755 +--- a/tests/qemu-iotests/211 ++++ b/tests/qemu-iotests/211 +@@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vdi']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options, ++ filters=[iotests.filter_qmp_testfiles]) + + if 'return' in result: + assert result['return'] == {} +@@ -51,7 +52,7 @@ with iotests.FilePath('t.vdi') as disk_path, \ + 'size': 0 }) + + vm.qmp_log('blockdev-add', driver='file', filename=disk_path, +- node_name='imgfile') ++ node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) + + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'imgfile', +diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 +index 95c8810..42b74f2 100755 +--- a/tests/qemu-iotests/212 ++++ b/tests/qemu-iotests/212 +@@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['parallels']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options, ++ filters=[iotests.filter_qmp_testfiles]) + + if 'return' in result: + assert result['return'] == {} +@@ -51,7 +52,7 @@ with iotests.FilePath('t.parallels') as disk_path, \ + 'size': 0 }) + + vm.qmp_log('blockdev-add', driver='file', filename=disk_path, +- node_name='imgfile') ++ node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) + + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'imgfile', +diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 +index 4054439..5604f3c 100755 +--- a/tests/qemu-iotests/213 ++++ b/tests/qemu-iotests/213 +@@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vhdx']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options, ++ filters=[iotests.filter_qmp_testfiles]) + + if 'return' in result: + assert result['return'] == {} +@@ -51,7 +52,7 @@ with iotests.FilePath('t.vhdx') as disk_path, \ + 'size': 0 }) + + vm.qmp_log('blockdev-add', driver='file', filename=disk_path, +- node_name='imgfile') ++ node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) + + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'imgfile', +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Remove-superfluous-rm-from-232.patch b/SOURCES/kvm-iotests-Remove-superfluous-rm-from-232.patch new file mode 100644 index 0000000..8d25ea0 --- /dev/null +++ b/SOURCES/kvm-iotests-Remove-superfluous-rm-from-232.patch @@ -0,0 +1,45 @@ +From f84dbeffdf969f2b06d4bf6d4cbd6b49c77bb58d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:27 +0100 +Subject: [PATCH 029/163] iotests: Remove superfluous rm from 232 + +RH-Author: John Snow +Message-id: <20190320161631.14841-16-jsnow@redhat.com> +Patchwork-id: 84957 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 15/19] iotests: Remove superfluous rm from 232 +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +This test creates no such file. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Message-id: 20190210145736.1486-4-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 8f4ed6983ab1bda264074ac98d32657b411223bc) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/232 | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 +index bc2972d..de884cd 100755 +--- a/tests/qemu-iotests/232 ++++ b/tests/qemu-iotests/232 +@@ -30,7 +30,6 @@ status=1 # failure is the default! + _cleanup() + { + _cleanup_test_img +- rm -f $TEST_IMG.snap + } + trap "_cleanup; exit \$status" 0 1 2 3 15 + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Skip-233-if-certtool-not-installed.patch b/SOURCES/kvm-iotests-Skip-233-if-certtool-not-installed.patch new file mode 100644 index 0000000..170815a --- /dev/null +++ b/SOURCES/kvm-iotests-Skip-233-if-certtool-not-installed.patch @@ -0,0 +1,55 @@ +From 1764efd987a39de271eac2e5bc9900f29819f6f0 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:14 +0100 +Subject: [PATCH 075/163] iotests: Skip 233 if certtool not installed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190327172308.31077-2-jsnow@redhat.com> +Patchwork-id: 85176 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/55] iotests: Skip 233 if certtool not installed +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The use of TLS while building qemu is optional. While the +'certtool' binary should be available on every platform that +supports building against TLS, that does not imply that the +developer has installed it. Make the test gracefully skip +in that case. + +Reported-by: Kevin Wolf +Signed-off-by: Eric Blake +Reviewed-by: John Snow +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Wainer dos Santos Moschetta +Signed-off-by: Kevin Wolf +(cherry picked from commit 155af09d44f584a790118f78448f50f140d0f788) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.tls | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls +index 39f17c1..eae8178 100644 +--- a/tests/qemu-iotests/common.tls ++++ b/tests/qemu-iotests/common.tls +@@ -31,6 +31,9 @@ tls_x509_cleanup() + + tls_x509_init() + { ++ (certtool --help) >/dev/null 2>&1 || \ ++ _notrun "certtool utility not found, skipping test" ++ + mkdir -p "${tls_dir}" + + # use a fixed key so we don't waste system entropy on +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Test-file-posix-locking-and-reopen.patch b/SOURCES/kvm-iotests-Test-file-posix-locking-and-reopen.patch new file mode 100644 index 0000000..0a3cc0b --- /dev/null +++ b/SOURCES/kvm-iotests-Test-file-posix-locking-and-reopen.patch @@ -0,0 +1,135 @@ +From bc3e5687b0f29cae1b5770aee8f4625b348deea1 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:07 +0100 +Subject: [PATCH 07/33] iotests: Test file-posix locking and reopen + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-8-mreitz@redhat.com> +Patchwork-id: 84226 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 7/7] iotests: Test file-posix locking and reopen +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +Signed-off-by: Max Reitz +Reviewed-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 6d0a4a0fb5c8f10c8eb68b52cfda0082b00ae963) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/182 | 71 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/182.out | 9 ++++++ + 2 files changed, 80 insertions(+) + +diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182 +index 4b31592..3b7689c 100755 +--- a/tests/qemu-iotests/182 ++++ b/tests/qemu-iotests/182 +@@ -31,6 +31,7 @@ status=1 # failure is the default! + _cleanup() + { + _cleanup_test_img ++ rm -f "$TEST_IMG.overlay" + } + trap "_cleanup; exit \$status" 0 1 2 3 15 + +@@ -71,6 +72,76 @@ echo 'quit' | $QEMU -nographic -monitor stdio \ + + _cleanup_qemu + ++echo ++echo '=== Testing reopen ===' ++echo ++ ++# This tests that reopening does not unshare any permissions it should ++# not unshare ++# (There was a bug where reopening shared exactly the opposite of the ++# permissions it was supposed to share) ++ ++_launch_qemu ++ ++_send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'qmp_capabilities'}" \ ++ 'return' ++ ++# Open the image without any format layer (we are not going to access ++# it, so that is fine) ++# This should keep all permissions shared. ++success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'blockdev-add', ++ 'arguments': { ++ 'node-name': 'node0', ++ 'driver': 'file', ++ 'filename': '$TEST_IMG', ++ 'locking': 'on' ++ } }" \ ++ 'return' \ ++ 'error' ++ ++# This snapshot will perform a reopen to drop R/W to RO. ++# It should still keep all permissions shared. ++success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'blockdev-snapshot-sync', ++ 'arguments': { ++ 'node-name': 'node0', ++ 'snapshot-file': '$TEST_IMG.overlay', ++ 'snapshot-node-name': 'node1' ++ } }" \ ++ 'return' \ ++ 'error' ++ ++# Now open the same file again ++# This does not require any permissions (and does not unshare any), so ++# this will not conflict with node0. ++success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'blockdev-add', ++ 'arguments': { ++ 'node-name': 'node1', ++ 'driver': 'file', ++ 'filename': '$TEST_IMG', ++ 'locking': 'on' ++ } }" \ ++ 'return' \ ++ 'error' ++ ++# Now we attach the image to a virtio-blk device. This device does ++# require some permissions (at least WRITE and READ_CONSISTENT), so if ++# reopening node0 unshared any (which it should not have), this will ++# fail (but it should not). ++success_or_failure=y _send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'device_add', ++ 'arguments': { ++ 'driver': 'virtio-blk', ++ 'drive': 'node1' ++ } }" \ ++ 'return' \ ++ 'error' ++ ++_cleanup_qemu ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/182.out b/tests/qemu-iotests/182.out +index f1463c8..af501ca 100644 +--- a/tests/qemu-iotests/182.out ++++ b/tests/qemu-iotests/182.out +@@ -5,4 +5,13 @@ Starting QEMU + Starting a second QEMU using the same image should fail + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0,file.locking=on: Failed to get "write" lock + Is another process using the image [TEST_DIR/t.qcow2]? ++ ++=== Testing reopen === ++ ++{"return": {}} ++{"return": {}} ++Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 size=197120 backing_file=TEST_DIR/t.qcow2 backing_fmt=file cluster_size=65536 lazy_refcounts=off refcount_bits=16 ++{"return": {}} ++{"return": {}} ++{"return": {}} + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Test-migration-with-blockdev.patch b/SOURCES/kvm-iotests-Test-migration-with-blockdev.patch new file mode 100644 index 0000000..fe2b5b1 --- /dev/null +++ b/SOURCES/kvm-iotests-Test-migration-with-blockdev.patch @@ -0,0 +1,209 @@ +From 15ebf0b3bcbca92d0d63a67be3deee35572f1f00 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 6 Dec 2018 10:03:56 +0100 +Subject: [PATCH 16/34] iotests: Test migration with -blockdev + +RH-Author: Kevin Wolf +Message-id: <20181128092947.24543-3-kwolf@redhat.com> +Patchwork-id: 83181 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH 2/2] iotests: Test migration with -blockdev +Bugzilla: 1633536 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laurent Vivier + +Check that block node activation and inactivation works with a block +graph that is built with individually created nodes. + +RHEL: Disabled query-migrate call on the destination; this returns only +an empty object in 2.12. Changed reference output for Python 2 (we lack +the compatibility patches from upstream that make the output independent +from the Python version). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 330ca111ea0979d8c6fc9b3958f72d6dce164d5a) +Signed-off-by: Kevin Wolf +--- + tests/qemu-iotests/234 | 123 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/234.out | 28 +++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 152 insertions(+) + create mode 100755 tests/qemu-iotests/234 + create mode 100644 tests/qemu-iotests/234.out + +diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234 +new file mode 100755 +index 0000000..2b0f869 +--- /dev/null ++++ b/tests/qemu-iotests/234 +@@ -0,0 +1,123 @@ ++#!/usr/bin/env python ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# 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 . ++# ++# Creator/Owner: Kevin Wolf ++# ++# Check that block node activation and inactivation works with a block graph ++# that is built with individually created nodes ++ ++import iotests ++import os ++ ++iotests.verify_image_format(supported_fmts=['qcow2']) ++iotests.verify_platform(['linux']) ++ ++with iotests.FilePath('img') as img_path, \ ++ iotests.FilePath('backing') as backing_path, \ ++ iotests.FilePath('mig_fifo_a') as fifo_a, \ ++ iotests.FilePath('mig_fifo_b') as fifo_b, \ ++ iotests.VM(path_suffix='a') as vm_a, \ ++ iotests.VM(path_suffix='b') as vm_b: ++ ++ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, backing_path, '64M') ++ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, img_path, '64M') ++ ++ os.mkfifo(fifo_a) ++ os.mkfifo(fifo_b) ++ ++ iotests.log('Launching source VM...') ++ (vm_a.add_blockdev('file,filename=%s,node-name=drive0-file' % (img_path)) ++ .add_blockdev('%s,file=drive0-file,node-name=drive0' % (iotests.imgfmt)) ++ .add_blockdev('file,filename=%s,node-name=drive0-backing-file' % (backing_path)) ++ .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt)) ++ .launch()) ++ ++ iotests.log('Launching destination VM...') ++ (vm_b.add_blockdev('file,filename=%s,node-name=drive0-file' % (img_path)) ++ .add_blockdev('%s,file=drive0-file,node-name=drive0' % (iotests.imgfmt)) ++ .add_blockdev('file,filename=%s,node-name=drive0-backing-file' % (backing_path)) ++ .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt)) ++ .add_incoming("exec: cat '%s'" % (fifo_a)) ++ .launch()) ++ ++ # Add a child node that was created after the parent node. The reverse case ++ # is covered by the -blockdev options above. ++ iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing', ++ overlay='drive0')) ++ iotests.log(vm_b.qmp('blockdev-snapshot', node='drive0-backing', ++ overlay='drive0')) ++ ++ iotests.log('Enabling migration QMP events on A...') ++ iotests.log(vm_a.qmp('migrate-set-capabilities', capabilities=[ ++ { ++ 'capability': 'events', ++ 'state': True ++ } ++ ])) ++ ++ iotests.log('Starting migration to B...') ++ iotests.log(vm_a.qmp('migrate', uri='exec:cat >%s' % (fifo_a))) ++ with iotests.Timeout(3, 'Migration does not complete'): ++ while True: ++ event = vm_a.event_wait('MIGRATION') ++ iotests.log(event, filters=[iotests.filter_qmp_event]) ++ if event['data']['status'] == 'completed': ++ break ++ ++ iotests.log(vm_a.qmp('query-migrate')['return']['status']) ++ # Returns only {} on this QEMU version (no status) ++ # iotests.log(vm_b.qmp('query-migrate')['return']['status']) ++ ++ iotests.log(vm_a.qmp('query-status')) ++ iotests.log(vm_b.qmp('query-status')) ++ ++ iotests.log('Add a second parent to drive0-file...') ++ iotests.log(vm_b.qmp('blockdev-add', driver='raw', file='drive0-file', ++ node_name='drive0-raw')) ++ ++ iotests.log('Restart A with -incoming and second parent...') ++ vm_a.shutdown() ++ (vm_a.add_blockdev('raw,file=drive0-file,node-name=drive0-raw') ++ .add_incoming("exec: cat '%s'" % (fifo_b)) ++ .launch()) ++ ++ iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing', ++ overlay='drive0')) ++ ++ iotests.log('Enabling migration QMP events on B...') ++ iotests.log(vm_b.qmp('migrate-set-capabilities', capabilities=[ ++ { ++ 'capability': 'events', ++ 'state': True ++ } ++ ])) ++ ++ iotests.log('Starting migration back to A...') ++ iotests.log(vm_b.qmp('migrate', uri='exec:cat >%s' % (fifo_b))) ++ with iotests.Timeout(3, 'Migration does not complete'): ++ while True: ++ event = vm_b.event_wait('MIGRATION') ++ iotests.log(event, filters=[iotests.filter_qmp_event]) ++ if event['data']['status'] == 'completed': ++ break ++ ++ # Returns only {} on this QEMU version (no status) ++ # iotests.log(vm_a.qmp('query-migrate')['return']['status']) ++ iotests.log(vm_b.qmp('query-migrate')['return']['status']) ++ ++ iotests.log(vm_a.qmp('query-status')) ++ iotests.log(vm_b.qmp('query-status')) +diff --git a/tests/qemu-iotests/234.out b/tests/qemu-iotests/234.out +new file mode 100644 +index 0000000..c7cd95f +--- /dev/null ++++ b/tests/qemu-iotests/234.out +@@ -0,0 +1,28 @@ ++Launching source VM... ++Launching destination VM... ++{u'return': {}} ++{u'return': {}} ++Enabling migration QMP events on A... ++{u'return': {}} ++Starting migration to B... ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'} ++completed ++{u'return': {u'status': u'postmigrate', u'singlestep': False, u'running': False}} ++{u'return': {u'status': u'running', u'singlestep': False, u'running': True}} ++Add a second parent to drive0-file... ++{u'return': {}} ++Restart A with -incoming and second parent... ++{u'return': {}} ++Enabling migration QMP events on B... ++{u'return': {}} ++Starting migration back to A... ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'} ++completed ++{u'return': {u'status': u'running', u'singlestep': False, u'running': True}} ++{u'return': {u'status': u'postmigrate', u'singlestep': False, u'running': False}} +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index fcbf3f3..0998dcd 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -226,3 +226,4 @@ + 229 auto quick + 231 auto quick + 232 auto quick ++234 auto quick migration +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Unify-log-outputs-between-Python-2-and-3.patch b/SOURCES/kvm-iotests-Unify-log-outputs-between-Python-2-and-3.patch new file mode 100644 index 0000000..3a04046 --- /dev/null +++ b/SOURCES/kvm-iotests-Unify-log-outputs-between-Python-2-and-3.patch @@ -0,0 +1,2185 @@ +From 8d1e45a4b4c46bae4c2b453ef575407bfd8b3539 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:15 +0100 +Subject: [PATCH 017/163] iotests: Unify log outputs between Python 2 and 3 + +RH-Author: John Snow +Message-id: <20190320161631.14841-4-jsnow@redhat.com> +Patchwork-id: 84940 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/19] iotests: Unify log outputs between Python 2 and 3 +Bugzilla: 1668956 +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +When dumping an object into the log, there are differences between +Python 2 and 3. First, unicode strings are prefixed by 'u' in Python 2 +(they are no longer in 3, because unicode strings are the default +there). Second, the order of keys in dicts may differ. Third, +especially long numbers are longs in Python 2 and thus get an 'L' +suffix, which does not happen in Python 3. + +We can get around all of these differences by dumping objects (lists and +dicts) in a language-independent format, namely JSON. The JSON +generator even allows emitting dicts with their keys sorted +alphabetically. + +This changes the output of all tests that use these logging functions +(dict keys are ordered now, strings in dicts are now enclosed in double +quotes instead of single quotes, the 'L' suffix of large integers is +dropped, and "true" and "false" are now in lower case). +The quote change necessitates a small change to a filter used in test +207. + +Suggested-by: Eduardo Habkost +Signed-off-by: Max Reitz +Reviewed-by: Cleber Rosa +Message-Id: <20181022135307.14398-10-mreitz@redhat.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit e21b5f34d669b82087597273f3783626947291a0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/194.out | 22 +- + tests/qemu-iotests/202.out | 12 +- + tests/qemu-iotests/203.out | 14 +- + tests/qemu-iotests/206.out | 218 ++++++++--------- + tests/qemu-iotests/207 | 2 +- + tests/qemu-iotests/207.out | 72 +++--- + tests/qemu-iotests/208.out | 8 +- + tests/qemu-iotests/210.out | 94 ++++---- + tests/qemu-iotests/211.out | 102 ++++---- + tests/qemu-iotests/212.out | 174 +++++++------- + tests/qemu-iotests/213.out | 182 +++++++-------- + tests/qemu-iotests/216.out | 4 +- + tests/qemu-iotests/218.out | 20 +- + tests/qemu-iotests/219.out | 526 +++++++++++++++++++++--------------------- + tests/qemu-iotests/222.out | 24 +- + tests/qemu-iotests/234.out | 36 +-- + tests/qemu-iotests/iotests.py | 10 +- + 17 files changed, 762 insertions(+), 758 deletions(-) + +diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out +index 50ac50d..7185785 100644 +--- a/tests/qemu-iotests/194.out ++++ b/tests/qemu-iotests/194.out +@@ -1,18 +1,18 @@ + Launching VMs... + Launching NBD server on destination... +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + Starting `drive-mirror` on source... +-{u'return': {}} ++{"return": {}} + Waiting for `drive-mirror` to complete... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror-job0', u'type': u'mirror', u'speed': 0, u'len': 1073741824, u'offset': 1073741824}, u'event': u'BLOCK_JOB_READY'} ++{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + Starting migration... +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'} ++{"return": {}} ++{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + Gracefully ending the `drive-mirror` job on source... +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror-job0', u'type': u'mirror', u'speed': 0, u'len': 1073741824, u'offset': 1073741824}, u'event': u'BLOCK_JOB_COMPLETED'} ++{"return": {}} ++{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + Stopping the NBD server on destination... +-{u'return': {}} ++{"return": {}} +diff --git a/tests/qemu-iotests/202.out b/tests/qemu-iotests/202.out +index d5ea374..9a8619e 100644 +--- a/tests/qemu-iotests/202.out ++++ b/tests/qemu-iotests/202.out +@@ -1,11 +1,11 @@ + Launching VM... + Adding IOThread... +-{u'return': {}} ++{"return": {}} + Adding blockdevs... +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + Setting iothread... +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + Creating external snapshots... +-{u'return': {}} ++{"return": {}} +diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out +index 1a11f09..9d4abba 100644 +--- a/tests/qemu-iotests/203.out ++++ b/tests/qemu-iotests/203.out +@@ -1,11 +1,11 @@ + Launching VM... + Setting IOThreads... +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + Enabling migration QMP events... +-{u'return': {}} ++{"return": {}} + Starting migration... +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'} ++{"return": {}} ++{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out +index 789eebe..91f4db5 100644 +--- a/tests/qemu-iotests/206.out ++++ b/tests/qemu-iotests/206.out +@@ -1,16 +1,16 @@ + === Successful image creation (defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} +- +-{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}} +-{u'return': {}} +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} ++ ++{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node_name": "imgfile"}} ++{"return": {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -24,15 +24,15 @@ Format specific information: + + === Successful image creation (inline blockdev-add, explicit defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -46,15 +46,15 @@ Format specific information: + + === Successful image creation (v3 non-default options) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -68,15 +68,15 @@ Format specific information: + + === Successful image creation (v2 non-default options) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -90,10 +90,10 @@ Format specific information: + + === Successful image creation (encrypted) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -144,113 +144,113 @@ Format specific information: + + === Invalid BlockdevRef === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}} ++{"return": {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid sizes === +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}} ++{"return": {}} + Job failed: Image size must be a multiple of 512 bytes +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}} ++{"return": {}} + Job failed: Could not resize image: Image size cannot be negative +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}} ++{"return": {}} + Job failed: Could not resize image: Image size cannot be negative +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} ++{"return": {}} + Job failed: Could not resize image: Failed to grow the L1 table: File too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid version === +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter 'v1'"}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}} ++{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}} ++{"return": {}} + Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}} ++{"return": {}} + Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid backing file options === +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}} ++{"return": {}} + Job failed: Backing file and preallocation cannot be used at the same time +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Backing format cannot be used without backing file +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid cluster size === +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size must be a power of two between 512 and 2048k +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size must be a power of two between 512 and 2048k +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size must be a power of two between 512 and 2048k +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size must be a power of two between 512 and 2048k +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}} ++{"return": {}} + Job failed: Could not resize image: Failed to grow the L1 table: File too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid refcount width === +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}} ++{"return": {}} + Job failed: Refcount width must be a power of two and may not exceed 64 bits +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}} ++{"return": {}} + Job failed: Refcount width must be a power of two and may not exceed 64 bits +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}} ++{"return": {}} + Job failed: Refcount width must be a power of two and may not exceed 64 bits +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 +index 444ae23..687b2ca 100755 +--- a/tests/qemu-iotests/207 ++++ b/tests/qemu-iotests/207 +@@ -28,7 +28,7 @@ iotests.verify_image_format(supported_fmts=['raw']) + iotests.verify_protocol(supported=['ssh']) + + def filter_hash(msg): +- return re.sub("'hash': '[0-9a-f]+'", "'hash': HASH", msg) ++ return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg) + + def blockdev_create(vm, options): + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, +diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out +index 078b7e6..45ac7c2 100644 +--- a/tests/qemu-iotests/207.out ++++ b/tests/qemu-iotests/207.out +@@ -1,9 +1,9 @@ + === Successful image creation (defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT +@@ -16,49 +16,49 @@ virtual size: 4.0M (4194304 bytes) + + === Test host-key-check options === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 8.0M (8388608 bytes) + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 4.0M (4194304 bytes) + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} ++{"return": {}} + Job failed: remote host key does not match host_key_check 'wrong' +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 8.0M (8388608 bytes) + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} ++{"return": {}} + Job failed: remote host key does not match host_key_check 'wrong' +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT +@@ -66,15 +66,15 @@ virtual size: 4.0M (4194304 bytes) + + === Invalid path and user === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} ++{"return": {}} + Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31) +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}} ++{"return": {}} + Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +diff --git a/tests/qemu-iotests/208.out b/tests/qemu-iotests/208.out +index 3687e9d..9ff2582 100644 +--- a/tests/qemu-iotests/208.out ++++ b/tests/qemu-iotests/208.out +@@ -1,9 +1,9 @@ + Launching VM... + Starting NBD server... +-{u'return': {}} ++{"return": {}} + Adding NBD export... +-{u'return': {}} ++{"return": {}} + Creating external snapshot... +-{u'return': {}} ++{"return": {}} + Stopping NBD server... +-{u'return': {}} ++{"return": {}} +diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out +index 078ba54..923cb05 100644 +--- a/tests/qemu-iotests/210.out ++++ b/tests/qemu-iotests/210.out +@@ -1,16 +1,16 @@ + === Successful image creation (defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} +- +-{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}} +-{u'return': {}} +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} ++ ++{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node_name": "imgfile"}} ++{"return": {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} + file format: IMGFMT +@@ -54,15 +54,15 @@ Format specific information: + + === Successful image creation (with non-default options) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} + file format: IMGFMT +@@ -106,18 +106,18 @@ Format specific information: + + === Invalid BlockdevRef === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}} ++{"return": {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Zero size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} + file format: IMGFMT +@@ -161,34 +161,34 @@ Format specific information: + + === Invalid sizes === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}} ++{"return": {}} + Job failed: The requested file size is too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}} ++{"return": {}} + Job failed: The requested file size is too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}} ++{"return": {}} + Job failed: The requested file size is too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Resize image with invalid sizes === + +-{'execute': 'block_resize', 'arguments': {'size': 9223372036854775296, 'node_name': 'node1'}} +-{u'error': {u'class': u'GenericError', u'desc': u'The requested file size is too large'}} +-{'execute': 'block_resize', 'arguments': {'size': 9223372036854775808L, 'node_name': 'node1'}} +-{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}} +-{'execute': 'block_resize', 'arguments': {'size': 18446744073709551104L, 'node_name': 'node1'}} +-{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}} +-{'execute': 'block_resize', 'arguments': {'size': -9223372036854775808, 'node_name': 'node1'}} +-{u'error': {u'class': u'GenericError', u'desc': u"Parameter 'size' expects a >0 size"}} ++{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775296}} ++{"error": {"class": "GenericError", "desc": "The requested file size is too large"}} ++{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775808}} ++{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} ++{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 18446744073709551104}} ++{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} ++{"execute": "block_resize", "arguments": {"node_name": "node1", "size": -9223372036854775808}} ++{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}} + image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} + file format: IMGFMT + virtual size: 0 (0 bytes) +diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out +index 6feaea3..eebb0ea 100644 +--- a/tests/qemu-iotests/211.out ++++ b/tests/qemu-iotests/211.out +@@ -1,16 +1,16 @@ + === Successful image creation (defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} +- +-{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}} +-{u'return': {}} +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} ++ ++{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node_name": "imgfile"}} ++{"return": {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -21,15 +21,15 @@ cluster_size: 1048576 + + === Successful image creation (explicit defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -40,15 +40,15 @@ cluster_size: 1048576 + + === Successful image creation (with non-default options) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -60,18 +60,18 @@ cluster_size: 1048576 + + === Invalid BlockdevRef === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}} ++{"return": {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Zero size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -80,10 +80,10 @@ cluster_size: 1048576 + + === Maximum size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -92,21 +92,21 @@ cluster_size: 1048576 + + === Invalid sizes === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}} ++{"return": {}} + Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000) +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}} ++{"return": {}} + Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000) +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}} ++{"return": {}} + Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000) +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out +index 9150da7..01da467 100644 +--- a/tests/qemu-iotests/212.out ++++ b/tests/qemu-iotests/212.out +@@ -1,16 +1,16 @@ + === Successful image creation (defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} +- +-{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}} +-{u'return': {}} +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} ++ ++{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node_name": "imgfile"}} ++{"return": {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -18,15 +18,15 @@ virtual size: 128M (134217728 bytes) + + === Successful image creation (explicit defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -34,15 +34,15 @@ virtual size: 64M (67108864 bytes) + + === Successful image creation (with non-default options) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -50,18 +50,18 @@ virtual size: 32M (33554432 bytes) + + === Invalid BlockdevRef === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}} ++{"return": {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Zero size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -69,10 +69,10 @@ virtual size: 0 (0 bytes) + + === Maximum size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -80,77 +80,77 @@ virtual size: 4096T (4503599627369984 bytes) + + === Invalid sizes === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}} ++{"return": {}} + Job failed: Image size must be a multiple of 512 bytes +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}} ++{"return": {}} + Job failed: Image size is too large for this cluster size +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}} ++{"return": {}} + Job failed: Image size is too large for this cluster size +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}} ++{"return": {}} + Job failed: Image size is too large for this cluster size +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}} ++{"return": {}} + Job failed: Image size is too large for this cluster size +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid cluster size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size must be a multiple of 512 bytes +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size must be a multiple of 512 bytes +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size is too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size is too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Cluster size is too large +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Image size is too large for this cluster size +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}} ++{"return": {}} + Job failed: Image size is too large for this cluster size +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out +index e1dcd47..0c9d65b 100644 +--- a/tests/qemu-iotests/213.out ++++ b/tests/qemu-iotests/213.out +@@ -1,16 +1,16 @@ + === Successful image creation (defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} +- +-{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}} +-{u'return': {}} +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} ++ ++{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node_name": "imgfile"}} ++{"return": {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -19,15 +19,15 @@ cluster_size: 8388608 + + === Successful image creation (explicit defaults) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -36,15 +36,15 @@ cluster_size: 8388608 + + === Successful image creation (with non-default options) === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -53,18 +53,18 @@ cluster_size: 268435456 + + === Invalid BlockdevRef === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}} ++{"return": {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Zero size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -73,10 +73,10 @@ cluster_size: 8388608 + + === Maximum size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}} +-{u'return': {}} +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}} ++{"return": {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + image: TEST_IMG + file format: IMGFMT +@@ -85,85 +85,85 @@ cluster_size: 67108864 + + === Invalid sizes === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}} ++{"return": {}} + Job failed: Image size too large; max of 64TB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}} ++{"return": {}} + Job failed: Image size too large; max of 64TB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}} ++{"return": {}} + Job failed: Image size too large; max of 64TB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}} ++{"return": {}} + Job failed: Image size too large; max of 64TB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid block size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Block size must be a multiple of 1 MB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Block size must be a multiple of 1 MB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Block size must be a power of two +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Block size must not exceed 268435456 +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}} ++{"return": {}} + Job failed: Block size must be a multiple of 1 MB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + + === Invalid log size === + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}} ++{"return": {}} + Job failed: Log size must be a multiple of 1 MB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}} ++{"return": {}} + Job failed: Log size must be a multiple of 1 MB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}} ++{"return": {}} + Job failed: Log size must be smaller than 4 GB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +-{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} +-{u'return': {}} ++{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}} ++{"return": {}} + Job failed: Log size must be a multiple of 1 MB +-{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-{u'return': {}} ++{"execute": "job-dismiss", "arguments": {"id": "job0"}} ++{"return": {}} + +diff --git a/tests/qemu-iotests/216.out b/tests/qemu-iotests/216.out +index 45ea857..a70aa5c 100644 +--- a/tests/qemu-iotests/216.out ++++ b/tests/qemu-iotests/216.out +@@ -7,8 +7,8 @@ Done + + --- Doing COR --- + +-{u'return': {}} +-{u'return': u''} ++{"return": {}} ++{"return": ""} + + --- Checking COR result --- + +diff --git a/tests/qemu-iotests/218.out b/tests/qemu-iotests/218.out +index 7dbf78e..825a657 100644 +--- a/tests/qemu-iotests/218.out ++++ b/tests/qemu-iotests/218.out +@@ -4,27 +4,27 @@ + --- force=false --- + + Cancelling job +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 65536, u'len': 1048576, u'offset': 65536}, u'event': u'BLOCK_JOB_CANCELLED'} ++{"return": {}} ++{"data": {"device": "mirror", "len": 1048576, "offset": 65536, "speed": 65536, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + --- force=true --- + + Cancelling job +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 65536, u'len': 1048576, u'offset': 65536}, u'event': u'BLOCK_JOB_CANCELLED'} ++{"return": {}} ++{"data": {"device": "mirror", "len": 1048576, "offset": 65536, "speed": 65536, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + === Cancel mirror job after convergence === + + --- force=false --- + +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_READY'} ++{"data": {"device": "mirror", "len": 1048576, "offset": 1048576, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + Cancelling job +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_COMPLETED'} ++{"return": {}} ++{"data": {"device": "mirror", "len": 1048576, "offset": 1048576, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + --- force=true --- + +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_READY'} ++{"data": {"device": "mirror", "len": 1048576, "offset": 1048576, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + Cancelling job +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_CANCELLED'} ++{"return": {}} ++{"data": {"device": "mirror", "len": 1048576, "offset": 1048576, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out +index 6dc07bc..8ebd3fe 100644 +--- a/tests/qemu-iotests/219.out ++++ b/tests/qemu-iotests/219.out +@@ -2,326 +2,326 @@ Launching VM... + + + Starting block job: drive-mirror (auto-finalize: True; auto-dismiss: True) +-{u'return': {}} +-{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'mirror'}]} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{"return": {}} ++{"return": [{"current-progress": "FILTERED", "id": "job0", "status": "running", "total-progress": "FILTERED", "type": "mirror"}]} ++{"data": {"id": "job0", "status": "created"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + Pause/resume in RUNNING + === Testing block-job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 65536, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "running", "total-progress": 4194304, "type": "mirror"}]} + === Testing block-job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "running", "total-progress": 4194304, "type": "mirror"}]} + === Testing job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "running", "total-progress": 4194304, "type": "mirror"}]} + === Testing job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'return': {}} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 327680, "id": "job0", "status": "running", "total-progress": 4194304, "type": "mirror"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"return": {}} + + Waiting for READY state... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"data": {"id": "job0", "status": "ready"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "ready", "total-progress": 4194304, "type": "mirror"}]} + + Pause/resume in READY + === Testing block-job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "standby"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "standby", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "ready"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "ready", "total-progress": 4194304, "type": "mirror"}]} + === Testing block-job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "standby"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "standby", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "ready"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "ready", "total-progress": 4194304, "type": "mirror"}]} + === Testing job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "standby"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "standby", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "ready"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "ready", "total-progress": 4194304, "type": "mirror"}]} + === Testing job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}} +-{u'return': {}} ++{"return": {}} ++{"data": {"id": "job0", "status": "standby"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "standby", "total-progress": 4194304, "type": "mirror"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "ready"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "ready", "total-progress": 4194304, "type": "mirror"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}} ++{"return": {}} + + Waiting for PENDING state... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': []} ++{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "null"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": []} + + + Starting block job: drive-backup (auto-finalize: True; auto-dismiss: True) +-{u'return': {}} +-{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{"return": {}} ++{"return": [{"current-progress": "FILTERED", "id": "job0", "status": "running", "total-progress": "FILTERED", "type": "backup"}]} ++{"data": {"id": "job0", "status": "created"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + Pause/resume in RUNNING + === Testing block-job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 65536, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing block-job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'return': {}} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 327680, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"return": {}} + + Waiting for PENDING state... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': []} ++{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "null"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": []} + + + Starting block job: drive-backup (auto-finalize: True; auto-dismiss: False) +-{u'return': {}} +-{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{"return": {}} ++{"return": [{"current-progress": "FILTERED", "id": "job0", "status": "running", "total-progress": "FILTERED", "type": "backup"}]} ++{"data": {"id": "job0", "status": "created"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + Pause/resume in RUNNING + === Testing block-job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 65536, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing block-job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'return': {}} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 327680, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"return": {}} + + Waiting for PENDING state... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'concluded', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': []} ++{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "concluded", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{"return": {}} ++{"data": {"id": "job0", "status": "null"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": []} + + + Starting block job: drive-backup (auto-finalize: False; auto-dismiss: True) +-{u'return': {}} +-{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{"return": {}} ++{"return": [{"current-progress": "FILTERED", "id": "job0", "status": "running", "total-progress": "FILTERED", "type": "backup"}]} ++{"data": {"id": "job0", "status": "created"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + Pause/resume in RUNNING + === Testing block-job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 65536, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing block-job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'return': {}} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 327680, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"return": {}} + + Waiting for PENDING state... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'pending', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': []} ++{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{"return": {}} ++{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "null"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": []} + + + Starting block job: drive-backup (auto-finalize: False; auto-dismiss: False) +-{u'return': {}} +-{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{"return": {}} ++{"return": [{"current-progress": "FILTERED", "id": "job0", "status": "running", "total-progress": "FILTERED", "type": "backup"}]} ++{"data": {"id": "job0", "status": "created"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + + Pause/resume in RUNNING + === Testing block-job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 65536, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing block-job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 131072, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/block-job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 196608, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} + === Testing job-pause/job-resume === +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} +-{u'return': {}} ++{"return": {}} ++{"data": {"id": "job0", "status": "paused"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 262144, "id": "job0", "status": "paused", "total-progress": 4194304, "type": "backup"}]} ++{"return": {}} ++{"data": {"id": "job0", "status": "running"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 327680, "id": "job0", "status": "running", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{"return": {}} + + Waiting for PENDING state... +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'pending', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': [{u'status': u'concluded', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} +-{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} +-{u'return': []} ++{"data": {"id": "job0", "status": "waiting"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"id": "job0", "status": "pending"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "pending", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{"return": {}} ++{"data": {"id": "job0", "status": "concluded"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": [{"current-progress": 4194304, "id": "job0", "status": "concluded", "total-progress": 4194304, "type": "backup"}]} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{"error": {"class": "GenericError", "desc": "Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{"return": {}} ++{"data": {"id": "job0", "status": "null"}, "event": "JOB_STATUS_CHANGE", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": []} +diff --git a/tests/qemu-iotests/222.out b/tests/qemu-iotests/222.out +index 48f336a..16643dd 100644 +--- a/tests/qemu-iotests/222.out ++++ b/tests/qemu-iotests/222.out +@@ -8,13 +8,13 @@ Done + + --- Setting up Fleecing Graph --- + +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + + --- Setting up NBD Export --- + +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + + --- Sanity Check --- + +@@ -29,13 +29,13 @@ read -P0 0x3fe0000 64k + --- Testing COW --- + + write -P0xab 0 64k +-{u'return': u''} ++{"return": ""} + write -P0xad 0x00f8000 64k +-{u'return': u''} ++{"return": ""} + write -P0x1d 0x2008000 64k +-{u'return': u''} ++{"return": ""} + write -P0xea 0x3fe0000 64k +-{u'return': u''} ++{"return": ""} + + --- Verifying Data --- + +@@ -49,10 +49,10 @@ read -P0 0x3fe0000 64k + + --- Cleanup --- + +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'drive0', u'type': u'backup', u'speed': 0, u'len': 67108864, u'offset': 393216}, u'event': u'BLOCK_JOB_CANCELLED'} +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"data": {"device": "drive0", "len": 67108864, "offset": 393216, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"return": {}} ++{"return": {}} + + --- Confirming writes --- + +diff --git a/tests/qemu-iotests/234.out b/tests/qemu-iotests/234.out +index c7cd95f..592625b 100644 +--- a/tests/qemu-iotests/234.out ++++ b/tests/qemu-iotests/234.out +@@ -1,28 +1,28 @@ + Launching source VM... + Launching destination VM... +-{u'return': {}} +-{u'return': {}} ++{"return": {}} ++{"return": {}} + Enabling migration QMP events on A... +-{u'return': {}} ++{"return": {}} + Starting migration to B... +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'} ++{"return": {}} ++{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + completed +-{u'return': {u'status': u'postmigrate', u'singlestep': False, u'running': False}} +-{u'return': {u'status': u'running', u'singlestep': False, u'running': True}} ++{"return": {"running": false, "singlestep": false, "status": "postmigrate"}} ++{"return": {"running": true, "singlestep": false, "status": "running"}} + Add a second parent to drive0-file... +-{u'return': {}} ++{"return": {}} + Restart A with -incoming and second parent... +-{u'return': {}} ++{"return": {}} + Enabling migration QMP events on B... +-{u'return': {}} ++{"return": {}} + Starting migration back to A... +-{u'return': {}} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'setup'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'active'}, u'event': u'MIGRATION'} +-{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'completed'}, u'event': u'MIGRATION'} ++{"return": {}} ++{"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} ++{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} + completed +-{u'return': {u'status': u'running', u'singlestep': False, u'running': True}} +-{u'return': {u'status': u'postmigrate', u'singlestep': False, u'running': False}} ++{"return": {"running": true, "singlestep": false, "status": "running"}} ++{"return": {"running": false, "singlestep": false, "status": "postmigrate"}} +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 2f22fab..1b9656a 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -248,7 +248,10 @@ def filter_img_info(output, filename): + def log(msg, filters=[]): + for flt in filters: + msg = flt(msg) +- print msg ++ if type(msg) is dict or type(msg) is list: ++ print(json.dumps(msg, sort_keys=True)) ++ else: ++ print(msg) + + class Timeout: + def __init__(self, seconds, errmsg = "Timeout"): +@@ -436,10 +439,11 @@ class VM(qtest.QEMUQtestMachine): + return result + + def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs): +- logmsg = "{'execute': '%s', 'arguments': %s}" % (cmd, kwargs) ++ logmsg = '{"execute": "%s", "arguments": %s}' % \ ++ (cmd, json.dumps(kwargs, sort_keys=True)) + log(logmsg, filters) + result = self.qmp(cmd, **kwargs) +- log(str(result), filters) ++ log(json.dumps(result, sort_keys=True), filters) + return result + + def run_job(self, job, auto_finalize=True, auto_dismiss=False): +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Wait-for-qemu-to-end-in-223.patch b/SOURCES/kvm-iotests-Wait-for-qemu-to-end-in-223.patch new file mode 100644 index 0000000..04b68a3 --- /dev/null +++ b/SOURCES/kvm-iotests-Wait-for-qemu-to-end-in-223.patch @@ -0,0 +1,71 @@ +From e5d7e4bd2388cebecc64469ea957676caba9bbe1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:07 +0100 +Subject: [PATCH 129/163] iotests: Wait for qemu to end in 223 + +RH-Author: John Snow +Message-id: <20190327172308.31077-55-jsnow@redhat.com> +Patchwork-id: 85219 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 54/55] iotests: Wait for qemu to end in 223 +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +When iotest 223 was first written, it didn't matter if we waited for +the qemu process to clean up. But with the introduction of a later +qemu-nbd process trying to reuse the same file, there is a race where +even though the asynchronous qemu process has responded to "quit", it +has not yet had time to unlock the file and exit, resulting in: + +-[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, +-{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true}, +-{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] ++qemu-nbd: Failed to blk_new_open 'tests/qemu-iotests/scratch/t.qcow2': Failed to get shared "write" lock ++Is another process using the image [tests/qemu-iotests/scratch/t.qcow2]? ++qemu-img: Could not open 'driver=nbd,server.type=unix,server.path=tests/qemu-iotests/scratch/qemu-nbd.sock,x-dirty-bitmap=qemu:dirty-bitmap:b': Failed to connect socket tests/qemu-iotests/scratch/qemu-nbd.sock: Connection refused ++./common.nbd: line 33: kill: (11122) - No such process + +Fixes: ddd09448 +Reported-by: Alberto Garcia +Signed-off-by: Eric Blake +Message-Id: <20190305182908.13557-1-eblake@redhat.com> +Tested-by: Alberto Garcia +Reviewed-by: Kevin Wolf +(cherry picked from commit 054be3605459d4342e9ee5a82ae0fcffeeb09e4d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/223 | 1 + + tests/qemu-iotests/223.out | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index f120a01..c0a4f9c 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -179,6 +179,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "error" # Again + _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" ++wait=yes _cleanup_qemu + + echo + echo "=== Use qemu-nbd as server ===" +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index 963ae28..0524ffb 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -89,6 +89,7 @@ read 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"error": {"class": "GenericError", "desc": "NBD server not running"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + + === Use qemu-nbd as server === + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-add-busy-recording-bit-test-to-124.patch b/SOURCES/kvm-iotests-add-busy-recording-bit-test-to-124.patch new file mode 100644 index 0000000..ba3d07b --- /dev/null +++ b/SOURCES/kvm-iotests-add-busy-recording-bit-test-to-124.patch @@ -0,0 +1,172 @@ +From 5252d9e158007252f01fb6de28e22918741e6f8e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:48 +0200 +Subject: [PATCH 143/163] iotests: add busy/recording bit test to 124 + +RH-Author: John Snow +Message-id: <20190403181857.9693-13-jsnow@redhat.com> +Patchwork-id: 85423 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/21] iotests: add busy/recording bit test to 124 +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +This adds a simple test that ensures the busy bit works for push backups, +as well as doubling as bonus test for incremental backups that get interrupted +by EIO errors. + +Recording bit tests are already handled sufficiently by 236. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Tested-by: Eric Blake +Message-id: 20190223000614.13894-11-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit c61b198b63219b489908c87371acae8c986ce4d3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/124 | 113 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/124.out | 4 +- + 2 files changed, 115 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 +index 439a86a..acfe04e 100755 +--- a/tests/qemu-iotests/124 ++++ b/tests/qemu-iotests/124 +@@ -634,6 +634,119 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): + self.vm.shutdown() + self.check_backups() + ++ def test_incremental_pause(self): ++ """ ++ Test an incremental backup that errors into a pause and is resumed. ++ """ ++ ++ drive0 = self.drives[0] ++ # NB: The blkdebug script here looks for a "flush, read, read" pattern. ++ # The flush occurs in hmp_io_writes, the first read in device_add, and ++ # the last read during the block job. ++ result = self.vm.qmp('blockdev-add', ++ node_name=drive0['id'], ++ driver=drive0['fmt'], ++ file={ ++ 'driver': 'blkdebug', ++ 'image': { ++ 'driver': 'file', ++ 'filename': drive0['file'] ++ }, ++ 'set-state': [{ ++ 'event': 'flush_to_disk', ++ 'state': 1, ++ 'new_state': 2 ++ },{ ++ 'event': 'read_aio', ++ 'state': 2, ++ 'new_state': 3 ++ }], ++ 'inject-error': [{ ++ 'event': 'read_aio', ++ 'errno': 5, ++ 'state': 3, ++ 'immediately': False, ++ 'once': True ++ }], ++ }) ++ self.assert_qmp(result, 'return', {}) ++ self.create_anchor_backup(drive0) ++ bitmap = self.add_bitmap('bitmap0', drive0) ++ ++ # Emulate guest activity ++ self.hmp_io_writes(drive0['id'], (('0xab', 0, 512), ++ ('0xfe', '16M', '256k'), ++ ('0x64', '32736k', '64k'))) ++ ++ # For the purposes of query-block visibility of bitmaps, add a drive ++ # frontend after we've written data; otherwise we can't use hmp-io ++ result = self.vm.qmp("device_add", ++ id="device0", ++ drive=drive0['id'], ++ driver="virtio-blk") ++ self.assert_qmp(result, 'return', {}) ++ ++ # Bitmap Status Check ++ query = self.vm.qmp('query-block') ++ ret = [bmap for bmap in query['return'][0]['dirty-bitmaps'] ++ if bmap.get('name') == bitmap.name][0] ++ self.assert_qmp(ret, 'count', 458752) ++ self.assert_qmp(ret, 'granularity', 65536) ++ self.assert_qmp(ret, 'status', 'active') ++ self.assert_qmp(ret, 'busy', False) ++ self.assert_qmp(ret, 'recording', True) ++ ++ # Start backup ++ parent, _ = bitmap.last_target() ++ target = self.prepare_backup(bitmap, parent) ++ res = self.vm.qmp('drive-backup', ++ job_id=bitmap.drive['id'], ++ device=bitmap.drive['id'], ++ sync='incremental', ++ bitmap=bitmap.name, ++ format=bitmap.drive['fmt'], ++ target=target, ++ mode='existing', ++ on_source_error='stop') ++ self.assert_qmp(res, 'return', {}) ++ ++ # Wait for the error ++ event = self.vm.event_wait(name="BLOCK_JOB_ERROR", ++ match={"data":{"device":bitmap.drive['id']}}) ++ self.assert_qmp(event, 'data', {'device': bitmap.drive['id'], ++ 'action': 'stop', ++ 'operation': 'read'}) ++ ++ # Bitmap Status Check ++ query = self.vm.qmp('query-block') ++ ret = [bmap for bmap in query['return'][0]['dirty-bitmaps'] ++ if bmap.get('name') == bitmap.name][0] ++ self.assert_qmp(ret, 'count', 458752) ++ self.assert_qmp(ret, 'granularity', 65536) ++ self.assert_qmp(ret, 'status', 'frozen') ++ self.assert_qmp(ret, 'busy', True) ++ self.assert_qmp(ret, 'recording', True) ++ ++ # Resume and check incremental backup for consistency ++ res = self.vm.qmp('block-job-resume', device=bitmap.drive['id']) ++ self.assert_qmp(res, 'return', {}) ++ self.wait_qmp_backup(bitmap.drive['id']) ++ ++ # Bitmap Status Check ++ query = self.vm.qmp('query-block') ++ ret = [bmap for bmap in query['return'][0]['dirty-bitmaps'] ++ if bmap.get('name') == bitmap.name][0] ++ self.assert_qmp(ret, 'count', 0) ++ self.assert_qmp(ret, 'granularity', 65536) ++ self.assert_qmp(ret, 'status', 'active') ++ self.assert_qmp(ret, 'busy', False) ++ self.assert_qmp(ret, 'recording', True) ++ ++ # Finalize / Cleanup ++ self.make_reference_backup(bitmap) ++ self.vm.shutdown() ++ self.check_backups() ++ + + if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) +diff --git a/tests/qemu-iotests/124.out b/tests/qemu-iotests/124.out +index e56cae0..281b69e 100644 +--- a/tests/qemu-iotests/124.out ++++ b/tests/qemu-iotests/124.out +@@ -1,5 +1,5 @@ +-........... ++............ + ---------------------------------------------------------------------- +-Ran 11 tests ++Ran 12 tests + + OK +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-add-filter_generated_node_ids.patch b/SOURCES/kvm-iotests-add-filter_generated_node_ids.patch new file mode 100644 index 0000000..c94cced --- /dev/null +++ b/SOURCES/kvm-iotests-add-filter_generated_node_ids.patch @@ -0,0 +1,45 @@ +From 08890e6fc7100a01624ed80662d2a7d204e9f3b8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:19 +0100 +Subject: [PATCH 021/163] iotests: add filter_generated_node_ids + +RH-Author: John Snow +Message-id: <20190320161631.14841-8-jsnow@redhat.com> +Patchwork-id: 84941 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/19] iotests: add filter_generated_node_ids +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +To mimic the common filter of the same name, but for the python tests. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-7-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit fa1151f811ffa1973b6980b09f095d0e2ebea08b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index c5739a6..5334ff4 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -233,6 +233,9 @@ def filter_testfiles(msg): + prefix = os.path.join(test_dir, "%s-" % (os.getpid())) + return msg.replace(prefix, 'TEST_DIR/PID-') + ++def filter_generated_node_ids(msg): ++ return re.sub("#block[0-9]+", "NODE_NAME", msg) ++ + def filter_img_info(output, filename): + lines = [] + for line in output.split('\n'): +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-add-iotest-236-for-testing-bitmap-merge.patch b/SOURCES/kvm-iotests-add-iotest-236-for-testing-bitmap-merge.patch new file mode 100644 index 0000000..c38e1bd --- /dev/null +++ b/SOURCES/kvm-iotests-add-iotest-236-for-testing-bitmap-merge.patch @@ -0,0 +1,570 @@ +From 85a2175420c8c79bf947f1f2af3d544548098b6e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:24 +0100 +Subject: [PATCH 026/163] iotests: add iotest 236 for testing bitmap merge + +RH-Author: John Snow +Message-id: <20190320161631.14841-13-jsnow@redhat.com> +Patchwork-id: 84950 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/19] iotests: add iotest 236 for testing bitmap merge +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +New interface, new smoke test. + +Signed-off-by: John Snow +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20181221093529.23855-12-jsnow@redhat.com> +[eblake: fix last-minute change to echo text] +Signed-off-by: Eric Blake +(cherry picked from commit 14da540f2a68b3f730b1a7c31de783f3d68f6fc7) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/236 | 161 +++++++++++++++++++++ + tests/qemu-iotests/236.out | 351 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 513 insertions(+) + create mode 100755 tests/qemu-iotests/236 + create mode 100644 tests/qemu-iotests/236.out + +diff --git a/tests/qemu-iotests/236 b/tests/qemu-iotests/236 +new file mode 100755 +index 0000000..79a6381 +--- /dev/null ++++ b/tests/qemu-iotests/236 +@@ -0,0 +1,161 @@ ++#!/usr/bin/env python ++# ++# Test bitmap merges. ++# ++# Copyright (c) 2018 John Snow for Red Hat, Inc. ++# ++# 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 . ++# ++# owner=jsnow@redhat.com ++ ++import iotests ++from iotests import log ++ ++iotests.verify_image_format(supported_fmts=['generic']) ++size = 64 * 1024 * 1024 ++granularity = 64 * 1024 ++ ++patterns = [("0x5d", "0", "64k"), ++ ("0xd5", "1M", "64k"), ++ ("0xdc", "32M", "64k"), ++ ("0xcd", "0x3ff0000", "64k")] # 64M - 64K ++ ++overwrite = [("0xab", "0", "64k"), # Full overwrite ++ ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K) ++ ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K) ++ ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K) ++ ++def query_bitmaps(vm): ++ res = vm.qmp("query-block") ++ return { "bitmaps": { device['device']: device.get('dirty-bitmaps', []) for ++ device in res['return'] } } ++ ++with iotests.FilePath('img') as img_path, \ ++ iotests.VM() as vm: ++ ++ log('--- Preparing image & VM ---\n') ++ iotests.qemu_img_create('-f', iotests.imgfmt, img_path, str(size)) ++ vm.add_drive(img_path) ++ vm.launch() ++ ++ log('\n--- Adding preliminary bitmaps A & B ---\n') ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="bitmapA", granularity=granularity) ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="bitmapB", granularity=granularity) ++ ++ # Dirties 4 clusters. count=262144 ++ log('\n--- Emulating writes ---\n') ++ for p in patterns: ++ cmd = "write -P%s %s %s" % p ++ log(cmd) ++ log(vm.hmp_qemu_io("drive0", cmd)) ++ ++ log(query_bitmaps(vm), indent=2) ++ ++ log('\n--- Submitting & Aborting Transaction ---\n') ++ vm.qmp_log("transaction", indent=2, actions=[ ++ { "type": "block-dirty-bitmap-disable", ++ "data": { "node": "drive0", "name": "bitmapB" }}, ++ { "type": "block-dirty-bitmap-add", ++ "data": { "node": "drive0", "name": "bitmapC", ++ "granularity": granularity }}, ++ { "type": "block-dirty-bitmap-clear", ++ "data": { "node": "drive0", "name": "bitmapA" }}, ++ { "type": "abort", "data": {}} ++ ]) ++ log(query_bitmaps(vm), indent=2) ++ ++ log('\n--- Disabling B & Adding C ---\n') ++ vm.qmp_log("transaction", indent=2, actions=[ ++ { "type": "block-dirty-bitmap-disable", ++ "data": { "node": "drive0", "name": "bitmapB" }}, ++ { "type": "block-dirty-bitmap-add", ++ "data": { "node": "drive0", "name": "bitmapC", ++ "granularity": granularity }}, ++ # Purely extraneous, but test that it works: ++ { "type": "block-dirty-bitmap-disable", ++ "data": { "node": "drive0", "name": "bitmapC" }}, ++ { "type": "block-dirty-bitmap-enable", ++ "data": { "node": "drive0", "name": "bitmapC" }}, ++ ]) ++ ++ log('\n--- Emulating further writes ---\n') ++ # Dirties 6 clusters, 3 of which are new in contrast to "A". ++ # A = 64 * 1024 * (4 + 3) = 458752 ++ # C = 64 * 1024 * 6 = 393216 ++ for p in overwrite: ++ cmd = "write -P%s %s %s" % p ++ log(cmd) ++ log(vm.hmp_qemu_io("drive0", cmd)) ++ ++ log('\n--- Disabling A & C ---\n') ++ vm.qmp_log("transaction", indent=2, actions=[ ++ { "type": "block-dirty-bitmap-disable", ++ "data": { "node": "drive0", "name": "bitmapA" }}, ++ { "type": "block-dirty-bitmap-disable", ++ "data": { "node": "drive0", "name": "bitmapC" }} ++ ]) ++ ++ # A: 7 clusters ++ # B: 4 clusters ++ # C: 6 clusters ++ log(query_bitmaps(vm), indent=2) ++ ++ log('\n--- Submitting & Aborting Merge Transaction ---\n') ++ vm.qmp_log("transaction", indent=2, actions=[ ++ { "type": "block-dirty-bitmap-add", ++ "data": { "node": "drive0", "name": "bitmapD", ++ "disabled": True, "granularity": granularity }}, ++ { "type": "block-dirty-bitmap-merge", ++ "data": { "node": "drive0", "target": "bitmapD", ++ "bitmaps": ["bitmapB", "bitmapC"] }}, ++ { "type": "abort", "data": {}} ++ ]) ++ log(query_bitmaps(vm), indent=2) ++ ++ log('\n--- Creating D as a merge of B & C ---\n') ++ # Good hygiene: create a disabled bitmap as a merge target. ++ vm.qmp_log("transaction", indent=2, actions=[ ++ { "type": "block-dirty-bitmap-add", ++ "data": { "node": "drive0", "name": "bitmapD", ++ "disabled": True, "granularity": granularity }}, ++ { "type": "block-dirty-bitmap-merge", ++ "data": { "node": "drive0", "target": "bitmapD", ++ "bitmaps": ["bitmapB", "bitmapC"] }} ++ ]) ++ ++ # A and D should now both have 7 clusters apiece. ++ # B and C remain unchanged with 4 and 6 respectively. ++ log(query_bitmaps(vm), indent=2) ++ ++ # A and D should be equivalent. ++ # Some formats round the size of the disk, so don't print the checksums. ++ check_a = vm.qmp('x-debug-block-dirty-bitmap-sha256', ++ node="drive0", name="bitmapA")['return']['sha256'] ++ check_d = vm.qmp('x-debug-block-dirty-bitmap-sha256', ++ node="drive0", name="bitmapD")['return']['sha256'] ++ assert(check_a == check_d) ++ ++ log('\n--- Removing bitmaps A, B, C, and D ---\n') ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapA") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapB") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapC") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapD") ++ ++ log('\n--- Final Query ---\n') ++ log(query_bitmaps(vm), indent=2) ++ ++ log('\n--- Done ---\n') ++ vm.shutdown() +diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out +new file mode 100644 +index 0000000..1dad24d +--- /dev/null ++++ b/tests/qemu-iotests/236.out +@@ -0,0 +1,351 @@ ++--- Preparing image & VM --- ++ ++ ++--- Adding preliminary bitmaps A & B --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmapA", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmapB", "node": "drive0"}} ++{"return": {}} ++ ++--- Emulating writes --- ++ ++write -P0x5d 0 64k ++{"return": ""} ++write -P0xd5 1M 64k ++{"return": ""} ++write -P0xdc 32M 64k ++{"return": ""} ++write -P0xcd 0x3ff0000 64k ++{"return": ""} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapB", ++ "status": "active" ++ }, ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapA", ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++--- Submitting & Aborting Transaction --- ++ ++{ ++ "execute": "transaction", ++ "arguments": { ++ "actions": [ ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapB" ++ }, ++ "type": "block-dirty-bitmap-disable" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapC", ++ "granularity": 65536 ++ }, ++ "type": "block-dirty-bitmap-add" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapA" ++ }, ++ "type": "block-dirty-bitmap-clear" ++ }, ++ { ++ "data": {}, ++ "type": "abort" ++ } ++ ] ++ } ++} ++{ ++ "error": { ++ "class": "GenericError", ++ "desc": "Transaction aborted using Abort action" ++ } ++} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapB", ++ "status": "active" ++ }, ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapA", ++ "status": "active" ++ } ++ ] ++ } ++} ++ ++--- Disabling B & Adding C --- ++ ++{ ++ "execute": "transaction", ++ "arguments": { ++ "actions": [ ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapB" ++ }, ++ "type": "block-dirty-bitmap-disable" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapC", ++ "granularity": 65536 ++ }, ++ "type": "block-dirty-bitmap-add" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapC" ++ }, ++ "type": "block-dirty-bitmap-disable" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapC" ++ }, ++ "type": "block-dirty-bitmap-enable" ++ } ++ ] ++ } ++} ++{ ++ "return": {} ++} ++ ++--- Emulating further writes --- ++ ++write -P0xab 0 64k ++{"return": ""} ++write -P0xad 0x00f8000 64k ++{"return": ""} ++write -P0x1d 0x2008000 64k ++{"return": ""} ++write -P0xea 0x3fe0000 64k ++{"return": ""} ++ ++--- Disabling A & C --- ++ ++{ ++ "execute": "transaction", ++ "arguments": { ++ "actions": [ ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapA" ++ }, ++ "type": "block-dirty-bitmap-disable" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "name": "bitmapC" ++ }, ++ "type": "block-dirty-bitmap-disable" ++ } ++ ] ++ } ++} ++{ ++ "return": {} ++} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmapC", ++ "status": "disabled" ++ }, ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapB", ++ "status": "disabled" ++ }, ++ { ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmapA", ++ "status": "disabled" ++ } ++ ] ++ } ++} ++ ++--- Submitting & Aborting Merge Transaction --- ++ ++{ ++ "execute": "transaction", ++ "arguments": { ++ "actions": [ ++ { ++ "data": { ++ "node": "drive0", ++ "disabled": true, ++ "name": "bitmapD", ++ "granularity": 65536 ++ }, ++ "type": "block-dirty-bitmap-add" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "target": "bitmapD", ++ "bitmaps": [ ++ "bitmapB", ++ "bitmapC" ++ ] ++ }, ++ "type": "block-dirty-bitmap-merge" ++ }, ++ { ++ "data": {}, ++ "type": "abort" ++ } ++ ] ++ } ++} ++{ ++ "error": { ++ "class": "GenericError", ++ "desc": "Transaction aborted using Abort action" ++ } ++} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmapC", ++ "status": "disabled" ++ }, ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapB", ++ "status": "disabled" ++ }, ++ { ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmapA", ++ "status": "disabled" ++ } ++ ] ++ } ++} ++ ++--- Creating D as a merge of B & C --- ++ ++{ ++ "execute": "transaction", ++ "arguments": { ++ "actions": [ ++ { ++ "data": { ++ "node": "drive0", ++ "disabled": true, ++ "name": "bitmapD", ++ "granularity": 65536 ++ }, ++ "type": "block-dirty-bitmap-add" ++ }, ++ { ++ "data": { ++ "node": "drive0", ++ "target": "bitmapD", ++ "bitmaps": [ ++ "bitmapB", ++ "bitmapC" ++ ] ++ }, ++ "type": "block-dirty-bitmap-merge" ++ } ++ ] ++ } ++} ++{ ++ "return": {} ++} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmapD", ++ "status": "disabled" ++ }, ++ { ++ "count": 393216, ++ "granularity": 65536, ++ "name": "bitmapC", ++ "status": "disabled" ++ }, ++ { ++ "count": 262144, ++ "granularity": 65536, ++ "name": "bitmapB", ++ "status": "disabled" ++ }, ++ { ++ "count": 458752, ++ "granularity": 65536, ++ "name": "bitmapA", ++ "status": "disabled" ++ } ++ ] ++ } ++} ++ ++--- Removing bitmaps A, B, C, and D --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapA", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapB", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapC", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapD", "node": "drive0"}} ++{"return": {}} ++ ++--- Final Query --- ++ ++{ ++ "bitmaps": { ++ "drive0": [] ++ } ++} ++ ++--- Done --- ++ +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 0998dcd..8662839 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -227,3 +227,4 @@ + 231 auto quick + 232 auto quick + 234 auto quick migration ++236 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-add-qmp-recursive-sorting-function.patch b/SOURCES/kvm-iotests-add-qmp-recursive-sorting-function.patch new file mode 100644 index 0000000..a98ebd7 --- /dev/null +++ b/SOURCES/kvm-iotests-add-qmp-recursive-sorting-function.patch @@ -0,0 +1,110 @@ +From c455d2804d7ef6c379b815b6787baf69d3cb760a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:20 +0100 +Subject: [PATCH 022/163] iotests: add qmp recursive sorting function + +RH-Author: John Snow +Message-id: <20190320161631.14841-9-jsnow@redhat.com> +Patchwork-id: 84944 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/19] iotests: add qmp recursive sorting function +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Python before 3.6 does not sort dictionaries (including kwargs). +Therefore, printing QMP objects involves sorting the keys to have +a predictable ordering in the iotests output. This means that +iotests output will sometimes show arguments in an order not +specified by the test author. + +Presently, we accomplish this by using json.dumps' sort_keys argument, +where we only serialize the arguments dictionary, but not the command. + +However, if we want to pretty-print QMP objects being sent to the +QEMU process, we need to build the entire command before logging it. +Ordinarily, this would then involve "arguments" being sorted above +"execute", which would necessitate a rather ugly and harder-to-read +change to many iotests outputs. + +To facilitate pretty-printing AND maintaining predictable output AND +having "arguments" sort after "execute", add a custom sort function +that takes a dictionary and recursively builds an OrderedDict that +maintains the specific key order we wish to see in iotests output. + +The qmp_log function uses this to build a QMP object that keeps +"execute" above "arguments", but sorts all keys and keys in any +subdicts in "arguments" lexicographically to maintain consistent +iotests output, with no incompatible changes to any current test. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-8-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 0706e87d72b02f28bfa04400388f9c9df1b9c943) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 5334ff4..bd508be 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -28,6 +28,7 @@ import json + import signal + import logging + import atexit ++from collections import OrderedDict + + sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts')) + import qtest +@@ -73,6 +74,16 @@ def qemu_img(*args): + sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + return exitcode + ++def ordered_kwargs(kwargs): ++ # kwargs prior to 3.6 are not ordered, so: ++ od = OrderedDict() ++ for k, v in sorted(kwargs.items()): ++ if isinstance(v, dict): ++ od[k] = ordered_kwargs(v) ++ else: ++ od[k] = v ++ return od ++ + def qemu_img_create(*args): + args = list(args) + +@@ -251,8 +262,10 @@ def filter_img_info(output, filename): + def log(msg, filters=[]): + for flt in filters: + msg = flt(msg) +- if type(msg) is dict or type(msg) is list: +- print(json.dumps(msg, sort_keys=True)) ++ if isinstance(msg, dict) or isinstance(msg, list): ++ # Don't sort if it's already sorted ++ do_sort = not isinstance(msg, OrderedDict) ++ print(json.dumps(msg, sort_keys=do_sort)) + else: + print(msg) + +@@ -442,8 +455,11 @@ class VM(qtest.QEMUQtestMachine): + return result + + def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs): +- logmsg = '{"execute": "%s", "arguments": %s}' % \ +- (cmd, json.dumps(kwargs, sort_keys=True)) ++ full_cmd = OrderedDict(( ++ ("execute", cmd), ++ ("arguments", ordered_kwargs(kwargs)) ++ )) ++ logmsg = json.dumps(full_cmd) + log(logmsg, filters) + result = self.qmp(cmd, **kwargs) + log(json.dumps(result, sort_keys=True), filters) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-avoid-broken-pipe-with-certtool.patch b/SOURCES/kvm-iotests-avoid-broken-pipe-with-certtool.patch new file mode 100644 index 0000000..739b88a --- /dev/null +++ b/SOURCES/kvm-iotests-avoid-broken-pipe-with-certtool.patch @@ -0,0 +1,126 @@ +From f4ab0fe995c89692656af2c792a66892fcfbb862 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:06 +0100 +Subject: [PATCH 128/163] iotests: avoid broken pipe with certtool +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190327172308.31077-54-jsnow@redhat.com> +Patchwork-id: 85220 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 53/55] iotests: avoid broken pipe with certtool +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +When we run "certtool 2>&1 | head -1" the latter command is likely to +complete and exit before certtool has written everything it wants to +stderr. In at least the RHEL-7 gnutls 3.3.29 this causes certtool to +quit with broken pipe before it has finished writing the desired +output file to disk. This causes non-deterministic failures of the +iotest 233 because the certs are sometimes zero length files. +If certtool fails the "head -1" means we also lose any useful error +message it would have printed. + +Thus this patch gets rid of the pipe and post-processes the output in a +more flexible & reliable manner. + +Reported-by: Thomas Huth +Signed-off-by: Daniel P. Berrangé +Message-Id: <20190220145819.30969-3-berrange@redhat.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +(cherry picked from commit 3e6f45446b11ccc20b4b751f70331f03d70369b8) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.tls | 48 ++++++++++++++++++++++++++++--------------- + 1 file changed, 32 insertions(+), 16 deletions(-) + +diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls +index eae8178..3caf989 100644 +--- a/tests/qemu-iotests/common.tls ++++ b/tests/qemu-iotests/common.tls +@@ -29,6 +29,17 @@ tls_x509_cleanup() + } + + ++tls_certtool() ++{ ++ certtool "$@" 1>"${tls_dir}"/certtool.log 2>&1 ++ if test "$?" = 0; then ++ head -1 "${tls_dir}"/certtool.log ++ else ++ cat "${tls_dir}"/certtool.log ++ fi ++ rm -f "${tls_dir}"/certtool.log ++} ++ + tls_x509_init() + { + (certtool --help) >/dev/null 2>&1 || \ +@@ -71,10 +82,11 @@ ca + cert_signing_key + EOF + +- certtool --generate-self-signed \ +- --load-privkey "${tls_dir}/key.pem" \ +- --template "${tls_dir}/ca.info" \ +- --outfile "${tls_dir}/$name-cert.pem" 2>&1 | head -1 ++ tls_certtool \ ++ --generate-self-signed \ ++ --load-privkey "${tls_dir}/key.pem" \ ++ --template "${tls_dir}/ca.info" \ ++ --outfile "${tls_dir}/$name-cert.pem" + + rm -f "${tls_dir}/ca.info" + } +@@ -98,12 +110,14 @@ encryption_key + signing_key + EOF + +- certtool --generate-certificate \ +- --load-ca-privkey "${tls_dir}/key.pem" \ +- --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ +- --load-privkey "${tls_dir}/key.pem" \ +- --template "${tls_dir}/cert.info" \ +- --outfile "${tls_dir}/$name/server-cert.pem" 2>&1 | head -1 ++ tls_certtool \ ++ --generate-certificate \ ++ --load-ca-privkey "${tls_dir}/key.pem" \ ++ --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ ++ --load-privkey "${tls_dir}/key.pem" \ ++ --template "${tls_dir}/cert.info" \ ++ --outfile "${tls_dir}/$name/server-cert.pem" ++ + ln -s "${tls_dir}/$caname-cert.pem" "${tls_dir}/$name/ca-cert.pem" + ln -s "${tls_dir}/key.pem" "${tls_dir}/$name/server-key.pem" + +@@ -127,12 +141,14 @@ encryption_key + signing_key + EOF + +- certtool --generate-certificate \ +- --load-ca-privkey "${tls_dir}/key.pem" \ +- --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ +- --load-privkey "${tls_dir}/key.pem" \ +- --template "${tls_dir}/cert.info" \ +- --outfile "${tls_dir}/$name/client-cert.pem" 2>&1 | head -1 ++ tls_certtool \ ++ --generate-certificate \ ++ --load-ca-privkey "${tls_dir}/key.pem" \ ++ --load-ca-certificate "${tls_dir}/$caname-cert.pem" \ ++ --load-privkey "${tls_dir}/key.pem" \ ++ --template "${tls_dir}/cert.info" \ ++ --outfile "${tls_dir}/$name/client-cert.pem" ++ + ln -s "${tls_dir}/$caname-cert.pem" "${tls_dir}/$name/ca-cert.pem" + ln -s "${tls_dir}/key.pem" "${tls_dir}/$name/client-key.pem" + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-change-qmp_log-filters-to-expect-QMP-objects.patch b/SOURCES/kvm-iotests-change-qmp_log-filters-to-expect-QMP-objects.patch new file mode 100644 index 0000000..20536f8 --- /dev/null +++ b/SOURCES/kvm-iotests-change-qmp_log-filters-to-expect-QMP-objects.patch @@ -0,0 +1,128 @@ +From 2a6c4e6212c3f342132a2aca22c84bbf886dc79b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:22 +0100 +Subject: [PATCH 024/163] iotests: change qmp_log filters to expect QMP objects + only + +RH-Author: John Snow +Message-id: <20190320161631.14841-11-jsnow@redhat.com> +Patchwork-id: 84946 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/19] iotests: change qmp_log filters to expect QMP objects only +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +As laid out in the previous commit's message: + +``` +Several places in iotests deal with serializing objects into JSON +strings, but to add pretty-printing it seems desirable to localize +all of those cases. + +log() seems like a good candidate for that centralized behavior. +log() can already serialize json objects, but when it does so, +it assumes filters=[] operates on QMP objects, not strings. + +qmp_log currently operates by dumping outgoing and incoming QMP +objects into strings and filtering them assuming that filters=[] +are string filters. +``` + +Therefore: + +Change qmp_log to treat filters as if they're always qmp object filters, +then change the logging call to rely on log()'s ability to serialize QMP +objects, so we're not duplicating that effort. + +Add a qmp version of filter_testfiles and adjust the only caller using +it for qmp_log to use the qmp version. + +Signed-off-by: John Snow +Message-Id: <20181221093529.23855-10-jsnow@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake +(cherry picked from commit 08fcd6111e1949f456e1b232ebeeb0cc17019a92) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/206 | 4 ++-- + tests/qemu-iotests/iotests.py | 28 +++++++++++++++++++++++++--- + 2 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206 +index e92550f..5bb738b 100755 +--- a/tests/qemu-iotests/206 ++++ b/tests/qemu-iotests/206 +@@ -27,7 +27,7 @@ iotests.verify_image_format(supported_fmts=['qcow2']) + + def blockdev_create(vm, options): + result = vm.qmp_log('blockdev-create', +- filters=[iotests.filter_testfiles], ++ filters=[iotests.filter_qmp_testfiles], + job_id='job0', options=options) + + if 'return' in result: +@@ -55,7 +55,7 @@ with iotests.FilePath('t.qcow2') as disk_path, \ + 'size': 0 }) + + vm.qmp_log('blockdev-add', +- filters=[iotests.filter_testfiles], ++ filters=[iotests.filter_qmp_testfiles], + driver='file', filename=disk_path, + node_name='imgfile') + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 30d198a..d2a8fbd 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -240,10 +240,33 @@ def filter_qmp_event(event): + event['timestamp']['microseconds'] = 'USECS' + return event + ++def filter_qmp(qmsg, filter_fn): ++ '''Given a string filter, filter a QMP object's values. ++ filter_fn takes a (key, value) pair.''' ++ # Iterate through either lists or dicts; ++ if isinstance(qmsg, list): ++ items = enumerate(qmsg) ++ else: ++ items = qmsg.items() ++ ++ for k, v in items: ++ if isinstance(v, list) or isinstance(v, dict): ++ qmsg[k] = filter_qmp(v, filter_fn) ++ else: ++ qmsg[k] = filter_fn(k, v) ++ return qmsg ++ + def filter_testfiles(msg): + prefix = os.path.join(test_dir, "%s-" % (os.getpid())) + return msg.replace(prefix, 'TEST_DIR/PID-') + ++def filter_qmp_testfiles(qmsg): ++ def _filter(key, value): ++ if key == 'filename' or key == 'backing-file': ++ return filter_testfiles(value) ++ return value ++ return filter_qmp(qmsg, _filter) ++ + def filter_generated_node_ids(msg): + return re.sub("#block[0-9]+", "NODE_NAME", msg) + +@@ -459,10 +482,9 @@ class VM(qtest.QEMUQtestMachine): + ("execute", cmd), + ("arguments", ordered_kwargs(kwargs)) + )) +- logmsg = json.dumps(full_cmd) +- log(logmsg, filters) ++ log(full_cmd, filters) + result = self.qmp(cmd, **kwargs) +- log(json.dumps(result, sort_keys=True), filters) ++ log(result, filters) + return result + + def run_job(self, job, auto_finalize=True, auto_dismiss=False): +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-ensure-we-print-nbd-server-log-on-error.patch b/SOURCES/kvm-iotests-ensure-we-print-nbd-server-log-on-error.patch new file mode 100644 index 0000000..3e14c99 --- /dev/null +++ b/SOURCES/kvm-iotests-ensure-we-print-nbd-server-log-on-error.patch @@ -0,0 +1,60 @@ +From c5f12193572b8d67f30a7a2b4e33ff6eef97558d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:05 +0100 +Subject: [PATCH 127/163] iotests: ensure we print nbd server log on error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190327172308.31077-53-jsnow@redhat.com> +Patchwork-id: 85222 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 52/55] iotests: ensure we print nbd server log on error +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +If we abort the iotest early the server.log file might contain useful +information for diagnosing the problem. Ensure its contents are +displayed in this case. + +Reviewed-by: Eric Blake +Signed-off-by: Daniel P. Berrangé +Message-Id: <20190220145819.30969-2-berrange@redhat.com> +[eblake: fix shell quoting] +Signed-off-by: Eric Blake +(cherry picked from commit 84f8b840a2d9ed248c80b3601d2d212cdf60cecf) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/233 | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 +index fc345a1..adb742f 100755 +--- a/tests/qemu-iotests/233 ++++ b/tests/qemu-iotests/233 +@@ -30,6 +30,8 @@ _cleanup() + { + nbd_server_stop + _cleanup_test_img ++ # If we aborted early we want to see this log for diagnosis ++ test -f "$TEST_DIR/server.log" && cat "$TEST_DIR/server.log" + rm -f "$TEST_DIR/server.log" + tls_x509_cleanup + } +@@ -120,6 +122,7 @@ $QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io + echo + echo "== final server log ==" + cat "$TEST_DIR/server.log" ++rm -f "$TEST_DIR/server.log" + + # success, all done + echo "*** done" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-fix-nbd-test-233-to-work-correctly-with-raw-.patch b/SOURCES/kvm-iotests-fix-nbd-test-233-to-work-correctly-with-raw-.patch new file mode 100644 index 0000000..436fee8 --- /dev/null +++ b/SOURCES/kvm-iotests-fix-nbd-test-233-to-work-correctly-with-raw-.patch @@ -0,0 +1,71 @@ +From e33997285c334322f45b36900f63786ba4de8cc9 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:41 +0100 +Subject: [PATCH 074/163] iotests: fix nbd test 233 to work correctly with raw + images +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-29-jsnow@redhat.com> +Patchwork-id: 85115 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 28/28] iotests: fix nbd test 233 to work correctly with raw images +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +The first qemu-io command must honour the $IMGFMT that is set rather +than hardcoding qcow2. The qemu-nbd commands should also set $IMGFMT +to avoid the insecure format probe warning. + +Signed-off-by: Daniel P. Berrangé +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit e4c8f2925d22584b2008aadea5c70e1e05c2a522) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/233 | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 +index a4da60d..1814efe 100755 +--- a/tests/qemu-iotests/233 ++++ b/tests/qemu-iotests/233 +@@ -66,7 +66,7 @@ $QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io + + echo + echo "== check TLS client to plain server fails ==" +-nbd_server_start_tcp_socket "$TEST_IMG" ++nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" + + $QEMU_IMG info --image-opts \ + --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ +@@ -78,7 +78,10 @@ nbd_server_stop + echo + echo "== check plain client to TLS server fails ==" + +-nbd_server_start_tcp_socket --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes --tls-creds tls0 "$TEST_IMG" ++nbd_server_start_tcp_socket \ ++ --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \ ++ --tls-creds tls0 \ ++ -f $IMGFMT "$TEST_IMG" + + $QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g" + +@@ -104,7 +107,7 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \ + driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ + 2>&1 | _filter_qemu_io + +-$QEMU_IO -f qcow2 -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io ++$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io + + # success, all done + echo "*** done" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-implement-pretty-print-for-log-and-qmp_log.patch b/SOURCES/kvm-iotests-implement-pretty-print-for-log-and-qmp_log.patch new file mode 100644 index 0000000..f7f48cd --- /dev/null +++ b/SOURCES/kvm-iotests-implement-pretty-print-for-log-and-qmp_log.patch @@ -0,0 +1,79 @@ +From ec929cb5c98bd8148bff965f80cd0472348199ba Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:23 +0100 +Subject: [PATCH 025/163] iotests: implement pretty-print for log and qmp_log + +RH-Author: John Snow +Message-id: <20190320161631.14841-12-jsnow@redhat.com> +Patchwork-id: 84952 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/19] iotests: implement pretty-print for log and qmp_log +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +If iotests have lines exceeding >998 characters long, git doesn't +want to send it plaintext to the list. We can solve this by allowing +the iotests to use pretty printed QMP output that we can match against +instead. + +As a bonus, it's much nicer for human eyes too. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-11-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 55cd64eab5cb7958c629edbf5f2233b87dfbd1b0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index d2a8fbd..d178469 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -282,13 +282,18 @@ def filter_img_info(output, filename): + lines.append(line) + return '\n'.join(lines) + +-def log(msg, filters=[]): ++def log(msg, filters=[], indent=None): ++ '''Logs either a string message or a JSON serializable message (like QMP). ++ If indent is provided, JSON serializable messages are pretty-printed.''' + for flt in filters: + msg = flt(msg) + if isinstance(msg, dict) or isinstance(msg, list): ++ # Python < 3.4 needs to know not to add whitespace when pretty-printing: ++ separators = (', ', ': ') if indent is None else (',', ': ') + # Don't sort if it's already sorted + do_sort = not isinstance(msg, OrderedDict) +- print(json.dumps(msg, sort_keys=do_sort)) ++ print(json.dumps(msg, sort_keys=do_sort, ++ indent=indent, separators=separators)) + else: + print(msg) + +@@ -477,14 +482,14 @@ class VM(qtest.QEMUQtestMachine): + result.append(filter_qmp_event(ev)) + return result + +- def qmp_log(self, cmd, filters=[], **kwargs): ++ def qmp_log(self, cmd, filters=[], indent=None, **kwargs): + full_cmd = OrderedDict(( + ("execute", cmd), + ("arguments", ordered_kwargs(kwargs)) + )) +- log(full_cmd, filters) ++ log(full_cmd, filters, indent=indent) + result = self.qmp(cmd, **kwargs) +- log(result, filters) ++ log(result, filters, indent=indent) + return result + + def run_job(self, job, auto_finalize=True, auto_dismiss=False): +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-improve-169.patch b/SOURCES/kvm-iotests-improve-169.patch new file mode 100644 index 0000000..9b67d86 --- /dev/null +++ b/SOURCES/kvm-iotests-improve-169.patch @@ -0,0 +1,70 @@ +From 2002520b4c5e6ca74367f9db22a53d5a463b9de2 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:42 +0100 +Subject: [PATCH 32/33] iotests: improve 169 + +RH-Author: John Snow +Message-id: <20190206221243.7407-23-jsnow@redhat.com> +Patchwork-id: 84281 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 22/23] iotests: improve 169 +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +Before previous patch, iotest 169 was actually broken for the case +test_persistent__not_migbitmap__offline_shared, while formally +passing. + +After migration log of vm_b had message: + + qemu-system-x86_64: Could not reopen qcow2 layer: Bitmap already + exists: bitmap0 + +which means that invalidation failed and bs->drv = NULL. + +It was because we've loaded bitmap twice: on open and on invalidation. + +Add code to 169, to catch such fails. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +(cherry picked from commit b9247fc1a8ffe5c367fa049f295fbb58c8ca9d05) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/169 | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169 +index df408f8..8b7947d 100755 +--- a/tests/qemu-iotests/169 ++++ b/tests/qemu-iotests/169 +@@ -24,6 +24,7 @@ import time + import itertools + import operator + import new ++import re + from iotests import qemu_img + + +@@ -133,6 +134,14 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): + + if should_migrate: + self.vm_b.shutdown() ++ ++ # catch 'Could not reopen qcow2 layer: Bitmap already exists' ++ # possible error ++ log = self.vm_b.get_log() ++ log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log) ++ log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log) ++ self.assertEqual(log, '') ++ + # recreate vm_b, as we don't want -incoming option (this will lead + # to "cat" process left alive after test finish) + self.vm_b = iotests.VM(path_suffix='b') +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-make-083-specific-to-raw.patch b/SOURCES/kvm-iotests-make-083-specific-to-raw.patch new file mode 100644 index 0000000..a257aef --- /dev/null +++ b/SOURCES/kvm-iotests-make-083-specific-to-raw.patch @@ -0,0 +1,77 @@ +From aa707f9fe5e43d297d3ebc201087fba331373993 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:16 +0100 +Subject: [PATCH 077/163] iotests: make 083 specific to raw + +RH-Author: John Snow +Message-id: <20190327172308.31077-4-jsnow@redhat.com> +Patchwork-id: 85179 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/55] iotests: make 083 specific to raw +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Cleber Rosa + +While testing the Python 3 changes which touch the 083 test, I noticed +that it would fail with qcow2. Expanding the testing, I noticed it +had nothing to do with the Python 3 changes, and in fact, it would not +pass on anything but raw: + + raw: pass + bochs: not generic + cloop: not generic + parallels: fail + qcow: fail + qcow2: fail + qed: fail + vdi: fail + vhdx: fail + vmdk: fail + vpc: fail + luks: fail + +The errors are a mixture I/O and "image not in xxx format", such as: + + === Check disconnect before data === + + Unexpected end-of-file before all bytes were read + -read failed: Input/output error + +can't open device nbd+tcp://127.0.0.1:PORT/foo: Could not open 'nbd://127.0.0.1:PORT/foo': Input/output error + + === Check disconnect after data === + + -read 512/512 bytes at offset 0 + -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +can't open device nbd+tcp://127.0.0.1:PORT/foo: Image not in qcow format + +I'm not aware if there's a quick fix, so, for the time being, it looks +like the honest approach is to make the test known to work on raw +only. + +Signed-off-by: Cleber Rosa +Signed-off-by: Kevin Wolf +(cherry picked from commit d98205c58667ca6750658834e8466ac41a3e572e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/083 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 +index 982adec..89f67db 100755 +--- a/tests/qemu-iotests/083 ++++ b/tests/qemu-iotests/083 +@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 + . ./common.rc + . ./common.filter + +-_supported_fmt generic ++_supported_fmt raw + _supported_proto nbd + _supported_os Linux + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-nbd-Stop-qemu-nbd-before-remaking-image.patch b/SOURCES/kvm-iotests-nbd-Stop-qemu-nbd-before-remaking-image.patch new file mode 100644 index 0000000..c137382 --- /dev/null +++ b/SOURCES/kvm-iotests-nbd-Stop-qemu-nbd-before-remaking-image.patch @@ -0,0 +1,90 @@ +From 1e5bf346765701c7301d3f86311b339288261558 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:18 +0100 +Subject: [PATCH 051/163] iotests: nbd: Stop qemu-nbd before remaking image + +RH-Author: John Snow +Message-id: <20190322032241.8111-6-jsnow@redhat.com> +Patchwork-id: 85093 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/28] iotests: nbd: Stop qemu-nbd before remaking image +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Fam Zheng + +197 is one example where _make_test_img is used twice without stopping +the NBD server in between. An error will occur like this: + + @@ -26,9 +26,13 @@ + + === Partial final cluster === + + +qemu-img: TEST_DIR/t.IMGFMT: Failed to get "resize" lock + +Is another process using the image? + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024 + +Failed to find an available port: Address already in use + read 1024/1024 bytes at offset 0 + +Patch _make_test_img to stop the old qemu-nbd before starting a new one, +which fixes this problem, and similarly 215. + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 2f9d4083f7fdafe82138e983a24ef30b81b029d7) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.rc | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc +index 9a65a11..1e567b0 100644 +--- a/tests/qemu-iotests/common.rc ++++ b/tests/qemu-iotests/common.rc +@@ -190,6 +190,16 @@ _use_sample_img() + fi + } + ++_stop_nbd_server() ++{ ++ if [ -f "${QEMU_TEST_DIR}/qemu-nbd.pid" ]; then ++ local QEMU_NBD_PID ++ read QEMU_NBD_PID < "${QEMU_TEST_DIR}/qemu-nbd.pid" ++ kill ${QEMU_NBD_PID} ++ rm -f "${QEMU_TEST_DIR}/qemu-nbd.pid" ++ fi ++} ++ + _make_test_img() + { + # extra qemu-img options can be added by tests +@@ -229,6 +239,10 @@ _make_test_img() + extra_img_options="-o $optstr $extra_img_options" + fi + ++ if [ $IMGPROTO = "nbd" ]; then ++ _stop_nbd_server ++ fi ++ + # XXX(hch): have global image options? + ( + if [ $use_backing = 1 ]; then +@@ -269,12 +283,7 @@ _cleanup_test_img() + case "$IMGPROTO" in + + nbd) +- if [ -f "${QEMU_TEST_DIR}/qemu-nbd.pid" ]; then +- local QEMU_NBD_PID +- read QEMU_NBD_PID < "${QEMU_TEST_DIR}/qemu-nbd.pid" +- kill ${QEMU_NBD_PID} +- rm -f "${QEMU_TEST_DIR}/qemu-nbd.pid" +- fi ++ _stop_nbd_server + rm -f "$TEST_IMG_FILE" + ;; + vxhs) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-remove-default-filters-from-qmp_log.patch b/SOURCES/kvm-iotests-remove-default-filters-from-qmp_log.patch new file mode 100644 index 0000000..658bd8d --- /dev/null +++ b/SOURCES/kvm-iotests-remove-default-filters-from-qmp_log.patch @@ -0,0 +1,92 @@ +From ca5abb0f6123f6699f84125c7c358e29c5cce2a7 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:21 +0100 +Subject: [PATCH 023/163] iotests: remove default filters from qmp_log + +RH-Author: John Snow +Message-id: <20190320161631.14841-10-jsnow@redhat.com> +Patchwork-id: 84942 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/19] iotests: remove default filters from qmp_log +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Several places in iotests deal with serializing objects into JSON +strings, but to add pretty-printing it seems desirable to localize +all of those cases. + +log() seems like a good candidate for that centralized behavior. +log() can already serialize json objects, but when it does so, +it assumes filters=[] operates on QMP objects, not strings. + +qmp_log currently operates by dumping outgoing and incoming QMP +objects into strings and filtering them assuming that filters=[] +are string filters. + +To have qmp_log use log's serialization, qmp_log will need to +accept only qmp filters, not text filters. + +However, only a single caller of qmp_log actually requires any +filters at all. I remove the default filter and add it explicitly +to the caller in preparation for refactoring qmp_log to use rich +filters instead. + +test 206 is amended to name the filter explicitly and the default +is removed. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-9-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit f8ca8609d8549def45b28e82ecac64adaeee9f12) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/206 | 8 ++++++-- + tests/qemu-iotests/iotests.py | 2 +- + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206 +index 128c334..e92550f 100755 +--- a/tests/qemu-iotests/206 ++++ b/tests/qemu-iotests/206 +@@ -26,7 +26,9 @@ from iotests import imgfmt + iotests.verify_image_format(supported_fmts=['qcow2']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', ++ filters=[iotests.filter_testfiles], ++ job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} +@@ -52,7 +54,9 @@ with iotests.FilePath('t.qcow2') as disk_path, \ + 'filename': disk_path, + 'size': 0 }) + +- vm.qmp_log('blockdev-add', driver='file', filename=disk_path, ++ vm.qmp_log('blockdev-add', ++ filters=[iotests.filter_testfiles], ++ driver='file', filename=disk_path, + node_name='imgfile') + + blockdev_create(vm, { 'driver': imgfmt, +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index bd508be..30d198a 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -454,7 +454,7 @@ class VM(qtest.QEMUQtestMachine): + result.append(filter_qmp_event(ev)) + return result + +- def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs): ++ def qmp_log(self, cmd, filters=[], **kwargs): + full_cmd = OrderedDict(( + ("execute", cmd), + ("arguments", ordered_kwargs(kwargs)) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests.py-Add-is_str.patch b/SOURCES/kvm-iotests.py-Add-is_str.patch new file mode 100644 index 0000000..6a86292 --- /dev/null +++ b/SOURCES/kvm-iotests.py-Add-is_str.patch @@ -0,0 +1,51 @@ +From f32cd24bac5efaf4331b864ad55eed80b0b0d89c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:30 +0100 +Subject: [PATCH 032/163] iotests.py: Add is_str() + +RH-Author: John Snow +Message-id: <20190320161631.14841-19-jsnow@redhat.com> +Patchwork-id: 84956 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 18/19] iotests.py: Add is_str() +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +On Python 2.x, strings are not always unicode strings. This function +checks whether a given value is a plain string, or a unicode string (if +there is a difference). + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Message-id: 20190210145736.1486-7-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 011a576113000f9c90a8450ef9116cca8d6f2523) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 4e9b2c4..64bb718 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -216,6 +216,12 @@ def image_size(img): + r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img) + return json.loads(r)['virtual-size'] + ++def is_str(val): ++ if sys.version_info.major >= 3: ++ return isinstance(val, str) ++ else: ++ return isinstance(val, str) or isinstance(val, unicode) ++ + test_dir_re = re.compile(r"%s" % test_dir) + def filter_test_dir(msg): + return test_dir_re.sub("TEST_DIR", msg) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests.py-Filter-filename-in-any-string-value.patch b/SOURCES/kvm-iotests.py-Filter-filename-in-any-string-value.patch new file mode 100644 index 0000000..f911146 --- /dev/null +++ b/SOURCES/kvm-iotests.py-Filter-filename-in-any-string-value.patch @@ -0,0 +1,49 @@ +From 8e28b84e9502f95c2f08e20ec44b1f161193c2d8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:31 +0100 +Subject: [PATCH 033/163] iotests.py: Filter filename in any string value + +RH-Author: John Snow +Message-id: <20190320161631.14841-20-jsnow@redhat.com> +Patchwork-id: 84954 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 19/19] iotests.py: Filter filename in any string value +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +filter_qmp_testfiles() currently filters the filename only for specific +keys. However, there are more keys that take filenames (such as +block-commit's @top and @base, or ssh's @path), and it does not make +sense to list them all here. "$TEST_DIR/$PID-" should have enough +entropy not to appear anywhere randomly. + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Message-id: 20190210145736.1486-8-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 56a6e5d0ca61f746577ea6223bcabbf7d6c576af) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 64bb718..a796ad2 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -269,7 +269,7 @@ def filter_testfiles(msg): + + def filter_qmp_testfiles(qmsg): + def _filter(key, value): +- if key == 'filename' or key == 'backing-file': ++ if is_str(value): + return filter_testfiles(value) + return value + return filter_qmp(qmsg, _filter) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests.py-don-t-abort-if-IMGKEYSECRET-is-undefined.patch b/SOURCES/kvm-iotests.py-don-t-abort-if-IMGKEYSECRET-is-undefined.patch new file mode 100644 index 0000000..60831cb --- /dev/null +++ b/SOURCES/kvm-iotests.py-don-t-abort-if-IMGKEYSECRET-is-undefined.patch @@ -0,0 +1,47 @@ +From ffb202539710de98044f20d13bd05843ed1dc94b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:18 +0100 +Subject: [PATCH 020/163] iotests.py: don't abort if IMGKEYSECRET is undefined + +RH-Author: John Snow +Message-id: <20190320161631.14841-7-jsnow@redhat.com> +Patchwork-id: 84943 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/19] iotests.py: don't abort if IMGKEYSECRET is undefined +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +Instead of using os.environ[], use .get with a default of empty string +to match the setup in check to allow us to import the iotests module +(for debugging, say) without needing a crafted environment just to +import the module. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181221093529.23855-6-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 58ebcb65d8e38fd693bf1e58dd941a4d7a8dfdef) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 1b9656a..c5739a6 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -61,7 +61,7 @@ socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper') + debug = False + + luks_default_secret_object = 'secret,id=keysec0,data=' + \ +- os.environ['IMGKEYSECRET'] ++ os.environ.get('IMGKEYSECRET', '') + luks_default_key_secret_opt = 'key-secret=keysec0' + + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iothread-fix-crash-with-invalid-properties.patch b/SOURCES/kvm-iothread-fix-crash-with-invalid-properties.patch new file mode 100644 index 0000000..a2995cd --- /dev/null +++ b/SOURCES/kvm-iothread-fix-crash-with-invalid-properties.patch @@ -0,0 +1,81 @@ +From 6470ace7aae0d6e76e8ca8cc450085a502877250 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 28 Nov 2018 16:04:27 +0100 +Subject: [PATCH 17/34] iothread: fix crash with invalid properties +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Stefan Hajnoczi +Message-id: <20181128160427.7389-2-stefanha@redhat.com> +Patchwork-id: 83183 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] iothread: fix crash with invalid properties +Bugzilla: 1607768 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Peter Xu +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Pankaj Gupta + +From: Marc-André Lureau + +-object iothread,id=foo,? will crash qemu: + +qemu-system-x86_64:qemu-thread-posix.c:128: qemu_cond_destroy: Assertion `cond->initialized' failed. + +Use thread_id != -1 to check if iothread_complete() finished +successfully and the mutex/cond have been initialized. + +Signed-off-by: Marc-André Lureau +Message-Id: <20180821100716.13803-1-marcandre.lureau@redhat.com> +Signed-off-by: Fam Zheng +(cherry picked from commit 14a2d11825ddc37d6547a80704ae6450e9e376c7) +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Miroslav Rezanina +--- + iothread.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/iothread.c b/iothread.c +index aff1281..2fb1cdf 100644 +--- a/iothread.c ++++ b/iothread.c +@@ -110,6 +110,7 @@ static void iothread_instance_init(Object *obj) + IOThread *iothread = IOTHREAD(obj); + + iothread->poll_max_ns = IOTHREAD_POLL_MAX_NS_DEFAULT; ++ iothread->thread_id = -1; + } + + static void iothread_instance_finalize(Object *obj) +@@ -117,6 +118,11 @@ static void iothread_instance_finalize(Object *obj) + IOThread *iothread = IOTHREAD(obj); + + iothread_stop(iothread); ++ ++ if (iothread->thread_id != -1) { ++ qemu_cond_destroy(&iothread->init_done_cond); ++ qemu_mutex_destroy(&iothread->init_done_lock); ++ } + /* + * Before glib2 2.33.10, there is a glib2 bug that GSource context + * pointer may not be cleared even if the context has already been +@@ -135,8 +141,6 @@ static void iothread_instance_finalize(Object *obj) + g_main_context_unref(iothread->worker_context); + iothread->worker_context = NULL; + } +- qemu_cond_destroy(&iothread->init_done_cond); +- qemu_mutex_destroy(&iothread->init_done_lock); + } + + static void iothread_complete(UserCreatable *obj, Error **errp) +@@ -147,7 +151,6 @@ static void iothread_complete(UserCreatable *obj, Error **errp) + + iothread->stopping = false; + iothread->running = true; +- iothread->thread_id = -1; + iothread->ctx = aio_context_new(&local_error); + if (!iothread->ctx) { + error_propagate(errp, local_error); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iscsi-Support-auto-read-only-option.patch b/SOURCES/kvm-iscsi-Support-auto-read-only-option.patch new file mode 100644 index 0000000..da2b179 --- /dev/null +++ b/SOURCES/kvm-iscsi-Support-auto-read-only-option.patch @@ -0,0 +1,50 @@ +From 546f992fdc25fd65f050efff3b4c8bf8f22d5a05 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:51 +0100 +Subject: [PATCH 10/34] iscsi: Support auto-read-only option + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-10-kwolf@redhat.com> +Patchwork-id: 83120 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 09/12] iscsi: Support auto-read-only option +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +If read-only=off, but auto-read-only=on is given, open the volume +read-write if we have the permissions, but instead of erroring out for +read-only volumes, just degrade to read-only. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 8f3bf50d340372662a35564c669e567c6c846943) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/iscsi.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/block/iscsi.c b/block/iscsi.c +index 2b45458..c412b12 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -1877,9 +1877,11 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, + /* Check the write protect flag of the LUN if we want to write */ + if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && + iscsilun->write_protected) { +- error_setg(errp, "Cannot open a write protected LUN as read-write"); +- ret = -EACCES; +- goto out; ++ ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp); ++ if (ret < 0) { ++ goto out; ++ } ++ flags &= ~BDRV_O_RDWR; + } + + iscsi_readcapacity_sync(iscsilun, &local_err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ivshmem-Fix-unplug-of-device-ivshmem-plain.patch b/SOURCES/kvm-ivshmem-Fix-unplug-of-device-ivshmem-plain.patch new file mode 100644 index 0000000..2c4acb7 --- /dev/null +++ b/SOURCES/kvm-ivshmem-Fix-unplug-of-device-ivshmem-plain.patch @@ -0,0 +1,94 @@ +From 1342ea3b7a14657c3e9f6e38ea3dcc0c2f42939e Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 29 Oct 2018 07:01:37 +0100 +Subject: [PATCH 07/22] ivshmem: Fix unplug of device "ivshmem-plain" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20181029070137.21196-4-armbru@redhat.com> +Patchwork-id: 82900 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] ivshmem: Fix unplug of device "ivshmem-plain" +Bugzilla: 1620373 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Igor Mammedov +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau + +Commit 2aece63c8a "hostmem: detect host backend memory is being used +properly" fixed "ivshmem-plain" to reject memory backends that are +already in use, and to block their deletion while in use. Two bugs +escaped review: + +* New ivshmem_plain_exit() fails to call ivshmem_exit(). This breaks + unplug. Reproducer: migration after unplug still fails with + "Migration is disabled when using feature 'peer mode' in device + 'ivshmem'". + +* It failed to update legacy "ivshmem". Harmless, because it creates + the memory backend itself, and nothing else should use it. + +Fix by moving the two host_memory_backend_set_mapped() calls into +ivshmem_common_realize() and ivshmem_exit(), guarded by s->hostmem. + +Fixes: 2aece63c8a9d2c3a8ff41d2febc4cdeff2633331 +Signed-off-by: Markus Armbruster +Message-Id: <20180926163709.22876-1-armbru@redhat.com> +Reviewed-by: Marc-André Lureau +Reviewed-by: Paolo Bonzini +(cherry picked from commit b266f1d1123396f9f5df865508f7555ab0c9582a) +Signed-off-by: Miroslav Rezanina +--- + hw/misc/ivshmem.c | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c +index 47456b8..28e55d4 100644 +--- a/hw/misc/ivshmem.c ++++ b/hw/misc/ivshmem.c +@@ -917,6 +917,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) + IVSHMEM_DPRINTF("using hostmem\n"); + + s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem); ++ host_memory_backend_set_mapped(s->hostmem, true); + } else { + Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr); + assert(chr); +@@ -999,6 +1000,10 @@ static void ivshmem_exit(PCIDevice *dev) + vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev)); + } + ++ if (s->hostmem) { ++ host_memory_backend_set_mapped(s->hostmem, false); ++ } ++ + if (s->peers) { + for (i = 0; i < s->nb_peers; i++) { + close_peer_eventfds(s, i); +@@ -1107,14 +1112,6 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) + } + + ivshmem_common_realize(dev, errp); +- host_memory_backend_set_mapped(s->hostmem, true); +-} +- +-static void ivshmem_plain_exit(PCIDevice *pci_dev) +-{ +- IVShmemState *s = IVSHMEM_COMMON(pci_dev); +- +- host_memory_backend_set_mapped(s->hostmem, false); + } + + static void ivshmem_plain_class_init(ObjectClass *klass, void *data) +@@ -1123,7 +1120,6 @@ static void ivshmem_plain_class_init(ObjectClass *klass, void *data) + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = ivshmem_plain_realize; +- k->exit = ivshmem_plain_exit; + dc->props = ivshmem_plain_properties; + dc->vmsd = &ivshmem_plain_vmsd; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-luks-Allow-share-rw-on.patch b/SOURCES/kvm-luks-Allow-share-rw-on.patch new file mode 100644 index 0000000..527a3ff --- /dev/null +++ b/SOURCES/kvm-luks-Allow-share-rw-on.patch @@ -0,0 +1,54 @@ +From baa218a4170b17e3699272a481ee04616c9432f0 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 21:08:22 +0100 +Subject: [PATCH 8/8] luks: Allow share-rw=on +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Max Reitz +Message-id: <20190204210822.10343-2-mreitz@redhat.com> +Patchwork-id: 84228 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] luks: Allow share-rw=on +Bugzilla: 1598119 +RH-Acked-by: John Snow +RH-Acked-by: Yash Mankad +RH-Acked-by: Kevin Wolf + +From: Fam Zheng + +Format drivers such as qcow2 don't allow sharing the same image between +two QEMU instances in order to prevent image corruptions, because of +metadata cache. LUKS driver don't modify metadata except for when +creating image, so it is safe to relax the permission. This makes +share-rw=on property work on virtual devices. + +Suggested-by: Daniel P. Berrangé +Signed-off-by: Fam Zheng +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Kevin Wolf +(cherry picked from commit 497da8236ab2663a8108858ba7ea59aac21c5fe6) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/crypto.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/block/crypto.c b/block/crypto.c +index 02f04f3..0bb0db6 100644 +--- a/block/crypto.c ++++ b/block/crypto.c +@@ -698,7 +698,9 @@ BlockDriver bdrv_crypto_luks = { + .bdrv_probe = block_crypto_probe_luks, + .bdrv_open = block_crypto_open_luks, + .bdrv_close = block_crypto_close, +- .bdrv_child_perm = bdrv_format_default_perms, ++ /* This driver doesn't modify LUKS metadata except when creating image. ++ * Allow share-rw=on as a special case. */ ++ .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_co_create = block_crypto_co_create_luks, + .bdrv_co_create_opts = block_crypto_co_create_opts_luks, + .bdrv_co_truncate = block_crypto_co_truncate, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-maint-Allow-for-EXAMPLES-in-texi2pod.patch b/SOURCES/kvm-maint-Allow-for-EXAMPLES-in-texi2pod.patch new file mode 100644 index 0000000..cb99787 --- /dev/null +++ b/SOURCES/kvm-maint-Allow-for-EXAMPLES-in-texi2pod.patch @@ -0,0 +1,62 @@ +From f7e8e465f2c37a28023dea7d3e99a074c0118e73 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:36 +0100 +Subject: [PATCH 098/163] maint: Allow for EXAMPLES in texi2pod + +RH-Author: John Snow +Message-id: <20190327172308.31077-24-jsnow@redhat.com> +Patchwork-id: 85195 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 23/55] maint: Allow for EXAMPLES in texi2pod +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The next commit will add an EXAMPLES section to qemu-nbd.8; +for that to work, we need to recognize EXAMPLES in texi2pod. +We also need to add a dependency from all man pages against +the generator script, since a change to the generator may +cause the resulting man page to differ. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit ae560cc34f9ff4662d4ca1425b88fd1f85f52817) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + Makefile | 1 + + scripts/texi2pod.pl | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index c95553f..a6711b2 100644 +--- a/Makefile ++++ b/Makefile +@@ -992,6 +992,7 @@ docs/interop/qemu-qmp-ref.dvi docs/interop/qemu-qmp-ref.html \ + docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7: \ + docs/interop/qemu-qmp-ref.texi docs/interop/qemu-qmp-qapi.texi + ++$(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl + + ifdef CONFIG_WIN32 + +diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl +index 39ce584..839b791 100755 +--- a/scripts/texi2pod.pl ++++ b/scripts/texi2pod.pl +@@ -398,7 +398,7 @@ $sects{NAME} = "$fn \- $tl\n"; + $sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; + + for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES +- BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { ++ BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) { + if(exists $sects{$sect}) { + $head = $sect; + $head =~ s/SEEALSO/SEE ALSO/; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-memory-cleanup-side-effects-of-memory_region_init_fo.patch b/SOURCES/kvm-memory-cleanup-side-effects-of-memory_region_init_fo.patch new file mode 100644 index 0000000..15b78ad --- /dev/null +++ b/SOURCES/kvm-memory-cleanup-side-effects-of-memory_region_init_fo.patch @@ -0,0 +1,191 @@ +From 2d02fc0e933a7d4a30e8bb7c665d898d00ac5e00 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Fri, 23 Nov 2018 11:58:47 +0100 +Subject: [PATCH 14/34] memory: cleanup side effects of + memory_region_init_foo() on failure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Igor Mammedov +Message-id: <1542974327-165907-1-git-send-email-imammedo@redhat.com> +Patchwork-id: 83127 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2] memory: cleanup side effects of memory_region_init_foo() on failure +Bugzilla: 1585155 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1585155 +Brew: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=19261375 + +if MemoryRegion intialization fails it's left in semi-initialized state, +where it's size is not 0 and attached as child to owner object. +And this leds to crash in following use-case: + (monitor) object_add memory-backend-file,id=mem1,size=99999G,mem-path=/tmp/foo,discard-data=yes + memory.c:2083: memory_region_get_ram_ptr: Assertion `mr->ram_block' failed + Aborted (core dumped) +it happens due to assumption that memory region is intialized when + memory_region_size() != 0 +and therefore it's ok to access it in + file_backend_unparent() + if (memory_region_size() != 0) + memory_region_get_ram_ptr() + +which happens when object_add fails and unparents failed backend making +file_backend_unparent() access invalid memory region. + +Fix it by making sure that memory_region_init_foo() APIs cleanup externally +visible side effects on failure (like set size to 0 and unparenting object) + +Signed-off-by: Igor Mammedov +Message-Id: <1536064777-42312-1-git-send-email-imammedo@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 1cd3d492624da399d66c4c3e6a5eabb8f96bb0a2) +Signed-off-by: Igor Mammedov +--- +v2: + - clean backport since dependency has been backported and merged as + (commit 754dd8f2 memory, exec: switch file ram allocation functions to 'flags' parameters) + + enter the commit message for your changes. Lines starting + +Signed-off-by: Miroslav Rezanina +--- + memory.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 42 insertions(+), 6 deletions(-) + +diff --git a/memory.c b/memory.c +index 7b47f53..4974f97 100644 +--- a/memory.c ++++ b/memory.c +@@ -1519,12 +1519,18 @@ void memory_region_init_ram_shared_nomigrate(MemoryRegion *mr, + bool share, + Error **errp) + { ++ Error *err = NULL; + memory_region_init(mr, owner, name, size); + mr->ram = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; +- mr->ram_block = qemu_ram_alloc(size, share, mr, errp); ++ mr->ram_block = qemu_ram_alloc(size, share, mr, &err); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; ++ if (err) { ++ mr->size = int128_zero(); ++ object_unparent(OBJECT(mr)); ++ error_propagate(errp, err); ++ } + } + + void memory_region_init_resizeable_ram(MemoryRegion *mr, +@@ -1537,13 +1543,19 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, + void *host), + Error **errp) + { ++ Error *err = NULL; + memory_region_init(mr, owner, name, size); + mr->ram = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; + mr->ram_block = qemu_ram_alloc_resizeable(size, max_size, resized, +- mr, errp); ++ mr, &err); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; ++ if (err) { ++ mr->size = int128_zero(); ++ object_unparent(OBJECT(mr)); ++ error_propagate(errp, err); ++ } + } + + #ifdef __linux__ +@@ -1556,13 +1568,19 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, + const char *path, + Error **errp) + { ++ Error *err = NULL; + memory_region_init(mr, owner, name, size); + mr->ram = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; + mr->align = align; +- mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, errp); ++ mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, &err); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; ++ if (err) { ++ mr->size = int128_zero(); ++ object_unparent(OBJECT(mr)); ++ error_propagate(errp, err); ++ } + } + + void memory_region_init_ram_from_fd(MemoryRegion *mr, +@@ -1573,14 +1591,20 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr, + int fd, + Error **errp) + { ++ Error *err = NULL; + memory_region_init(mr, owner, name, size); + mr->ram = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; + mr->ram_block = qemu_ram_alloc_from_fd(size, mr, + share ? RAM_SHARED : 0, +- fd, errp); ++ fd, &err); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; ++ if (err) { ++ mr->size = int128_zero(); ++ object_unparent(OBJECT(mr)); ++ error_propagate(errp, err); ++ } + } + #endif + +@@ -1631,13 +1655,19 @@ void memory_region_init_rom_nomigrate(MemoryRegion *mr, + uint64_t size, + Error **errp) + { ++ Error *err = NULL; + memory_region_init(mr, owner, name, size); + mr->ram = true; + mr->readonly = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; +- mr->ram_block = qemu_ram_alloc(size, false, mr, errp); ++ mr->ram_block = qemu_ram_alloc(size, false, mr, &err); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; ++ if (err) { ++ mr->size = int128_zero(); ++ object_unparent(OBJECT(mr)); ++ error_propagate(errp, err); ++ } + } + + void memory_region_init_rom_device_nomigrate(MemoryRegion *mr, +@@ -1648,6 +1678,7 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr, + uint64_t size, + Error **errp) + { ++ Error *err = NULL; + assert(ops); + memory_region_init(mr, owner, name, size); + mr->ops = ops; +@@ -1655,7 +1686,12 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr, + mr->terminates = true; + mr->rom_device = true; + mr->destructor = memory_region_destructor_ram; +- mr->ram_block = qemu_ram_alloc(size, false, mr, errp); ++ mr->ram_block = qemu_ram_alloc(size, false, mr, &err); ++ if (err) { ++ mr->size = int128_zero(); ++ object_unparent(OBJECT(mr)); ++ error_propagate(errp, err); ++ } + } + + void memory_region_init_iommu(void *_iommu_mr, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-Support-adding-migration-blockers-earlier.patch b/SOURCES/kvm-migration-Support-adding-migration-blockers-earlier.patch new file mode 100644 index 0000000..2cb57ca --- /dev/null +++ b/SOURCES/kvm-migration-Support-adding-migration-blockers-earlier.patch @@ -0,0 +1,81 @@ +From 7d01c30800f4009d770cb44e377886a7a47f3e47 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:20 +0200 +Subject: [PATCH 53/53] migration: Support adding migration blockers earlier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-32-armbru@redhat.com> +Patchwork-id: 88011 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 31/31] migration: Support adding migration blockers earlier +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +migrate_add_blocker() asserts we have a current_migration object, in +migrate_get_current(). We do only after migration_object_init(). + +This contributes to the following dependency cycle: + +* configure_blockdev() must run before machine_set_property() + so machine properties can refer to block backends + +* machine_set_property() before configure_accelerator() + so machine properties like kvm-irqchip get applied + +* configure_accelerator() before migration_object_init() + so that Xen's accelerator compat properties get applied. + +* migration_object_init() before configure_blockdev() + so configure_blockdev() can add migration blockers + +The cycle was closed when recent commit cda4aa9a5a0 "Create block +backends before setting machine properties" added the first +dependency, and satisfied it by violating the last one. Broke block +backends that add migration blockers, as demonstrated by qemu-iotests +055. + +To fix it, break the last dependency: make migrate_add_blocker() +usable before migration_object_init(). + +The previous commit already removed the use of migrate_get_current() +from migrate_add_blocker() itself. Didn't quite do the trick, as +there's another one hiding in migration_is_idle(). + +The use there isn't actually necessary: when no migration object has +been created yet, migration is surely idle. Make migration_is_idle() +return true then. + +Fixes: cda4aa9a5a08777cf13e164c0543bd4888b8adce +Signed-off-by: Markus Armbruster +Message-Id: <20190401090827.20793-4-armbru@redhat.com> +Reviewed-by: Igor Mammedov +(cherry picked from commit daff7f0bbe9950d045bb5b74f202295f70ab3aaa) +Signed-off-by: Miroslav Rezanina +--- + migration/migration.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/migration/migration.c b/migration/migration.c +index 83b8d6a..69011d1 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1270,7 +1270,11 @@ bool migration_in_postcopy_after_devices(MigrationState *s) + + bool migration_is_idle(void) + { +- MigrationState *s = migrate_get_current(); ++ MigrationState *s = current_migration; ++ ++ if (!s) { ++ return true; ++ } + + switch (s->state) { + case MIGRATION_STATUS_NONE: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-cleanup-in-error-paths-in-loadvm.patch b/SOURCES/kvm-migration-cleanup-in-error-paths-in-loadvm.patch new file mode 100644 index 0000000..49ff72a --- /dev/null +++ b/SOURCES/kvm-migration-cleanup-in-error-paths-in-loadvm.patch @@ -0,0 +1,54 @@ +From 5496cb7128658bd4b3cb24ce741bba4df3c09656 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Mon, 19 Nov 2018 16:19:21 +0100 +Subject: [PATCH 22/22] migration: cleanup in error paths in loadvm + +RH-Author: Dr. David Alan Gilbert +Message-id: <20181119161921.15191-3-dgilbert@redhat.com> +Patchwork-id: 83049 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/2] migration: cleanup in error paths in loadvm +Bugzilla: 1608877 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Peter Xu +RH-Acked-by: Pankaj Gupta + +From: "Dr. David Alan Gilbert" + +There's a couple of error paths in qemu_loadvm_state +which happen early on but after we've initialised the +load state; that needs to be cleaned up otherwise +we can hit asserts if the state gets reinitialised later. + +Signed-off-by: Dr. David Alan Gilbert +Message-Id: <20180914170430.54271-3-dgilbert@redhat.com> +Reviewed-by: Peter Xu +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 096c83b7219c5a2145435afc8be750281e9cb447) +Signed-off-by: Danilo C. L. de Paula +(cherry picked from commit 020674a9569df103bdd6a8cef29ce8013c92a8b8) +Signed-off-by: Miroslav Rezanina +--- + migration/savevm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/migration/savevm.c b/migration/savevm.c +index 7a5d9ff..e5d57fa 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -2146,11 +2146,13 @@ int qemu_loadvm_state(QEMUFile *f) + if (migrate_get_current()->send_configuration) { + if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) { + error_report("Configuration section missing"); ++ qemu_loadvm_state_cleanup(); + return -EINVAL; + } + ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0); + + if (ret) { ++ qemu_loadvm_state_cleanup(); + return ret; + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-postcopy-Clear-have_listen_thread.patch b/SOURCES/kvm-migration-postcopy-Clear-have_listen_thread.patch new file mode 100644 index 0000000..dcc86ec --- /dev/null +++ b/SOURCES/kvm-migration-postcopy-Clear-have_listen_thread.patch @@ -0,0 +1,53 @@ +From c6b775765f1b05c78fdaf24966c3c4f1d768a9ac Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Mon, 19 Nov 2018 16:19:20 +0100 +Subject: [PATCH 21/22] migration/postcopy: Clear have_listen_thread + +RH-Author: Dr. David Alan Gilbert +Message-id: <20181119161921.15191-2-dgilbert@redhat.com> +Patchwork-id: 83047 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/2] migration/postcopy: Clear have_listen_thread +Bugzilla: 1608877 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Peter Xu +RH-Acked-by: Pankaj Gupta + +From: "Dr. David Alan Gilbert" + +Clear have_listen_thread when we exit the thread. +The fallout from this was that various things thought there was +an ongoing postcopy after the postcopy had finished. + +The case that failed was postcopy->savevm->loadvm. + +This corresponds to RH bug https://bugzilla.redhat.com/show_bug.cgi?id=1608765 + +Signed-off-by: Dr. David Alan Gilbert +Message-Id: <20180914170430.54271-2-dgilbert@redhat.com> +Reviewed-by: Peter Xu +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 9cf4bb8730c669c40550e635a9e2b8ee4f1664ca) + Manual merge due to context + +Signed-off-by: Danilo C. L. de Paula +(cherry picked from commit 66e37a444b4b4818957dabadcc4580f1877e4ebb) +Signed-off-by: Miroslav Rezanina +--- + migration/savevm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/migration/savevm.c b/migration/savevm.c +index b975d3a..7a5d9ff 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -1621,6 +1621,7 @@ static void *postcopy_ram_listen_thread(void *opaque) + migration_incoming_state_destroy(); + qemu_loadvm_state_cleanup(); + ++ mis->have_listen_thread = false; + return NULL; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mips_malta-Clean-up-definition-of-flash-memory-size-.patch b/SOURCES/kvm-mips_malta-Clean-up-definition-of-flash-memory-size-.patch new file mode 100644 index 0000000..75edaee --- /dev/null +++ b/SOURCES/kvm-mips_malta-Clean-up-definition-of-flash-memory-size-.patch @@ -0,0 +1,56 @@ +From 43d46e014933fd009b39dd780ef33ac8cd2081d3 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:04 +0200 +Subject: [PATCH 37/53] mips_malta: Clean up definition of flash memory size + somewhat +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-16-armbru@redhat.com> +Patchwork-id: 88009 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 15/31] mips_malta: Clean up definition of flash memory size somewhat +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +pflash_cfi01_register() takes a size in bytes, a block size in bytes +and a number of blocks. mips_malta_init() passes BIOS_SIZE, 65536, +FLASH_SIZE >> 16. Actually consistent only because BIOS_SIZE (defined +in include/hw/mips/bios.h as (4 * MiB)) matches FLASH_SIZE (defined +locally as 0x400000). Confusing all the same. + +Pass FLASH_SIZE instead of BIOS_SIZE. + +Cc: Aurelien Jarno +Cc: Aleksandar Rikalo +Signed-off-by: Markus Armbruster +Reviewed-by: Alex Bennée +Reviewed-by: Richard Henderson +Message-Id: <20190308094610.21210-14-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +(cherry picked from commit 7ebfece56a9370eecd4b425b109dd722b09b9303) +Signed-off-by: Miroslav Rezanina +--- + hw/mips/mips_malta.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index 857bdb8..e46a252 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -1063,7 +1063,7 @@ void mips_malta_init(MachineState *machine) + /* Load firmware in flash / BIOS. */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", +- BIOS_SIZE, ++ FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 65536, FLASH_SIZE >> 16, + 4, 0x0000, 0x0000, 0x0000, 0x0000, be); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mips_malta-Delete-disabled-broken-DEBUG_BOARD_INIT-c.patch b/SOURCES/kvm-mips_malta-Delete-disabled-broken-DEBUG_BOARD_INIT-c.patch new file mode 100644 index 0000000..b68dca3 --- /dev/null +++ b/SOURCES/kvm-mips_malta-Delete-disabled-broken-DEBUG_BOARD_INIT-c.patch @@ -0,0 +1,74 @@ +From 186549785eab7b0b7ac1063b942a317c80867766 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:01 +0200 +Subject: [PATCH 34/53] mips_malta: Delete disabled, broken DEBUG_BOARD_INIT + code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-13-armbru@redhat.com> +Patchwork-id: 88001 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 12/31] mips_malta: Delete disabled, broken DEBUG_BOARD_INIT code +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +The debug code under DEBUG_BOARD_INIT doesn't compile: + + hw/mips/mips_malta.c:1273:16: error: implicit declaration of function ‘blk_name’; did you mean ‘basename’? [-Werror=implicit-function-declaration] + blk_name(dinfo->bdrv), fl_sectors); + ^~~~~~~~ + hw/mips/mips_malta.c:1273:16: error: nested extern declaration of ‘blk_name’ [-Werror=nested-externs] + hw/mips/mips_malta.c:1273:30: error: ‘DriveInfo’ {aka ‘struct DriveInfo’} has no member named ‘bdrv’ + blk_name(dinfo->bdrv), fl_sectors); + ^~ + +Delete it. + +Reported-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +Reviewed-by: Aleksandar Markovic +Message-Id: <20190308094610.21210-11-armbru@redhat.com> +Reviewed-by: Alex Bennée +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +(cherry picked from commit 5a4abb197b2ee8e6c545a8ec6e0bf9ca4e470127) +Signed-off-by: Miroslav Rezanina +--- + hw/mips/mips_malta.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index 88fd7d6..7f19bdc 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -58,8 +58,6 @@ + #include "exec/semihost.h" + #include "hw/mips/cps.h" + +-//#define DEBUG_BOARD_INIT +- + #define ENVP_ADDR 0x80002000l + #define ENVP_NB_ENTRIES 16 + #define ENVP_ENTRY_SIZE 256 +@@ -1066,14 +1064,6 @@ void mips_malta_init(MachineState *machine) + + /* Load firmware in flash / BIOS. */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); +-#ifdef DEBUG_BOARD_INIT +- if (dinfo) { +- printf("Register parallel flash %d size " TARGET_FMT_lx " at " +- "addr %08llx '%s' %x\n", +- fl_idx, bios_size, FLASH_ADDRESS, +- blk_name(dinfo->bdrv), fl_sectors); +- } +-#endif + fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", + BIOS_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mmap-alloc-fix-hugetlbfs-misaligned-length-in-ppc64.patch b/SOURCES/kvm-mmap-alloc-fix-hugetlbfs-misaligned-length-in-ppc64.patch new file mode 100644 index 0000000..190c954 --- /dev/null +++ b/SOURCES/kvm-mmap-alloc-fix-hugetlbfs-misaligned-length-in-ppc64.patch @@ -0,0 +1,181 @@ +From 6eda983528f3d74ecd4bdecf6aae127e9c93ed48 Mon Sep 17 00:00:00 2001 +From: Sam Bobroff +Date: Tue, 16 Apr 2019 05:29:10 +0200 +Subject: [PATCH 163/163] mmap-alloc: fix hugetlbfs misaligned length in ppc64 + +RH-Author: Sam Bobroff +Message-id: <1555392550-21945-3-git-send-email-sbobroff@redhat.com> +Patchwork-id: 85702 +O-Subject: [RHEL-7.7 qemu-kvm-rhev BZ1672819 PATCH 2/2 REPOST] mmap-alloc: fix hugetlbfs misaligned length in ppc64 +Bugzilla: 1672819 +RH-Acked-by: David Gibson +RH-Acked-by: Thomas Huth +RH-Acked-by: Pankaj Gupta + +From: Murilo Opsfelder Araujo + +The commit 7197fb4058bcb68986bae2bb2c04d6370f3e7218 ("util/mmap-alloc: +fix hugetlb support on ppc64") fixed Huge TLB mappings on ppc64. + +However, we still need to consider the underlying huge page size +during munmap() because it requires that both address and length be a +multiple of the underlying huge page size for Huge TLB mappings. +Quote from "Huge page (Huge TLB) mappings" paragraph under NOTES +section of the munmap(2) manual: + + "For munmap(), addr and length must both be a multiple of the + underlying huge page size." + +On ppc64, the munmap() in qemu_ram_munmap() does not work for Huge TLB +mappings because the mapped segment can be aligned with the underlying +huge page size, not aligned with the native system page size, as +returned by getpagesize(). + +This has the side effect of not releasing huge pages back to the pool +after a hugetlbfs file-backed memory device is hot-unplugged. + +This patch fixes the situation in qemu_ram_mmap() and +qemu_ram_munmap() by considering the underlying page size on ppc64. + +After this patch, memory hot-unplug releases huge pages back to the +pool. + +Fixes: 7197fb4058bcb68986bae2bb2c04d6370f3e7218 +Signed-off-by: Murilo Opsfelder Araujo +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Greg Kurz +(cherry picked from commit 7265c2b9716369b339d778b9ef64a8161eb8f99b) + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1672819 +Testing: Check that hugepage backed RAM removed from a guest is free'd +on the host. +Signed-off-by: Sam Bobroff +Upstream: Patch is in dgibson/ppc-for-4.0 + +Signed-off-by: Miroslav Rezanina +--- + exec.c | 4 ++-- + include/qemu/mmap-alloc.h | 2 +- + util/mmap-alloc.c | 22 ++++++++++++++++------ + util/oslib-posix.c | 2 +- + 4 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/exec.c b/exec.c +index d87a51a..82e85ff 100644 +--- a/exec.c ++++ b/exec.c +@@ -1714,7 +1714,7 @@ static void *file_ram_alloc(RAMBlock *block, + if (mem_prealloc) { + os_mem_prealloc(fd, area, memory, smp_cpus, errp); + if (errp && *errp) { +- qemu_ram_munmap(area, memory); ++ qemu_ram_munmap(fd, area, memory); + return NULL; + } + } +@@ -2235,7 +2235,7 @@ static void reclaim_ramblock(RAMBlock *block) + xen_invalidate_map_cache_entry(block->host); + #ifndef _WIN32 + } else if (block->fd >= 0) { +- qemu_ram_munmap(block->host, block->max_length); ++ qemu_ram_munmap(block->fd, block->host, block->max_length); + close(block->fd); + #endif + } else { +diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h +index 50385e3..ef04f0e 100644 +--- a/include/qemu/mmap-alloc.h ++++ b/include/qemu/mmap-alloc.h +@@ -9,6 +9,6 @@ size_t qemu_mempath_getpagesize(const char *mem_path); + + void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared); + +-void qemu_ram_munmap(void *ptr, size_t size); ++void qemu_ram_munmap(int fd, void *ptr, size_t size); + + #endif +diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c +index 94ee517..19607c1 100644 +--- a/util/mmap-alloc.c ++++ b/util/mmap-alloc.c +@@ -78,6 +78,7 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + int flags; + int guardfd; + size_t offset; ++ size_t pagesize; + size_t total; + void *guardptr; + void *ptr; +@@ -98,7 +99,8 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + * anonymous memory is OK. + */ + flags = MAP_PRIVATE; +- if (fd == -1 || qemu_fd_getpagesize(fd) == getpagesize()) { ++ pagesize = qemu_fd_getpagesize(fd); ++ if (fd == -1 || pagesize == getpagesize()) { + guardfd = -1; + flags |= MAP_ANONYMOUS; + } else { +@@ -107,6 +109,7 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + } + #else + guardfd = -1; ++ pagesize = getpagesize(); + flags = MAP_PRIVATE | MAP_ANONYMOUS; + #endif + +@@ -118,7 +121,7 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + + assert(is_power_of_2(align)); + /* Always align to host page size */ +- assert(align >= getpagesize()); ++ assert(align >= pagesize); + + flags = MAP_FIXED; + flags |= fd == -1 ? MAP_ANONYMOUS : 0; +@@ -141,17 +144,24 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + * a guard page guarding against potential buffer overflows. + */ + total -= offset; +- if (total > size + getpagesize()) { +- munmap(ptr + size + getpagesize(), total - size - getpagesize()); ++ if (total > size + pagesize) { ++ munmap(ptr + size + pagesize, total - size - pagesize); + } + + return ptr; + } + +-void qemu_ram_munmap(void *ptr, size_t size) ++void qemu_ram_munmap(int fd, void *ptr, size_t size) + { ++ size_t pagesize; ++ + if (ptr) { + /* Unmap both the RAM block and the guard page */ +- munmap(ptr, size + getpagesize()); ++#if defined(__powerpc64__) && defined(__linux__) ++ pagesize = qemu_fd_getpagesize(fd); ++#else ++ pagesize = getpagesize(); ++#endif ++ munmap(ptr, size + pagesize); + } + } +diff --git a/util/oslib-posix.c b/util/oslib-posix.c +index 13b6f8d..a24dd01 100644 +--- a/util/oslib-posix.c ++++ b/util/oslib-posix.c +@@ -153,7 +153,7 @@ void qemu_vfree(void *ptr) + void qemu_anon_ram_free(void *ptr, size_t size) + { + trace_qemu_anon_ram_free(ptr, size); +- qemu_ram_munmap(ptr, size); ++ qemu_ram_munmap(-1, ptr, size); + } + + void qemu_set_block(int fd) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mmap-alloc-unfold-qemu_ram_mmap.patch b/SOURCES/kvm-mmap-alloc-unfold-qemu_ram_mmap.patch new file mode 100644 index 0000000..b819948 --- /dev/null +++ b/SOURCES/kvm-mmap-alloc-unfold-qemu_ram_mmap.patch @@ -0,0 +1,142 @@ +From 5e5b310f575cab0403a84de8e6e7505d6f167730 Mon Sep 17 00:00:00 2001 +From: Sam Bobroff +Date: Tue, 16 Apr 2019 05:29:09 +0200 +Subject: [PATCH 162/163] mmap-alloc: unfold qemu_ram_mmap() + +RH-Author: Sam Bobroff +Message-id: <1555392550-21945-2-git-send-email-sbobroff@redhat.com> +Patchwork-id: 85701 +O-Subject: [RHEL-7.7 qemu-kvm-rhev BZ1672819 PATCH 1/2 REPOST] mmap-alloc: unfold qemu_ram_mmap() +Bugzilla: 1672819 +RH-Acked-by: David Gibson +RH-Acked-by: Thomas Huth +RH-Acked-by: Pankaj Gupta + +From: Murilo Opsfelder Araujo + +Unfold parts of qemu_ram_mmap() for the sake of understanding, moving +declarations to the top, and keeping architecture-specifics in the +ifdef-else blocks. No changes in the function behaviour. + +Give ptr and ptr1 meaningful names: + ptr -> guardptr : pointer to the PROT_NONE guard region + ptr1 -> ptr : pointer to the mapped memory returned to caller + +Signed-off-by: Murilo Opsfelder Araujo +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Greg Kurz +(cherry picked from commit 94af9e34821c5c47a3c69fe242e32d0b33c2fff6) + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1672819 +Testing: Check that hugepage backed RAM removed from a guest is free'd +on the host. +Signed-off-by: Sam Bobroff +Upstream: Patch is in dgibson/ppc-for-4.0 + +Signed-off-by: Miroslav Rezanina +--- + util/mmap-alloc.c | 53 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 34 insertions(+), 19 deletions(-) + +diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c +index 2fd8cbc..94ee517 100644 +--- a/util/mmap-alloc.c ++++ b/util/mmap-alloc.c +@@ -75,11 +75,19 @@ size_t qemu_mempath_getpagesize(const char *mem_path) + + void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + { ++ int flags; ++ int guardfd; ++ size_t offset; ++ size_t total; ++ void *guardptr; ++ void *ptr; ++ + /* + * Note: this always allocates at least one extra page of virtual address + * space, even if size is already aligned. + */ +- size_t total = size + align; ++ total = size + align; ++ + #if defined(__powerpc64__) && defined(__linux__) + /* On ppc64 mappings in the same segment (aka slice) must share the same + * page size. Since we will be re-allocating part of this segment +@@ -89,16 +97,22 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + * We do this unless we are using the system page size, in which case + * anonymous memory is OK. + */ +- int anonfd = fd == -1 || qemu_fd_getpagesize(fd) == getpagesize() ? -1 : fd; +- int flags = anonfd == -1 ? MAP_ANONYMOUS : MAP_NORESERVE; +- void *ptr = mmap(0, total, PROT_NONE, flags | MAP_PRIVATE, anonfd, 0); ++ flags = MAP_PRIVATE; ++ if (fd == -1 || qemu_fd_getpagesize(fd) == getpagesize()) { ++ guardfd = -1; ++ flags |= MAP_ANONYMOUS; ++ } else { ++ guardfd = fd; ++ flags |= MAP_NORESERVE; ++ } + #else +- void *ptr = mmap(0, total, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); ++ guardfd = -1; ++ flags = MAP_PRIVATE | MAP_ANONYMOUS; + #endif +- size_t offset; +- void *ptr1; + +- if (ptr == MAP_FAILED) { ++ guardptr = mmap(0, total, PROT_NONE, flags, guardfd, 0); ++ ++ if (guardptr == MAP_FAILED) { + return MAP_FAILED; + } + +@@ -106,19 +120,20 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + /* Always align to host page size */ + assert(align >= getpagesize()); + +- offset = QEMU_ALIGN_UP((uintptr_t)ptr, align) - (uintptr_t)ptr; +- ptr1 = mmap(ptr + offset, size, PROT_READ | PROT_WRITE, +- MAP_FIXED | +- (fd == -1 ? MAP_ANONYMOUS : 0) | +- (shared ? MAP_SHARED : MAP_PRIVATE), +- fd, 0); +- if (ptr1 == MAP_FAILED) { +- munmap(ptr, total); ++ flags = MAP_FIXED; ++ flags |= fd == -1 ? MAP_ANONYMOUS : 0; ++ flags |= shared ? MAP_SHARED : MAP_PRIVATE; ++ offset = QEMU_ALIGN_UP((uintptr_t)guardptr, align) - (uintptr_t)guardptr; ++ ++ ptr = mmap(guardptr + offset, size, PROT_READ | PROT_WRITE, flags, fd, 0); ++ ++ if (ptr == MAP_FAILED) { ++ munmap(guardptr, total); + return MAP_FAILED; + } + + if (offset > 0) { +- munmap(ptr, offset); ++ munmap(guardptr, offset); + } + + /* +@@ -127,10 +142,10 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) + */ + total -= offset; + if (total > size + getpagesize()) { +- munmap(ptr1 + size + getpagesize(), total - size - getpagesize()); ++ munmap(ptr + size + getpagesize(), total - size - getpagesize()); + } + +- return ptr1; ++ return ptr; + } + + void qemu_ram_munmap(void *ptr, size_t size) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-monitor-move-init-global-earlier.patch b/SOURCES/kvm-monitor-move-init-global-earlier.patch new file mode 100644 index 0000000..1dac255 --- /dev/null +++ b/SOURCES/kvm-monitor-move-init-global-earlier.patch @@ -0,0 +1,67 @@ +From 6d69ed6b8b79cf43a8e0fa72167e7550fe6a936f Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:50 +0200 +Subject: [PATCH 23/53] monitor: move init global earlier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-2-armbru@redhat.com> +Patchwork-id: 87989 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 01/31] monitor: move init global earlier +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Peter Xu + +Before this patch, monitor fd helpers might be called even earlier than +monitor_init_globals(). This can be problematic. + +After previous work, now monitor_init_globals() does not depend on +accelerator initialization any more. Call it earlier (before CLI +parsing; that's where the monitor APIs might be called) to make sure it +is called before any of the monitor APIs. + +Suggested-by: Markus Armbruster +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Markus Armbruster +Signed-off-by: Peter Xu +Message-Id: <20180608035511.7439-7-peterx@redhat.com> +Signed-off-by: Markus Armbruster +(cherry picked from commit d32749deb61513c5456901f20e19887e1bc3d7f3) +Signed-off-by: Miroslav Rezanina +--- + vl.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/vl.c b/vl.c +index 92a98ab..a22da93 100644 +--- a/vl.c ++++ b/vl.c +@@ -3157,6 +3157,7 @@ int main(int argc, char **argv, char **envp) + + runstate_init(); + postcopy_infrastructure_init(); ++ monitor_init_globals(); + + if (qcrypto_init(&err) < 0) { + error_reportf_err(err, "cannot initialize crypto: "); +@@ -4591,12 +4592,6 @@ int main(int argc, char **argv, char **envp) + default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); + default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); + +- /* +- * Note: qtest_enabled() (which is used in monitor_qapi_event_init()) +- * depends on configure_accelerator() above. +- */ +- monitor_init_globals(); +- + if (qemu_opts_foreach(qemu_find_opts("mon"), + mon_init_func, NULL, NULL)) { + exit(1); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Add-some-error-case-testing-to-iotests-223.patch b/SOURCES/kvm-nbd-Add-some-error-case-testing-to-iotests-223.patch new file mode 100644 index 0000000..dda30f7 --- /dev/null +++ b/SOURCES/kvm-nbd-Add-some-error-case-testing-to-iotests-223.patch @@ -0,0 +1,131 @@ +From 0237c861ddbb4584443c45436c53e0282ecc10fd Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:26 +0100 +Subject: [PATCH 087/163] nbd: Add some error case testing to iotests 223 + +RH-Author: John Snow +Message-id: <20190327172308.31077-14-jsnow@redhat.com> +Patchwork-id: 85175 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/55] nbd: Add some error case testing to iotests 223 +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Testing success paths is important, but it's also nice to highlight +expected failure handling, to show that we don't crash, and so that +upcoming tests that change behavior can demonstrate the resulting +effects on error paths. + +Add the following errors: +Attempting to export without a running server +Attempting to start a second server +Attempting to export a bad node name +Attempting to export a name that is already exported +Attempting to export an enabled bitmap +Attempting to remove an already removed export +Attempting to quit server a second time + +All of these properly complain except for a second server-stop, +which will be fixed next. + +Signed-off-by: Eric Blake +Message-Id: <20190111194720.15671-2-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 2d2fd67428f0cfbffea16969d2635af3e2d78d3d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/223 | 19 +++++++++++++++++-- + tests/qemu-iotests/223.out | 7 +++++++ + 2 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index 5513dc6..61b46a2 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -107,6 +107,7 @@ echo + + _launch_qemu 2> >(_filter_nbd) + ++# Intentionally provoke some errors as well, to check error handling + silent= + _send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", +@@ -114,18 +115,29 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", + "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", + "arguments":{"node":"n", "name":"b"}}' "return" +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", +- "arguments":{"node":"n", "name":"b2"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", ++ "arguments":{"device":"n"}}' "error" # Attempt add without server + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", + "arguments":{"addr":{"type":"unix", + "data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", ++ "arguments":{"addr":{"type":"unix", ++ "data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", ++ "arguments":{"device":"nosuch"}}' "error" # Attempt to export missing node ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", ++ "arguments":{"device":"n"}}' "error" # Attempt to export same name twice + _send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", + "arguments":{"name":"n", "bitmap":"b"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n", "name":"n2"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", ++ "arguments":{"name":"n2", "bitmap":"b2"}}' "error" # Attempt enabled bitmap ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", ++ "arguments":{"node":"n", "name":"b2"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", + "arguments":{"name":"n2", "bitmap":"b2"}}' "return" + + echo +@@ -157,7 +169,10 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + "arguments":{"name":"n"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + "arguments":{"name":"n2"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", ++ "arguments":{"name":"n2"}}' "error" # Attempt duplicate clean + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" # Oops + _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" + + # success, all done +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index de41747..c1eed62 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -27,10 +27,15 @@ wrote 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"return": {}} + {"return": {}} ++{"error": {"class": "GenericError", "desc": "NBD server not running"}} + {"return": {}} ++{"error": {"class": "GenericError", "desc": "NBD server already running"}} + {"return": {}} ++{"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}} ++{"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}} + {"return": {}} + {"return": {}} ++{"error": {"class": "GenericError", "desc": "Bitmap 'b2' is enabled"}} + {"return": {}} + {"return": {}} + +@@ -62,6 +67,8 @@ read 2097152/2097152 bytes at offset 2097152 + + {"return": {}} + {"return": {}} ++{"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}} ++{"return": {}} + {"return": {}} + {"return": {}} + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Allow-bitmap-export-during-QMP-nbd-server-add.patch b/SOURCES/kvm-nbd-Allow-bitmap-export-during-QMP-nbd-server-add.patch new file mode 100644 index 0000000..a90ab45 --- /dev/null +++ b/SOURCES/kvm-nbd-Allow-bitmap-export-during-QMP-nbd-server-add.patch @@ -0,0 +1,200 @@ +From d5c834ab75d9e3e67e6f8489fef32dc4d22443a1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:30 +0100 +Subject: [PATCH 091/163] nbd: Allow bitmap export during QMP nbd-server-add + +RH-Author: John Snow +Message-id: <20190327172308.31077-18-jsnow@redhat.com> +Patchwork-id: 85188 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 17/55] nbd: Allow bitmap export during QMP nbd-server-add +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +With the experimental x-nbd-server-add-bitmap command, there was +a window of time where an NBD client could see the export but not +the associated dirty bitmap, which can cause a client that planned +on using the dirty bitmap to be forced to treat the entire image +as dirty as a safety fallback. Furthermore, if the QMP client +successfully exports a disk but then fails to add the bitmap, it +has to take on the burden of removing the export. Since we don't +allow changing the exposed dirty bitmap (whether to a different +bitmap, or removing advertisement of the bitmap), it is nicer to +make the bitmap tied to the export at the time the export is +created, with automatic failure to export if the bitmap is not +available. + +The experimental command included an optional 'bitmap-export-name' +field for remapping the name exposed over NBD to be different from +the bitmap name stored on disk. However, my libvirt demo code +for implementing differential backups on top of persistent bitmaps +did not need to take advantage of that feature (it is instead +possible to create a new temporary bitmap with the desired name, +use block-dirty-bitmap-merge to merge one or more persistent +bitmaps into the temporary, then associate the temporary with the +NBD export, if control is needed over the exported bitmap name). +Hence, I'm not copying that part of the experiment over to the +stable addition. For more details on the libvirt demo, see +https://www.redhat.com/archives/libvir-list/2018-October/msg01254.html, +https://kvmforum2018.sched.com/event/FzuB/facilitating-incremental-backup-eric-blake-red-hat + +This patch focuses on the user interface, and reduces (but does +not completely eliminate) the window where an NBD client can see +the export but not the dirty bitmap, with less work to clean up +after errors. Later patches will add further cleanups now that +this interface is declared stable via a single QMP command, +including removing the race window. + +Update test 223 to use the new interface. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190111194720.15671-6-eblake@redhat.com> +(cherry picked from commit 5fcbeb06812685a2c6d7e0e6f28f018987d08b79) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 12 +++++++++++- + hmp.c | 5 +++-- + qapi/block.json | 7 ++++++- + tests/qemu-iotests/223 | 19 ++++++++----------- + tests/qemu-iotests/223.out | 5 +---- + 5 files changed, 29 insertions(+), 19 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index 582ffde..ec8cf0a 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -140,7 +140,8 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr, + } + + void qmp_nbd_server_add(const char *device, bool has_name, const char *name, +- bool has_writable, bool writable, Error **errp) ++ bool has_writable, bool writable, ++ bool has_bitmap, const char *bitmap, Error **errp) + { + BlockDriverState *bs = NULL; + BlockBackend *on_eject_blk; +@@ -185,6 +186,15 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + * our only way of accessing it is through nbd_export_find(), so we can drop + * the strong reference that is @exp. */ + nbd_export_put(exp); ++ ++ if (has_bitmap) { ++ Error *err = NULL; ++ nbd_export_bitmap(exp, bitmap, bitmap, &err); ++ if (err) { ++ error_propagate(errp, err); ++ nbd_export_remove(exp, NBD_SERVER_REMOVE_MODE_HARD, NULL); ++ } ++ } + } + + void qmp_nbd_server_remove(const char *name, +diff --git a/hmp.c b/hmp.c +index cc088da..59e52b9 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -2212,7 +2212,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) + } + + qmp_nbd_server_add(info->value->device, false, NULL, +- true, writable, &local_err); ++ true, writable, false, NULL, &local_err); + + if (local_err != NULL) { + qmp_nbd_server_stop(NULL); +@@ -2233,7 +2233,8 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict) + bool writable = qdict_get_try_bool(qdict, "writable", false); + Error *local_err = NULL; + +- qmp_nbd_server_add(device, !!name, name, true, writable, &local_err); ++ qmp_nbd_server_add(device, !!name, name, true, writable, ++ false, NULL, &local_err); + hmp_handle_error(mon, &local_err); + } + +diff --git a/qapi/block.json b/qapi/block.json +index ba85ceb..b04fcdc 100644 +--- a/qapi/block.json ++++ b/qapi/block.json +@@ -313,6 +313,10 @@ + # + # @writable: Whether clients should be able to write to the device via the + # NBD connection (default false). ++ ++# @bitmap: Also export the dirty bitmap reachable from @device, so the ++# NBD client can use NBD_OPT_SET_META_CONTEXT with ++# "qemu:dirty-bitmap:NAME" to inspect the bitmap. (since 4.0) + # + # Returns: error if the server is not running, or export with the same name + # already exists. +@@ -320,7 +324,8 @@ + # Since: 1.3.0 + ## + { 'command': 'nbd-server-add', +- 'data': {'device': 'str', '*name': 'str', '*writable': 'bool'} } ++ 'data': {'device': 'str', '*name': 'str', '*writable': 'bool', ++ '*bitmap': 'str' } } + + ## + # @NbdServerRemoveMode: +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index f200e31..0bcc98a 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -126,23 +126,20 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", + "arguments":{"addr":{"type":"unix", + "data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", +- "arguments":{"device":"n"}}' "return" ++ "arguments":{"device":"n", "bitmap":"b"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"nosuch"}}' "error" # Attempt to export missing node + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n"}}' "error" # Attempt to export same name twice +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", +- "arguments":{"name":"n", "bitmap":"b"}}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", +- "arguments":{"device":"n", "name":"n2"}}' "return" +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", +- "arguments":{"name":"n2", "bitmap":"b2"}}' "error" # Enabled vs. read-only +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", +- "arguments":{"name":"n2"}}' "return" ++ "arguments":{"device":"n", "name":"n2", ++ "bitmap":"b2"}}' "error" # enabled vs. read-only ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", ++ "arguments":{"device":"n", "name":"n2", ++ "bitmap":"b3"}}' "error" # Missing bitmap + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", +- "arguments":{"device":"n", "name":"n2", "writable":true}}' "return" +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", +- "arguments":{"name":"n2", "bitmap":"b2"}}' "return" ++ "arguments":{"device":"n", "name":"n2", "writable":true, ++ "bitmap":"b2"}}' "return" + + echo + echo "=== Contrast normal status to large granularity dirty-bitmap ===" +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index 3028857..a0c2dec 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -33,11 +33,8 @@ wrote 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}} + {"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}} +-{"return": {}} +-{"return": {}} + {"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}} +-{"return": {}} +-{"return": {}} ++{"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}} + {"return": {}} + + === Contrast normal status to large granularity dirty-bitmap === +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Document-timeline-of-various-features.patch b/SOURCES/kvm-nbd-Document-timeline-of-various-features.patch new file mode 100644 index 0000000..ba8793b --- /dev/null +++ b/SOURCES/kvm-nbd-Document-timeline-of-various-features.patch @@ -0,0 +1,81 @@ +From 627a30ded957f715a9832e8fe93feb3f03575095 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:21 +0100 +Subject: [PATCH 082/163] nbd: Document timeline of various features + +RH-Author: John Snow +Message-id: <20190327172308.31077-9-jsnow@redhat.com> +Patchwork-id: 85169 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/55] nbd: Document timeline of various features +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +It can be useful to figure out which NBD protocol features are +exposed by a server, as well as what features a client will +take advantage of if available, for a given qemu release. It's +not always precise to base features on version numbers (thanks +to downstream backports), but any documentation is better than +making users search through git logs themselves. + +This patch originally stemmed from a request to document that +pristine 3.0 has a known bug where NBD_OPT_LIST_META_CONTEXT +with 0 queries forgot to advertise an available +"qemu:dirty-bitmap" context, but documenting bugs like this (or +the fact that 3.0 also botched NBD_CMD_CACHE) gets to be too +much details, especially since buggy releases will be less +likely connection targets over time. Instead, I chose to just +remind users to check stable release branches. + +Suggested-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake +Message-Id: <20181215135324.152629-3-eblake@redhat.com> +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit ba2d3b3ab217784822e4232f0acd71fc523d571f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + docs/interop/nbd.txt | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt +index 77b5f45..fc64473 100644 +--- a/docs/interop/nbd.txt ++++ b/docs/interop/nbd.txt +@@ -15,7 +15,6 @@ Qemu supports the "base:allocation" metadata context as defined in the + NBD protocol specification, and also defines an additional metadata + namespace "qemu". + +- + == "qemu" namespace == + + The "qemu" namespace currently contains only one type of context, +@@ -36,3 +35,21 @@ in addition to "qemu:dirty-bitmap:": + namespace. + * "qemu:dirty-bitmap:" - returns list of all available dirty-bitmap + metadata contexts. ++ ++= Features by version = ++ ++The following list documents which qemu version first implemented ++various features (both as a server exposing the feature, and as a ++client taking advantage of the feature when present), to make it ++easier to plan for cross-version interoperability. Note that in ++several cases, the initial release containing a feature may require ++additional patches from the corresponding stable branch to fix bugs in ++the operation of that feature. ++ ++* 2.6: NBD_OPT_STARTTLS with TLS X.509 Certificates ++* 2.8: NBD_CMD_WRITE_ZEROES ++* 2.10: NBD_OPT_GO, NBD_INFO_BLOCK ++* 2.11: NBD_OPT_STRUCTURED_REPLY ++* 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation" ++* 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK), ++NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Don-t-lose-server-s-error-to-NBD_CMD_BLOCK_STATU.patch b/SOURCES/kvm-nbd-Don-t-lose-server-s-error-to-NBD_CMD_BLOCK_STATU.patch new file mode 100644 index 0000000..9c4058b --- /dev/null +++ b/SOURCES/kvm-nbd-Don-t-lose-server-s-error-to-NBD_CMD_BLOCK_STATU.patch @@ -0,0 +1,83 @@ +From 436070bc736adc93d90292f5b5a3a2b75c36017d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:13 +0200 +Subject: [PATCH 03/53] nbd: Don't lose server's error to NBD_CMD_BLOCK_STATUS + +RH-Author: John Snow +Message-id: <20190506175629.11079-4-jsnow@redhat.com> +Patchwork-id: 87189 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/19] nbd: Don't lose server's error to NBD_CMD_BLOCK_STATUS +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +When the server replies with a (structured [*]) error to +NBD_CMD_BLOCK_STATUS, without any extent information sent first, the +client code was blindly throwing away the server's error code and +instead telling the caller that EIO occurred. This has been broken +since its introduction in 78a33ab5 (v2.12, where we should have called: + error_setg(&local_err, "Server did not reply with any status extents"); + nbd_iter_error(&iter, false, -EIO, &local_err); +to declare the situation as a non-fatal error if no earlier error had +already been flagged, rather than just blindly slamming iter.err and +iter.ret), although it is more noticeable since commit 7f86068d, which +actually tries hard to preserve the server's code thanks to a separate +iter.request_ret. + +[*] The spec is clear that the server is also permitted to reply with +a simple error, but that's a separate fix. + +I was able to provoke this scenario with a hack to the server, then +seeing whether ENOMEM makes it back to the caller: + +| diff --git a/nbd/server.c b/nbd/server.c +| index fd013a2817a..29c7995de02 100644 +| --- a/nbd/server.c +| +++ b/nbd/server.c +| @@ -2269,6 +2269,8 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, +| "discard failed", errp); +| +| case NBD_CMD_BLOCK_STATUS: +| + return nbd_send_generic_reply(client, request->handle, -ENOMEM, +| + "no status for you today", errp); +| if (!request->len) { +| return nbd_send_generic_reply(client, request->handle, -EINVAL, +| "need non-zero length", errp); +| -- + +Signed-off-by: Eric Blake +Message-Id: <20190325190104.30213-2-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit b29f3a3d2a5fab40dbb4a65fa2f91821ebffae51) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index f3c31d1..532f90c 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -756,12 +756,9 @@ static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + payload = NULL; + } + +- if (!extent->length && !iter.err) { +- error_setg(&iter.err, +- "Server did not reply with any status extents"); +- if (!iter.ret) { +- iter.ret = -EIO; +- } ++ if (!extent->length && !iter.request_ret) { ++ error_setg(&local_err, "Server did not reply with any status extents"); ++ nbd_iter_channel_error(&iter, -EIO, &local_err); + } + + error_propagate(errp, iter.err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Don-t-take-address-of-fields-in-packed-structs.patch b/SOURCES/kvm-nbd-Don-t-take-address-of-fields-in-packed-structs.patch new file mode 100644 index 0000000..06c0f28 --- /dev/null +++ b/SOURCES/kvm-nbd-Don-t-take-address-of-fields-in-packed-structs.patch @@ -0,0 +1,308 @@ +From a2bf5f1541eb073c7c4214e71b0f52d3bcc82914 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:22 +0100 +Subject: [PATCH 055/163] nbd: Don't take address of fields in packed structs + +RH-Author: John Snow +Message-id: <20190322032241.8111-10-jsnow@redhat.com> +Patchwork-id: 85095 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/28] nbd: Don't take address of fields in packed structs +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Peter Maydell + +Taking the address of a field in a packed struct is a bad idea, because +it might not be actually aligned enough for that pointer type (and +thus cause a crash on dereference on some host architectures). Newer +versions of clang warn about this. Avoid the bug by not using the +"modify in place" byte swapping functions. + +This patch was produced with the following spatch script: +@@ +expression E; +@@ +-be16_to_cpus(&E); ++E = be16_to_cpu(E); +@@ +expression E; +@@ +-be32_to_cpus(&E); ++E = be32_to_cpu(E); +@@ +expression E; +@@ +-be64_to_cpus(&E); ++E = be64_to_cpu(E); +@@ +expression E; +@@ +-cpu_to_be16s(&E); ++E = cpu_to_be16(E); +@@ +expression E; +@@ +-cpu_to_be32s(&E); ++E = cpu_to_be32(E); +@@ +expression E; +@@ +-cpu_to_be64s(&E); ++E = cpu_to_be64(E); + +Signed-off-by: Peter Maydell +Message-Id: <20180927164200.15097-1-peter.maydell@linaro.org> +Reviewed-by: Eric Blake +[eblake: rebase, and squash in missed changes] +Signed-off-by: Eric Blake +(cherry picked from commit 80c7c2b00d607221bb43815d2c1951d54229b3ee) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 44 ++++++++++++++++++++++---------------------- + nbd/server.c | 24 ++++++++++++------------ + 2 files changed, 34 insertions(+), 34 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 40b74d9..b4d457a 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -117,10 +117,10 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, + nbd_send_opt_abort(ioc); + return -1; + } +- be64_to_cpus(&reply->magic); +- be32_to_cpus(&reply->option); +- be32_to_cpus(&reply->type); +- be32_to_cpus(&reply->length); ++ reply->magic = be64_to_cpu(reply->magic); ++ reply->option = be32_to_cpu(reply->option); ++ reply->type = be32_to_cpu(reply->type); ++ reply->length = be32_to_cpu(reply->length); + + trace_nbd_receive_option_reply(reply->option, nbd_opt_lookup(reply->option), + reply->type, nbd_rep_lookup(reply->type), +@@ -396,7 +396,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + return -1; + } + len -= sizeof(type); +- be16_to_cpus(&type); ++ type = be16_to_cpu(type); + switch (type) { + case NBD_INFO_EXPORT: + if (len != sizeof(info->size) + sizeof(info->flags)) { +@@ -410,13 +410,13 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + nbd_send_opt_abort(ioc); + return -1; + } +- be64_to_cpus(&info->size); ++ info->size = be64_to_cpu(info->size); + if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { + error_prepend(errp, "failed to read info flags: "); + nbd_send_opt_abort(ioc); + return -1; + } +- be16_to_cpus(&info->flags); ++ info->flags = be16_to_cpu(info->flags); + trace_nbd_receive_negotiate_size_flags(info->size, info->flags); + break; + +@@ -433,7 +433,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + nbd_send_opt_abort(ioc); + return -1; + } +- be32_to_cpus(&info->min_block); ++ info->min_block = be32_to_cpu(info->min_block); + if (!is_power_of_2(info->min_block)) { + error_setg(errp, "server minimum block size %" PRIu32 + " is not a power of two", info->min_block); +@@ -447,7 +447,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + nbd_send_opt_abort(ioc); + return -1; + } +- be32_to_cpus(&info->opt_block); ++ info->opt_block = be32_to_cpu(info->opt_block); + if (!is_power_of_2(info->opt_block) || + info->opt_block < info->min_block) { + error_setg(errp, "server preferred block size %" PRIu32 +@@ -461,7 +461,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + nbd_send_opt_abort(ioc); + return -1; + } +- be32_to_cpus(&info->max_block); ++ info->max_block = be32_to_cpu(info->max_block); + if (info->max_block < info->min_block) { + error_setg(errp, "server maximum block size %" PRIu32 + " is not valid", info->max_block); +@@ -668,7 +668,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + if (nbd_read(ioc, &received_id, sizeof(received_id), errp) < 0) { + return -1; + } +- be32_to_cpus(&received_id); ++ received_id = be32_to_cpu(received_id); + + reply.length -= sizeof(received_id); + name = g_malloc(reply.length + 1); +@@ -872,13 +872,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + error_prepend(errp, "Failed to read export length: "); + goto fail; + } +- be64_to_cpus(&info->size); ++ info->size = be64_to_cpu(info->size); + + if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { + error_prepend(errp, "Failed to read export flags: "); + goto fail; + } +- be16_to_cpus(&info->flags); ++ info->flags = be16_to_cpu(info->flags); + } else if (magic == NBD_CLIENT_MAGIC) { + uint32_t oldflags; + +@@ -895,13 +895,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + error_prepend(errp, "Failed to read export length: "); + goto fail; + } +- be64_to_cpus(&info->size); ++ info->size = be64_to_cpu(info->size); + + if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { + error_prepend(errp, "Failed to read export flags: "); + goto fail; + } +- be32_to_cpus(&oldflags); ++ oldflags = be32_to_cpu(oldflags); + if (oldflags & ~0xffff) { + error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); + goto fail; +@@ -1080,8 +1080,8 @@ static int nbd_receive_simple_reply(QIOChannel *ioc, NBDSimpleReply *reply, + return ret; + } + +- be32_to_cpus(&reply->error); +- be64_to_cpus(&reply->handle); ++ reply->error = be32_to_cpu(reply->error); ++ reply->handle = be64_to_cpu(reply->handle); + + return 0; + } +@@ -1105,10 +1105,10 @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, + return ret; + } + +- be16_to_cpus(&chunk->flags); +- be16_to_cpus(&chunk->type); +- be64_to_cpus(&chunk->handle); +- be32_to_cpus(&chunk->length); ++ chunk->flags = be16_to_cpu(chunk->flags); ++ chunk->type = be16_to_cpu(chunk->type); ++ chunk->handle = be64_to_cpu(chunk->handle); ++ chunk->length = be32_to_cpu(chunk->length); + + return 0; + } +@@ -1128,7 +1128,7 @@ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) + return ret; + } + +- be32_to_cpus(&reply->magic); ++ reply->magic = be32_to_cpu(reply->magic); + + switch (reply->magic) { + case NBD_SIMPLE_REPLY_MAGIC: +diff --git a/nbd/server.c b/nbd/server.c +index a9fec45..df76324 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -333,7 +333,7 @@ static int nbd_opt_read_name(NBDClient *client, char *name, uint32_t *length, + if (ret <= 0) { + return ret; + } +- cpu_to_be32s(&len); ++ len = cpu_to_be32(len); + + if (len > NBD_MAX_NAME_SIZE) { + return nbd_opt_invalid(client, errp, +@@ -486,7 +486,7 @@ static int nbd_negotiate_send_info(NBDClient *client, + if (rc < 0) { + return rc; + } +- cpu_to_be16s(&info); ++ info = cpu_to_be16(info); + if (nbd_write(client->ioc, &info, sizeof(info), errp) < 0) { + return -EIO; + } +@@ -551,14 +551,14 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + if (rc <= 0) { + return rc; + } +- be16_to_cpus(&requests); ++ requests = be16_to_cpu(requests); + trace_nbd_negotiate_handle_info_requests(requests); + while (requests--) { + rc = nbd_opt_read(client, &request, sizeof(request), errp); + if (rc <= 0) { + return rc; + } +- be16_to_cpus(&request); ++ request = be16_to_cpu(request); + trace_nbd_negotiate_handle_info_request(request, + nbd_info_lookup(request)); + /* We care about NBD_INFO_NAME and NBD_INFO_BLOCK_SIZE; +@@ -618,9 +618,9 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + /* maximum - At most 32M, but smaller as appropriate. */ + sizes[2] = MIN(blk_get_max_transfer(exp->blk), NBD_MAX_BUFFER_SIZE); + trace_nbd_negotiate_handle_info_block_size(sizes[0], sizes[1], sizes[2]); +- cpu_to_be32s(&sizes[0]); +- cpu_to_be32s(&sizes[1]); +- cpu_to_be32s(&sizes[2]); ++ sizes[0] = cpu_to_be32(sizes[0]); ++ sizes[1] = cpu_to_be32(sizes[1]); ++ sizes[2] = cpu_to_be32(sizes[2]); + rc = nbd_negotiate_send_info(client, NBD_INFO_BLOCK_SIZE, + sizeof(sizes), sizes, errp); + if (rc < 0) { +@@ -904,7 +904,7 @@ static int nbd_negotiate_meta_query(NBDClient *client, + if (ret <= 0) { + return ret; + } +- cpu_to_be32s(&len); ++ len = cpu_to_be32(len); + + if (len < ns_len) { + trace_nbd_negotiate_meta_query_skip("length too short"); +@@ -971,7 +971,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client, + if (ret <= 0) { + return ret; + } +- cpu_to_be32s(&nb_queries); ++ nb_queries = cpu_to_be32(nb_queries); + trace_nbd_negotiate_meta_context(nbd_opt_lookup(client->opt), + export_name, nb_queries); + +@@ -1049,7 +1049,7 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, + error_prepend(errp, "read failed: "); + return -EIO; + } +- be32_to_cpus(&flags); ++ flags = be32_to_cpu(flags); + trace_nbd_negotiate_options_flags(flags); + if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) { + fixedNewstyle = true; +@@ -1900,8 +1900,8 @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, + extents_end = extent + 1; + + for (extent = extents; extent < extents_end; extent++) { +- cpu_to_be32s(&extent->flags); +- cpu_to_be32s(&extent->length); ++ extent->flags = cpu_to_be32(extent->flags); ++ extent->length = cpu_to_be32(extent->length); + } + + *bytes -= remaining_bytes; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Forbid-nbd-server-stop-when-server-is-not-runnin.patch b/SOURCES/kvm-nbd-Forbid-nbd-server-stop-when-server-is-not-runnin.patch new file mode 100644 index 0000000..68645e1 --- /dev/null +++ b/SOURCES/kvm-nbd-Forbid-nbd-server-stop-when-server-is-not-runnin.patch @@ -0,0 +1,78 @@ +From 4c382f6bee06a3af0b05e321beca89e39b6caa1f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:27 +0100 +Subject: [PATCH 088/163] nbd: Forbid nbd-server-stop when server is not + running + +RH-Author: John Snow +Message-id: <20190327172308.31077-15-jsnow@redhat.com> +Patchwork-id: 85187 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 14/55] nbd: Forbid nbd-server-stop when server is not running +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Since we already forbid other nbd-server commands when not +in the right state, it is unlikely that any caller was relying +on a second stop to behave as a silent no-op. Update iotest +223 to show the improved behavior. + +Signed-off-by: Eric Blake +Message-Id: <20190111194720.15671-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 7801c3a7fd7042fd2f9435af4b9a6d2094073174) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 5 +++++ + tests/qemu-iotests/223 | 2 +- + tests/qemu-iotests/223.out | 2 +- + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index 1d170c8..ca58491 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -214,6 +214,11 @@ void qmp_nbd_server_remove(const char *name, + + void qmp_nbd_server_stop(Error **errp) + { ++ if (!nbd_server) { ++ error_setg(errp, "NBD server not running"); ++ return; ++ } ++ + nbd_export_close_all(); + + nbd_server_free(nbd_server); +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index 61b46a2..a401609 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -172,7 +172,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + "arguments":{"name":"n2"}}' "error" # Attempt duplicate clean + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" +-_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" # Oops ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "error" # Again + _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" + + # success, all done +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index c1eed62..7d28c1a 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -69,6 +69,6 @@ read 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}} + {"return": {}} +-{"return": {}} ++{"error": {"class": "GenericError", "desc": "NBD server not running"}} + {"return": {}} + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Merge-nbd_export_bitmap-into-nbd_export_new.patch b/SOURCES/kvm-nbd-Merge-nbd_export_bitmap-into-nbd_export_new.patch new file mode 100644 index 0000000..4fb89d2 --- /dev/null +++ b/SOURCES/kvm-nbd-Merge-nbd_export_bitmap-into-nbd_export_new.patch @@ -0,0 +1,226 @@ +From 13ac133e5fbde2559899dc3717b2a2c20ce9aeb1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:32 +0100 +Subject: [PATCH 093/163] nbd: Merge nbd_export_bitmap into nbd_export_new + +RH-Author: John Snow +Message-id: <20190327172308.31077-20-jsnow@redhat.com> +Patchwork-id: 85190 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 19/55] nbd: Merge nbd_export_bitmap into nbd_export_new +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +We only have one caller that wants to export a bitmap name, +which it does right after creation of the export. But there is +still a brief window of time where an NBD client could see the +export but not the dirty bitmap, which a robust client would +have to interpret as meaning the entire image should be treated +as dirty. Better is to eliminate the window entirely, by +inlining nbd_export_bitmap() into nbd_export_new(), and refusing +to create the bitmap in the first place if the requested bitmap +can't be located. + +We also no longer need logic for setting a different bitmap +name compared to the bitmap being exported. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190111194720.15671-8-eblake@redhat.com> +(cherry picked from commit 678ba275c77b5b12f3bc9bb369a1b824fc9f679f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 11 +------ + include/block/nbd.h | 9 ++---- + nbd/server.c | 87 ++++++++++++++++++++++++----------------------------- + qemu-nbd.c | 5 +-- + 4 files changed, 47 insertions(+), 65 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index cd86b38..c76d541 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -175,7 +175,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + writable = false; + } + +- exp = nbd_export_new(bs, 0, -1, name, NULL, ++ exp = nbd_export_new(bs, 0, -1, name, NULL, bitmap, + writable ? 0 : NBD_FLAG_READ_ONLY, + NULL, false, on_eject_blk, errp); + if (!exp) { +@@ -186,15 +186,6 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + * our only way of accessing it is through nbd_export_find(), so we can drop + * the strong reference that is @exp. */ + nbd_export_put(exp); +- +- if (has_bitmap) { +- Error *err = NULL; +- nbd_export_bitmap(exp, bitmap, bitmap, &err); +- if (err) { +- error_propagate(errp, err); +- nbd_export_remove(exp, NBD_SERVER_REMOVE_MODE_HARD, NULL); +- } +- } + } + + void qmp_nbd_server_remove(const char *name, +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 2f9a2ae..1971b55 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -296,9 +296,9 @@ typedef struct NBDClient NBDClient; + + NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + const char *name, const char *description, +- uint16_t nbdflags, void (*close)(NBDExport *), +- bool writethrough, BlockBackend *on_eject_blk, +- Error **errp); ++ const char *bitmap, uint16_t nbdflags, ++ void (*close)(NBDExport *), bool writethrough, ++ BlockBackend *on_eject_blk, Error **errp); + void nbd_export_close(NBDExport *exp); + void nbd_export_remove(NBDExport *exp, NbdServerRemoveMode mode, Error **errp); + void nbd_export_get(NBDExport *exp); +@@ -319,9 +319,6 @@ void nbd_client_put(NBDClient *client); + void nbd_server_start(SocketAddress *addr, const char *tls_creds, + Error **errp); + +-void nbd_export_bitmap(NBDExport *exp, const char *bitmap, +- const char *bitmap_export_name, Error **errp); +- + /* nbd_read + * Reads @size bytes from @ioc. Returns 0 on success. + */ +diff --git a/nbd/server.c b/nbd/server.c +index 6c02b57..6b13601 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1457,9 +1457,9 @@ static void nbd_eject_notifier(Notifier *n, void *data) + + NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + const char *name, const char *description, +- uint16_t nbdflags, void (*close)(NBDExport *), +- bool writethrough, BlockBackend *on_eject_blk, +- Error **errp) ++ const char *bitmap, uint16_t nbdflags, ++ void (*close)(NBDExport *), bool writethrough, ++ BlockBackend *on_eject_blk, Error **errp) + { + AioContext *ctx; + BlockBackend *blk; +@@ -1507,6 +1507,43 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + } + exp->size -= exp->size % BDRV_SECTOR_SIZE; + ++ if (bitmap) { ++ BdrvDirtyBitmap *bm = NULL; ++ BlockDriverState *bs = blk_bs(blk); ++ ++ while (true) { ++ bm = bdrv_find_dirty_bitmap(bs, bitmap); ++ if (bm != NULL || bs->backing == NULL) { ++ break; ++ } ++ ++ bs = bs->backing->bs; ++ } ++ ++ if (bm == NULL) { ++ error_setg(errp, "Bitmap '%s' is not found", bitmap); ++ goto fail; ++ } ++ ++ if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) && ++ bdrv_dirty_bitmap_enabled(bm)) { ++ error_setg(errp, ++ "Enabled bitmap '%s' incompatible with readonly export", ++ bitmap); ++ goto fail; ++ } ++ ++ if (bdrv_dirty_bitmap_user_locked(bm)) { ++ error_setg(errp, "Bitmap '%s' is in use", bitmap); ++ goto fail; ++ } ++ ++ bdrv_dirty_bitmap_set_qmp_locked(bm, true); ++ exp->export_bitmap = bm; ++ exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s", ++ bitmap); ++ } ++ + exp->close = close; + exp->ctx = blk_get_aio_context(blk); + blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp); +@@ -2424,47 +2461,3 @@ void nbd_client_new(QIOChannelSocket *sioc, + co = qemu_coroutine_create(nbd_co_client_start, client); + qemu_coroutine_enter(co); + } +- +-void nbd_export_bitmap(NBDExport *exp, const char *bitmap, +- const char *bitmap_export_name, Error **errp) +-{ +- BdrvDirtyBitmap *bm = NULL; +- BlockDriverState *bs = blk_bs(exp->blk); +- +- if (exp->export_bitmap) { +- error_setg(errp, "Export bitmap is already set"); +- return; +- } +- +- while (true) { +- bm = bdrv_find_dirty_bitmap(bs, bitmap); +- if (bm != NULL || bs->backing == NULL) { +- break; +- } +- +- bs = bs->backing->bs; +- } +- +- if (bm == NULL) { +- error_setg(errp, "Bitmap '%s' is not found", bitmap); +- return; +- } +- +- if ((exp->nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) && +- bdrv_dirty_bitmap_enabled(bm)) { +- error_setg(errp, +- "Enabled bitmap '%s' incompatible with readonly export", +- bitmap); +- return; +- } +- +- if (bdrv_dirty_bitmap_user_locked(bm)) { +- error_setg(errp, "Bitmap '%s' is in use", bitmap); +- return; +- } +- +- bdrv_dirty_bitmap_set_qmp_locked(bm, true); +- exp->export_bitmap = bm; +- exp->export_bitmap_context = +- g_strdup_printf("qemu:dirty-bitmap:%s", bitmap_export_name); +-} +diff --git a/qemu-nbd.c b/qemu-nbd.c +index c85aee4..ac4c958 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -1018,8 +1018,9 @@ int main(int argc, char **argv) + } + + export = nbd_export_new(bs, dev_offset, fd_size, export_name, +- export_description, nbdflags, nbd_export_closed, +- writethrough, NULL, &error_fatal); ++ export_description, NULL, nbdflags, ++ nbd_export_closed, writethrough, NULL, ++ &error_fatal); + + if (device) { + #if HAVE_NBD_DEVICE +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Merge-nbd_export_set_name-into-nbd_export_new.patch b/SOURCES/kvm-nbd-Merge-nbd_export_set_name-into-nbd_export_new.patch new file mode 100644 index 0000000..ce61da8 --- /dev/null +++ b/SOURCES/kvm-nbd-Merge-nbd_export_set_name-into-nbd_export_new.patch @@ -0,0 +1,224 @@ +From 629f726f14a40cfe4edf74ec0d213eed935e5a79 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:29 +0100 +Subject: [PATCH 090/163] nbd: Merge nbd_export_set_name into nbd_export_new + +RH-Author: John Snow +Message-id: <20190327172308.31077-17-jsnow@redhat.com> +Patchwork-id: 85171 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 16/55] nbd: Merge nbd_export_set_name into nbd_export_new +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The existing NBD code had a weird split where nbd_export_new() +created an export but did not add it to the list of exported +names until a later nbd_export_set_name() came along and grabbed +a second reference on the object; later, the first call to +nbd_export_close() drops the second reference while removing +the export from the list. This is in part because the QAPI +NbdServerRemoveNode enum documents the possibility of adding a +mode where we could do a soft disconnect: preventing new clients, +but waiting for existing clients to gracefully quit, based on +the mode used when calling nbd_export_close(). + +But in spite of all that, note that we never change the name of +an NBD export while it is exposed, which means it is easier to +just inline the process of setting the name as part of creating +the export. + +Inline the contents of nbd_export_set_name() and +nbd_export_set_description() into the two points in an export +lifecycle where they matter, then adjust both callers to pass +the name up front. Note that for creation, all callers pass a +non-NULL name, (passing NULL at creation was for old style +servers, but we removed support for that in commit 7f7dfe2a), +so we can add an assert and do things unconditionally; but for +cleanup, because of the dual nature of nbd_export_close(), we +still have to be careful to avoid use-after-free. Along the +way, add a comment reminding ourselves of the potential of +adding a middle mode disconnect. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190111194720.15671-5-eblake@redhat.com> +(cherry picked from commit 3fa4c76590569f9dc128beb3eee65aaefcb6321e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 5 ++--- + include/block/nbd.h | 3 +-- + nbd/server.c | 52 +++++++++++++++++++++++----------------------------- + qemu-nbd.c | 8 +++----- + 4 files changed, 29 insertions(+), 39 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index ca58491..582ffde 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -174,14 +174,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + writable = false; + } + +- exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, ++ exp = nbd_export_new(bs, 0, -1, name, NULL, ++ writable ? 0 : NBD_FLAG_READ_ONLY, + NULL, false, on_eject_blk, errp); + if (!exp) { + return; + } + +- nbd_export_set_name(exp, name); +- + /* The list of named exports has a strong reference to this export now and + * our only way of accessing it is through nbd_export_find(), so we can drop + * the strong reference that is @exp. */ +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 65402d3..2f9a2ae 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -295,6 +295,7 @@ typedef struct NBDExport NBDExport; + typedef struct NBDClient NBDClient; + + NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, ++ const char *name, const char *description, + uint16_t nbdflags, void (*close)(NBDExport *), + bool writethrough, BlockBackend *on_eject_blk, + Error **errp); +@@ -306,8 +307,6 @@ void nbd_export_put(NBDExport *exp); + BlockBackend *nbd_export_get_blockdev(NBDExport *exp); + + NBDExport *nbd_export_find(const char *name); +-void nbd_export_set_name(NBDExport *exp, const char *name); +-void nbd_export_set_description(NBDExport *exp, const char *description); + void nbd_export_close_all(void); + + void nbd_client_new(QIOChannelSocket *sioc, +diff --git a/nbd/server.c b/nbd/server.c +index c0f2e85..6c02b57 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1456,6 +1456,7 @@ static void nbd_eject_notifier(Notifier *n, void *data) + } + + NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, ++ const char *name, const char *description, + uint16_t nbdflags, void (*close)(NBDExport *), + bool writethrough, BlockBackend *on_eject_blk, + Error **errp) +@@ -1471,6 +1472,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + * that BDRV_O_INACTIVE is cleared and the image is ready for write + * access since the export could be available before migration handover. + */ ++ assert(name); + ctx = bdrv_get_aio_context(bs); + aio_context_acquire(ctx); + bdrv_invalidate_cache(bs, NULL); +@@ -1494,6 +1496,8 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + QTAILQ_INIT(&exp->clients); + exp->blk = blk; + exp->dev_offset = dev_offset; ++ exp->name = g_strdup(name); ++ exp->description = g_strdup(description); + exp->nbdflags = nbdflags; + exp->size = size < 0 ? blk_getlength(blk) : size; + if (exp->size < 0) { +@@ -1513,10 +1517,14 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + exp->eject_notifier.notify = nbd_eject_notifier; + blk_add_remove_bs_notifier(on_eject_blk, &exp->eject_notifier); + } ++ QTAILQ_INSERT_TAIL(&exports, exp, next); ++ nbd_export_get(exp); + return exp; + + fail: + blk_unref(blk); ++ g_free(exp->name); ++ g_free(exp->description); + g_free(exp); + return NULL; + } +@@ -1533,43 +1541,29 @@ NBDExport *nbd_export_find(const char *name) + return NULL; + } + +-void nbd_export_set_name(NBDExport *exp, const char *name) +-{ +- if (exp->name == name) { +- return; +- } +- +- nbd_export_get(exp); +- if (exp->name != NULL) { +- g_free(exp->name); +- exp->name = NULL; +- QTAILQ_REMOVE(&exports, exp, next); +- nbd_export_put(exp); +- } +- if (name != NULL) { +- nbd_export_get(exp); +- exp->name = g_strdup(name); +- QTAILQ_INSERT_TAIL(&exports, exp, next); +- } +- nbd_export_put(exp); +-} +- +-void nbd_export_set_description(NBDExport *exp, const char *description) +-{ +- g_free(exp->description); +- exp->description = g_strdup(description); +-} +- + void nbd_export_close(NBDExport *exp) + { + NBDClient *client, *next; + + nbd_export_get(exp); ++ /* ++ * TODO: Should we expand QMP NbdServerRemoveNode enum to allow a ++ * close mode that stops advertising the export to new clients but ++ * still permits existing clients to run to completion? Because of ++ * that possibility, nbd_export_close() can be called more than ++ * once on an export. ++ */ + QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) { + client_close(client, true); + } +- nbd_export_set_name(exp, NULL); +- nbd_export_set_description(exp, NULL); ++ if (exp->name) { ++ nbd_export_put(exp); ++ g_free(exp->name); ++ exp->name = NULL; ++ QTAILQ_REMOVE(&exports, exp, next); ++ } ++ g_free(exp->description); ++ exp->description = NULL; + nbd_export_put(exp); + } + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index c37defb..c85aee4 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -1017,11 +1017,9 @@ int main(int argc, char **argv) + } + } + +- export = nbd_export_new(bs, dev_offset, fd_size, nbdflags, +- nbd_export_closed, writethrough, +- NULL, &error_fatal); +- nbd_export_set_name(export, export_name); +- nbd_export_set_description(export, export_description); ++ export = nbd_export_new(bs, dev_offset, fd_size, export_name, ++ export_description, nbdflags, nbd_export_closed, ++ writethrough, NULL, &error_fatal); + + if (device) { + #if HAVE_NBD_DEVICE +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Only-require-disabled-bitmap-for-read-only-expor.patch b/SOURCES/kvm-nbd-Only-require-disabled-bitmap-for-read-only-expor.patch new file mode 100644 index 0000000..a8bb16f --- /dev/null +++ b/SOURCES/kvm-nbd-Only-require-disabled-bitmap-for-read-only-expor.patch @@ -0,0 +1,149 @@ +From 36341fd3c27fd361efe22a7c2758fff1b245867f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:28 +0100 +Subject: [PATCH 089/163] nbd: Only require disabled bitmap for read-only + exports + +RH-Author: John Snow +Message-id: <20190327172308.31077-16-jsnow@redhat.com> +Patchwork-id: 85180 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 15/55] nbd: Only require disabled bitmap for read-only exports +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Our initial implementation of x-nbd-server-add-bitmap put +in a restriction because of incremental backups: in that +usage, we are exporting one qcow2 file (the temporary overlay +target of a blockdev-backup sync:none job) and a dirty bitmap +owned by a second qcow2 file (the source of the +blockdev-backup, which is the backing file of the temporary). +While both qcow2 files are still writable (the target in +order to capture copy-on-write of old contents, and the +source in order to track live guest writes in the meantime), +the NBD client expects to see constant data, including the +dirty bitmap. An enabled bitmap in the source would be +modified by guest writes, which is at odds with the NBD +export being a read-only constant view, hence the initial +code choice of enforcing a disabled bitmap (the intent is +that the exposed bitmap was disabled in the same transaction +that started the blockdev-backup job, although we don't want +to track enough state to actually enforce that). + +However, consider the case of a bitmap contained in a read-only +node (including when the bitmap is found in a backing layer of +the active image). Because the node can't be modified, the +bitmap won't change due to writes, regardless of whether it is +still enabled. Forbidding the export unless the bitmap is +disabled is awkward, paritcularly since we can't change the +bitmap to be disabled (because the node is read-only). + +Alternatively, consider the case of live storage migration, +where management directs the destination to create a writable +NBD server, then performs a drive-mirror from the source to +the target, prior to doing the rest of the live migration. +Since storage migration can be time-consuming, it may be wise +to let the destination include a dirty bitmap to track which +portions it has already received, where even if the migration +is interrupted and restarted, the source can query the +destination block status in order to potentially minimize +re-sending data that has not changed in the meantime on a +second attempt. Such code has not been written, and might not +be trivial (after all, a cluster being marked dirty in the +bitmap does not necessarily guarantee it has the desired +contents), but it makes sense that letting an active dirty +bitmap be exposed and changing alongside writes may prove +useful in the future. + +Solve both issues by gating the restriction against a +disabled bitmap to only happen when the caller has requested +a read-only export, and where the BDS that owns the bitmap +(whether or not it is the BDS handed to nbd_export_new() or +from its backing chain) is still writable. We could drop +the check altogether (if management apps are prepared to +deal with a changing bitmap even on a read-only image), but +for now keeping a check for the read-only case still stands +a chance of preventing management errors. + +Update iotest 223 to show the looser behavior by leaving +a bitmap enabled the whole run; note that we have to tear +down and re-export a node when handling an error. + +Signed-off-by: Eric Blake +Message-Id: <20190111194720.15671-4-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 702aa50d61497d29ef3b5e9c75d1404b3e6fd831) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 7 +++++-- + tests/qemu-iotests/223 | 10 +++++++--- + tests/qemu-iotests/223.out | 3 ++- + 3 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index abf03e8..c0f2e85 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -2456,8 +2456,11 @@ void nbd_export_bitmap(NBDExport *exp, const char *bitmap, + return; + } + +- if (bdrv_dirty_bitmap_enabled(bm)) { +- error_setg(errp, "Bitmap '%s' is enabled", bitmap); ++ if ((exp->nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) && ++ bdrv_dirty_bitmap_enabled(bm)) { ++ error_setg(errp, ++ "Enabled bitmap '%s' incompatible with readonly export", ++ bitmap); + return; + } + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index a401609..f200e31 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -61,6 +61,8 @@ echo "=== Create partially sparse image, then add dirty bitmaps ===" + echo + + # Two bitmaps, to contrast granularity issues ++# Also note that b will be disabled, while b2 is left enabled, to ++# check for read-only interactions + _make_test_img -o cluster_size=4k 4M + $QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io + run_qemu < +Date: Mon, 6 May 2019 17:56:14 +0200 +Subject: [PATCH 04/53] nbd: Permit simple error to NBD_CMD_BLOCK_STATUS + +RH-Author: John Snow +Message-id: <20190506175629.11079-5-jsnow@redhat.com> +Patchwork-id: 87186 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/19] nbd: Permit simple error to NBD_CMD_BLOCK_STATUS +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +The NBD spec is clear that when structured replies are active, a +simple error reply is acceptable to any command except for +NBD_CMD_READ. However, we were mistakenly requiring structured errors +for NBD_CMD_BLOCK_STATUS, and hanging up on a server that gave a +simple error (since qemu does not behave as such a server, we didn't +notice the problem until now). Broken since its introduction in +commit 78a33ab5 (v2.12). + +Noticed while debugging a separate failure reported by nbdkit while +working out its initial implementation of BLOCK_STATUS, although it +turns out that nbdkit also chose to send structured error replies for +BLOCK_STATUS, so I had to manually provoke the situation by hacking +qemu's server to send a simple error reply: + +| diff --git i/nbd/server.c w/nbd/server.c +| index fd013a2817a..833288d7c45 100644 +| 00--- i/nbd/server.c +| +++ w/nbd/server.c +| @@ -2269,6 +2269,8 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, +| "discard failed", errp); +| +| case NBD_CMD_BLOCK_STATUS: +| + return nbd_co_send_simple_reply(client, request->handle, ENOMEM, +| + NULL, 0, errp); +| if (!request->len) { +| return nbd_send_generic_reply(client, request->handle, -EINVAL, +| "need non-zero length", errp); +| + +Signed-off-by: Eric Blake +Acked-by: Richard W.M. Jones +Message-Id: <20190325190104.30213-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit ebd82cd872726549d0a55d329d22c731e2e660ff) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 532f90c..eee909f 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -716,9 +716,7 @@ static int nbd_co_receive_blockstatus_reply(NBDClientSession *s, + bool received = false; + + assert(!extent->length); +- NBD_FOREACH_REPLY_CHUNK(s, iter, handle, s->info.structured_reply, +- NULL, &reply, &payload) +- { ++ NBD_FOREACH_REPLY_CHUNK(s, iter, handle, false, NULL, &reply, &payload) { + int ret; + NBDStructuredReplyChunk *chunk = &reply.structured; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Remove-x-nbd-server-add-bitmap.patch b/SOURCES/kvm-nbd-Remove-x-nbd-server-add-bitmap.patch new file mode 100644 index 0000000..e85273d --- /dev/null +++ b/SOURCES/kvm-nbd-Remove-x-nbd-server-add-bitmap.patch @@ -0,0 +1,101 @@ +From d8f27c2a04ed34863b67d6a7914acc0ad1559dff Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:31 +0100 +Subject: [PATCH 092/163] nbd: Remove x-nbd-server-add-bitmap + +RH-Author: John Snow +Message-id: <20190327172308.31077-19-jsnow@redhat.com> +Patchwork-id: 85178 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 18/55] nbd: Remove x-nbd-server-add-bitmap +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Now that nbd-server-add can do the same functionality (well, other +than making the exported bitmap name different than the underlying +bitamp - but we argued that was not essential, since it is just as +easy to create a new non-persistent bitmap with the desired name), +we no longer need the experimental separate command. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190111194720.15671-7-eblake@redhat.com> +(cherry picked from commit 7dc570b3806e5b0a4c9219061556ed5a4a0de80c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 23 ----------------------- + qapi/block.json | 23 ----------------------- + 2 files changed, 46 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index ec8cf0a..cd86b38 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -233,26 +233,3 @@ void qmp_nbd_server_stop(Error **errp) + nbd_server_free(nbd_server); + nbd_server = NULL; + } +- +-void qmp_x_nbd_server_add_bitmap(const char *name, const char *bitmap, +- bool has_bitmap_export_name, +- const char *bitmap_export_name, +- Error **errp) +-{ +- NBDExport *exp; +- +- if (!nbd_server) { +- error_setg(errp, "NBD server not running"); +- return; +- } +- +- exp = nbd_export_find(name); +- if (exp == NULL) { +- error_setg(errp, "Export '%s' is not found", name); +- return; +- } +- +- nbd_export_bitmap(exp, bitmap, +- has_bitmap_export_name ? bitmap_export_name : bitmap, +- errp); +-} +diff --git a/qapi/block.json b/qapi/block.json +index b04fcdc..6b1d317 100644 +--- a/qapi/block.json ++++ b/qapi/block.json +@@ -369,29 +369,6 @@ + 'data': {'name': 'str', '*mode': 'NbdServerRemoveMode'} } + + ## +-# @x-nbd-server-add-bitmap: +-# +-# Expose a dirty bitmap associated with the selected export. The bitmap search +-# starts at the device attached to the export, and includes all backing files. +-# The exported bitmap is then locked until the NBD export is removed. +-# +-# @name: Export name. +-# +-# @bitmap: Bitmap name to search for. +-# +-# @bitmap-export-name: How the bitmap will be seen by nbd clients +-# (default @bitmap) +-# +-# Note: the client must use NBD_OPT_SET_META_CONTEXT with a query of +-# "qemu:dirty-bitmap:NAME" (where NAME matches @bitmap-export-name) to access +-# the exposed bitmap. +-# +-# Since: 3.0 +-## +- { 'command': 'x-nbd-server-add-bitmap', +- 'data': {'name': 'str', 'bitmap': 'str', '*bitmap-export-name': 'str'} } +- +-## + # @nbd-server-stop: + # + # Stop QEMU's embedded NBD server, and unregister all devices previously +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Support-auto-read-only-option.patch b/SOURCES/kvm-nbd-Support-auto-read-only-option.patch new file mode 100644 index 0000000..e9be703 --- /dev/null +++ b/SOURCES/kvm-nbd-Support-auto-read-only-option.patch @@ -0,0 +1,52 @@ +From 02778d4e42af5fa6c9dd985bee2ae04b2646bbcd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:47 +0100 +Subject: [PATCH 06/34] nbd: Support auto-read-only option + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-6-kwolf@redhat.com> +Patchwork-id: 83121 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 05/12] nbd: Support auto-read-only option +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +If read-only=off, but auto-read-only=on is given, open a read-write NBD +connection if the server provides a read-write export, but instead of +erroring out for read-only exports, just degrade to read-only. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 6c2e581d4d7751f035e9bac0384703879c8a1538) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 98637c0..80d3625 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -988,11 +988,11 @@ int nbd_client_init(BlockDriverState *bs, + logout("Failed to negotiate with the NBD server\n"); + return ret; + } +- if (client->info.flags & NBD_FLAG_READ_ONLY && +- !bdrv_is_read_only(bs)) { +- error_setg(errp, +- "request for write access conflicts with read-only export"); +- return -EACCES; ++ if (client->info.flags & NBD_FLAG_READ_ONLY) { ++ ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp); ++ if (ret < 0) { ++ return ret; ++ } + } + if (client->info.flags & NBD_FLAG_SEND_FUA) { + bs->supported_write_flags = BDRV_REQ_FUA; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Tolerate-some-server-non-compliance-in-NBD_CMD_B.patch b/SOURCES/kvm-nbd-Tolerate-some-server-non-compliance-in-NBD_CMD_B.patch new file mode 100644 index 0000000..14128b0 --- /dev/null +++ b/SOURCES/kvm-nbd-Tolerate-some-server-non-compliance-in-NBD_CMD_B.patch @@ -0,0 +1,125 @@ +From 557b85bcd4aedf4550b272abb57f817f7dc8eba1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:12 +0200 +Subject: [PATCH 02/53] nbd: Tolerate some server non-compliance in + NBD_CMD_BLOCK_STATUS + +RH-Author: John Snow +Message-id: <20190506175629.11079-3-jsnow@redhat.com> +Patchwork-id: 87193 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/19] nbd: Tolerate some server non-compliance in NBD_CMD_BLOCK_STATUS +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +The NBD spec states that NBD_CMD_FLAG_REQ_ONE (which we currently +always use) should not reply with an extent larger than our request, +and that the server's response should be exactly one extent. Right +now, that means that if a server sends more than one extent, we treat +the server as broken, fail the block status request, and disconnect, +which prevents all further use of the block device. But while good +software should be strict in what it sends, it should be tolerant in +what it receives. + +While trying to implement NBD_CMD_BLOCK_STATUS in nbdkit, we +temporarily had a non-compliant server sending too many extents in +spite of REQ_ONE. Oddly enough, 'qemu-img convert' with qemu 3.1 +failed with a somewhat useful message: + qemu-img: Protocol error: invalid payload for NBD_REPLY_TYPE_BLOCK_STATUS + +which then disappeared with commit d8b4bad8, on the grounds that an +error message flagged only at the time of coroutine teardown is +pointless, and instead we should rely on the actual failed API to +report an error - in other words, the 3.1 behavior was masking the +fact that qemu-img was not reporting an error. That has since been +fixed in the previous patch, where qemu-img convert now fails with: + qemu-img: error while reading block status of sector 0: Invalid argument + +But even that is harsh. Since we already partially relaxed things in +commit acfd8f7a to tolerate a server that exceeds the cap (although +that change was made prior to the NBD spec actually putting a cap on +the extent length during REQ_ONE - in fact, the NBD spec change was +BECAUSE of the qemu behavior prior to that commit), it's not that much +harder to argue that we should also tolerate a server that sends too +many extents. But at the same time, it's nice to trace when we are +being tolerant of server non-compliance, in order to help server +writers fix their implementations to be more portable (if they refer +to our traces, rather than just stderr). + +Reported-by: Richard W.M. Jones +Signed-off-by: Eric Blake +Message-Id: <20190323212639.579-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit a39286dd61e455014694cb6aa44cfa9e5c86d101) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 21 ++++++++++++++++----- + block/trace-events | 1 + + 2 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 1230850..f3c31d1 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -227,8 +227,8 @@ static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk *chunk, + } + + /* nbd_parse_blockstatus_payload +- * support only one extent in reply and only for +- * base:allocation context ++ * Based on our request, we expect only one extent in reply, for the ++ * base:allocation context. + */ + static int nbd_parse_blockstatus_payload(NBDClientSession *client, + NBDStructuredReplyChunk *chunk, +@@ -237,7 +237,8 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, + { + uint32_t context_id; + +- if (chunk->length != sizeof(context_id) + sizeof(*extent)) { ++ /* The server succeeded, so it must have sent [at least] one extent */ ++ if (chunk->length < sizeof(context_id) + sizeof(*extent)) { + error_setg(errp, "Protocol error: invalid payload for " + "NBD_REPLY_TYPE_BLOCK_STATUS"); + return -EINVAL; +@@ -263,10 +264,20 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, + return -EINVAL; + } + +- /* The server is allowed to send us extra information on the final +- * extent; just clamp it to the length we requested. */ ++ /* ++ * We used NBD_CMD_FLAG_REQ_ONE, so the server should not have ++ * sent us any more than one extent, nor should it have included ++ * status beyond our request in that extent. However, it's easy ++ * enough to ignore the server's noncompliance without killing the ++ * connection; just ignore trailing extents, and clamp things to ++ * the length of our request. ++ */ ++ if (chunk->length > sizeof(context_id) + sizeof(*extent)) { ++ trace_nbd_parse_blockstatus_compliance("more than one extent"); ++ } + if (extent->length > orig_length) { + extent->length = orig_length; ++ trace_nbd_parse_blockstatus_compliance("extent length too large"); + } + + return 0; +diff --git a/block/trace-events b/block/trace-events +index 6d4d399..59c6f54 100644 +--- a/block/trace-events ++++ b/block/trace-events +@@ -152,5 +152,6 @@ nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64 + nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d" + + # block/nbd-client.c ++nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non-compliant server: %s" + nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" + nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-change-error-checking-order-for-bitmaps.patch b/SOURCES/kvm-nbd-change-error-checking-order-for-bitmaps.patch new file mode 100644 index 0000000..5be341b --- /dev/null +++ b/SOURCES/kvm-nbd-change-error-checking-order-for-bitmaps.patch @@ -0,0 +1,62 @@ +From 4118dc26c6ad7a69c11522d25ead648ffdf0088e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 18:18:43 +0200 +Subject: [PATCH 138/163] nbd: change error checking order for bitmaps + +RH-Author: John Snow +Message-id: <20190403181857.9693-8-jsnow@redhat.com> +Patchwork-id: 85414 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/21] nbd: change error checking order for bitmaps +Bugzilla: 1677073 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Sergio Lopez Pascual + +Check that the bitmap is not in use prior to it checking if it is +not enabled/recording guest writes. The bitmap being busy was likely +at the behest of the user, so this error has a greater chance of being +understood by the user. + +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20190223000614.13894-6-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 3b78a92776bf1199b6864f2f38d9d341fb741f36) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 0910d09..de21c64 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1510,6 +1510,11 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + goto fail; + } + ++ if (bdrv_dirty_bitmap_user_locked(bm)) { ++ error_setg(errp, "Bitmap '%s' is in use", bitmap); ++ goto fail; ++ } ++ + if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) && + bdrv_dirty_bitmap_enabled(bm)) { + error_setg(errp, +@@ -1518,11 +1523,6 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + goto fail; + } + +- if (bdrv_dirty_bitmap_user_locked(bm)) { +- error_setg(errp, "Bitmap '%s' is in use", bitmap); +- goto fail; +- } +- + bdrv_dirty_bitmap_set_qmp_locked(bm, true); + exp->export_bitmap = bm; + exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Add-meta-contexts-to-nbd_receive_export_l.patch b/SOURCES/kvm-nbd-client-Add-meta-contexts-to-nbd_receive_export_l.patch new file mode 100644 index 0000000..8d3e317 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Add-meta-contexts-to-nbd_receive_export_l.patch @@ -0,0 +1,142 @@ +From 1c6d308e59fe4d6f50a0664eea5c0d09b8075f20 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:52 +0100 +Subject: [PATCH 114/163] nbd/client: Add meta contexts to + nbd_receive_export_list() + +RH-Author: John Snow +Message-id: <20190327172308.31077-40-jsnow@redhat.com> +Patchwork-id: 85199 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 39/55] nbd/client: Add meta contexts to nbd_receive_export_list() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +We want to be able to detect whether a given qemu NBD server is +exposing the right export(s) and dirty bitmaps, at least for +regression testing. We could use 'nbd-client -l' from the upstream +NBD project to list exports, but it's annoying to rely on +out-of-tree binaries; furthermore, nbd-client doesn't necessarily +know about all of the qemu NBD extensions. Thus, we plan on adding +a new mode to qemu-nbd that merely sniffs all possible information +from the server during handshake phase, then disconnects and dumps +the information. + +This patch continues the work of the previous patch, by adding the +ability to track the list of available meta contexts into +NBDExportInfo. It benefits from the recent refactoring patches +with a new nbd_list_meta_contexts() that reuses much of the same +framework as setting a meta context. + +Note: a malicious server could exhaust memory of a client by feeding +an unending loop of contexts; perhaps we could place a limit on how +many we are willing to receive. But this is no different from our +earlier analysis on a server sending an unending list of exports, +and the death of a client due to memory exhaustion when the client +was going to exit soon anyways is not really a denial of service +attack. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-19-eblake@redhat.com> +(cherry picked from commit 0b576b6bfb56291bb13db0a54d99adf2f3706030) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 2 ++ + nbd/client.c | 41 +++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 41 insertions(+), 2 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 19332b4..4faf394 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -284,6 +284,8 @@ struct NBDExportInfo { + + /* Set by server results during nbd_receive_export_list() */ + char *description; ++ int n_contexts; ++ char **contexts; + }; + typedef struct NBDExportInfo NBDExportInfo; + +diff --git a/nbd/client.c b/nbd/client.c +index 8a32169..798b82f 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -818,6 +818,36 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + } + + /* ++ * nbd_list_meta_contexts: ++ * Request the server to list all meta contexts for export @info->name. ++ * return 0 if list is complete (even if empty), ++ * -1 with errp set for any error ++ */ ++static int nbd_list_meta_contexts(QIOChannel *ioc, ++ NBDExportInfo *info, ++ Error **errp) ++{ ++ int ret; ++ ++ if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT, ++ info->name, NULL, errp) < 0) { ++ return -1; ++ } ++ ++ while (1) { ++ char *context; ++ ++ ret = nbd_receive_one_meta_context(ioc, NBD_OPT_LIST_META_CONTEXT, ++ &context, NULL, errp); ++ if (ret <= 0) { ++ return ret; ++ } ++ info->contexts = g_renew(char *, info->contexts, ++info->n_contexts); ++ info->contexts[info->n_contexts - 1] = context; ++ } ++} ++ ++/* + * nbd_start_negotiate: + * Start the handshake to the server. After a positive return, the server + * is ready to accept additional NBD_OPT requests. +@@ -1066,7 +1096,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + /* Clean up result of nbd_receive_export_list */ + void nbd_free_export_list(NBDExportInfo *info, int count) + { +- int i; ++ int i, j; + + if (!info) { + return; +@@ -1075,6 +1105,10 @@ void nbd_free_export_list(NBDExportInfo *info, int count) + for (i = 0; i < count; i++) { + g_free(info[i].name); + g_free(info[i].description); ++ for (j = 0; j < info[i].n_contexts; j++) { ++ g_free(info[i].contexts[j]); ++ } ++ g_free(info[i].contexts); + } + g_free(info); + } +@@ -1144,7 +1178,10 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + break; + } + +- /* TODO: Grab meta contexts */ ++ if (result == 3 && ++ nbd_list_meta_contexts(ioc, &array[i], errp) < 0) { ++ goto out; ++ } + } + + /* Send NBD_OPT_ABORT as a courtesy before hanging up */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Add-nbd_receive_export_list.patch b/SOURCES/kvm-nbd-client-Add-nbd_receive_export_list.patch new file mode 100644 index 0000000..2c690c6 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Add-nbd_receive_export_list.patch @@ -0,0 +1,269 @@ +From 2304c1c3b634b52dcca0a42c4986a04fc2b89369 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:51 +0100 +Subject: [PATCH 113/163] nbd/client: Add nbd_receive_export_list() + +RH-Author: John Snow +Message-id: <20190327172308.31077-39-jsnow@redhat.com> +Patchwork-id: 85212 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 38/55] nbd/client: Add nbd_receive_export_list() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +We want to be able to detect whether a given qemu NBD server is +exposing the right export(s) and dirty bitmaps, at least for +regression testing. We could use 'nbd-client -l' from the upstream +NBD project to list exports, but it's annoying to rely on +out-of-tree binaries; furthermore, nbd-client doesn't necessarily +know about all of the qemu NBD extensions. Thus, we plan on adding +a new mode to qemu-nbd that merely sniffs all possible information +from the server during handshake phase, then disconnects and dumps +the information. + +This patch adds the low-level client code for grabbing the list +of exports. It benefits from the recent refactoring patches, in +order to share as much code as possible when it comes to doing +validation of server replies. The resulting information is stored +in an array of NBDExportInfo which has been expanded to any +description string, along with a convenience function for freeing +the list. + +Note: a malicious server could exhaust memory of a client by feeding +an unending loop of exports; perhaps we should place a limit on how +many we are willing to receive. But note that a server could +reasonably be serving an export for every file in a large directory, +where an arbitrary limit in the client means we can't list anything +from such a server; the same happens if we just run until the client +fails to malloc() and thus dies by an abort(), where the limit is +no longer arbitrary but determined by available memory. Since the +client is already planning on being short-lived, it's hard to call +this a denial of service attack that would starve off other uses, +so it does not appear to be a security issue. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-18-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit d21a2d3451d7f1defea5104ce28938f228fab0d4) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 15 +++++- + nbd/client.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 143 insertions(+), 4 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index be19aac..19332b4 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2016-2017 Red Hat, Inc. ++ * Copyright (C) 2016-2019 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori + * + * Network Block Device +@@ -262,6 +262,9 @@ struct NBDExportInfo { + /* Set by client before nbd_receive_negotiate() */ + bool request_sizes; + char *x_dirty_bitmap; ++ ++ /* Set by client before nbd_receive_negotiate(), or by server results ++ * during nbd_receive_export_list() */ + char *name; /* must be non-NULL */ + + /* In-out fields, set by client before nbd_receive_negotiate() and +@@ -269,7 +272,8 @@ struct NBDExportInfo { + bool structured_reply; + bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */ + +- /* Set by server results during nbd_receive_negotiate() */ ++ /* Set by server results during nbd_receive_negotiate() and ++ * nbd_receive_export_list() */ + uint64_t size; + uint16_t flags; + uint32_t min_block; +@@ -277,12 +281,19 @@ struct NBDExportInfo { + uint32_t max_block; + + uint32_t context_id; ++ ++ /* Set by server results during nbd_receive_export_list() */ ++ char *description; + }; + typedef struct NBDExportInfo NBDExportInfo; + + int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + const char *hostname, QIOChannel **outioc, + NBDExportInfo *info, Error **errp); ++void nbd_free_export_list(NBDExportInfo *info, int count); ++int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, ++ const char *hostname, NBDExportInfo **info, ++ Error **errp); + int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, + Error **errp); + int nbd_send_request(QIOChannel *ioc, NBDRequest *request); +diff --git a/nbd/client.c b/nbd/client.c +index fa1657a..8a32169 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -836,7 +836,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + + trace_nbd_start_negotiate(tlscreds, hostname ? hostname : ""); + +- *zeroes = true; ++ if (zeroes) { ++ *zeroes = true; ++ } + if (outioc) { + *outioc = NULL; + } +@@ -880,7 +882,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE; + } + if (globalflags & NBD_FLAG_NO_ZEROES) { +- *zeroes = false; ++ if (zeroes) { ++ *zeroes = false; ++ } + clientflags |= NBD_FLAG_C_NO_ZEROES; + } + /* client requested flags */ +@@ -1059,6 +1063,130 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + return 0; + } + ++/* Clean up result of nbd_receive_export_list */ ++void nbd_free_export_list(NBDExportInfo *info, int count) ++{ ++ int i; ++ ++ if (!info) { ++ return; ++ } ++ ++ for (i = 0; i < count; i++) { ++ g_free(info[i].name); ++ g_free(info[i].description); ++ } ++ g_free(info); ++} ++ ++/* ++ * nbd_receive_export_list: ++ * Query details about a server's exports, then disconnect without ++ * going into transmission phase. Return a count of the exports listed ++ * in @info by the server, or -1 on error. Caller must free @info using ++ * nbd_free_export_list(). ++ */ ++int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, ++ const char *hostname, NBDExportInfo **info, ++ Error **errp) ++{ ++ int result; ++ int count = 0; ++ int i; ++ int rc; ++ int ret = -1; ++ NBDExportInfo *array = NULL; ++ QIOChannel *sioc = NULL; ++ ++ *info = NULL; ++ result = nbd_start_negotiate(ioc, tlscreds, hostname, &sioc, true, NULL, ++ errp); ++ if (tlscreds && sioc) { ++ ioc = sioc; ++ } ++ ++ switch (result) { ++ case 2: ++ case 3: ++ /* newstyle - use NBD_OPT_LIST to populate array, then try ++ * NBD_OPT_INFO on each array member. If structured replies ++ * are enabled, also try NBD_OPT_LIST_META_CONTEXT. */ ++ if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) { ++ goto out; ++ } ++ while (1) { ++ char *name; ++ char *desc; ++ ++ rc = nbd_receive_list(ioc, &name, &desc, errp); ++ if (rc < 0) { ++ goto out; ++ } else if (rc == 0) { ++ break; ++ } ++ array = g_renew(NBDExportInfo, array, ++count); ++ memset(&array[count - 1], 0, sizeof(*array)); ++ array[count - 1].name = name; ++ array[count - 1].description = desc; ++ array[count - 1].structured_reply = result == 3; ++ } ++ ++ for (i = 0; i < count; i++) { ++ array[i].request_sizes = true; ++ rc = nbd_opt_info_or_go(ioc, NBD_OPT_INFO, &array[i], errp); ++ if (rc < 0) { ++ goto out; ++ } else if (rc == 0) { ++ /* ++ * Pointless to try rest of loop. If OPT_INFO doesn't work, ++ * it's unlikely that meta contexts work either ++ */ ++ break; ++ } ++ ++ /* TODO: Grab meta contexts */ ++ } ++ ++ /* Send NBD_OPT_ABORT as a courtesy before hanging up */ ++ nbd_send_opt_abort(ioc); ++ break; ++ case 1: /* newstyle, but limited to EXPORT_NAME */ ++ error_setg(errp, "Server does not support export lists"); ++ /* We can't even send NBD_OPT_ABORT, so merely hang up */ ++ goto out; ++ case 0: /* oldstyle, parse length and flags */ ++ array = g_new0(NBDExportInfo, 1); ++ array->name = g_strdup(""); ++ count = 1; ++ ++ if (nbd_negotiate_finish_oldstyle(ioc, array, errp) < 0) { ++ goto out; ++ } ++ ++ /* Send NBD_CMD_DISC as a courtesy to the server, but ignore all ++ * errors now that we have the information we wanted. */ ++ if (nbd_drop(ioc, 124, NULL) == 0) { ++ NBDRequest request = { .type = NBD_CMD_DISC }; ++ ++ nbd_send_request(ioc, &request); ++ } ++ break; ++ default: ++ goto out; ++ } ++ ++ *info = array; ++ array = NULL; ++ ret = count; ++ ++ out: ++ qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); ++ qio_channel_close(ioc, NULL); ++ object_unref(OBJECT(sioc)); ++ nbd_free_export_list(array, count); ++ return ret; ++} ++ + #ifdef __linux__ + int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, + Error **errp) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Change-signature-of-nbd_negotiate_simple_.patch b/SOURCES/kvm-nbd-client-Change-signature-of-nbd_negotiate_simple_.patch new file mode 100644 index 0000000..3c0f64a --- /dev/null +++ b/SOURCES/kvm-nbd-client-Change-signature-of-nbd_negotiate_simple_.patch @@ -0,0 +1,191 @@ +From 6b1be3a2c8f8eb10c46a4d98ada0347569284141 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:44 +0100 +Subject: [PATCH 106/163] nbd/client: Change signature of + nbd_negotiate_simple_meta_context() + +RH-Author: John Snow +Message-id: <20190327172308.31077-32-jsnow@redhat.com> +Patchwork-id: 85194 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 31/55] nbd/client: Change signature of nbd_negotiate_simple_meta_context() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Pass 'info' instead of three separate parameters related to info, +when requesting the server to set the meta context. Update the +NBDExportInfo struct to rename the received id field to match the +fact that we are currently overloading the field to match whatever +context the user supplied through the x-dirty-bitmap hack, as well +as adding a TODO comment to remind future patches about a desire +to request two contexts at once. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-11-eblake@redhat.com> +(cherry picked from commit 2df94eb52b68d16f8a050bc28dd94a8c7d3366ec) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 4 ++-- + include/block/nbd.h | 2 +- + nbd/client.c | 53 +++++++++++++++++++++++++---------------------------- + 3 files changed, 28 insertions(+), 31 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 3309376..8135396 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -249,11 +249,11 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, + } + + context_id = payload_advance32(&payload); +- if (client->info.meta_base_allocation_id != context_id) { ++ if (client->info.context_id != context_id) { + error_setg(errp, "Protocol error: unexpected context id %d for " + "NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context " + "id is %d", context_id, +- client->info.meta_base_allocation_id); ++ client->info.context_id); + return -EINVAL; + } + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 00d3eb5..be19aac 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -276,7 +276,7 @@ struct NBDExportInfo { + uint32_t opt_block; + uint32_t max_block; + +- uint32_t meta_base_allocation_id; ++ uint32_t context_id; + }; + typedef struct NBDExportInfo NBDExportInfo; + +diff --git a/nbd/client.c b/nbd/client.c +index 8227e69..7799389 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -630,26 +630,30 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, + } + + /* nbd_negotiate_simple_meta_context: +- * Set one meta context. Simple means that reply must contain zero (not +- * negotiated) or one (negotiated) contexts. More contexts would be considered +- * as a protocol error. It's also implied that meta-data query equals queried +- * context name, so, if server replies with something different than @context, +- * it is considered an error too. +- * return 1 for successful negotiation, context_id is set ++ * Request the server to set the meta context for export @info->name ++ * using @info->x_dirty_bitmap with a fallback to "base:allocation", ++ * setting @info->context_id to the resulting id. Fail if the server ++ * responds with more than one context or with a context different ++ * than the query. ++ * return 1 for successful negotiation, + * 0 if operation is unsupported, + * -1 with errp set for any other error + */ + static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, +- const char *export, +- const char *context, +- uint32_t *context_id, ++ NBDExportInfo *info, + Error **errp) + { ++ /* ++ * TODO: Removing the x_dirty_bitmap hack will mean refactoring ++ * this function to request and store ids for multiple contexts ++ * (both base:allocation and a dirty bitmap), at which point this ++ * function should lose the term _simple. ++ */ + int ret; + NBDOptionReply reply; +- uint32_t received_id = 0; ++ const char *context = info->x_dirty_bitmap ?: "base:allocation"; + bool received = false; +- uint32_t export_len = strlen(export); ++ uint32_t export_len = strlen(info->name); + uint32_t context_len = strlen(context); + uint32_t data_len = sizeof(export_len) + export_len + + sizeof(uint32_t) + /* number of queries */ +@@ -657,9 +661,9 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + char *data = g_malloc(data_len); + char *p = data; + +- trace_nbd_opt_meta_request(context, export); ++ trace_nbd_opt_meta_request(context, info->name); + stl_be_p(p, export_len); +- memcpy(p += sizeof(export_len), export, export_len); ++ memcpy(p += sizeof(export_len), info->name, export_len); + stl_be_p(p += export_len, 1); + stl_be_p(p += sizeof(uint32_t), context_len); + memcpy(p += sizeof(context_len), context, context_len); +@@ -685,7 +689,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + if (reply.type == NBD_REP_META_CONTEXT) { + char *name; + +- if (reply.length != sizeof(received_id) + context_len) { ++ if (reply.length != sizeof(info->context_id) + context_len) { + error_setg(errp, "Failed to negotiate meta context '%s', server " + "answered with unexpected length %" PRIu32, context, + reply.length); +@@ -693,12 +697,13 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + return -1; + } + +- if (nbd_read(ioc, &received_id, sizeof(received_id), errp) < 0) { ++ if (nbd_read(ioc, &info->context_id, sizeof(info->context_id), ++ errp) < 0) { + return -1; + } +- received_id = be32_to_cpu(received_id); ++ info->context_id = be32_to_cpu(info->context_id); + +- reply.length -= sizeof(received_id); ++ reply.length -= sizeof(info->context_id); + name = g_malloc(reply.length + 1); + if (nbd_read(ioc, name, reply.length, errp) < 0) { + g_free(name); +@@ -715,7 +720,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + } + g_free(name); + +- trace_nbd_opt_meta_reply(context, received_id); ++ trace_nbd_opt_meta_reply(context, info->context_id); + received = true; + + /* receive NBD_REP_ACK */ +@@ -744,12 +749,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + return -1; + } + +- if (received) { +- *context_id = received_id; +- return 1; +- } +- +- return 0; ++ return received; + } + + int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, +@@ -848,10 +848,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + } + + if (info->structured_reply && base_allocation) { +- result = nbd_negotiate_simple_meta_context( +- ioc, info->name, +- info->x_dirty_bitmap ?: "base:allocation", +- &info->meta_base_allocation_id, errp); ++ result = nbd_negotiate_simple_meta_context(ioc, info, errp); + if (result < 0) { + goto fail; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Drop-pointless-buf-variable.patch b/SOURCES/kvm-nbd-client-Drop-pointless-buf-variable.patch new file mode 100644 index 0000000..1942f7c --- /dev/null +++ b/SOURCES/kvm-nbd-client-Drop-pointless-buf-variable.patch @@ -0,0 +1,115 @@ +From 4f4e329628b6d530cf74d792f0297f651e18e6ba Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:24 +0100 +Subject: [PATCH 085/163] nbd/client: Drop pointless buf variable + +RH-Author: John Snow +Message-id: <20190327172308.31077-12-jsnow@redhat.com> +Patchwork-id: 85182 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/55] nbd/client: Drop pointless buf variable +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +There's no need to read into a temporary buffer (oversized +since commit 7d3123e1) followed by a byteswap into a uint64_t +to check for a magic number via memcmp(), when the code +immediately below demonstrates reading into the uint64_t then +byteswapping in place and checking for a magic number via +integer math. What's more, having a different error message +when the server's first reply byte is 0 is unusual - it's no +different from any other wrong magic number, and we already +detected short reads. That whole strlen() issue has been +present and useless since commit 1d45f8b5 in 2010; perhaps it +was leftover debugging (since the correct magic number happens +to be ASCII)? Make the error messages more consistent and +detailed while touching things. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181215135324.152629-9-eblake@redhat.com> +(cherry picked from commit ef2e35fcc8e14bcc9366df5fdf53f65d679f8dca) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 22 +++++++--------------- + nbd/nbd-internal.h | 3 ++- + 2 files changed, 9 insertions(+), 16 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 5a03a84..f625c20 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -733,7 +733,6 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + QIOChannel **outioc, NBDExportInfo *info, + Error **errp) + { +- char buf[256]; + uint64_t magic; + int rc; + bool zeroes = true; +@@ -754,27 +753,20 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + goto fail; + } + +- if (nbd_read(ioc, buf, 8, errp) < 0) { +- error_prepend(errp, "Failed to read data: "); +- goto fail; +- } +- +- buf[8] = '\0'; +- if (strlen(buf) == 0) { +- error_setg(errp, "Server connection closed unexpectedly"); ++ if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { ++ error_prepend(errp, "Failed to read initial magic: "); + goto fail; + } +- +- magic = ldq_be_p(buf); ++ magic = be64_to_cpu(magic); + trace_nbd_receive_negotiate_magic(magic); + +- if (memcmp(buf, "NBDMAGIC", 8) != 0) { +- error_setg(errp, "Invalid magic received"); ++ if (magic != NBD_INIT_MAGIC) { ++ error_setg(errp, "Bad initial magic received: 0x%" PRIx64, magic); + goto fail; + } + + if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { +- error_prepend(errp, "Failed to read magic: "); ++ error_prepend(errp, "Failed to read server magic: "); + goto fail; + } + magic = be64_to_cpu(magic); +@@ -913,7 +905,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + } + info->flags = oldflags; + } else { +- error_setg(errp, "Bad magic received"); ++ error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); + goto fail; + } + +diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h +index f38be9e..82aa221 100644 +--- a/nbd/nbd-internal.h ++++ b/nbd/nbd-internal.h +@@ -46,8 +46,9 @@ + /* Size of oldstyle negotiation */ + #define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124) + ++#define NBD_INIT_MAGIC 0x4e42444d41474943LL /* ASCII "NBDMAGIC" */ + #define NBD_REQUEST_MAGIC 0x25609513 +-#define NBD_OPTS_MAGIC 0x49484156454F5054LL ++#define NBD_OPTS_MAGIC 0x49484156454F5054LL /* ASCII "IHAVEOPT" */ + #define NBD_CLIENT_MAGIC 0x0000420281861253LL + #define NBD_REP_MAGIC 0x0003e889045565a9LL + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Fix-error-message-for-server-with-unusabl.patch b/SOURCES/kvm-nbd-client-Fix-error-message-for-server-with-unusabl.patch new file mode 100644 index 0000000..26b4fb2 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Fix-error-message-for-server-with-unusabl.patch @@ -0,0 +1,48 @@ +From 4f02070b0278bfaebe0f9af1fcb5f2624693f57c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:28 +0200 +Subject: [PATCH 18/53] nbd/client: Fix error message for server with unusable + sizing + +RH-Author: John Snow +Message-id: <20190506175629.11079-19-jsnow@redhat.com> +Patchwork-id: 87188 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 18/19] nbd/client: Fix error message for server with unusable sizing +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Add a missing space to the error message used when giving up on a +server that insists on an alignment which renders the last few bytes +of the export unreadable. + +Fixes: 3add3ab78 +Signed-off-by: Eric Blake +Message-Id: <20190404145226.32649-1-eblake@redhat.com> +Reviewed-by: Kevin Wolf +(cherry picked from commit e53f88df77e70350b0eda92a2e5e39f67792008f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 4309569..49754120 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -428,7 +428,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + } + if (info->min_block && + !QEMU_IS_ALIGNED(info->size, info->min_block)) { +- error_setg(errp, "export size %" PRIu64 "is not multiple of " ++ error_setg(errp, "export size %" PRIu64 " is not multiple of " + "minimum block size %" PRIu32, info->size, + info->min_block); + nbd_send_opt_abort(ioc); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Fix-error-messages-during-NBD_INFO_BLOCK_.patch b/SOURCES/kvm-nbd-client-Fix-error-messages-during-NBD_INFO_BLOCK_.patch new file mode 100644 index 0000000..791c7e2 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Fix-error-messages-during-NBD_INFO_BLOCK_.patch @@ -0,0 +1,75 @@ +From 1180606c147edadc4a7979baae377fb983dc5fd2 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:15 +0100 +Subject: [PATCH 048/163] nbd/client: Fix error messages during + NBD_INFO_BLOCK_SIZE + +RH-Author: John Snow +Message-id: <20190322032241.8111-3-jsnow@redhat.com> +Patchwork-id: 85091 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/28] nbd/client: Fix error messages during NBD_INFO_BLOCK_SIZE +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +A missing space makes for poor error messages, and sizes can't +go negative. Also, we missed diagnosing a server that sends +a maximum block size less than the minimum. + +Fixes: 081dd1fe +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +Message-Id: <20180501154654.943782-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit e475d108f1b3d3163f0affea67cdedbe5fc9752b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index a151fa5..40b74d9 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -435,8 +435,8 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + } + be32_to_cpus(&info->min_block); + if (!is_power_of_2(info->min_block)) { +- error_setg(errp, "server minimum block size %" PRId32 +- "is not a power of two", info->min_block); ++ error_setg(errp, "server minimum block size %" PRIu32 ++ " is not a power of two", info->min_block); + nbd_send_opt_abort(ioc); + return -1; + } +@@ -450,8 +450,8 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + be32_to_cpus(&info->opt_block); + if (!is_power_of_2(info->opt_block) || + info->opt_block < info->min_block) { +- error_setg(errp, "server preferred block size %" PRId32 +- "is not valid", info->opt_block); ++ error_setg(errp, "server preferred block size %" PRIu32 ++ " is not valid", info->opt_block); + nbd_send_opt_abort(ioc); + return -1; + } +@@ -462,6 +462,12 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + return -1; + } + be32_to_cpus(&info->max_block); ++ if (info->max_block < info->min_block) { ++ error_setg(errp, "server maximum block size %" PRIu32 ++ " is not valid", info->max_block); ++ nbd_send_opt_abort(ioc); ++ return -1; ++ } + trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block, + info->max_block); + break; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Lower-min_block-for-block-status-unaligne.patch b/SOURCES/kvm-nbd-client-Lower-min_block-for-block-status-unaligne.patch new file mode 100644 index 0000000..3b7b50e --- /dev/null +++ b/SOURCES/kvm-nbd-client-Lower-min_block-for-block-status-unaligne.patch @@ -0,0 +1,119 @@ +From 7122c1ace9649d525da8670d5e57aaa8b7c6a686 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:18 +0200 +Subject: [PATCH 08/53] nbd/client: Lower min_block for block-status, unaligned + size + +RH-Author: John Snow +Message-id: <20190506175629.11079-9-jsnow@redhat.com> +Patchwork-id: 87187 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/19] nbd/client: Lower min_block for block-status, unaligned size +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +We have a latent bug in our NBD client code, tickled by the brand new +nbdkit 1.11.10 block status support: + +$ nbdkit --filter=log --filter=truncate -U - \ + data data="1" size=511 truncate=64K logfile=/dev/stdout \ + --run 'qemu-img convert $nbd /var/tmp/out' +... +qemu-img: block/io.c:2122: bdrv_co_block_status: Assertion `*pnum && QEMU_IS_ALIGNED(*pnum, align) && align > offset - aligned_offset' failed. + +The culprit? Our implementation of .bdrv_co_block_status can return +unaligned block status for any server that operates with a lower +actual alignment than what we tell the block layer in +request_alignment, in violation of the block layer's constraints. To +date, we've been unable to trip the bug, because qemu as NBD server +always advertises block sizing (at which point it is a server bug if +the server sends unaligned status - although qemu 3.1 is such a server +and I've sent separate patches for 4.0 both to get the server to obey +the spec, and to let the client to tolerate server oddities at EOF). + +But nbdkit does not (yet) advertise block sizing, and therefore is not +in violation of the spec for returning block status at whatever +boundaries it wants, and those unaligned results can occur anywhere +rather than just at EOF. While we are still wise to avoid sending +sub-sector read/write requests to a server of unknown origin, we MUST +consider that a server telling us block status without an advertised +block size is correct. So, we either have to munge unaligned answers +from the server into aligned ones that we hand back to the block +layer, or we have to tell the block layer about a smaller alignment. + +Similarly, if the server advertises an image size that is not +sector-aligned, we might as well assume that the server intends to let +us access those tail bytes, and therefore supports a minimum block +size of 1, regardless of whether the server supports block status +(although we still need more patches to fix the problem that with an +unaligned image, we can send read or block status requests that exceed +EOF to the server). Again, qemu as server cannot trip this problem +(because it rounds images to sector alignment), but nbdkit advertised +unaligned size even before it gained block status support. + +Solve both alignment problems at once by using better heuristics on +what alignment to report to the block layer when the server did not +give us something to work with. Note that very few NBD servers +implement block status (to date, only qemu and nbdkit are known to do +so); and as the NBD spec mentioned block sizing constraints prior to +documenting block status, it can be assumed that any future +implementations of block status are aware that they must advertise +block size if they want a minimum size other than 1. + +We've had a long history of struggles with picking the right alignment +to use in the block layer, as evidenced by the commit message of +fd8d372d (v2.12) that introduced the current choice of forced 512-byte +alignment. + +There is no iotest coverage for this fix, because qemu can't provoke +it, and I didn't want to make test 241 dependent on nbdkit. + +Fixes: fd8d372d +Reported-by: Richard W.M. Jones +Signed-off-by: Eric Blake +Message-Id: <20190329042750.14704-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +Tested-by: Richard W.M. Jones +(cherry picked from commit 7da537f70d929800ba9c657b8a47a7b827695ccc) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/block/nbd.c b/block/nbd.c +index 838a8fe..670b9bd 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -437,7 +437,24 @@ static void nbd_refresh_limits(BlockDriverState *bs, Error **errp) + uint32_t min = s->info.min_block; + uint32_t max = MIN_NON_ZERO(NBD_MAX_BUFFER_SIZE, s->info.max_block); + +- bs->bl.request_alignment = min ? min : BDRV_SECTOR_SIZE; ++ /* ++ * If the server did not advertise an alignment: ++ * - a size that is not sector-aligned implies that an alignment ++ * of 1 can be used to access those tail bytes ++ * - advertisement of block status requires an alignment of 1, so ++ * that we don't violate block layer constraints that block ++ * status is always aligned (as we can't control whether the ++ * server will report sub-sector extents, such as a hole at EOF ++ * on an unaligned POSIX file) ++ * - otherwise, assume the server is so old that we are safer avoiding ++ * sub-sector requests ++ */ ++ if (!min) { ++ min = (!QEMU_IS_ALIGNED(s->info.size, BDRV_SECTOR_SIZE) || ++ s->info.base_allocation) ? 1 : BDRV_SECTOR_SIZE; ++ } ++ ++ bs->bl.request_alignment = min; + bs->bl.max_pdiscard = max; + bs->bl.max_pwrite_zeroes = max; + bs->bl.max_transfer = max; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Make-x-dirty-bitmap-more-reliable.patch b/SOURCES/kvm-nbd-client-Make-x-dirty-bitmap-more-reliable.patch new file mode 100644 index 0000000..17cfd49 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Make-x-dirty-bitmap-more-reliable.patch @@ -0,0 +1,57 @@ +From 4a378f730e73452bf9bf3a5c761f7d0efdae9d27 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:39 +0100 +Subject: [PATCH 072/163] nbd/client: Make x-dirty-bitmap more reliable + +RH-Author: John Snow +Message-id: <20190322032241.8111-27-jsnow@redhat.com> +Patchwork-id: 85106 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 26/28] nbd/client: Make x-dirty-bitmap more reliable +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The implementation of x-dirty-bitmap in qemu 3.0 (commit 216ee365) +silently falls back to treating the server as not supporting +NBD_CMD_BLOCK_STATUS if a requested meta_context name was not +negotiated, which in turn means treating the _entire_ image as +data. Since our hack relied on using 'qemu-img map' to view +which portions of the image were dirty by seeing what the +redirected bdrv_block_status() treats as holes, this means +that our fallback treats the entire image as clean. Better +would have been to treat the entire image as dirty, or to fail +to connect because the user's request for a specific context +could not be honored. This patch goes with the latter. + +Signed-off-by: Eric Blake +Message-Id: <20181130023232.3079982-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 47829c40794160debdb33b4a042d182e776876d4) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 76e9ca3..e6e27da 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -992,6 +992,11 @@ int nbd_client_init(BlockDriverState *bs, + logout("Failed to negotiate with the NBD server\n"); + return ret; + } ++ if (x_dirty_bitmap && !client->info.base_allocation) { ++ error_setg(errp, "requested x-dirty-bitmap %s not found", ++ x_dirty_bitmap); ++ return -EINVAL; ++ } + if (client->info.flags & NBD_FLAG_READ_ONLY) { + ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp); + if (ret < 0) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-More-consistent-error-messages.patch b/SOURCES/kvm-nbd-client-More-consistent-error-messages.patch new file mode 100644 index 0000000..d720bb5 --- /dev/null +++ b/SOURCES/kvm-nbd-client-More-consistent-error-messages.patch @@ -0,0 +1,89 @@ +From 1ff1deba5e09af78b2fe8095fc0472dfd0051f1c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:22 +0100 +Subject: [PATCH 083/163] nbd/client: More consistent error messages + +RH-Author: John Snow +Message-id: <20190327172308.31077-10-jsnow@redhat.com> +Patchwork-id: 85185 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/55] nbd/client: More consistent error messages +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Consolidate on using decimal (not hex), on outputting the +option reply name (not just value), and a consistent comma between +clauses, when the client reports protocol discrepancies from the +server. While it won't affect normal operation, it makes +debugging additions easier. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181215135324.152629-6-eblake@redhat.com> +(cherry picked from commit 6c5c035138218a384a229e7b6b9cf51451621c6a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 0ad7147..e774147 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -132,8 +132,9 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, + return -1; + } + if (reply->option != opt) { +- error_setg(errp, "Unexpected option type %x expected %x", +- reply->option, opt); ++ error_setg(errp, "Unexpected option type %u (%s), expected %u (%s)", ++ reply->option, nbd_opt_lookup(reply->option), ++ opt, nbd_opt_lookup(opt)); + nbd_send_opt_abort(ioc); + return -1; + } +@@ -267,8 +268,9 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + } + return 0; + } else if (reply.type != NBD_REP_SERVER) { +- error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", +- reply.type, NBD_REP_SERVER); ++ error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", ++ reply.type, nbd_rep_lookup(reply.type), ++ NBD_REP_SERVER, nbd_rep_lookup(NBD_REP_SERVER)); + nbd_send_opt_abort(ioc); + return -1; + } +@@ -380,9 +382,9 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + return 1; + } + if (reply.type != NBD_REP_INFO) { +- error_setg(errp, "unexpected reply type %" PRIu32 +- " (%s), expected %u", +- reply.type, nbd_rep_lookup(reply.type), NBD_REP_INFO); ++ error_setg(errp, "unexpected reply type %u (%s), expected %u (%s)", ++ reply.type, nbd_rep_lookup(reply.type), ++ NBD_REP_INFO, nbd_rep_lookup(NBD_REP_INFO)); + nbd_send_opt_abort(ioc); + return -1; + } +@@ -706,8 +708,9 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + } + + if (reply.type != NBD_REP_ACK) { +- error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", +- reply.type, NBD_REP_ACK); ++ error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", ++ reply.type, nbd_rep_lookup(reply.type), ++ NBD_REP_ACK, nbd_rep_lookup(NBD_REP_ACK)); + nbd_send_opt_abort(ioc); + return -1; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Move-export-name-into-NBDExportInfo.patch b/SOURCES/kvm-nbd-client-Move-export-name-into-NBDExportInfo.patch new file mode 100644 index 0000000..fab3d52 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Move-export-name-into-NBDExportInfo.patch @@ -0,0 +1,257 @@ +From 0736b0b842bcd0acefed2523d2e0cda3876ca469 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:43 +0100 +Subject: [PATCH 105/163] nbd/client: Move export name into NBDExportInfo + +RH-Author: John Snow +Message-id: <20190327172308.31077-31-jsnow@redhat.com> +Patchwork-id: 85203 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 30/55] nbd/client: Move export name into NBDExportInfo +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Refactor the 'name' parameter of nbd_receive_negotiate() from +being a separate parameter into being part of the in-out 'info'. +This also spills over to a simplification of nbd_opt_go(). + +The main driver for this refactoring is that an upcoming patch +would like to add support to qemu-nbd to list information about +all exports available on a server, where the name(s) will be +provided by the server instead of the client. But another benefit +is that we can now allow the client to explicitly specify the +empty export name "" even when connecting to an oldstyle server +(even if qemu is no longer such a server after commit 7f7dfe2a). + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-10-eblake@redhat.com> +(cherry picked from commit 6dc1667d6881add34e9bad48ac2a848134ea8a6d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 5 +++-- + include/block/nbd.h | 8 ++++---- + nbd/client.c | 39 ++++++++++++++++++--------------------- + nbd/trace-events | 2 +- + qemu-nbd.c | 6 ++++-- + 5 files changed, 30 insertions(+), 30 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index ef32075..3309376 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -999,10 +999,11 @@ int nbd_client_init(BlockDriverState *bs, + client->info.structured_reply = true; + client->info.base_allocation = true; + client->info.x_dirty_bitmap = g_strdup(x_dirty_bitmap); +- ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, +- tlscreds, hostname, ++ client->info.name = g_strdup(export ?: ""); ++ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), tlscreds, hostname, + &client->ioc, &client->info, errp); + g_free(client->info.x_dirty_bitmap); ++ g_free(client->info.name); + if (ret < 0) { + logout("Failed to negotiate with the NBD server\n"); + return ret; +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 24be957..00d3eb5 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -262,6 +262,7 @@ struct NBDExportInfo { + /* Set by client before nbd_receive_negotiate() */ + bool request_sizes; + char *x_dirty_bitmap; ++ char *name; /* must be non-NULL */ + + /* In-out fields, set by client before nbd_receive_negotiate() and + * updated by server results during nbd_receive_negotiate() */ +@@ -279,10 +280,9 @@ struct NBDExportInfo { + }; + typedef struct NBDExportInfo NBDExportInfo; + +-int nbd_receive_negotiate(QIOChannel *ioc, const char *name, +- QCryptoTLSCreds *tlscreds, const char *hostname, +- QIOChannel **outioc, NBDExportInfo *info, +- Error **errp); ++int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, ++ const char *hostname, QIOChannel **outioc, ++ NBDExportInfo *info, Error **errp); + int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, + Error **errp); + int nbd_send_request(QIOChannel *ioc, NBDRequest *request); +diff --git a/nbd/client.c b/nbd/client.c +index fd4ba8d..8227e69 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -330,15 +330,14 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, + } + + +-/* Returns -1 if NBD_OPT_GO proves the export @wantname cannot be ++/* Returns -1 if NBD_OPT_GO proves the export @info->name cannot be + * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and + * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to +- * go (with @info populated). */ +-static int nbd_opt_go(QIOChannel *ioc, const char *wantname, +- NBDExportInfo *info, Error **errp) ++ * go (with the rest of @info populated). */ ++static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + { + NBDOptionReply reply; +- uint32_t len = strlen(wantname); ++ uint32_t len = strlen(info->name); + uint16_t type; + int error; + char *buf; +@@ -348,10 +347,10 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, + * flags still 0 is a witness of a broken server. */ + info->flags = 0; + +- trace_nbd_opt_go_start(wantname); ++ trace_nbd_opt_go_start(info->name); + buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1); + stl_be_p(buf, len); +- memcpy(buf + 4, wantname, len); ++ memcpy(buf + 4, info->name, len); + /* At most one request, everything else up to server */ + stw_be_p(buf + 4 + len, info->request_sizes); + if (info->request_sizes) { +@@ -753,10 +752,9 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + return 0; + } + +-int nbd_receive_negotiate(QIOChannel *ioc, const char *name, +- QCryptoTLSCreds *tlscreds, const char *hostname, +- QIOChannel **outioc, NBDExportInfo *info, +- Error **errp) ++int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, ++ const char *hostname, QIOChannel **outioc, ++ NBDExportInfo *info, Error **errp) + { + uint64_t magic; + int rc; +@@ -766,6 +764,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + + trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : ""); + ++ assert(info->name); ++ trace_nbd_receive_negotiate_name(info->name); + info->structured_reply = false; + info->base_allocation = false; + rc = -EINVAL; +@@ -834,10 +834,6 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + goto fail; + } + } +- if (!name) { +- trace_nbd_receive_negotiate_default_name(); +- name = ""; +- } + if (fixedNewStyle) { + int result; + +@@ -853,7 +849,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + + if (info->structured_reply && base_allocation) { + result = nbd_negotiate_simple_meta_context( +- ioc, name, info->x_dirty_bitmap ?: "base:allocation", ++ ioc, info->name, ++ info->x_dirty_bitmap ?: "base:allocation", + &info->meta_base_allocation_id, errp); + if (result < 0) { + goto fail; +@@ -866,7 +863,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + * TLS). If it is not available, fall back to + * NBD_OPT_LIST for nicer error messages about a missing + * export, then use NBD_OPT_EXPORT_NAME. */ +- result = nbd_opt_go(ioc, name, info, errp); ++ result = nbd_opt_go(ioc, info, errp); + if (result < 0) { + goto fail; + } +@@ -879,12 +876,12 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + * query gives us better error reporting if the + * export name is not available. + */ +- if (nbd_receive_query_exports(ioc, name, errp) < 0) { ++ if (nbd_receive_query_exports(ioc, info->name, errp) < 0) { + goto fail; + } + } + /* write the export name request */ +- if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, name, ++ if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name, + errp) < 0) { + goto fail; + } +@@ -904,8 +901,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + } else if (magic == NBD_CLIENT_MAGIC) { + uint32_t oldflags; + +- if (name) { +- error_setg(errp, "Server does not support export names"); ++ if (*info->name) { ++ error_setg(errp, "Server does not support non-empty export names"); + goto fail; + } + if (tlscreds) { +diff --git a/nbd/trace-events b/nbd/trace-events +index d1e1ca6..c3966d2 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -17,7 +17,7 @@ nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of contex + nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" + nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 + nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32 +-nbd_receive_negotiate_default_name(void) "Using default NBD export name \"\"" ++nbd_receive_negotiate_name(const char *name) "Requesting NBD export name '%s'" + nbd_receive_negotiate_size_flags(uint64_t size, uint16_t flags) "Size is %" PRIu64 ", export flags 0x%" PRIx16 + nbd_init_set_socket(void) "Setting NBD socket" + nbd_init_set_block_size(unsigned long block_size) "Setting block size to %lu" +diff --git a/qemu-nbd.c b/qemu-nbd.c +index efca0e4..3c53870 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -264,7 +264,7 @@ static void *show_parts(void *arg) + static void *nbd_client_thread(void *arg) + { + char *device = arg; +- NBDExportInfo info = { .request_sizes = false, }; ++ NBDExportInfo info = { .request_sizes = false, .name = g_strdup("") }; + QIOChannelSocket *sioc; + int fd; + int ret; +@@ -279,7 +279,7 @@ static void *nbd_client_thread(void *arg) + goto out; + } + +- ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, ++ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), + NULL, NULL, NULL, &info, &local_error); + if (ret < 0) { + if (local_error) { +@@ -318,6 +318,7 @@ static void *nbd_client_thread(void *arg) + } + close(fd); + object_unref(OBJECT(sioc)); ++ g_free(info.name); + kill(getpid(), SIGTERM); + return (void *) EXIT_SUCCESS; + +@@ -326,6 +327,7 @@ out_fd: + out_socket: + object_unref(OBJECT(sioc)); + out: ++ g_free(info.name); + kill(getpid(), SIGTERM); + return (void *) EXIT_FAILURE; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Pull-out-oldstyle-size-determination.patch b/SOURCES/kvm-nbd-client-Pull-out-oldstyle-size-determination.patch new file mode 100644 index 0000000..b59ae4d --- /dev/null +++ b/SOURCES/kvm-nbd-client-Pull-out-oldstyle-size-determination.patch @@ -0,0 +1,116 @@ +From 4b3d650918d54c4034e0162421410c1a076a057b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:49 +0100 +Subject: [PATCH 111/163] nbd/client: Pull out oldstyle size determination + +RH-Author: John Snow +Message-id: <20190327172308.31077-37-jsnow@redhat.com> +Patchwork-id: 85197 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 36/55] nbd/client: Pull out oldstyle size determination +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Another refactoring creating nbd_negotiate_finish_oldstyle() +for further reuse during 'qemu-nbd --list'. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-16-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit b3c9d33bc4e7c2ab2828b16ebc96f0414b0f1acf) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 49 ++++++++++++++++++++++++++++++++----------------- + 1 file changed, 32 insertions(+), 17 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 77cc123..6829c68 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -814,7 +814,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + * Start the handshake to the server. After a positive return, the server + * is ready to accept additional NBD_OPT requests. + * Returns: negative errno: failure talking to server +- * 0: server is oldstyle, client must still parse export size ++ * 0: server is oldstyle, must call nbd_negotiate_finish_oldstyle + * 1: server is newstyle, but can only accept EXPORT_NAME + * 2: server is newstyle, but lacks structured replies + * 3: server is newstyle and set up for structured replies +@@ -921,6 +921,36 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + } + + /* ++ * nbd_negotiate_finish_oldstyle: ++ * Populate @info with the size and export flags from an oldstyle server, ++ * but does not consume 124 bytes of reserved zero padding. ++ * Returns 0 on success, -1 with @errp set on failure ++ */ ++static int nbd_negotiate_finish_oldstyle(QIOChannel *ioc, NBDExportInfo *info, ++ Error **errp) ++{ ++ uint32_t oldflags; ++ ++ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { ++ error_prepend(errp, "Failed to read export length: "); ++ return -EINVAL; ++ } ++ info->size = be64_to_cpu(info->size); ++ ++ if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { ++ error_prepend(errp, "Failed to read export flags: "); ++ return -EINVAL; ++ } ++ oldflags = be32_to_cpu(oldflags); ++ if (oldflags & ~0xffff) { ++ error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); ++ return -EINVAL; ++ } ++ info->flags = oldflags; ++ return 0; ++} ++ ++/* + * nbd_receive_negotiate: + * Connect to server, complete negotiation, and move into transmission phase. + * Returns: negative errno: failure talking to server +@@ -933,7 +963,6 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + int result; + bool zeroes; + bool base_allocation = info->base_allocation; +- uint32_t oldflags; + + assert(info->name); + trace_nbd_receive_negotiate_name(info->name); +@@ -1006,23 +1035,9 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + error_setg(errp, "Server does not support non-empty export names"); + return -EINVAL; + } +- +- if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { +- error_prepend(errp, "Failed to read export length: "); +- return -EINVAL; +- } +- info->size = be64_to_cpu(info->size); +- +- if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { +- error_prepend(errp, "Failed to read export flags: "); +- return -EINVAL; +- } +- oldflags = be32_to_cpu(oldflags); +- if (oldflags & ~0xffff) { +- error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); ++ if (nbd_negotiate_finish_oldstyle(ioc, info, errp) < 0) { + return -EINVAL; + } +- info->flags = oldflags; + break; + default: + return result; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Refactor-nbd_opt_go-to-support-NBD_OPT_IN.patch b/SOURCES/kvm-nbd-client-Refactor-nbd_opt_go-to-support-NBD_OPT_IN.patch new file mode 100644 index 0000000..1799d93 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Refactor-nbd_opt_go-to-support-NBD_OPT_IN.patch @@ -0,0 +1,154 @@ +From 265ca77d8f1c82a680789bdb26fc7992077de567 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:50 +0100 +Subject: [PATCH 112/163] nbd/client: Refactor nbd_opt_go() to support + NBD_OPT_INFO + +RH-Author: John Snow +Message-id: <20190327172308.31077-38-jsnow@redhat.com> +Patchwork-id: 85198 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 37/55] nbd/client: Refactor nbd_opt_go() to support NBD_OPT_INFO +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Rename the function to nbd_opt_info_or_go() with an added parameter +and slight changes to comments and trace messages, in order to +reuse the function for NBD_OPT_INFO. + +Signed-off-by: Eric Blake +Message-Id: <20190117193658.16413-17-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 138796d0f545ad4b6c74ad2cbe5f6e08c454a0b9) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 36 ++++++++++++++++++++++-------------- + nbd/trace-events | 8 ++++---- + 2 files changed, 26 insertions(+), 18 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 6829c68..fa1657a 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -330,11 +330,16 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, + } + + +-/* Returns -1 if NBD_OPT_GO proves the export @info->name cannot be +- * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and ++/* ++ * nbd_opt_info_or_go: ++ * Send option for NBD_OPT_INFO or NBD_OPT_GO and parse the reply. ++ * Returns -1 if the option proves the export @info->name cannot be ++ * used, 0 if the option is unsupported (fall back to NBD_OPT_LIST and + * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to +- * go (with the rest of @info populated). */ +-static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) ++ * go (with the rest of @info populated). ++ */ ++static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, ++ NBDExportInfo *info, Error **errp) + { + NBDOptionReply reply; + uint32_t len = strlen(info->name); +@@ -347,7 +352,8 @@ static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + * flags still 0 is a witness of a broken server. */ + info->flags = 0; + +- trace_nbd_opt_go_start(info->name); ++ assert(opt == NBD_OPT_GO || opt == NBD_OPT_INFO); ++ trace_nbd_opt_info_go_start(nbd_opt_lookup(opt), info->name); + buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1); + stl_be_p(buf, len); + memcpy(buf + 4, info->name, len); +@@ -356,7 +362,7 @@ static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + if (info->request_sizes) { + stw_be_p(buf + 4 + len + 2, NBD_INFO_BLOCK_SIZE); + } +- error = nbd_send_option_request(ioc, NBD_OPT_GO, ++ error = nbd_send_option_request(ioc, opt, + 4 + len + 2 + 2 * info->request_sizes, + buf, errp); + g_free(buf); +@@ -365,7 +371,7 @@ static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + } + + while (1) { +- if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) { ++ if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { + return -1; + } + error = nbd_handle_reply_err(ioc, &reply, errp); +@@ -375,8 +381,10 @@ static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + len = reply.length; + + if (reply.type == NBD_REP_ACK) { +- /* Server is done sending info and moved into transmission +- phase, but make sure it sent flags */ ++ /* ++ * Server is done sending info, and moved into transmission ++ * phase for NBD_OPT_GO, but make sure it sent flags ++ */ + if (len) { + error_setg(errp, "server sent invalid NBD_REP_ACK"); + return -1; +@@ -385,7 +393,7 @@ static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + error_setg(errp, "broken server omitted NBD_INFO_EXPORT"); + return -1; + } +- trace_nbd_opt_go_success(); ++ trace_nbd_opt_info_go_success(nbd_opt_lookup(opt)); + return 1; + } + if (reply.type != NBD_REP_INFO) { +@@ -479,12 +487,12 @@ static int nbd_opt_go(QIOChannel *ioc, NBDExportInfo *info, Error **errp) + nbd_send_opt_abort(ioc); + return -1; + } +- trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block, +- info->max_block); ++ trace_nbd_opt_info_block_size(info->min_block, info->opt_block, ++ info->max_block); + break; + + default: +- trace_nbd_opt_go_info_unknown(type, nbd_info_lookup(type)); ++ trace_nbd_opt_info_unknown(type, nbd_info_lookup(type)); + if (nbd_drop(ioc, len, errp) < 0) { + error_prepend(errp, "Failed to read info payload: "); + nbd_send_opt_abort(ioc); +@@ -993,7 +1001,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + * TLS). If it is not available, fall back to + * NBD_OPT_LIST for nicer error messages about a missing + * export, then use NBD_OPT_EXPORT_NAME. */ +- result = nbd_opt_go(ioc, info, errp); ++ result = nbd_opt_info_or_go(ioc, NBD_OPT_GO, info, errp); + if (result < 0) { + return -EINVAL; + } +diff --git a/nbd/trace-events b/nbd/trace-events +index 663d116..7f10ebd 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -4,10 +4,10 @@ nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, co + nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s" + nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback" + nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'" +-nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'" +-nbd_opt_go_success(void) "Export is good to go" +-nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)" +-nbd_opt_go_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32 ++nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'" ++nbd_opt_info_go_success(const char *opt) "Export is ready after %s request" ++nbd_opt_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)" ++nbd_opt_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32 + nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'" + nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'" + nbd_receive_starttls_new_client(void) "Setting up TLS" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Refactor-nbd_receive_list.patch b/SOURCES/kvm-nbd-client-Refactor-nbd_receive_list.patch new file mode 100644 index 0000000..373b956 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Refactor-nbd_receive_list.patch @@ -0,0 +1,240 @@ +From ff100c505e2a1cdc0a405008513948caa935b6cb Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:42 +0100 +Subject: [PATCH 104/163] nbd/client: Refactor nbd_receive_list() + +RH-Author: John Snow +Message-id: <20190327172308.31077-30-jsnow@redhat.com> +Patchwork-id: 85210 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 29/55] nbd/client: Refactor nbd_receive_list() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Right now, nbd_receive_list() is only called by +nbd_receive_query_exports(), which in turn is only called if the +server lacks NBD_OPT_GO but has working option negotiation, and is +merely used as a quality-of-implementation trick since servers +can't give decent errors for NBD_OPT_EXPORT_NAME. However, servers +that lack NBD_OPT_GO are becoming increasingly rare (nbdkit was a +latecomer, in Aug 2018, but qemu has been such a server since commit +f37708f6 in July 2017 and released in 2.10), so it no longer makes +sense to micro-optimize that function for performance. + +Furthermore, when debugging a server's implementation, tracing the +full reply (both names and descriptions) is useful, not to mention +that upcoming patches adding 'qemu-nbd --list' will want to collect +that data. And when you consider that a server can send an export +name up to the NBD protocol length limit of 4k; but our current +NBD_MAX_NAME_SIZE is only 256, we can't trace all valid server +names without more storage, but 4k is large enough that the heap +is better than the stack for long names. + +Thus, I'm changing the division of labor, with nbd_receive_list() +now always malloc'ing a result on success (the malloc is bounded +by the fact that we reject servers with a reply length larger +than 32M), and moving the comparison to 'wantname' to the caller. + +There is a minor change in behavior where a server with 0 exports +(an immediate NBD_REP_ACK reply) is now no longer distinguished +from a server without LIST support (NBD_REP_ERR_UNSUP); this +information could be preserved with a complication to the calling +contract to provide a bit more information, but I didn't see the +point. After all, the worst that can happen if our guess at a +match is wrong is that the caller will get a cryptic disconnect +when NBD_OPT_EXPORT_NAME fails (which is no different from what +would happen if we had not tried LIST), while treating an empty +list as immediate failure would prevent connecting to really old +servers that really did lack LIST. Besides, NBD servers with 0 +exports are rare (qemu can do it when using QMP nbd-server-start +without nbd-server-add - but qemu understands NBD_OPT_GO and +thus won't tickle this change in behavior). + +Fix the spelling of foundExport to match coding standards while +in the area. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-9-eblake@redhat.com> +(cherry picked from commit 091d0bf3c94737fc451a9b3f4eddf3a4d74c90b8) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 91 ++++++++++++++++++++++++++++++++++++-------------------- + nbd/trace-events | 1 + + 2 files changed, 59 insertions(+), 33 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index f625c20..fd4ba8d 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -234,18 +234,24 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, + return result; + } + +-/* Process another portion of the NBD_OPT_LIST reply. Set *@match if +- * the current reply matches @want or if the server does not support +- * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration +- * is complete, positive if more replies are expected, or negative +- * with @errp set if an unrecoverable error occurred. */ +-static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, ++/* nbd_receive_list: ++ * Process another portion of the NBD_OPT_LIST reply, populating any ++ * name received into *@name. If @description is non-NULL, and the ++ * server provided a description, that is also populated. The caller ++ * must eventually call g_free() on success. ++ * Returns 1 if name and description were set and iteration must continue, ++ * 0 if iteration is complete (including if OPT_LIST unsupported), ++ * -1 with @errp set if an unrecoverable error occurred. ++ */ ++static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, + Error **errp) + { ++ int ret = -1; + NBDOptionReply reply; + uint32_t len; + uint32_t namelen; +- char name[NBD_MAX_NAME_SIZE + 1]; ++ char *local_name = NULL; ++ char *local_desc = NULL; + int error; + + if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) { +@@ -253,9 +259,6 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + } + error = nbd_handle_reply_err(ioc, &reply, errp); + if (error <= 0) { +- /* The server did not support NBD_OPT_LIST, so set *match on +- * the assumption that any name will be accepted. */ +- *match = true; + return error; + } + len = reply.length; +@@ -292,33 +295,38 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + nbd_send_opt_abort(ioc); + return -1; + } +- if (namelen != strlen(want)) { +- if (nbd_drop(ioc, len, errp) < 0) { +- error_prepend(errp, +- "failed to skip export name with wrong length: "); +- nbd_send_opt_abort(ioc); +- return -1; +- } +- return 1; +- } + +- assert(namelen < sizeof(name)); +- if (nbd_read(ioc, name, namelen, errp) < 0) { ++ local_name = g_malloc(namelen + 1); ++ if (nbd_read(ioc, local_name, namelen, errp) < 0) { + error_prepend(errp, "failed to read export name: "); + nbd_send_opt_abort(ioc); +- return -1; ++ goto out; + } +- name[namelen] = '\0'; ++ local_name[namelen] = '\0'; + len -= namelen; +- if (nbd_drop(ioc, len, errp) < 0) { +- error_prepend(errp, "failed to read export description: "); +- nbd_send_opt_abort(ioc); +- return -1; ++ if (len) { ++ local_desc = g_malloc(len + 1); ++ if (nbd_read(ioc, local_desc, len, errp) < 0) { ++ error_prepend(errp, "failed to read export description: "); ++ nbd_send_opt_abort(ioc); ++ goto out; ++ } ++ local_desc[len] = '\0'; + } +- if (!strcmp(name, want)) { +- *match = true; ++ ++ trace_nbd_receive_list(local_name, local_desc ?: ""); ++ *name = local_name; ++ local_name = NULL; ++ if (description) { ++ *description = local_desc; ++ local_desc = NULL; + } +- return 1; ++ ret = 1; ++ ++ out: ++ g_free(local_name); ++ g_free(local_desc); ++ return ret; + } + + +@@ -493,7 +501,8 @@ static int nbd_receive_query_exports(QIOChannel *ioc, + const char *wantname, + Error **errp) + { +- bool foundExport = false; ++ bool list_empty = true; ++ bool found_export = false; + + trace_nbd_receive_query_exports_start(wantname); + if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) { +@@ -501,14 +510,25 @@ static int nbd_receive_query_exports(QIOChannel *ioc, + } + + while (1) { +- int ret = nbd_receive_list(ioc, wantname, &foundExport, errp); ++ char *name; ++ int ret = nbd_receive_list(ioc, &name, NULL, errp); + + if (ret < 0) { + /* Server gave unexpected reply */ + return -1; + } else if (ret == 0) { + /* Done iterating. */ +- if (!foundExport) { ++ if (list_empty) { ++ /* ++ * We don't have enough context to tell a server that ++ * sent an empty list apart from a server that does ++ * not support the list command; but as this function ++ * is just used to trigger a nicer error message ++ * before trying NBD_OPT_EXPORT_NAME, assume the ++ * export is available. ++ */ ++ return 0; ++ } else if (!found_export) { + error_setg(errp, "No export with name '%s' available", + wantname); + nbd_send_opt_abort(ioc); +@@ -517,6 +537,11 @@ static int nbd_receive_query_exports(QIOChannel *ioc, + trace_nbd_receive_query_exports_success(wantname); + return 0; + } ++ list_empty = false; ++ if (!strcmp(name, wantname)) { ++ found_export = true; ++ } ++ g_free(name); + } + } + +diff --git a/nbd/trace-events b/nbd/trace-events +index 5492042..d1e1ca6 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -3,6 +3,7 @@ nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending o + nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32 + nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s" + nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback" ++nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'" + nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'" + nbd_opt_go_success(void) "Export is good to go" + nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Refactor-return-of-nbd_receive_negotiate.patch b/SOURCES/kvm-nbd-client-Refactor-return-of-nbd_receive_negotiate.patch new file mode 100644 index 0000000..f93ad79 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Refactor-return-of-nbd_receive_negotiate.patch @@ -0,0 +1,222 @@ +From c1211f220981f1846895caead20e5aa5ae58ab5e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:47 +0100 +Subject: [PATCH 109/163] nbd/client: Refactor return of + nbd_receive_negotiate() + +RH-Author: John Snow +Message-id: <20190327172308.31077-35-jsnow@redhat.com> +Patchwork-id: 85196 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 34/55] nbd/client: Refactor return of nbd_receive_negotiate() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The function could only ever return 0 or -EINVAL; make this +clearer by dropping a useless 'fail:' label. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-14-eblake@redhat.com> +(cherry picked from commit 2b8d0954514192133b0119942edfd7a0c146900d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 51 +++++++++++++++++++++++---------------------------- + 1 file changed, 23 insertions(+), 28 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index c7bb708..9028fd0 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -814,7 +814,6 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + NBDExportInfo *info, Error **errp) + { + uint64_t magic; +- int rc; + bool zeroes = true; + bool structured_reply = info->structured_reply; + bool base_allocation = info->base_allocation; +@@ -825,31 +824,30 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + trace_nbd_receive_negotiate_name(info->name); + info->structured_reply = false; + info->base_allocation = false; +- rc = -EINVAL; + + if (outioc) { + *outioc = NULL; + } + if (tlscreds && !outioc) { + error_setg(errp, "Output I/O channel required for TLS"); +- goto fail; ++ return -EINVAL; + } + + if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { + error_prepend(errp, "Failed to read initial magic: "); +- goto fail; ++ return -EINVAL; + } + magic = be64_to_cpu(magic); + trace_nbd_receive_negotiate_magic(magic); + + if (magic != NBD_INIT_MAGIC) { + error_setg(errp, "Bad initial magic received: 0x%" PRIx64, magic); +- goto fail; ++ return -EINVAL; + } + + if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { + error_prepend(errp, "Failed to read server magic: "); +- goto fail; ++ return -EINVAL; + } + magic = be64_to_cpu(magic); + trace_nbd_receive_negotiate_magic(magic); +@@ -861,7 +859,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + + if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) { + error_prepend(errp, "Failed to read server flags: "); +- goto fail; ++ return -EINVAL; + } + globalflags = be16_to_cpu(globalflags); + trace_nbd_receive_negotiate_server_flags(globalflags); +@@ -877,18 +875,18 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + clientflags = cpu_to_be32(clientflags); + if (nbd_write(ioc, &clientflags, sizeof(clientflags), errp) < 0) { + error_prepend(errp, "Failed to send clientflags field: "); +- goto fail; ++ return -EINVAL; + } + if (tlscreds) { + if (fixedNewStyle) { + *outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp); + if (!*outioc) { +- goto fail; ++ return -EINVAL; + } + ioc = *outioc; + } else { + error_setg(errp, "Server does not support STARTTLS"); +- goto fail; ++ return -EINVAL; + } + } + if (fixedNewStyle) { +@@ -899,7 +897,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + NBD_OPT_STRUCTURED_REPLY, + errp); + if (result < 0) { +- goto fail; ++ return -EINVAL; + } + info->structured_reply = result == 1; + } +@@ -907,7 +905,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + if (info->structured_reply && base_allocation) { + result = nbd_negotiate_simple_meta_context(ioc, info, errp); + if (result < 0) { +- goto fail; ++ return -EINVAL; + } + info->base_allocation = result == 1; + } +@@ -919,7 +917,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + * export, then use NBD_OPT_EXPORT_NAME. */ + result = nbd_opt_go(ioc, info, errp); + if (result < 0) { +- goto fail; ++ return -EINVAL; + } + if (result > 0) { + return 0; +@@ -931,25 +929,25 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + * export name is not available. + */ + if (nbd_receive_query_exports(ioc, info->name, errp) < 0) { +- goto fail; ++ return -EINVAL; + } + } + /* write the export name request */ + if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name, + errp) < 0) { +- goto fail; ++ return -EINVAL; + } + + /* Read the response */ + if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { + error_prepend(errp, "Failed to read export length: "); +- goto fail; ++ return -EINVAL; + } + info->size = be64_to_cpu(info->size); + + if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { + error_prepend(errp, "Failed to read export flags: "); +- goto fail; ++ return -EINVAL; + } + info->flags = be16_to_cpu(info->flags); + } else if (magic == NBD_CLIENT_MAGIC) { +@@ -957,43 +955,40 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + + if (*info->name) { + error_setg(errp, "Server does not support non-empty export names"); +- goto fail; ++ return -EINVAL; + } + if (tlscreds) { + error_setg(errp, "Server does not support STARTTLS"); +- goto fail; ++ return -EINVAL; + } + + if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { + error_prepend(errp, "Failed to read export length: "); +- goto fail; ++ return -EINVAL; + } + info->size = be64_to_cpu(info->size); + + if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { + error_prepend(errp, "Failed to read export flags: "); +- goto fail; ++ return -EINVAL; + } + oldflags = be32_to_cpu(oldflags); + if (oldflags & ~0xffff) { + error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); +- goto fail; ++ return -EINVAL; + } + info->flags = oldflags; + } else { + error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); +- goto fail; ++ return -EINVAL; + } + + trace_nbd_receive_negotiate_size_flags(info->size, info->flags); + if (zeroes && nbd_drop(ioc, 124, errp) < 0) { + error_prepend(errp, "Failed to read reserved block: "); +- goto fail; ++ return -EINVAL; + } +- rc = 0; +- +-fail: +- return rc; ++ return 0; + } + + #ifdef __linux__ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Reject-inaccessible-tail-of-inconsistent-.patch b/SOURCES/kvm-nbd-client-Reject-inaccessible-tail-of-inconsistent-.patch new file mode 100644 index 0000000..e22f066 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Reject-inaccessible-tail-of-inconsistent-.patch @@ -0,0 +1,64 @@ +From c03c9a78664b0f3e27bba21167e621d5068feb0b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:20 +0200 +Subject: [PATCH 10/53] nbd/client: Reject inaccessible tail of inconsistent + server + +RH-Author: John Snow +Message-id: <20190506175629.11079-11-jsnow@redhat.com> +Patchwork-id: 87183 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/19] nbd/client: Reject inaccessible tail of inconsistent server +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +The NBD spec suggests that a server should never advertise a size +inconsistent with its minimum block alignment, as that tail is +effectively inaccessible to a compliant client obeying those block +constraints. Since we have a habit of rounding up rather than +truncating, to avoid losing the last few bytes of user input, and we +cannot access the tail when the server advertises bogus block sizing, +abort the connection to alert the server to fix their bug. And +rejecting such servers matches what we already did for a min_block +that was not a power of 2 or which was larger than max_block. + +Does not impact either qemu (which always sends properly aligned +sizes) or nbdkit (which does not send minimum block requirements yet); +so this is mostly aimed at new NBD server implementations, and ensures +that the rest of our code can assume the size is aligned. + +Signed-off-by: Eric Blake +Message-Id: <20190330155704.24191-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 3add3ab78247fd347fd6f377a4b951022ac35d35) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/nbd/client.c b/nbd/client.c +index 10a52ad..4309569 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -426,6 +426,14 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + nbd_send_opt_abort(ioc); + return -1; + } ++ if (info->min_block && ++ !QEMU_IS_ALIGNED(info->size, info->min_block)) { ++ error_setg(errp, "export size %" PRIu64 "is not multiple of " ++ "minimum block size %" PRIu32, info->size, ++ info->min_block); ++ nbd_send_opt_abort(ioc); ++ return -1; ++ } + trace_nbd_receive_negotiate_size_flags(info->size, info->flags); + break; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Relax-handling-of-large-NBD_CMD_BLOCK_STA.patch b/SOURCES/kvm-nbd-client-Relax-handling-of-large-NBD_CMD_BLOCK_STA.patch new file mode 100644 index 0000000..34245a2 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Relax-handling-of-large-NBD_CMD_BLOCK_STA.patch @@ -0,0 +1,69 @@ +From 9e909e2a2640b08e7bf10232321a1b1dc81df69c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:16 +0100 +Subject: [PATCH 049/163] nbd/client: Relax handling of large + NBD_CMD_BLOCK_STATUS reply + +RH-Author: John Snow +Message-id: <20190322032241.8111-4-jsnow@redhat.com> +Patchwork-id: 85090 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/28] nbd/client: Relax handling of large NBD_CMD_BLOCK_STATUS reply +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The NBD spec is proposing a relaxation of NBD_CMD_BLOCK_STATUS +where a server may have the final extent per context give a +length beyond the original request, if it can easily prove that +subsequent bytes have the same status, on the grounds that a +client can take advantage of this information for fewer block +status requests. Since qemu 2.12 as a client always sends +NBD_CMD_FLAG_REQ_ONE, and rejects a server that sends extra +length, the upstream NBD spec will probably limit this behavior +to clients that don't request REQ_ONE semantics; but it doesn't +hurt to relax qemu to always be permissive of this server +behavior, even if it continues to use REQ_ONE. + +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +Message-Id: <20180503222626.1303410-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit acfd8f7a5f92e703d2d046cbe3d510008a697194) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 80d3625..76e9ca3 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -259,14 +259,18 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, + + if (extent->length == 0 || + (client->info.min_block && !QEMU_IS_ALIGNED(extent->length, +- client->info.min_block)) || +- extent->length > orig_length) +- { ++ client->info.min_block))) { + error_setg(errp, "Protocol error: server sent status chunk with " + "invalid length"); + return -EINVAL; + } + ++ /* The server is allowed to send us extra information on the final ++ * extent; just clamp it to the length we requested. */ ++ if (extent->length > orig_length) { ++ extent->length = orig_length; ++ } ++ + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Report-offsets-in-bdrv_block_status.patch b/SOURCES/kvm-nbd-client-Report-offsets-in-bdrv_block_status.patch new file mode 100644 index 0000000..5bccb9e --- /dev/null +++ b/SOURCES/kvm-nbd-client-Report-offsets-in-bdrv_block_status.patch @@ -0,0 +1,166 @@ +From df5a366613d42ec2dc5dae33e10b6fdd5db09e0d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:19 +0200 +Subject: [PATCH 09/53] nbd/client: Report offsets in bdrv_block_status + +RH-Author: John Snow +Message-id: <20190506175629.11079-10-jsnow@redhat.com> +Patchwork-id: 87199 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/19] nbd/client: Report offsets in bdrv_block_status +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +It is desirable for 'qemu-img map' to have the same output for a file +whether it is served over file or nbd protocols. However, ever since +we implemented block status for NBD (2.12), the NBD protocol forgot to +inform the block layer that as the final layer in the chain, the +offset is valid; without an offset, the human-readable form of +qemu-img map gives up with the unhelpful: + +$ nbdkit -U - data data="1" size=512 --run 'qemu-img map $nbd' +Offset Length Mapped to File +qemu-img: File contains external, encrypted or compressed clusters. + +The --output=json form always works, because it is reporting the +lower-level bdrv_block_status results directly rather than trying to +filter out sparse ranges for human consumption - but now it also +shows the offset member. + +With this patch, the human output changes to: + +Offset Length Mapped to File +0 0x200 0 nbd+unix://?socket=/tmp/nbdkitOxeoLa/socket + +This change is observable to several iotests. + +Fixes: 78a33ab5 +Reported-by: Richard W.M. Jones +Signed-off-by: Eric Blake +Message-Id: <20190329042750.14704-4-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit a62a85ef5ccd764d03d72d6c3cd558f9755b3457) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 9 +++++++-- + tests/qemu-iotests/209.out | 4 ++-- + tests/qemu-iotests/223.out | 18 +++++++++--------- + tests/qemu-iotests/241.out | 6 +++--- + 4 files changed, 21 insertions(+), 16 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 09e20b2..9b5779f 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -959,7 +959,9 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + + if (!client->info.base_allocation) { + *pnum = bytes; +- return BDRV_BLOCK_DATA; ++ *map = offset; ++ *file = bs; ++ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; + } + + ret = nbd_co_send_request(bs, &request, NULL); +@@ -982,8 +984,11 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + + assert(extent.length); + *pnum = extent.length; ++ *map = offset; ++ *file = bs; + return (extent.flags & NBD_STATE_HOLE ? 0 : BDRV_BLOCK_DATA) | +- (extent.flags & NBD_STATE_ZERO ? BDRV_BLOCK_ZERO : 0); ++ (extent.flags & NBD_STATE_ZERO ? BDRV_BLOCK_ZERO : 0) | ++ BDRV_BLOCK_OFFSET_VALID; + } + + void nbd_client_detach_aio_context(BlockDriverState *bs) +diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out +index 0d29724..214e27b 100644 +--- a/tests/qemu-iotests/209.out ++++ b/tests/qemu-iotests/209.out +@@ -1,2 +1,2 @@ +-[{ "start": 0, "length": 524288, "depth": 0, "zero": false, "data": true}, +-{ "start": 524288, "length": 524288, "depth": 0, "zero": true, "data": false}] ++[{ "start": 0, "length": 524288, "depth": 0, "zero": false, "data": true, "offset": 0}, ++{ "start": 524288, "length": 524288, "depth": 0, "zero": true, "data": false, "offset": 524288}] +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index 0524ffb..a620f82 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -67,18 +67,18 @@ read 1048576/1048576 bytes at offset 1048576 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + read 2097152/2097152 bytes at offset 2097152 + 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true}, +-{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false}, +-{ "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true}] ++[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++{ "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] + [{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, +-{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true}, ++{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + + === Contrast to small granularity dirty-bitmap === + +-[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true}, ++[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, +-{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true}, ++{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + + === End qemu NBD server === +@@ -94,10 +94,10 @@ read 2097152/2097152 bytes at offset 2097152 + === Use qemu-nbd as server === + + [{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, +-{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true}, ++{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] +-[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true}, ++[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, +-{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true}, ++{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, + { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + *** done +diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out +index b76a623..f22eabb 100644 +--- a/tests/qemu-iotests/241.out ++++ b/tests/qemu-iotests/241.out +@@ -4,7 +4,7 @@ QA output created by 241 + + size: 1024 + min block: 512 +-[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] ++[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] + 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) + + === Exporting unaligned raw image, forced server sector alignment === +@@ -14,13 +14,13 @@ WARNING: Image format was not specified for '/home/eblake/qemu/tests/qemu-iotest + Specify the 'raw' format explicitly to remove the restrictions. + size: 1024 + min block: 512 +-[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] ++[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] + 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) + + === Exporting unaligned raw image, forced client sector alignment === + + size: 1024 + min block: 512 +-[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] ++[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] + 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Send-NBD_CMD_DISC-if-open-fails-after-con.patch b/SOURCES/kvm-nbd-client-Send-NBD_CMD_DISC-if-open-fails-after-con.patch new file mode 100644 index 0000000..e4ba4a9 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Send-NBD_CMD_DISC-if-open-fails-after-con.patch @@ -0,0 +1,81 @@ +From fbb8b7e5e064ea6a467119772097242311e65628 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:40 +0100 +Subject: [PATCH 073/163] nbd/client: Send NBD_CMD_DISC if open fails after + connect + +RH-Author: John Snow +Message-id: <20190322032241.8111-28-jsnow@redhat.com> +Patchwork-id: 85114 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 27/28] nbd/client: Send NBD_CMD_DISC if open fails after connect +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +If nbd_client_init() fails after we are already connected, +then the server will spam logs with: + +Disconnect client, due to: Unexpected end-of-file before all bytes were read + +unless we gracefully disconnect before closing the connection. + +Ways to trigger this: + +$ opts=driver=nbd,export=foo,server.type=inet,server.host=localhost,server.port=10809 +$ qemu-img map --output=json --image-opts $opts,read-only=off +$ qemu-img map --output=json --image-opts $opts,x-dirty-bitmap=nosuch: + +Signed-off-by: Eric Blake +Message-Id: <20181130023232.3079982-4-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit c688e6ca7b41a105241054853d250df64addbf8f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index e6e27da..fc5b7ed 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -995,12 +995,13 @@ int nbd_client_init(BlockDriverState *bs, + if (x_dirty_bitmap && !client->info.base_allocation) { + error_setg(errp, "requested x-dirty-bitmap %s not found", + x_dirty_bitmap); +- return -EINVAL; ++ ret = -EINVAL; ++ goto fail; + } + if (client->info.flags & NBD_FLAG_READ_ONLY) { + ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp); + if (ret < 0) { +- return ret; ++ goto fail; + } + } + if (client->info.flags & NBD_FLAG_SEND_FUA) { +@@ -1029,4 +1030,17 @@ int nbd_client_init(BlockDriverState *bs, + + logout("Established connection with NBD server\n"); + return 0; ++ ++ fail: ++ /* ++ * We have connected, but must fail for other reasons. The ++ * connection is still blocking; send NBD_CMD_DISC as a courtesy ++ * to the server. ++ */ ++ { ++ NBDRequest request = { .type = NBD_CMD_DISC }; ++ ++ nbd_send_request(client->ioc ?: QIO_CHANNEL(sioc), &request); ++ return ret; ++ } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Split-handshake-into-two-functions.patch b/SOURCES/kvm-nbd-client-Split-handshake-into-two-functions.patch new file mode 100644 index 0000000..438773b --- /dev/null +++ b/SOURCES/kvm-nbd-client-Split-handshake-into-two-functions.patch @@ -0,0 +1,263 @@ +From 17d3f9b474fe65d1b4fc128d18e3a7a52b32c62d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:48 +0100 +Subject: [PATCH 110/163] nbd/client: Split handshake into two functions + +RH-Author: John Snow +Message-id: <20190327172308.31077-36-jsnow@redhat.com> +Patchwork-id: 85213 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 35/55] nbd/client: Split handshake into two functions +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +An upcoming patch will add the ability for qemu-nbd to list +the services provided by an NBD server. Share the common +code of the TLS handshake by splitting the initial exchange +into a separate function, leaving only the export handling +in the original function. Functionally, there should be no +change in behavior in this patch, although some of the code +motion may be difficult to follow due to indentation changes +(view with 'git diff -w' for a smaller changeset). + +I considered an enum for the return code coordinating state +between the two functions, but in the end just settled with +ample comments. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-15-eblake@redhat.com> +(cherry picked from commit 10b89988d6b0f5f2aed794bed5b4e774858548f4) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 145 ++++++++++++++++++++++++++++++++++++------------------- + nbd/trace-events | 2 +- + 2 files changed, 96 insertions(+), 51 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 9028fd0..77cc123 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -809,22 +809,26 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + return received; + } + +-int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, +- const char *hostname, QIOChannel **outioc, +- NBDExportInfo *info, Error **errp) ++/* ++ * nbd_start_negotiate: ++ * Start the handshake to the server. After a positive return, the server ++ * is ready to accept additional NBD_OPT requests. ++ * Returns: negative errno: failure talking to server ++ * 0: server is oldstyle, client must still parse export size ++ * 1: server is newstyle, but can only accept EXPORT_NAME ++ * 2: server is newstyle, but lacks structured replies ++ * 3: server is newstyle and set up for structured replies ++ */ ++static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, ++ const char *hostname, QIOChannel **outioc, ++ bool structured_reply, bool *zeroes, ++ Error **errp) + { + uint64_t magic; +- bool zeroes = true; +- bool structured_reply = info->structured_reply; +- bool base_allocation = info->base_allocation; + +- trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : ""); +- +- assert(info->name); +- trace_nbd_receive_negotiate_name(info->name); +- info->structured_reply = false; +- info->base_allocation = false; ++ trace_nbd_start_negotiate(tlscreds, hostname ? hostname : ""); + ++ *zeroes = true; + if (outioc) { + *outioc = NULL; + } +@@ -868,7 +872,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE; + } + if (globalflags & NBD_FLAG_NO_ZEROES) { +- zeroes = false; ++ *zeroes = false; + clientflags |= NBD_FLAG_C_NO_ZEROES; + } + /* client requested flags */ +@@ -890,7 +894,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + } + } + if (fixedNewStyle) { +- int result; ++ int result = 0; + + if (structured_reply) { + result = nbd_request_simple_option(ioc, +@@ -899,39 +903,85 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + if (result < 0) { + return -EINVAL; + } +- info->structured_reply = result == 1; + } ++ return 2 + result; ++ } else { ++ return 1; ++ } ++ } else if (magic == NBD_CLIENT_MAGIC) { ++ if (tlscreds) { ++ error_setg(errp, "Server does not support STARTTLS"); ++ return -EINVAL; ++ } ++ return 0; ++ } else { ++ error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); ++ return -EINVAL; ++ } ++} + +- if (info->structured_reply && base_allocation) { +- result = nbd_negotiate_simple_meta_context(ioc, info, errp); +- if (result < 0) { +- return -EINVAL; +- } +- info->base_allocation = result == 1; +- } ++/* ++ * nbd_receive_negotiate: ++ * Connect to server, complete negotiation, and move into transmission phase. ++ * Returns: negative errno: failure talking to server ++ * 0: server is connected ++ */ ++int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, ++ const char *hostname, QIOChannel **outioc, ++ NBDExportInfo *info, Error **errp) ++{ ++ int result; ++ bool zeroes; ++ bool base_allocation = info->base_allocation; ++ uint32_t oldflags; + +- /* Try NBD_OPT_GO first - if it works, we are done (it +- * also gives us a good message if the server requires +- * TLS). If it is not available, fall back to +- * NBD_OPT_LIST for nicer error messages about a missing +- * export, then use NBD_OPT_EXPORT_NAME. */ +- result = nbd_opt_go(ioc, info, errp); ++ assert(info->name); ++ trace_nbd_receive_negotiate_name(info->name); ++ ++ result = nbd_start_negotiate(ioc, tlscreds, hostname, outioc, ++ info->structured_reply, &zeroes, errp); ++ ++ info->structured_reply = false; ++ info->base_allocation = false; ++ if (tlscreds && *outioc) { ++ ioc = *outioc; ++ } ++ ++ switch (result) { ++ case 3: /* newstyle, with structured replies */ ++ info->structured_reply = true; ++ if (base_allocation) { ++ result = nbd_negotiate_simple_meta_context(ioc, info, errp); + if (result < 0) { + return -EINVAL; + } +- if (result > 0) { +- return 0; +- } +- /* Check our desired export is present in the +- * server export list. Since NBD_OPT_EXPORT_NAME +- * cannot return an error message, running this +- * query gives us better error reporting if the +- * export name is not available. +- */ +- if (nbd_receive_query_exports(ioc, info->name, errp) < 0) { +- return -EINVAL; +- } ++ info->base_allocation = result == 1; ++ } ++ /* fall through */ ++ case 2: /* newstyle, try OPT_GO */ ++ /* Try NBD_OPT_GO first - if it works, we are done (it ++ * also gives us a good message if the server requires ++ * TLS). If it is not available, fall back to ++ * NBD_OPT_LIST for nicer error messages about a missing ++ * export, then use NBD_OPT_EXPORT_NAME. */ ++ result = nbd_opt_go(ioc, info, errp); ++ if (result < 0) { ++ return -EINVAL; + } ++ if (result > 0) { ++ return 0; ++ } ++ /* Check our desired export is present in the ++ * server export list. Since NBD_OPT_EXPORT_NAME ++ * cannot return an error message, running this ++ * query gives us better error reporting if the ++ * export name is not available. ++ */ ++ if (nbd_receive_query_exports(ioc, info->name, errp) < 0) { ++ return -EINVAL; ++ } ++ /* fall through */ ++ case 1: /* newstyle, but limited to EXPORT_NAME */ + /* write the export name request */ + if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name, + errp) < 0) { +@@ -950,17 +1000,12 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + return -EINVAL; + } + info->flags = be16_to_cpu(info->flags); +- } else if (magic == NBD_CLIENT_MAGIC) { +- uint32_t oldflags; +- ++ break; ++ case 0: /* oldstyle, parse length and flags */ + if (*info->name) { + error_setg(errp, "Server does not support non-empty export names"); + return -EINVAL; + } +- if (tlscreds) { +- error_setg(errp, "Server does not support STARTTLS"); +- return -EINVAL; +- } + + if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { + error_prepend(errp, "Failed to read export length: "); +@@ -978,9 +1023,9 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + return -EINVAL; + } + info->flags = oldflags; +- } else { +- error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); +- return -EINVAL; ++ break; ++ default: ++ return result; + } + + trace_nbd_receive_negotiate_size_flags(info->size, info->flags); +diff --git a/nbd/trace-events b/nbd/trace-events +index b4802c1..663d116 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -14,7 +14,7 @@ nbd_receive_starttls_new_client(void) "Setting up TLS" + nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake" + nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s" + nbd_opt_meta_reply(const char *optname, const char *context, uint32_t id) "Received %s mapping of %s to id %" PRIu32 +-nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" ++nbd_start_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" + nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 + nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32 + nbd_receive_negotiate_name(const char *name) "Requesting NBD export name '%s'" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Split-out-nbd_receive_one_meta_context.patch b/SOURCES/kvm-nbd-client-Split-out-nbd_receive_one_meta_context.patch new file mode 100644 index 0000000..47716aa --- /dev/null +++ b/SOURCES/kvm-nbd-client-Split-out-nbd_receive_one_meta_context.patch @@ -0,0 +1,240 @@ +From eead0dbc83d4f8e8da21017976a353c513c3b2b3 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:46 +0100 +Subject: [PATCH 108/163] nbd/client: Split out nbd_receive_one_meta_context() + +RH-Author: John Snow +Message-id: <20190327172308.31077-34-jsnow@redhat.com> +Patchwork-id: 85193 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 33/55] nbd/client: Split out nbd_receive_one_meta_context() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Extract portions of nbd_negotiate_simple_meta_context() to +a new function nbd_receive_one_meta_context() that copies the +pattern of nbd_receive_list() for performing the argument +validation of one reply. The error message when the server +replies with more than one context changes slightly, but +that shouldn't happen in the common case. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-13-eblake@redhat.com> +(cherry picked from commit 0182c1aed9e6a9314023c7264c5c264da2f4a4ce) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 147 ++++++++++++++++++++++++++++++++++--------------------- + nbd/trace-events | 2 +- + 2 files changed, 91 insertions(+), 58 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 96da68e..c7bb708 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -669,7 +669,86 @@ static int nbd_send_meta_query(QIOChannel *ioc, uint32_t opt, + return ret; + } + +-/* nbd_negotiate_simple_meta_context: ++/* ++ * nbd_receive_one_meta_context: ++ * Called in a loop to receive and trace one set/list meta context reply. ++ * Pass non-NULL @name or @id to collect results back to the caller, which ++ * must eventually call g_free(). ++ * return 1 if name is set and iteration must continue, ++ * 0 if iteration is complete (including if option is unsupported), ++ * -1 with errp set for any error ++ */ ++static int nbd_receive_one_meta_context(QIOChannel *ioc, ++ uint32_t opt, ++ char **name, ++ uint32_t *id, ++ Error **errp) ++{ ++ int ret; ++ NBDOptionReply reply; ++ char *local_name = NULL; ++ uint32_t local_id; ++ ++ if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { ++ return -1; ++ } ++ ++ ret = nbd_handle_reply_err(ioc, &reply, errp); ++ if (ret <= 0) { ++ return ret; ++ } ++ ++ if (reply.type == NBD_REP_ACK) { ++ if (reply.length != 0) { ++ error_setg(errp, "Unexpected length to ACK response"); ++ nbd_send_opt_abort(ioc); ++ return -1; ++ } ++ return 0; ++ } else if (reply.type != NBD_REP_META_CONTEXT) { ++ error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", ++ reply.type, nbd_rep_lookup(reply.type), ++ NBD_REP_META_CONTEXT, nbd_rep_lookup(NBD_REP_META_CONTEXT)); ++ nbd_send_opt_abort(ioc); ++ return -1; ++ } ++ ++ if (reply.length <= sizeof(local_id) || ++ reply.length > NBD_MAX_BUFFER_SIZE) { ++ error_setg(errp, "Failed to negotiate meta context, server " ++ "answered with unexpected length %" PRIu32, ++ reply.length); ++ nbd_send_opt_abort(ioc); ++ return -1; ++ } ++ ++ if (nbd_read(ioc, &local_id, sizeof(local_id), errp) < 0) { ++ return -1; ++ } ++ local_id = be32_to_cpu(local_id); ++ ++ reply.length -= sizeof(local_id); ++ local_name = g_malloc(reply.length + 1); ++ if (nbd_read(ioc, local_name, reply.length, errp) < 0) { ++ g_free(local_name); ++ return -1; ++ } ++ local_name[reply.length] = '\0'; ++ trace_nbd_opt_meta_reply(nbd_opt_lookup(opt), local_name, local_id); ++ ++ if (name) { ++ *name = local_name; ++ } else { ++ g_free(local_name); ++ } ++ if (id) { ++ *id = local_id; ++ } ++ return 1; ++} ++ ++/* ++ * nbd_negotiate_simple_meta_context: + * Request the server to set the meta context for export @info->name + * using @info->x_dirty_bitmap with a fallback to "base:allocation", + * setting @info->context_id to the resulting id. Fail if the server +@@ -690,50 +769,21 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + * function should lose the term _simple. + */ + int ret; +- NBDOptionReply reply; + const char *context = info->x_dirty_bitmap ?: "base:allocation"; + bool received = false; ++ char *name = NULL; + + if (nbd_send_meta_query(ioc, NBD_OPT_SET_META_CONTEXT, + info->name, context, errp) < 0) { + return -1; + } + +- if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply, +- errp) < 0) +- { ++ ret = nbd_receive_one_meta_context(ioc, NBD_OPT_SET_META_CONTEXT, ++ &name, &info->context_id, errp); ++ if (ret < 0) { + return -1; + } +- +- ret = nbd_handle_reply_err(ioc, &reply, errp); +- if (ret <= 0) { +- return ret; +- } +- +- if (reply.type == NBD_REP_META_CONTEXT) { +- char *name; +- +- if (reply.length != sizeof(info->context_id) + strlen(context)) { +- error_setg(errp, "Failed to negotiate meta context '%s', server " +- "answered with unexpected length %" PRIu32, context, +- reply.length); +- nbd_send_opt_abort(ioc); +- return -1; +- } +- +- if (nbd_read(ioc, &info->context_id, sizeof(info->context_id), +- errp) < 0) { +- return -1; +- } +- info->context_id = be32_to_cpu(info->context_id); +- +- reply.length -= sizeof(info->context_id); +- name = g_malloc(reply.length + 1); +- if (nbd_read(ioc, name, reply.length, errp) < 0) { +- g_free(name); +- return -1; +- } +- name[reply.length] = '\0'; ++ if (ret == 1) { + if (strcmp(context, name)) { + error_setg(errp, "Failed to negotiate meta context '%s', server " + "answered with different context '%s'", context, +@@ -743,36 +793,19 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + return -1; + } + g_free(name); +- +- trace_nbd_opt_meta_reply(context, info->context_id); + received = true; + +- /* receive NBD_REP_ACK */ +- if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply, +- errp) < 0) +- { ++ ret = nbd_receive_one_meta_context(ioc, NBD_OPT_SET_META_CONTEXT, ++ NULL, NULL, errp); ++ if (ret < 0) { + return -1; + } +- +- ret = nbd_handle_reply_err(ioc, &reply, errp); +- if (ret <= 0) { +- return ret; +- } + } +- +- if (reply.type != NBD_REP_ACK) { +- error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", +- reply.type, nbd_rep_lookup(reply.type), +- NBD_REP_ACK, nbd_rep_lookup(NBD_REP_ACK)); ++ if (ret != 0) { ++ error_setg(errp, "Server answered with more than one context"); + nbd_send_opt_abort(ioc); + return -1; + } +- if (reply.length) { +- error_setg(errp, "Unexpected length to ACK response"); +- nbd_send_opt_abort(ioc); +- return -1; +- } +- + return received; + } + +diff --git a/nbd/trace-events b/nbd/trace-events +index 59521e4..b4802c1 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -13,7 +13,7 @@ nbd_receive_query_exports_success(const char *wantname) "Found desired export na + nbd_receive_starttls_new_client(void) "Setting up TLS" + nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake" + nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s" +-nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of context %s to id %" PRIu32 ++nbd_opt_meta_reply(const char *optname, const char *context, uint32_t id) "Received %s mapping of %s to id %" PRIu32 + nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" + nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 + nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Split-out-nbd_send_meta_query.patch b/SOURCES/kvm-nbd-client-Split-out-nbd_send_meta_query.patch new file mode 100644 index 0000000..729ac33 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Split-out-nbd_send_meta_query.patch @@ -0,0 +1,140 @@ +From 0406c2a938cf46c81c2d6c8ed14a4994993a3860 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:45 +0100 +Subject: [PATCH 107/163] nbd/client: Split out nbd_send_meta_query() + +RH-Author: John Snow +Message-id: <20190327172308.31077-33-jsnow@redhat.com> +Patchwork-id: 85202 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 32/55] nbd/client: Split out nbd_send_meta_query() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Refactor nbd_negotiate_simple_meta_context() to pull out the +code that can be reused to send a LIST request for 0 or 1 query. +No semantic change. The old comment about 'sizeof(uint32_t)' +being equivalent to '/* number of queries */' is no longer +needed, now that we are computing 'sizeof(queries)' instead. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-12-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 757b3ab989dea1c3143dd0d499441415ac7fcbc0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 64 ++++++++++++++++++++++++++++++++++++++------------------ + nbd/trace-events | 2 +- + 2 files changed, 45 insertions(+), 21 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 7799389..96da68e 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -629,6 +629,46 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, + return QIO_CHANNEL(tioc); + } + ++/* ++ * nbd_send_meta_query: ++ * Send 0 or 1 set/list meta context queries. ++ * Return 0 on success, -1 with errp set for any error ++ */ ++static int nbd_send_meta_query(QIOChannel *ioc, uint32_t opt, ++ const char *export, const char *query, ++ Error **errp) ++{ ++ int ret; ++ uint32_t export_len = strlen(export); ++ uint32_t queries = !!query; ++ uint32_t query_len = 0; ++ uint32_t data_len; ++ char *data; ++ char *p; ++ ++ data_len = sizeof(export_len) + export_len + sizeof(queries); ++ if (query) { ++ query_len = strlen(query); ++ data_len += sizeof(query_len) + query_len; ++ } else { ++ assert(opt == NBD_OPT_LIST_META_CONTEXT); ++ } ++ p = data = g_malloc(data_len); ++ ++ trace_nbd_opt_meta_request(nbd_opt_lookup(opt), query ?: "(all)", export); ++ stl_be_p(p, export_len); ++ memcpy(p += sizeof(export_len), export, export_len); ++ stl_be_p(p += export_len, queries); ++ if (query) { ++ stl_be_p(p += sizeof(queries), query_len); ++ memcpy(p += sizeof(query_len), query, query_len); ++ } ++ ++ ret = nbd_send_option_request(ioc, opt, data_len, data, errp); ++ g_free(data); ++ return ret; ++} ++ + /* nbd_negotiate_simple_meta_context: + * Request the server to set the meta context for export @info->name + * using @info->x_dirty_bitmap with a fallback to "base:allocation", +@@ -653,26 +693,10 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + NBDOptionReply reply; + const char *context = info->x_dirty_bitmap ?: "base:allocation"; + bool received = false; +- uint32_t export_len = strlen(info->name); +- uint32_t context_len = strlen(context); +- uint32_t data_len = sizeof(export_len) + export_len + +- sizeof(uint32_t) + /* number of queries */ +- sizeof(context_len) + context_len; +- char *data = g_malloc(data_len); +- char *p = data; +- +- trace_nbd_opt_meta_request(context, info->name); +- stl_be_p(p, export_len); +- memcpy(p += sizeof(export_len), info->name, export_len); +- stl_be_p(p += export_len, 1); +- stl_be_p(p += sizeof(uint32_t), context_len); +- memcpy(p += sizeof(context_len), context, context_len); + +- ret = nbd_send_option_request(ioc, NBD_OPT_SET_META_CONTEXT, data_len, data, +- errp); +- g_free(data); +- if (ret < 0) { +- return ret; ++ if (nbd_send_meta_query(ioc, NBD_OPT_SET_META_CONTEXT, ++ info->name, context, errp) < 0) { ++ return -1; + } + + if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply, +@@ -689,7 +713,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + if (reply.type == NBD_REP_META_CONTEXT) { + char *name; + +- if (reply.length != sizeof(info->context_id) + context_len) { ++ if (reply.length != sizeof(info->context_id) + strlen(context)) { + error_setg(errp, "Failed to negotiate meta context '%s', server " + "answered with unexpected length %" PRIu32, context, + reply.length); +diff --git a/nbd/trace-events b/nbd/trace-events +index c3966d2..59521e4 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -12,7 +12,7 @@ nbd_receive_query_exports_start(const char *wantname) "Querying export list for + nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'" + nbd_receive_starttls_new_client(void) "Setting up TLS" + nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake" +-nbd_opt_meta_request(const char *context, const char *export) "Requesting to set meta context %s for export %s" ++nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s" + nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of context %s to id %" PRIu32 + nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" + nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Support-qemu-img-convert-from-unaligned-s.patch b/SOURCES/kvm-nbd-client-Support-qemu-img-convert-from-unaligned-s.patch new file mode 100644 index 0000000..f0f059a --- /dev/null +++ b/SOURCES/kvm-nbd-client-Support-qemu-img-convert-from-unaligned-s.patch @@ -0,0 +1,132 @@ +From c443306c82400c6e04fe4af771552e88abb469a8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:21 +0200 +Subject: [PATCH 11/53] nbd/client: Support qemu-img convert from unaligned + size + +RH-Author: John Snow +Message-id: <20190506175629.11079-12-jsnow@redhat.com> +Patchwork-id: 87184 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/19] nbd/client: Support qemu-img convert from unaligned size +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +If an NBD server advertises a size that is not a multiple of a sector, +the block layer rounds up that size, even though we set info.size to +the exact byte value sent by the server. The block layer then proceeds +to let us read or query block status on the hole that it added past +EOF, which the NBD server is unlikely to be happy with. Fortunately, +qemu as a server never advertizes an unaligned size, so we generally +don't run into this problem; but the nbdkit server makes it easy to +test: + +$ printf %1000d 1 > f1 +$ ~/nbdkit/nbdkit -fv file f1 & pid=$! +$ qemu-img convert -f raw nbd://localhost:10809 f2 +$ kill $pid +$ qemu-img compare f1 f2 + +Pre-patch, the server attempts a 1024-byte read, which nbdkit +rightfully rejects as going beyond its advertised 1000 byte size; the +conversion fails and the output files differ (not even the first +sector is copied, because qemu-img does not follow ddrescue's habit of +trying smaller reads to get as much information as possible in spite +of errors). Post-patch, the client's attempts to read (and query block +status, for new enough nbdkit) are properly truncated to the server's +length, with sane handling of the hole the block layer forced on +us. Although f2 ends up as a larger file (1024 bytes instead of 1000), +qemu-img compare shows the two images to have identical contents for +display to the guest. + +I didn't add iotests coverage since I didn't want to add a dependency +on nbdkit in iotests. I also did NOT patch write, trim, or write +zeroes - these commands continue to fail (usually with ENOSPC, but +whatever the server chose), because we really can't write to the end +of the file, and because 'qemu-img convert' is the most common case +where we care about being tolerant (which is read-only). Perhaps we +could truncate the request if the client is writing zeros to the tail, +but that seems like more work, especially if the block layer is fixed +in 4.1 to track byte-accurate sizing (in which case this patch would +be reverted as unnecessary). + +Signed-off-by: Eric Blake +Message-Id: <20190329042750.14704-5-eblake@redhat.com> +Tested-by: Richard W.M. Jones +(cherry picked from commit 9cf638508c0090b33ada4155c7cbb684e08e5ee9) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 39 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 38 insertions(+), 1 deletion(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 9b5779f..a1a84a8 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -835,6 +835,25 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + if (!bytes) { + return 0; + } ++ /* ++ * Work around the fact that the block layer doesn't do ++ * byte-accurate sizing yet - if the read exceeds the server's ++ * advertised size because the block layer rounded size up, then ++ * truncate the request to the server and tail-pad with zero. ++ */ ++ if (offset >= client->info.size) { ++ assert(bytes < BDRV_SECTOR_SIZE); ++ qemu_iovec_memset(qiov, 0, 0, bytes); ++ return 0; ++ } ++ if (offset + bytes > client->info.size) { ++ uint64_t slop = offset + bytes - client->info.size; ++ ++ assert(slop < BDRV_SECTOR_SIZE); ++ qemu_iovec_memset(qiov, bytes - slop, 0, slop); ++ request.len -= slop; ++ } ++ + ret = nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + return ret; +@@ -953,7 +972,8 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + .from = offset, + .len = MIN(MIN_NON_ZERO(QEMU_ALIGN_DOWN(INT_MAX, + bs->bl.request_alignment), +- client->info.max_block), bytes), ++ client->info.max_block), ++ MIN(bytes, client->info.size - offset)), + .flags = NBD_CMD_FLAG_REQ_ONE, + }; + +@@ -964,6 +984,23 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, + return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; + } + ++ /* ++ * Work around the fact that the block layer doesn't do ++ * byte-accurate sizing yet - if the status request exceeds the ++ * server's advertised size because the block layer rounded size ++ * up, we truncated the request to the server (above), or are ++ * called on just the hole. ++ */ ++ if (offset >= client->info.size) { ++ *pnum = bytes; ++ assert(bytes < BDRV_SECTOR_SIZE); ++ /* Intentionally don't report offset_valid for the hole */ ++ return BDRV_BLOCK_ZERO; ++ } ++ ++ if (client->info.min_block) { ++ assert(QEMU_IS_ALIGNED(request.len, client->info.min_block)); ++ } + ret = nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Trace-all-server-option-error-messages.patch b/SOURCES/kvm-nbd-client-Trace-all-server-option-error-messages.patch new file mode 100644 index 0000000..9e40b43 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Trace-all-server-option-error-messages.patch @@ -0,0 +1,61 @@ +From 3fb57e060f7c7a01f4061eab781b03ad789f5bf5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:18 +0100 +Subject: [PATCH 079/163] nbd/client: Trace all server option error messages + +RH-Author: John Snow +Message-id: <20190327172308.31077-6-jsnow@redhat.com> +Patchwork-id: 85181 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/55] nbd/client: Trace all server option error messages +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Not all servers send free-form text alongside option error replies, but +for servers that do (such as qemu), we pass the server's message as a +hint alongside our own error reporting. However, it would also be +useful to trace such server messages, since we can't guarantee how the +hint may be consumed. + +Signed-off-by: Eric Blake +Message-Id: <20181218225714.284495-3-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit bee21ef0950c8b109d3bad05a3c3f2d94ec1a3af) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 2 ++ + nbd/trace-events | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/nbd/client.c b/nbd/client.c +index b4d457a..0ad7147 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -171,6 +171,8 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, + goto cleanup; + } + msg[reply->length] = '\0'; ++ trace_nbd_server_error_msg(reply->type, ++ nbd_reply_type_lookup(reply->type), msg); + } + + switch (reply->type) { +diff --git a/nbd/trace-events b/nbd/trace-events +index 5e1d4af..5492042 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -1,6 +1,7 @@ + # nbd/client.c + nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32 + nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32 ++nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s" + nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback" + nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'" + nbd_opt_go_success(void) "Export is good to go" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Trace-server-noncompliance-on-structured-.patch b/SOURCES/kvm-nbd-client-Trace-server-noncompliance-on-structured-.patch new file mode 100644 index 0000000..9472b2c --- /dev/null +++ b/SOURCES/kvm-nbd-client-Trace-server-noncompliance-on-structured-.patch @@ -0,0 +1,107 @@ +From debd78a4fda361c6a78bfc3f0e3577909bad3555 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:24 +0200 +Subject: [PATCH 14/53] nbd/client: Trace server noncompliance on structured + reads + +RH-Author: John Snow +Message-id: <20190506175629.11079-15-jsnow@redhat.com> +Patchwork-id: 87192 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 14/19] nbd/client: Trace server noncompliance on structured reads +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Just as we recently added a trace for a server sending block status +that doesn't match the server's advertised minimum block alignment, +let's do the same for read chunks. But since qemu 3.1 is such a +server (because it advertised 512-byte alignment, but when serving a +file that ends in data but is not sector-aligned, NBD_CMD_READ would +detect a mid-sector change between data and hole at EOF and the +resulting read chunks are unaligned), we don't want to change our +behavior of otherwise tolerating unaligned reads. + +Note that even though we fixed the server for 4.0 to advertise an +actual block alignment (which gets rid of the unaligned reads at EOF +for posix files), we can still trigger it via other means: + +$ qemu-nbd --image-opts driver=blkdebug,align=512,image.driver=file,image.filename=/path/to/non-aligned-file + +Arguably, that is a bug in the blkdebug block status function, for +leaking a block status that is not aligned. It may also be possible to +observe issues with a backing layer with smaller alignment than the +active layer, although so far I have been unable to write a reliable +iotest for that scenario. + +Signed-off-by: Eric Blake +Message-Id: <20190330165349.32256-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 75d34eb98ca0bb2f49d607fcaefd9c482e56b15d) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 12 ++++++++++-- + block/trace-events | 1 + + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index a1a84a8..69e3708 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -198,7 +198,8 @@ static inline uint64_t payload_advance64(uint8_t **payload) + return ldq_be_p(*payload - 8); + } + +-static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk *chunk, ++static int nbd_parse_offset_hole_payload(NBDClientSession *client, ++ NBDStructuredReplyChunk *chunk, + uint8_t *payload, uint64_t orig_offset, + QEMUIOVector *qiov, Error **errp) + { +@@ -220,6 +221,10 @@ static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk *chunk, + " region"); + return -EINVAL; + } ++ if (client->info.min_block && ++ !QEMU_IS_ALIGNED(hole_size, client->info.min_block)) { ++ trace_nbd_structured_read_compliance("hole"); ++ } + + qemu_iovec_memset(qiov, offset - orig_offset, 0, hole_size); + +@@ -377,6 +382,9 @@ static int nbd_co_receive_offset_data_payload(NBDClientSession *s, + " region"); + return -EINVAL; + } ++ if (s->info.min_block && !QEMU_IS_ALIGNED(data_size, s->info.min_block)) { ++ trace_nbd_structured_read_compliance("data"); ++ } + + qemu_iovec_init(&sub_qiov, qiov->niov); + qemu_iovec_concat(&sub_qiov, qiov, offset - orig_offset, data_size); +@@ -699,7 +707,7 @@ static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t handle, + * in qiov */ + break; + case NBD_REPLY_TYPE_OFFSET_HOLE: +- ret = nbd_parse_offset_hole_payload(&reply.structured, payload, ++ ret = nbd_parse_offset_hole_payload(s, &reply.structured, payload, + offset, qiov, &local_err); + if (ret < 0) { + s->quit = true; +diff --git a/block/trace-events b/block/trace-events +index 59c6f54..19abca2 100644 +--- a/block/trace-events ++++ b/block/trace-events +@@ -153,5 +153,6 @@ nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pa + + # block/nbd-client.c + nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non-compliant server: %s" ++nbd_structured_read_compliance(const char *type) "server sent non-compliant unaligned read %s chunk" + nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" + nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Work-around-3.0-bug-for-listing-meta-cont.patch b/SOURCES/kvm-nbd-client-Work-around-3.0-bug-for-listing-meta-cont.patch new file mode 100644 index 0000000..82b2e35 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Work-around-3.0-bug-for-listing-meta-cont.patch @@ -0,0 +1,99 @@ +From 1d8de67d4435beff1839b868672a05c4195c9d92 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:54 +0100 +Subject: [PATCH 116/163] nbd/client: Work around 3.0 bug for listing meta + contexts + +RH-Author: John Snow +Message-id: <20190327172308.31077-42-jsnow@redhat.com> +Patchwork-id: 85211 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 41/55] nbd/client: Work around 3.0 bug for listing meta contexts +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Commit 3d068aff forgot to advertise available qemu: contexts +when the client requests a list with 0 queries. Furthermore, +3.0 shipped with a qemu-img hack of x-dirty-bitmap (commit +216ee365) that _silently_ acts as though the entire image is +clean if a requested bitmap is not present. Both bugs have +been recently fixed, so that a modern qemu server gives full +context output right away, and the client refuses a +connection if a requested x-dirty-bitmap was not found. + +Still, it is likely that there will be users that have to +work with a mix of old and new qemu versions, depending on +which features get backported where, at which point being +able to rely on 'qemu-img --list' output to know for sure +whether a given NBD export has the desired dirty bitmap is +much nicer than blindly connecting and risking that the +entire image may appear clean. We can make our --list code +smart enough to work around buggy servers by tracking +whether we've seen any qemu: replies in the original 0-query +list; if not, repeat with a single query on "qemu:" (which +may still have no replies, but then we know for sure we +didn't trip up on the server bug). + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20190117193658.16413-21-eblake@redhat.com> +(cherry picked from commit 7c6f5ddca62905e67025aa0657e8a011cbdffa11) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/nbd/client.c b/nbd/client.c +index 798b82f..8a083c2 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -21,6 +21,7 @@ + #include "qapi/error.h" + #include "trace.h" + #include "nbd-internal.h" ++#include "qemu/cutils.h" + + /* Definitions for opaque data types */ + +@@ -828,6 +829,8 @@ static int nbd_list_meta_contexts(QIOChannel *ioc, + Error **errp) + { + int ret; ++ int seen_any = false; ++ int seen_qemu = false; + + if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT, + info->name, NULL, errp) < 0) { +@@ -839,9 +842,25 @@ static int nbd_list_meta_contexts(QIOChannel *ioc, + + ret = nbd_receive_one_meta_context(ioc, NBD_OPT_LIST_META_CONTEXT, + &context, NULL, errp); ++ if (ret == 0 && seen_any && !seen_qemu) { ++ /* ++ * Work around qemu 3.0 bug: the server forgot to send ++ * "qemu:" replies to 0 queries. If we saw at least one ++ * reply (probably base:allocation), but none of them were ++ * qemu:, then run a more specific query to make sure. ++ */ ++ seen_qemu = true; ++ if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT, ++ info->name, "qemu:", errp) < 0) { ++ return -1; ++ } ++ continue; ++ } + if (ret <= 0) { + return ret; + } ++ seen_any = true; ++ seen_qemu |= strstart(context, "qemu:", NULL); + info->contexts = g_renew(char *, info->contexts, ++info->n_contexts); + info->contexts[info->n_contexts - 1] = context; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-Work-around-server-BLOCK_STATUS-misalignm.patch b/SOURCES/kvm-nbd-client-Work-around-server-BLOCK_STATUS-misalignm.patch new file mode 100644 index 0000000..5696616 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Work-around-server-BLOCK_STATUS-misalignm.patch @@ -0,0 +1,111 @@ +From 00edcf411c7d8e58faa15f2cb07829b8f7f74a60 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:16 +0200 +Subject: [PATCH 06/53] nbd-client: Work around server BLOCK_STATUS + misalignment at EOF + +RH-Author: John Snow +Message-id: <20190506175629.11079-7-jsnow@redhat.com> +Patchwork-id: 87194 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/19] nbd-client: Work around server BLOCK_STATUS misalignment at EOF +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +The NBD spec is clear that a server that advertises a minimum block +size should reply to NBD_CMD_BLOCK_STATUS with extents aligned +accordingly. However, we know that the qemu NBD server implementation +has had a corner-case bug where it is not compliant with the spec, +present since the introduction of NBD_CMD_BLOCK_STATUS in qemu 2.12 +(and unlikely to be patched in time for 4.0). Namely, when qemu is +serving a file that is not a multiple of 512 bytes, it rounds the size +advertised over NBD up to the next sector boundary (someday, I'd like +to fix that to be byte-accurate, but it's a much bigger audit not +appropriate for this release); yet if the final sector contains data +prior to EOF, lseek(SEEK_HOLE) will point to the implicit hole +mid-sector which qemu then reported over NBD. + +We are well within our rights to hang up on a server that can't follow +the spec, but it is more useful to try and keep the connection alive +in spite of the problem. Do so by tracing a message about the problem, +and then either truncating the request back to an aligned boundary (if +it covered more than the final sector) or widening it out to the full +boundary with a forced status of data (since truncating would result +in 0 bytes, but we have to make progress, and valid since data is a +default-safe answer). And in practice, since the problem only happens +on a sector that starts with data and ends with a hole, we are going +to want to read that full sector anyway (where qemu as the server +fills in the tail beyond EOF with appropriate NUL bytes). + +Easy reproduction: +$ printf %1000d 1 > file +$ qemu-nbd -f raw -t file & pid=$! +$ qemu-img map --output=json -f raw nbd://localhost:10809 +qemu-img: Could not read file metadata: Invalid argument +$ kill $pid + +where the patched version instead succeeds with: +[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true}] + +Signed-off-by: Eric Blake +Message-Id: <20190326171317.4036-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 737d3f524481bb2ef68d3eba1caa636ff143e16a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 30 ++++++++++++++++++++++++++---- + 1 file changed, 26 insertions(+), 4 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index eee909f..09e20b2 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -256,15 +256,37 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, + extent->length = payload_advance32(&payload); + extent->flags = payload_advance32(&payload); + +- if (extent->length == 0 || +- (client->info.min_block && !QEMU_IS_ALIGNED(extent->length, +- client->info.min_block))) { ++ if (extent->length == 0) { + error_setg(errp, "Protocol error: server sent status chunk with " +- "invalid length"); ++ "zero length"); + return -EINVAL; + } + + /* ++ * A server sending unaligned block status is in violation of the ++ * protocol, but as qemu-nbd 3.1 is such a server (at least for ++ * POSIX files that are not a multiple of 512 bytes, since qemu ++ * rounds files up to 512-byte multiples but lseek(SEEK_HOLE) ++ * still sees an implicit hole beyond the real EOF), it's nicer to ++ * work around the misbehaving server. If the request included ++ * more than the final unaligned block, truncate it back to an ++ * aligned result; if the request was only the final block, round ++ * up to the full block and change the status to fully-allocated ++ * (always a safe status, even if it loses information). ++ */ ++ if (client->info.min_block && !QEMU_IS_ALIGNED(extent->length, ++ client->info.min_block)) { ++ trace_nbd_parse_blockstatus_compliance("extent length is unaligned"); ++ if (extent->length > client->info.min_block) { ++ extent->length = QEMU_ALIGN_DOWN(extent->length, ++ client->info.min_block); ++ } else { ++ extent->length = client->info.min_block; ++ extent->flags = 0; ++ } ++ } ++ ++ /* + * We used NBD_CMD_FLAG_REQ_ONE, so the server should not have + * sent us any more than one extent, nor should it have included + * status beyond our request in that extent. However, it's easy +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-fix-nbd_negotiate_simple_meta_context.patch b/SOURCES/kvm-nbd-client-fix-nbd_negotiate_simple_meta_context.patch new file mode 100644 index 0000000..96e8bc8 --- /dev/null +++ b/SOURCES/kvm-nbd-client-fix-nbd_negotiate_simple_meta_context.patch @@ -0,0 +1,59 @@ +From 8f9f560d48befb6c527e876347d883f8ed3c128a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:14 +0100 +Subject: [PATCH 047/163] nbd/client: fix nbd_negotiate_simple_meta_context + +RH-Author: John Snow +Message-id: <20190322032241.8111-2-jsnow@redhat.com> +Patchwork-id: 85092 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/28] nbd/client: fix nbd_negotiate_simple_meta_context +Bugzilla: 1691563 +RH-Acked-by: Richard Jones +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Initialize received variable. Otherwise, is is possible for server to +answer without any contexts, but we will set context_id to something +random (received_id is not initialized too) and return 1, which is +wrong. + +To solve it, just initialize received to false. Initialize received_id +too, just to make all possible checkers happy. + +Bug was introduced in 78a33ab58782efdb206de14 "nbd: BLOCK_STATUS for +standard get_block_status function: client part" with the whole +function. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180427142002.21930-2-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +(cherry picked from commit 89aa0d87634e2cb98517509dc8bdb876f26ecf8b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 25603f2..a151fa5 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -613,8 +613,8 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, + { + int ret; + NBDOptionReply reply; +- uint32_t received_id; +- bool received; ++ uint32_t received_id = 0; ++ bool received = false; + uint32_t export_len = strlen(export); + uint32_t context_len = strlen(context); + uint32_t data_len = sizeof(export_len) + export_len + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-fix-NBD_FLAG_SEND_CACHE-value.patch b/SOURCES/kvm-nbd-fix-NBD_FLAG_SEND_CACHE-value.patch new file mode 100644 index 0000000..2f0e513 --- /dev/null +++ b/SOURCES/kvm-nbd-fix-NBD_FLAG_SEND_CACHE-value.patch @@ -0,0 +1,96 @@ +From 5d77bd2fe5220f026648c9e2f49e65ff45c5475d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 9 Oct 2018 22:14:32 +0200 +Subject: [PATCH 02/22] nbd: fix NBD_FLAG_SEND_CACHE value + +RH-Author: John Snow +Message-id: <20181009221432.18359-3-jsnow@redhat.com> +Patchwork-id: 82509 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] nbd: fix NBD_FLAG_SEND_CACHE value +Bugzilla: 1636148 +RH-Acked-by: Eric Blake +RH-Acked-by: Thomas Huth +RH-Acked-by: Stefan Hajnoczi + +From: "Denis V. Lunev" + +Commit bc37b06a5 added NBD_CMD_CACHE support, but used the wrong value +for NBD_FLAG_SEND_CACHE flag for negotiation. That commit picked bit 8, +which had already been assigned by the NBD specification to mean +NBD_FLAG_CAN_MULTI_CONN, and which was already implemented in the +Linux kernel as a part of stable userspace-kernel API since 4.10: + +"bit 8, NBD_FLAG_CAN_MULTI_CONN: Indicates that the server operates +entirely without cache, or that the cache it uses is shared among all +connections to the given device. In particular, if this flag is +present, then the effects of NBD_CMD_FLUSH and NBD_CMD_FLAG_FUA +MUST be visible across all connections when the server sends its reply +to that command to the client. In the absense of this flag, clients +SHOULD NOT multiplex their commands over more than one connection to +the export. +... +bit 10, NBD_FLAG_SEND_CACHE: documents that the server understands +NBD_CMD_CACHE; however, note that server implementations exist +which support the command without advertising this bit, and +conversely that this bit does not guarantee that the command will +succeed or have an impact." + +Consequences: +- a client trying to use NBD_CMD_CACHE per the NBD spec will not +see the feature as available from a qemu 3.0 server (not fatal, +clients already have to be prepared for caching to not exist) +- a client accidentally coded to the qemu 3.0 bit value instead +of following the spec may interpret NBD_CMD_CACHE as being available +when it is not (probably not fatal, the spec says the server should +gracefully fail unknown commands, and that clients of NBD_CMD_CACHE +should be prepared for failure even when the feature is advertised); +such clients are unlikely (perhaps only in unreleased Virtuozzo code), +and will disappear over time +- a client prepared to use multiple connections based on +NBD_FLAG_CAN_MULTI_CONN may cause data corruption when it assumes +that caching is consistent when in reality qemu 3.0 did not have +a consistent cache. Partially mitigated by using read-only +connections (where nothing needs to be flushed, so caching is +indeed consistent) or when using qemu-nbd with the default -e 1 +(at most one client at a time); visible only when using -e 2 or +more for a writable export. + +Thus the commit fixes negotiation flag in QEMU according to the +specification. + +Signed-off-by: Denis V. Lunev +CC: Vladimir Sementsov-Ogievskiy +CC: Valery Vdovin +CC: Eric Blake +CC: Paolo Bonzini +CC: qemu-stable@nongnu.org +Message-Id: <20181004100313.4253-1-den@openvz.org> +Reviewed-by: Eric Blake +[eblake: enhance commit message, add defines for unimplemented flags] +Signed-off-by: Eric Blake +(cherry picked from commit df91328adab8490367776d2b21b35d790a606120) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 4638c83..a53b0cf 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -135,7 +135,9 @@ typedef struct NBDExtent { + #define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ + #define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send WRITE_ZEROES */ + #define NBD_FLAG_SEND_DF (1 << 7) /* Send DF (Do not Fragment) */ +-#define NBD_FLAG_SEND_CACHE (1 << 8) /* Send CACHE (prefetch) */ ++#define NBD_FLAG_CAN_MULTI_CONN (1 << 8) /* Multi-client cache consistent */ ++#define NBD_FLAG_SEND_RESIZE (1 << 9) /* Send resize */ ++#define NBD_FLAG_SEND_CACHE (1 << 10) /* Send CACHE (prefetch) */ + + /* New-style handshake (global) flags, sent from server to client, and + control what will happen during handshake phase. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-fix-whitespace-in-server-error-message.patch b/SOURCES/kvm-nbd-fix-whitespace-in-server-error-message.patch new file mode 100644 index 0000000..c92f125 --- /dev/null +++ b/SOURCES/kvm-nbd-fix-whitespace-in-server-error-message.patch @@ -0,0 +1,64 @@ +From 344f6a6e7dbdd6aae5d3564e46ade0970246eaca Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:29 +0100 +Subject: [PATCH 062/163] nbd: fix whitespace in server error message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-17-jsnow@redhat.com> +Patchwork-id: 85107 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 16/28] nbd: fix whitespace in server error message +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +A space was missing after the option number was printed: + + Option 0x8not permitted before TLS + +becomes + + Option 0x8 not permitted before TLS + +This fixes + + commit 3668328303429f3bc93ab3365c66331600b06a2d + Author: Eric Blake + Date: Fri Oct 14 13:33:09 2016 -0500 + + nbd: Send message along with server NBD_REP_ERR errors + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20181116155325.22428-2-berrange@redhat.com> +Reviewed-by: Eric Blake +[eblake: move lone space to next line] +Signed-off-by: Eric Blake +(cherry picked from commit 0b0bb124bb797b2fc3389ffa1e933fc34fe6dacb) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index d414861..418b1d4 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1136,7 +1136,7 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, + default: + ret = nbd_opt_drop(client, NBD_REP_ERR_TLS_REQD, errp, + "Option 0x%" PRIx32 +- "not permitted before TLS", option); ++ " not permitted before TLS", option); + /* Let the client keep trying, unless they asked to + * quit. In this mode, we've already sent an error, so + * we can't ack the abort. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-forbid-use-of-frozen-bitmaps.patch b/SOURCES/kvm-nbd-forbid-use-of-frozen-bitmaps.patch new file mode 100644 index 0000000..269e757 --- /dev/null +++ b/SOURCES/kvm-nbd-forbid-use-of-frozen-bitmaps.patch @@ -0,0 +1,46 @@ +From 7017ebd29ae40208efdf2bad4846c220a6952b60 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:36 +0100 +Subject: [PATCH 26/33] nbd: forbid use of frozen bitmaps + +RH-Author: John Snow +Message-id: <20190206221243.7407-17-jsnow@redhat.com> +Patchwork-id: 84273 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 16/23] nbd: forbid use of frozen bitmaps +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +Whether it's "locked" or "frozen", it's in use and should +not be allowed for the purposes of this operation. + +Signed-off-by: John Snow +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-id: 20181002230218.13949-7-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit d9782022bda7f8eccaf961044e9efe980dc90c04) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 1ce3f44..e094300 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -2435,8 +2435,8 @@ void nbd_export_bitmap(NBDExport *exp, const char *bitmap, + return; + } + +- if (bdrv_dirty_bitmap_qmp_locked(bm)) { +- error_setg(errp, "Bitmap '%s' is locked", bitmap); ++ if (bdrv_dirty_bitmap_user_locked(bm)) { ++ error_setg(errp, "Bitmap '%s' is in use", bitmap); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-generalize-usage-of-nbd_read.patch b/SOURCES/kvm-nbd-generalize-usage-of-nbd_read.patch new file mode 100644 index 0000000..c0f8810 --- /dev/null +++ b/SOURCES/kvm-nbd-generalize-usage-of-nbd_read.patch @@ -0,0 +1,481 @@ +From 3523bdc1d6abb74fdc0a572c9fecd7f2633ec4b9 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:57 +0100 +Subject: [PATCH 119/163] nbd: generalize usage of nbd_read + +RH-Author: John Snow +Message-id: <20190327172308.31077-45-jsnow@redhat.com> +Patchwork-id: 85205 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 44/55] nbd: generalize usage of nbd_read +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +We generally do very similar things around nbd_read: error_prepend +specifying what we have tried to read, and be_to_cpu conversion of +integers. + +So, it seems reasonable to move common things to helper functions, +which: +1. simplify code a bit +2. generalize nbd_read error descriptions, all starting with + "Failed to read" +3. make it more difficult to forget to convert things from BE + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20190128165830.165170-1-vsementsov@virtuozzo.com> +[eblake: rename macro to DEF_NBD_READ_N and formatting tweaks; +checkpatch has false positive complaint] +Signed-off-by: Eric Blake +(cherry picked from commit e6798f06a67a25def45a6636259de38cc38f1414) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 5 ++- + include/block/nbd.h | 32 +++++++++++++++++-- + nbd/client.c | 88 ++++++++++++++++++----------------------------------- + nbd/common.c | 2 +- + nbd/server.c | 27 ++++++---------- + 5 files changed, 71 insertions(+), 83 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 8135396..5c97052 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -337,10 +337,9 @@ static int nbd_co_receive_offset_data_payload(NBDClientSession *s, + return -EINVAL; + } + +- if (nbd_read(s->ioc, &offset, sizeof(offset), errp) < 0) { ++ if (nbd_read64(s->ioc, &offset, "OFFSET_DATA offset", errp) < 0) { + return -EIO; + } +- be64_to_cpus(&offset); + + data_size = chunk->length - sizeof(offset); + assert(data_size); +@@ -387,7 +386,7 @@ static coroutine_fn int nbd_co_receive_structured_payload( + } + + *payload = g_new(char, len); +- ret = nbd_read(s->ioc, *payload, len, errp); ++ ret = nbd_read(s->ioc, *payload, len, "structured payload", errp); + if (ret < 0) { + g_free(*payload); + *payload = NULL; +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 4faf394..96cfb1d 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -23,6 +23,7 @@ + #include "qapi/qapi-types-block.h" + #include "io/channel-socket.h" + #include "crypto/tlscreds.h" ++#include "qapi/error.h" + + /* Handshake phase structs - this struct is passed on the wire */ + +@@ -336,11 +337,38 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, + * Reads @size bytes from @ioc. Returns 0 on success. + */ + static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size, +- Error **errp) ++ const char *desc, Error **errp) + { +- return qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0; ++ int ret = qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0; ++ ++ if (ret < 0) { ++ if (desc) { ++ error_prepend(errp, "Failed to read %s: ", desc); ++ } ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#define DEF_NBD_READ_N(bits) \ ++static inline int nbd_read##bits(QIOChannel *ioc, \ ++ uint##bits##_t *val, \ ++ const char *desc, Error **errp) \ ++{ \ ++ if (nbd_read(ioc, val, sizeof(*val), desc, errp) < 0) { \ ++ return -1; \ ++ } \ ++ *val = be##bits##_to_cpu(*val); \ ++ return 0; \ + } + ++DEF_NBD_READ_N(16) /* Defines nbd_read16(). */ ++DEF_NBD_READ_N(32) /* Defines nbd_read32(). */ ++DEF_NBD_READ_N(64) /* Defines nbd_read64(). */ ++ ++#undef DEF_NBD_READ_N ++ + static inline bool nbd_reply_is_simple(NBDReply *reply) + { + return reply->magic == NBD_SIMPLE_REPLY_MAGIC; +diff --git a/nbd/client.c b/nbd/client.c +index 8a083c2..10a52ad 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -113,8 +113,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, + NBDOptionReply *reply, Error **errp) + { + QEMU_BUILD_BUG_ON(sizeof(*reply) != 20); +- if (nbd_read(ioc, reply, sizeof(*reply), errp) < 0) { +- error_prepend(errp, "failed to read option reply: "); ++ if (nbd_read(ioc, reply, sizeof(*reply), "option reply", errp) < 0) { + nbd_send_opt_abort(ioc); + return -1; + } +@@ -166,8 +165,8 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, + goto cleanup; + } + msg = g_malloc(reply->length + 1); +- if (nbd_read(ioc, msg, reply->length, errp) < 0) { +- error_prepend(errp, "failed to read option error %" PRIu32 ++ if (nbd_read(ioc, msg, reply->length, NULL, errp) < 0) { ++ error_prepend(errp, "Failed to read option error %" PRIu32 + " (%s) message: ", + reply->type, nbd_rep_lookup(reply->type)); + goto cleanup; +@@ -284,12 +283,10 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, + nbd_send_opt_abort(ioc); + return -1; + } +- if (nbd_read(ioc, &namelen, sizeof(namelen), errp) < 0) { +- error_prepend(errp, "failed to read option name length: "); ++ if (nbd_read32(ioc, &namelen, "option name length", errp) < 0) { + nbd_send_opt_abort(ioc); + return -1; + } +- namelen = be32_to_cpu(namelen); + len -= sizeof(namelen); + if (len < namelen) { + error_setg(errp, "incorrect option name length"); +@@ -298,8 +295,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, + } + + local_name = g_malloc(namelen + 1); +- if (nbd_read(ioc, local_name, namelen, errp) < 0) { +- error_prepend(errp, "failed to read export name: "); ++ if (nbd_read(ioc, local_name, namelen, "export name", errp) < 0) { + nbd_send_opt_abort(ioc); + goto out; + } +@@ -307,8 +303,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description, + len -= namelen; + if (len) { + local_desc = g_malloc(len + 1); +- if (nbd_read(ioc, local_desc, len, errp) < 0) { +- error_prepend(errp, "failed to read export description: "); ++ if (nbd_read(ioc, local_desc, len, "export description", errp) < 0) { + nbd_send_opt_abort(ioc); + goto out; + } +@@ -410,13 +405,11 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + nbd_send_opt_abort(ioc); + return -1; + } +- if (nbd_read(ioc, &type, sizeof(type), errp) < 0) { +- error_prepend(errp, "failed to read info type: "); ++ if (nbd_read16(ioc, &type, "info type", errp) < 0) { + nbd_send_opt_abort(ioc); + return -1; + } + len -= sizeof(type); +- type = be16_to_cpu(type); + switch (type) { + case NBD_INFO_EXPORT: + if (len != sizeof(info->size) + sizeof(info->flags)) { +@@ -425,18 +418,14 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + nbd_send_opt_abort(ioc); + return -1; + } +- if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { +- error_prepend(errp, "failed to read info size: "); ++ if (nbd_read64(ioc, &info->size, "info size", errp) < 0) { + nbd_send_opt_abort(ioc); + return -1; + } +- info->size = be64_to_cpu(info->size); +- if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { +- error_prepend(errp, "failed to read info flags: "); ++ if (nbd_read16(ioc, &info->flags, "info flags", errp) < 0) { + nbd_send_opt_abort(ioc); + return -1; + } +- info->flags = be16_to_cpu(info->flags); + trace_nbd_receive_negotiate_size_flags(info->size, info->flags); + break; + +@@ -447,27 +436,23 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + nbd_send_opt_abort(ioc); + return -1; + } +- if (nbd_read(ioc, &info->min_block, sizeof(info->min_block), +- errp) < 0) { +- error_prepend(errp, "failed to read info minimum block size: "); ++ if (nbd_read32(ioc, &info->min_block, "info minimum block size", ++ errp) < 0) { + nbd_send_opt_abort(ioc); + return -1; + } +- info->min_block = be32_to_cpu(info->min_block); + if (!is_power_of_2(info->min_block)) { + error_setg(errp, "server minimum block size %" PRIu32 + " is not a power of two", info->min_block); + nbd_send_opt_abort(ioc); + return -1; + } +- if (nbd_read(ioc, &info->opt_block, sizeof(info->opt_block), +- errp) < 0) { +- error_prepend(errp, +- "failed to read info preferred block size: "); ++ if (nbd_read32(ioc, &info->opt_block, "info preferred block size", ++ errp) < 0) ++ { + nbd_send_opt_abort(ioc); + return -1; + } +- info->opt_block = be32_to_cpu(info->opt_block); + if (!is_power_of_2(info->opt_block) || + info->opt_block < info->min_block) { + error_setg(errp, "server preferred block size %" PRIu32 +@@ -475,13 +460,12 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, + nbd_send_opt_abort(ioc); + return -1; + } +- if (nbd_read(ioc, &info->max_block, sizeof(info->max_block), +- errp) < 0) { +- error_prepend(errp, "failed to read info maximum block size: "); ++ if (nbd_read32(ioc, &info->max_block, "info maximum block size", ++ errp) < 0) ++ { + nbd_send_opt_abort(ioc); + return -1; + } +- info->max_block = be32_to_cpu(info->max_block); + if (info->max_block < info->min_block) { + error_setg(errp, "server maximum block size %" PRIu32 + " is not valid", info->max_block); +@@ -731,14 +715,13 @@ static int nbd_receive_one_meta_context(QIOChannel *ioc, + return -1; + } + +- if (nbd_read(ioc, &local_id, sizeof(local_id), errp) < 0) { ++ if (nbd_read32(ioc, &local_id, "context id", errp) < 0) { + return -1; + } +- local_id = be32_to_cpu(local_id); + + reply.length -= sizeof(local_id); + local_name = g_malloc(reply.length + 1); +- if (nbd_read(ioc, local_name, reply.length, errp) < 0) { ++ if (nbd_read(ioc, local_name, reply.length, "context name", errp) < 0) { + g_free(local_name); + return -1; + } +@@ -896,11 +879,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + return -EINVAL; + } + +- if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { +- error_prepend(errp, "Failed to read initial magic: "); ++ if (nbd_read64(ioc, &magic, "initial magic", errp) < 0) { + return -EINVAL; + } +- magic = be64_to_cpu(magic); + trace_nbd_receive_negotiate_magic(magic); + + if (magic != NBD_INIT_MAGIC) { +@@ -908,11 +889,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + return -EINVAL; + } + +- if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { +- error_prepend(errp, "Failed to read server magic: "); ++ if (nbd_read64(ioc, &magic, "server magic", errp) < 0) { + return -EINVAL; + } +- magic = be64_to_cpu(magic); + trace_nbd_receive_negotiate_magic(magic); + + if (magic == NBD_OPTS_MAGIC) { +@@ -920,11 +899,9 @@ static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + uint16_t globalflags; + bool fixedNewStyle = false; + +- if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) { +- error_prepend(errp, "Failed to read server flags: "); ++ if (nbd_read16(ioc, &globalflags, "server flags", errp) < 0) { + return -EINVAL; + } +- globalflags = be16_to_cpu(globalflags); + trace_nbd_receive_negotiate_server_flags(globalflags); + if (globalflags & NBD_FLAG_FIXED_NEWSTYLE) { + fixedNewStyle = true; +@@ -992,17 +969,13 @@ static int nbd_negotiate_finish_oldstyle(QIOChannel *ioc, NBDExportInfo *info, + { + uint32_t oldflags; + +- if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { +- error_prepend(errp, "Failed to read export length: "); ++ if (nbd_read64(ioc, &info->size, "export length", errp) < 0) { + return -EINVAL; + } +- info->size = be64_to_cpu(info->size); + +- if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { +- error_prepend(errp, "Failed to read export flags: "); ++ if (nbd_read32(ioc, &oldflags, "export flags", errp) < 0) { + return -EINVAL; + } +- oldflags = be32_to_cpu(oldflags); + if (oldflags & ~0xffff) { + error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); + return -EINVAL; +@@ -1079,17 +1052,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, + } + + /* Read the response */ +- if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { +- error_prepend(errp, "Failed to read export length: "); ++ if (nbd_read64(ioc, &info->size, "export length", errp) < 0) { + return -EINVAL; + } +- info->size = be64_to_cpu(info->size); + +- if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { +- error_prepend(errp, "Failed to read export flags: "); ++ if (nbd_read16(ioc, &info->flags, "export flags", errp) < 0) { + return -EINVAL; + } +- info->flags = be16_to_cpu(info->flags); + break; + case 0: /* oldstyle, parse length and flags */ + if (*info->name) { +@@ -1379,7 +1348,7 @@ static int nbd_receive_simple_reply(QIOChannel *ioc, NBDSimpleReply *reply, + assert(reply->magic == NBD_SIMPLE_REPLY_MAGIC); + + ret = nbd_read(ioc, (uint8_t *)reply + sizeof(reply->magic), +- sizeof(*reply) - sizeof(reply->magic), errp); ++ sizeof(*reply) - sizeof(reply->magic), "reply", errp); + if (ret < 0) { + return ret; + } +@@ -1404,7 +1373,8 @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, + assert(chunk->magic == NBD_STRUCTURED_REPLY_MAGIC); + + ret = nbd_read(ioc, (uint8_t *)chunk + sizeof(chunk->magic), +- sizeof(*chunk) - sizeof(chunk->magic), errp); ++ sizeof(*chunk) - sizeof(chunk->magic), "structured chunk", ++ errp); + if (ret < 0) { + return ret; + } +diff --git a/nbd/common.c b/nbd/common.c +index 41f5ed8..cc8b278 100644 +--- a/nbd/common.c ++++ b/nbd/common.c +@@ -31,7 +31,7 @@ int nbd_drop(QIOChannel *ioc, size_t size, Error **errp) + buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); + while (size > 0) { + ssize_t count = MIN(65536, size); +- ret = nbd_read(ioc, buffer, MIN(65536, size), errp); ++ ret = nbd_read(ioc, buffer, MIN(65536, size), NULL, errp); + + if (ret < 0) { + goto cleanup; +diff --git a/nbd/server.c b/nbd/server.c +index cb0d563..838c150 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -438,8 +438,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, + error_setg(errp, "Bad length received"); + return -EINVAL; + } +- if (nbd_read(client->ioc, name, client->optlen, errp) < 0) { +- error_prepend(errp, "read failed: "); ++ if (nbd_read(client->ioc, name, client->optlen, "export name", errp) < 0) { + return -EIO; + } + name[client->optlen] = '\0'; +@@ -1046,11 +1045,9 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, + ... Rest of request + */ + +- if (nbd_read(client->ioc, &flags, sizeof(flags), errp) < 0) { +- error_prepend(errp, "read failed: "); ++ if (nbd_read32(client->ioc, &flags, "flags", errp) < 0) { + return -EIO; + } +- flags = be32_to_cpu(flags); + trace_nbd_negotiate_options_flags(flags); + if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) { + fixedNewstyle = true; +@@ -1070,30 +1067,23 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, + uint32_t option, length; + uint64_t magic; + +- if (nbd_read(client->ioc, &magic, sizeof(magic), errp) < 0) { +- error_prepend(errp, "read failed: "); ++ if (nbd_read64(client->ioc, &magic, "opts magic", errp) < 0) { + return -EINVAL; + } +- magic = be64_to_cpu(magic); + trace_nbd_negotiate_options_check_magic(magic); + if (magic != NBD_OPTS_MAGIC) { + error_setg(errp, "Bad magic received"); + return -EINVAL; + } + +- if (nbd_read(client->ioc, &option, +- sizeof(option), errp) < 0) { +- error_prepend(errp, "read failed: "); ++ if (nbd_read32(client->ioc, &option, "option", errp) < 0) { + return -EINVAL; + } +- option = be32_to_cpu(option); + client->opt = option; + +- if (nbd_read(client->ioc, &length, sizeof(length), errp) < 0) { +- error_prepend(errp, "read failed: "); ++ if (nbd_read32(client->ioc, &length, "option length", errp) < 0) { + return -EINVAL; + } +- length = be32_to_cpu(length); + assert(!client->optlen); + client->optlen = length; + +@@ -1306,7 +1296,7 @@ static int nbd_receive_request(QIOChannel *ioc, NBDRequest *request, + uint32_t magic; + int ret; + +- ret = nbd_read(ioc, buf, sizeof(buf), errp); ++ ret = nbd_read(ioc, buf, sizeof(buf), "request", errp); + if (ret < 0) { + return ret; + } +@@ -2111,8 +2101,9 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, + } + } + if (request->type == NBD_CMD_WRITE) { +- if (nbd_read(client->ioc, req->data, request->len, errp) < 0) { +- error_prepend(errp, "reading from socket failed: "); ++ if (nbd_read(client->ioc, req->data, request->len, "CMD_WRITE data", ++ errp) < 0) ++ { + return -EIO; + } + req->complete = true; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-publish-_lookup-functions.patch b/SOURCES/kvm-nbd-publish-_lookup-functions.patch new file mode 100644 index 0000000..de1ab32 --- /dev/null +++ b/SOURCES/kvm-nbd-publish-_lookup-functions.patch @@ -0,0 +1,68 @@ +From 9dc089506f5893e309c458e5466566d112a7bb62 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:17 +0100 +Subject: [PATCH 078/163] nbd: publish _lookup functions + +RH-Author: John Snow +Message-id: <20190327172308.31077-5-jsnow@redhat.com> +Patchwork-id: 85172 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/55] nbd: publish _lookup functions +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +These functions are used for formatting pretty trace points. We are +going to add some in block/nbd-client, so, let's publish all these +functions at once. Note, that nbd_reply_type_lookup is already +published, and constants, "named" by these functions live in +include/block/nbd.h too. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181102151152.288399-3-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +(cherry picked from commit 757a0d05ea22d63e667db08a80b6ec6f1d53a12f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 5 +++++ + nbd/nbd-internal.h | 5 ----- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 6a5bfe5..65402d3 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -343,5 +343,10 @@ static inline bool nbd_reply_is_structured(NBDReply *reply) + } + + const char *nbd_reply_type_lookup(uint16_t type); ++const char *nbd_opt_lookup(uint32_t opt); ++const char *nbd_rep_lookup(uint32_t rep); ++const char *nbd_info_lookup(uint16_t info); ++const char *nbd_cmd_lookup(uint16_t info); ++const char *nbd_err_lookup(int err); + + #endif +diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h +index eeff78d..f38be9e 100644 +--- a/nbd/nbd-internal.h ++++ b/nbd/nbd-internal.h +@@ -100,11 +100,6 @@ struct NBDTLSHandshakeData { + + void nbd_tls_handshake(QIOTask *task, + void *opaque); +-const char *nbd_opt_lookup(uint32_t opt); +-const char *nbd_rep_lookup(uint32_t rep); +-const char *nbd_info_lookup(uint16_t info); +-const char *nbd_cmd_lookup(uint16_t info); +-const char *nbd_err_lookup(int err); + + int nbd_drop(QIOChannel *ioc, size_t size, Error **errp); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Advertise-actual-minimum-block-size.patch b/SOURCES/kvm-nbd-server-Advertise-actual-minimum-block-size.patch new file mode 100644 index 0000000..c101dab --- /dev/null +++ b/SOURCES/kvm-nbd-server-Advertise-actual-minimum-block-size.patch @@ -0,0 +1,172 @@ +From 3086eb8eb3a2bf4aec260fea793519899432ad70 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:23 +0200 +Subject: [PATCH 13/53] nbd/server: Advertise actual minimum block size + +RH-Author: John Snow +Message-id: <20190506175629.11079-14-jsnow@redhat.com> +Patchwork-id: 87196 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/19] nbd/server: Advertise actual minimum block size +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Both NBD_CMD_BLOCK_STATUS and structured NBD_CMD_READ will split their +reply according to bdrv_block_status() boundaries. If the block device +has a request_alignment smaller than 512, but we advertise a block +alignment of 512 to the client, then this can result in the server +reply violating client expectations by reporting a smaller region of +the export than what the client is permitted to address (although this +is less of an issue for qemu 4.0 clients, given recent client patches +to overlook our non-compliance at EOF). Since it's always better to +be strict in what we send, it is worth advertising the actual minimum +block limit rather than blindly rounding it up to 512. + +Note that this patch is not foolproof - it is still possible to +provoke non-compliant server behavior using: + +$ qemu-nbd --image-opts driver=blkdebug,align=512,image.driver=file,image.filename=/path/to/non-aligned-file + +That is arguably a bug in the blkdebug driver (it should never pass +back block status smaller than its alignment, even if it has to make +multiple bdrv_get_status calls and determine the +least-common-denominator status among the group to return). It may +also be possible to observe issues with a backing layer with smaller +alignment than the active layer, although so far I have been unable to +write a reliable iotest for that scenario (but again, an issue like +that could be argued to be a bug in the block layer, or something +where we need a flag to bdrv_block_status() to state whether the +result must be aligned to the current layer's limits or can be +subdivided for accuracy when chasing backing files). + +Anyways, as blkdebug is not normally used, and as this patch makes our +server more interoperable with qemu 3.1 clients, it is worth applying +now, even while we still work on a larger patch series for the 4.1 +timeframe to have byte-accurate file lengths. + +Note that the iotests output changes - for 223 and 233, we can see the +server's better granularity advertisement; and for 241, the three test +cases have the following effects: +- natural alignment: the server's smaller alignment is now advertised, +and the hole reported at EOF is now the right result; we've gotten rid +of the server's non-compliance +- forced server alignment: the server still advertises 512 bytes, but +still sends a mid-sector hole. This is still a server compliance bug, +which needs to be fixed in the block layer in a later patch; output +does not change because the client is already being tolerant of the +non-compliance +- forced client alignment: the server's smaller alignment means that +the client now sees the server's status change mid-sector without any +protocol violations, but the fact that the map shows an unaligned +mid-sector hole is evidence of the block layer problems with aligned +block status, to be fixed in a later patch + +Signed-off-by: Eric Blake +Message-Id: <20190329042750.14704-7-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +[eblake: rebase to enhanced iotest 241 coverage] +(cherry picked from commit b0245d6478ea5906e3d7a542244d5c015fd47bc7) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 13 ++++++++----- + tests/qemu-iotests/223.out | 4 ++-- + tests/qemu-iotests/233.out | 2 +- + tests/qemu-iotests/241.out | 10 ++++++---- + 4 files changed, 17 insertions(+), 12 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 9b87c7f..706f95a 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -607,13 +607,16 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + /* Send NBD_INFO_BLOCK_SIZE always, but tweak the minimum size + * according to whether the client requested it, and according to + * whether this is OPT_INFO or OPT_GO. */ +- /* minimum - 1 for back-compat, or 512 if client is new enough. +- * TODO: consult blk_bs(blk)->bl.request_alignment? */ +- sizes[0] = +- (client->opt == NBD_OPT_INFO || blocksize) ? BDRV_SECTOR_SIZE : 1; ++ /* minimum - 1 for back-compat, or actual if client will obey it. */ ++ if (client->opt == NBD_OPT_INFO || blocksize) { ++ sizes[0] = blk_get_request_alignment(exp->blk); ++ } else { ++ sizes[0] = 1; ++ } ++ assert(sizes[0] <= NBD_MAX_BUFFER_SIZE); + /* preferred - Hard-code to 4096 for now. + * TODO: is blk_bs(blk)->bl.opt_transfer appropriate? */ +- sizes[1] = 4096; ++ sizes[1] = MAX(4096, sizes[0]); + /* maximum - At most 32M, but smaller as appropriate. */ + sizes[2] = MIN(blk_get_max_transfer(exp->blk), NBD_MAX_BUFFER_SIZE); + trace_nbd_negotiate_handle_info_block_size(sizes[0], sizes[1], sizes[2]); +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index a620f82..805cfbf 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -41,7 +41,7 @@ exports available: 2 + export: 'n' + size: 4194304 + flags: 0x4ef ( readonly flush fua trim zeroes df cache ) +- min block: 512 ++ min block: 1 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 +@@ -50,7 +50,7 @@ exports available: 2 + export: 'n2' + size: 4194304 + flags: 0x4ed ( flush fua trim zeroes df cache ) +- min block: 512 ++ min block: 1 + opt block: 4096 + max block: 33554432 + available meta contexts: 2 +diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out +index 6d45f3b..cd83b86 100644 +--- a/tests/qemu-iotests/233.out ++++ b/tests/qemu-iotests/233.out +@@ -33,7 +33,7 @@ exports available: 1 + export: '' + size: 67108864 + flags: 0x4ed ( flush fua trim zeroes df cache ) +- min block: 512 ++ min block: 1 + opt block: 4096 + max block: 33554432 + available meta contexts: 1 +diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out +index f22eabb..f481074 100644 +--- a/tests/qemu-iotests/241.out ++++ b/tests/qemu-iotests/241.out +@@ -3,8 +3,9 @@ QA output created by 241 + === Exporting unaligned raw image, natural alignment === + + size: 1024 +- min block: 512 +-[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] ++ min block: 1 ++[{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 1000, "length": 24, "depth": 0, "zero": true, "data": true, "offset": OFFSET}] + 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) + + === Exporting unaligned raw image, forced server sector alignment === +@@ -20,7 +21,8 @@ WARNING: Image format was not specified for '/home/eblake/qemu/tests/qemu-iotest + === Exporting unaligned raw image, forced client sector alignment === + + size: 1024 +- min block: 512 +-[{ "start": 0, "length": 1024, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] ++ min block: 1 ++[{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 1000, "length": 24, "depth": 0, "zero": true, "data": true, "offset": OFFSET}] + 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Advertise-all-contexts-in-response-to-bar.patch b/SOURCES/kvm-nbd-server-Advertise-all-contexts-in-response-to-bar.patch new file mode 100644 index 0000000..2b7a55f --- /dev/null +++ b/SOURCES/kvm-nbd-server-Advertise-all-contexts-in-response-to-bar.patch @@ -0,0 +1,48 @@ +From 1ca9e169f34ef1c548b45a05f460f69e97ae0201 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:38 +0100 +Subject: [PATCH 071/163] nbd/server: Advertise all contexts in response to + bare LIST + +RH-Author: John Snow +Message-id: <20190322032241.8111-26-jsnow@redhat.com> +Patchwork-id: 85109 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 25/28] nbd/server: Advertise all contexts in response to bare LIST +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The NBD spec, and even our code comment, says that if the client +asks for NBD_OPT_LIST_META_CONTEXT with 0 queries, then we should +reply with (a possibly-compressed representation of) ALL contexts +that we are willing to let them try. But commit 3d068aff forgot +to advertise qemu:dirty-bitmap:FOO. + +Signed-off-by: Eric Blake +Message-Id: <20181130023232.3079982-2-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit e31d802479df9daff1994a7ed1e36bbc5bb19d03) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/nbd/server.c b/nbd/server.c +index e8fd6b4..abf03e8 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -978,6 +978,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client, + if (client->opt == NBD_OPT_LIST_META_CONTEXT && !nb_queries) { + /* enable all known contexts */ + meta->base_allocation = true; ++ meta->bitmap = !!meta->exp->export_bitmap; + } else { + for (i = 0; i < nb_queries; ++i) { + ret = nbd_negotiate_meta_query(client, meta, errp); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Don-t-fail-NBD_OPT_INFO-for-byte-aligned-.patch b/SOURCES/kvm-nbd-server-Don-t-fail-NBD_OPT_INFO-for-byte-aligned-.patch new file mode 100644 index 0000000..f5af51f --- /dev/null +++ b/SOURCES/kvm-nbd-server-Don-t-fail-NBD_OPT_INFO-for-byte-aligned-.patch @@ -0,0 +1,67 @@ +From 2b50f8a038624daf0b38795f33c7e9f5c21798a8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:27 +0200 +Subject: [PATCH 17/53] nbd/server: Don't fail NBD_OPT_INFO for byte-aligned + sources + +RH-Author: John Snow +Message-id: <20190506175629.11079-18-jsnow@redhat.com> +Patchwork-id: 87191 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 17/19] nbd/server: Don't fail NBD_OPT_INFO for byte-aligned sources +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +In commit 0c1d50bd, I added a couple of TODO comments about whether we +consult bl.request_alignment when responding to NBD_OPT_INFO. At the +time, qemu as server was hard-coding an advertised alignment of 512 to +clients that promised to obey constraints, and there was no function +for getting at a device's preferred alignment. But in hindsight, +advertising 512 when the block device prefers 1 caused other +compliance problems, and commit b0245d64 changed one of the two TODO +comments to advertise a more accurate alignment. Time to fix the other +TODO. Doesn't really impact qemu as client (our normal client doesn't +use NBD_OPT_INFO, and qemu-nbd --list promises to obey block sizes), +but it might prove useful to other clients. + +Fixes: b0245d64 +Signed-off-by: Eric Blake +Message-Id: <20190403030526.12258-4-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 099fbcd65c2064a4ba8251e749bf600055027759) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 42f77ae..ad29373 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -643,11 +643,14 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + return rc; + } + +- /* If the client is just asking for NBD_OPT_INFO, but forgot to +- * request block sizes, return an error. +- * TODO: consult blk_bs(blk)->request_align, and only error if it +- * is not 1? */ +- if (client->opt == NBD_OPT_INFO && !blocksize) { ++ /* ++ * If the client is just asking for NBD_OPT_INFO, but forgot to ++ * request block sizes in a situation that would impact ++ * performance, then return an error. But for NBD_OPT_GO, we ++ * tolerate all clients, regardless of alignments. ++ */ ++ if (client->opt == NBD_OPT_INFO && !blocksize && ++ blk_get_request_alignment(exp->blk) > 1) { + return nbd_negotiate_send_rep_err(client, + NBD_REP_ERR_BLOCK_SIZE_REQD, + errp, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Favor-u-int64_t-over-off_t.patch b/SOURCES/kvm-nbd-server-Favor-u-int64_t-over-off_t.patch new file mode 100644 index 0000000..b7fc43e --- /dev/null +++ b/SOURCES/kvm-nbd-server-Favor-u-int64_t-over-off_t.patch @@ -0,0 +1,198 @@ +From 7d033c0f2aa0c3a2c2c2b85cba48cf898284f66b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:40 +0100 +Subject: [PATCH 102/163] nbd/server: Favor [u]int64_t over off_t + +RH-Author: John Snow +Message-id: <20190327172308.31077-28-jsnow@redhat.com> +Patchwork-id: 85192 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 27/55] nbd/server: Favor [u]int64_t over off_t +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Although our compile-time environment is set up so that we always +support long files with 64-bit off_t, we have no guarantee whether +off_t is the same type as int64_t. This requires casts when +printing values, and prevents us from directly using qemu_strtoi64() +(which will be done in the next patch). Let's just flip to uint64_t +where possible, and stick to int64_t for detecting failure of +blk_getlength(); we also keep the assertions added in the previous +patch that the resulting values fit in 63 bits. The overflow check +in nbd_co_receive_request() was already sane (request->from is +validated to fit in 63 bits, and request->len is 32 bits, so the +addition can't overflow 64 bits), but rewrite it in a form easier +to recognize as a typical overflow check. + +Rename the variable 'description' to keep line lengths reasonable. + +Suggested-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake +Message-Id: <20190117193658.16413-7-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 9d26dfcbab62746b3e66ec7784d75c13ff499669) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 4 ++-- + nbd/server.c | 18 +++++++++--------- + qemu-nbd.c | 29 +++++++++++------------------ + 3 files changed, 22 insertions(+), 29 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 1971b55..24be957 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -294,8 +294,8 @@ int nbd_errno_to_system_errno(int err); + typedef struct NBDExport NBDExport; + typedef struct NBDClient NBDClient; + +-NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, +- const char *name, const char *description, ++NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, ++ uint64_t size, const char *name, const char *desc, + const char *bitmap, uint16_t nbdflags, + void (*close)(NBDExport *), bool writethrough, + BlockBackend *on_eject_blk, Error **errp); +diff --git a/nbd/server.c b/nbd/server.c +index 51ee809..cb0d563 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -77,8 +77,8 @@ struct NBDExport { + BlockBackend *blk; + char *name; + char *description; +- off_t dev_offset; +- off_t size; ++ uint64_t dev_offset; ++ uint64_t size; + uint16_t nbdflags; + QTAILQ_HEAD(, NBDClient) clients; + QTAILQ_ENTRY(NBDExport) next; +@@ -1455,8 +1455,8 @@ static void nbd_eject_notifier(Notifier *n, void *data) + nbd_export_close(exp); + } + +-NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, +- const char *name, const char *description, ++NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, ++ uint64_t size, const char *name, const char *desc, + const char *bitmap, uint16_t nbdflags, + void (*close)(NBDExport *), bool writethrough, + BlockBackend *on_eject_blk, Error **errp) +@@ -1495,12 +1495,12 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + exp->refcount = 1; + QTAILQ_INIT(&exp->clients); + exp->blk = blk; +- assert(dev_offset >= 0 && dev_offset <= INT64_MAX); ++ assert(dev_offset <= INT64_MAX); + exp->dev_offset = dev_offset; + exp->name = g_strdup(name); +- exp->description = g_strdup(description); ++ exp->description = g_strdup(desc); + exp->nbdflags = nbdflags; +- assert(size >= 0 && size <= INT64_MAX - dev_offset); ++ assert(size <= INT64_MAX - dev_offset); + exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE); + + if (bitmap) { +@@ -2130,10 +2130,10 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, + return -EROFS; + } + if (request->from > client->exp->size || +- request->from + request->len > client->exp->size) { ++ request->len > client->exp->size - request->from) { + error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" PRIu32 + ", Size: %" PRIu64, request->from, request->len, +- (uint64_t)client->exp->size); ++ client->exp->size); + return (request->type == NBD_CMD_WRITE || + request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL; + } +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 5c90c5e..598caa6 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -176,7 +176,7 @@ static void read_partition(uint8_t *p, struct partition_record *r) + } + + static int find_partition(BlockBackend *blk, int partition, +- off_t *offset, off_t *size) ++ uint64_t *offset, uint64_t *size) + { + struct partition_record mbr[4]; + uint8_t data[MBR_SIZE]; +@@ -500,14 +500,14 @@ int main(int argc, char **argv) + { + BlockBackend *blk; + BlockDriverState *bs; +- off_t dev_offset = 0; ++ uint64_t dev_offset = 0; + uint16_t nbdflags = 0; + bool disconnect = false; + const char *bindto = NULL; + const char *port = NULL; + char *sockpath = NULL; + char *device = NULL; +- off_t fd_size; ++ int64_t fd_size; + QemuOpts *sn_opts = NULL; + const char *sn_id_or_name = NULL; + const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:"; +@@ -665,10 +665,6 @@ int main(int argc, char **argv) + error_report("Invalid offset `%s'", optarg); + exit(EXIT_FAILURE); + } +- if (dev_offset < 0) { +- error_report("Offset must be positive `%s'", optarg); +- exit(EXIT_FAILURE); +- } + break; + case 'l': + if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { +@@ -1005,15 +1001,14 @@ int main(int argc, char **argv) + } + + if (dev_offset >= fd_size) { +- error_report("Offset (%lld) has to be smaller than the image size " +- "(%lld)", +- (long long int)dev_offset, (long long int)fd_size); ++ error_report("Offset (%" PRIu64 ") has to be smaller than the image " ++ "size (%" PRId64 ")", dev_offset, fd_size); + exit(EXIT_FAILURE); + } + fd_size -= dev_offset; + + if (partition != -1) { +- off_t limit; ++ uint64_t limit; + + if (dev_offset) { + error_report("Cannot request partition and offset together"); +@@ -1027,15 +1022,13 @@ int main(int argc, char **argv) + } + /* + * MBR partition limits are (32-bit << 9); this assert lets +- * the compiler know that we have two positive values that +- * can't overflow 64 bits. ++ * the compiler know that we can't overflow 64 bits. + */ +- assert(dev_offset >= 0 && dev_offset + limit >= dev_offset); ++ assert(dev_offset + limit >= dev_offset); + if (dev_offset + limit > fd_size) { +- error_report("Discovered partition %d at offset %lld size %lld, " +- "but size exceeds file length %lld", partition, +- (long long int) dev_offset, (long long int) limit, +- (long long int) fd_size); ++ error_report("Discovered partition %d at offset %" PRIu64 ++ " size %" PRIu64 ", but size exceeds file length %" ++ PRId64, partition, dev_offset, limit, fd_size); + exit(EXIT_FAILURE); + } + fd_size = limit; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Fix-blockstatus-trace.patch b/SOURCES/kvm-nbd-server-Fix-blockstatus-trace.patch new file mode 100644 index 0000000..eb575d9 --- /dev/null +++ b/SOURCES/kvm-nbd-server-Fix-blockstatus-trace.patch @@ -0,0 +1,68 @@ +From cd17af9ea6c8ef48387770a2fd65c93b93f0de65 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:25 +0200 +Subject: [PATCH 15/53] nbd/server: Fix blockstatus trace + +RH-Author: John Snow +Message-id: <20190506175629.11079-16-jsnow@redhat.com> +Patchwork-id: 87197 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 15/19] nbd/server: Fix blockstatus trace +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Don't increment remaining_bytes until we know that we will actually be +including the current block status extent in the reply; otherwise, the +value traced will include a bytes value that is oversized by the +length of the next block status extent which did not get sent because +it instead ended the loop. + +Fixes: fb7afc79 +Signed-off-by: Eric Blake +Message-Id: <20190403030526.12258-2-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 2178a569be16b18f04ed854d24fd2281b6a429c5) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 706f95a..6ae2154 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1880,17 +1880,12 @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, + + flags = (ret & BDRV_BLOCK_ALLOCATED ? 0 : NBD_STATE_HOLE) | + (ret & BDRV_BLOCK_ZERO ? NBD_STATE_ZERO : 0); +- offset += num; +- remaining_bytes -= num; + + if (first_extent) { + extent->flags = flags; + extent->length = num; + first_extent = false; +- continue; +- } +- +- if (flags == extent->flags) { ++ } else if (flags == extent->flags) { + /* extend current extent */ + extent->length += num; + } else { +@@ -1903,6 +1898,8 @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, + extent->flags = flags; + extent->length = num; + } ++ offset += num; ++ remaining_bytes -= num; + } + + extents_end = extent + 1; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Hoist-length-check-to-qmp_nbd_server_add.patch b/SOURCES/kvm-nbd-server-Hoist-length-check-to-qmp_nbd_server_add.patch new file mode 100644 index 0000000..a4fb3d9 --- /dev/null +++ b/SOURCES/kvm-nbd-server-Hoist-length-check-to-qmp_nbd_server_add.patch @@ -0,0 +1,106 @@ +From 0591484b860fb6e25f86eceec0ba2e8b8d1673c4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:39 +0100 +Subject: [PATCH 101/163] nbd/server: Hoist length check to qmp_nbd_server_add + +RH-Author: John Snow +Message-id: <20190327172308.31077-27-jsnow@redhat.com> +Patchwork-id: 85201 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 26/55] nbd/server: Hoist length check to qmp_nbd_server_add +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +We only had two callers to nbd_export_new; qemu-nbd.c always +passed a valid offset/length pair (because it already checked +the file length, to ensure that offset was in bounds), while +blockdev-nbd.c always passed 0/-1. Then nbd_export_new reduces +the size to a multiple of BDRV_SECTOR_SIZE (can only happen +when offset is not sector-aligned, since bdrv_getlength() +currently rounds up) (someday, it would be nice to have +byte-accurate lengths - but not today). + +However, I'm finding it easier to work with the code if we are +consistent on having both callers pass in a valid length, and +just assert that things are sane in nbd_export_new, meaning +that no negative values were passed, and that offset+size does +not exceed 63 bits (as that really is a fundamental limit to +later operations, whether we use off_t or uint64_t). + +Signed-off-by: Eric Blake +Message-Id: <20190117193658.16413-6-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 7596bbb390838359e4789996f349bda0cad56b0e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 10 +++++++++- + nbd/server.c | 10 +++------- + 2 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index c76d541..d73ac1b 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -146,6 +146,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + BlockDriverState *bs = NULL; + BlockBackend *on_eject_blk; + NBDExport *exp; ++ int64_t len; + + if (!nbd_server) { + error_setg(errp, "NBD server not running"); +@@ -168,6 +169,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + return; + } + ++ len = bdrv_getlength(bs); ++ if (len < 0) { ++ error_setg_errno(errp, -len, ++ "Failed to determine the NBD export's length"); ++ return; ++ } ++ + if (!has_writable) { + writable = false; + } +@@ -175,7 +183,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, + writable = false; + } + +- exp = nbd_export_new(bs, 0, -1, name, NULL, bitmap, ++ exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, + writable ? 0 : NBD_FLAG_READ_ONLY, + NULL, false, on_eject_blk, errp); + if (!exp) { +diff --git a/nbd/server.c b/nbd/server.c +index 6b13601..51ee809 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1495,17 +1495,13 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size, + exp->refcount = 1; + QTAILQ_INIT(&exp->clients); + exp->blk = blk; ++ assert(dev_offset >= 0 && dev_offset <= INT64_MAX); + exp->dev_offset = dev_offset; + exp->name = g_strdup(name); + exp->description = g_strdup(description); + exp->nbdflags = nbdflags; +- exp->size = size < 0 ? blk_getlength(blk) : size; +- if (exp->size < 0) { +- error_setg_errno(errp, -exp->size, +- "Failed to determine the NBD export's length"); +- goto fail; +- } +- exp->size -= exp->size % BDRV_SECTOR_SIZE; ++ assert(size >= 0 && size <= INT64_MAX - dev_offset); ++ exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE); + + if (bitmap) { + BdrvDirtyBitmap *bm = NULL; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Ignore-write-errors-when-replying-to-NBD_.patch b/SOURCES/kvm-nbd-server-Ignore-write-errors-when-replying-to-NBD_.patch new file mode 100644 index 0000000..8163c38 --- /dev/null +++ b/SOURCES/kvm-nbd-server-Ignore-write-errors-when-replying-to-NBD_.patch @@ -0,0 +1,65 @@ +From d706e465682307df95a723e1a74b32c0db93e259 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:30 +0100 +Subject: [PATCH 063/163] nbd/server: Ignore write errors when replying to + NBD_OPT_ABORT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-18-jsnow@redhat.com> +Patchwork-id: 85105 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 17/28] nbd/server: Ignore write errors when replying to NBD_OPT_ABORT +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Commit 37ec36f6 intentionally ignores errors when trying to reply +to an NBD_OPT_ABORT request for plaintext clients, but did not make +the same change for a TLS server. Since NBD_OPT_ABORT is +documented as being a potential for an EPIPE when the client hangs +up without waiting for our reply, we don't need to pollute the +server's output with that failure. + +Signed-off-by: Eric Blake +Message-Id: <20181117223221.2198751-1-eblake@redhat.com> +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit 3e99ebb9d3df15ce0ecf1b435816c9c46ee9a1ad) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 418b1d4..e8fd6b4 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1134,12 +1134,16 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, + return -EINVAL; + + default: +- ret = nbd_opt_drop(client, NBD_REP_ERR_TLS_REQD, errp, ++ /* Let the client keep trying, unless they asked to ++ * quit. Always try to give an error back to the ++ * client; but when replying to OPT_ABORT, be aware ++ * that the client may hang up before receiving the ++ * error, in which case we are fine ignoring the ++ * resulting EPIPE. */ ++ ret = nbd_opt_drop(client, NBD_REP_ERR_TLS_REQD, ++ option == NBD_OPT_ABORT ? NULL : errp, + "Option 0x%" PRIx32 + " not permitted before TLS", option); +- /* Let the client keep trying, unless they asked to +- * quit. In this mode, we've already sent an error, so +- * we can't ack the abort. */ + if (option == NBD_OPT_ABORT) { + return 1; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Kill-pointless-shadowed-variable.patch b/SOURCES/kvm-nbd-server-Kill-pointless-shadowed-variable.patch new file mode 100644 index 0000000..b77828d --- /dev/null +++ b/SOURCES/kvm-nbd-server-Kill-pointless-shadowed-variable.patch @@ -0,0 +1,51 @@ +From 19dc347405263456be2c13750a97ee4567665c58 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:23:04 +0100 +Subject: [PATCH 126/163] nbd/server: Kill pointless shadowed variable + +RH-Author: John Snow +Message-id: <20190327172308.31077-52-jsnow@redhat.com> +Patchwork-id: 85217 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 51/55] nbd/server: Kill pointless shadowed variable +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +lgtm.com pointed out that commit 678ba275 introduced a shadowed +declaration of local variable 'bs'; thankfully, the inner 'bs' +obtained by 'blk_bs(blk)' matches the outer one given that we had +'blk_insert_bs(blk, bs, errp)' a few lines earlier, and there are +no later uses of 'bs' beyond the scope of the 'if (bitmap)' to +care if we change the value stored in 'bs' while traveling the +backing chain to find a bitmap. So simply get rid of the extra +declaration. + +Reported-by: Peter Maydell +Signed-off-by: Eric Blake +Message-Id: <20190207191357.6665-1-eblake@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 269ee27e99cfbff983a9ab067ae22f6182f11fe2) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 838c150..0910d09 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1495,7 +1495,6 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, + + if (bitmap) { + BdrvDirtyBitmap *bm = NULL; +- BlockDriverState *bs = blk_bs(blk); + + while (true) { + bm = bdrv_find_dirty_bitmap(bs, bitmap); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Trace-client-noncompliance-on-unaligned-r.patch b/SOURCES/kvm-nbd-server-Trace-client-noncompliance-on-unaligned-r.patch new file mode 100644 index 0000000..f3ce0de --- /dev/null +++ b/SOURCES/kvm-nbd-server-Trace-client-noncompliance-on-unaligned-r.patch @@ -0,0 +1,140 @@ +From a3c2d291823493cd39a79e0b2a38c9af29090cf0 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:26 +0200 +Subject: [PATCH 16/53] nbd/server: Trace client noncompliance on unaligned + requests + +RH-Author: John Snow +Message-id: <20190506175629.11079-17-jsnow@redhat.com> +Patchwork-id: 87198 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 16/19] nbd/server: Trace client noncompliance on unaligned requests +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +We've recently added traces for clients to flag server non-compliance; +let's do the same for servers to flag client non-compliance. According +to the spec, if the client requests NBD_INFO_BLOCK_SIZE, it is +promising to send all requests aligned to those boundaries. Of +course, if the client does not request NBD_INFO_BLOCK_SIZE, then it +made no promises so we shouldn't flag anything; and because we are +willing to handle clients that made no promises (the spec allows us to +use NBD_REP_ERR_BLOCK_SIZE_REQD if we had been unwilling), we already +have to handle unaligned requests (which the block layer already does +on our behalf). So even though the spec allows us to return EINVAL +for clients that promised to behave, it's easier to always answer +unaligned requests. Still, flagging non-compliance can be useful in +debugging a client that is trying to be maximally portable. + +Qemu as client used to have one spot where it sent non-compliant +requests: if the server sends an unaligned reply to +NBD_CMD_BLOCK_STATUS, and the client was iterating over the entire +disk, the next request would start at that unaligned point; this was +fixed in commit a39286dd when the client was taught to work around +server non-compliance; but is equally fixed if the server is patched +to not send unaligned replies in the first place (yes, qemu 4.0 as +server still has few such bugs, although they will be patched in +4.1). Fortunately, I did not find any more spots where qemu as client +was non-compliant. I was able to test the patch by using the following +hack to convince qemu-io to run various unaligned commands, coupled +with serving 512-byte alignment by intentionally omitting '-f raw' on +the server while viewing server traces. + +| diff --git i/nbd/client.c w/nbd/client.c +| index 427980bdd22..1858b2aac35 100644 +| --- i/nbd/client.c +| +++ w/nbd/client.c +| @@ -449,6 +449,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt, +| nbd_send_opt_abort(ioc); +| return -1; +| } +| + info->min_block = 1;//hack +| if (!is_power_of_2(info->min_block)) { +| error_setg(errp, "server minimum block size %" PRIu32 +| " is not a power of two", info->min_block); + +Signed-off-by: Eric Blake +Message-Id: <20190403030526.12258-3-eblake@redhat.com> +[eblake: address minor review nits] +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 6e280648d21d8c0aa8a101b62d0732cd1e608743) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 17 ++++++++++++++++- + nbd/trace-events | 1 + + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 6ae2154..42f77ae 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -124,6 +124,8 @@ struct NBDClient { + int nb_requests; + bool closing; + ++ uint32_t check_align; /* If non-zero, check for aligned client requests */ ++ + bool structured_reply; + NBDExportMetaContexts export_meta; + +@@ -533,6 +535,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + bool blocksize = false; + uint32_t sizes[3]; + char buf[sizeof(uint64_t) + sizeof(uint16_t)]; ++ uint32_t check_align = 0; + + /* Client sends: + 4 bytes: L, name length (can be 0) +@@ -609,7 +612,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + * whether this is OPT_INFO or OPT_GO. */ + /* minimum - 1 for back-compat, or actual if client will obey it. */ + if (client->opt == NBD_OPT_INFO || blocksize) { +- sizes[0] = blk_get_request_alignment(exp->blk); ++ check_align = sizes[0] = blk_get_request_alignment(exp->blk); + } else { + sizes[0] = 1; + } +@@ -660,6 +663,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + + if (client->opt == NBD_OPT_GO) { + client->exp = exp; ++ client->check_align = check_align; + QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); + nbd_export_get(client->exp); + nbd_check_meta_export(client); +@@ -2126,6 +2130,17 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, + return (request->type == NBD_CMD_WRITE || + request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL; + } ++ if (client->check_align && !QEMU_IS_ALIGNED(request->from | request->len, ++ client->check_align)) { ++ /* ++ * The block layer gracefully handles unaligned requests, but ++ * it's still worth tracing client non-compliance ++ */ ++ trace_nbd_co_receive_align_compliance(nbd_cmd_lookup(request->type), ++ request->from, ++ request->len, ++ client->check_align); ++ } + valid_flags = NBD_CMD_FLAG_FUA; + if (request->type == NBD_CMD_READ && client->structured_reply) { + valid_flags |= NBD_CMD_FLAG_DF; +diff --git a/nbd/trace-events b/nbd/trace-events +index 7f10ebd..bd42cc8 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -71,4 +71,5 @@ nbd_co_send_structured_error(uint64_t handle, int err, const char *errname, cons + nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)" + nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32 + nbd_co_receive_request_cmd_write(uint32_t len) "Reading %" PRIu32 " byte(s)" ++nbd_co_receive_align_compliance(const char *op, uint64_t from, uint32_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx32 ", align=0x%" PRIx32 + nbd_trip(void) "Reading request" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-drop-old-style-negotiation.patch b/SOURCES/kvm-nbd-server-drop-old-style-negotiation.patch new file mode 100644 index 0000000..75d60ad --- /dev/null +++ b/SOURCES/kvm-nbd-server-drop-old-style-negotiation.patch @@ -0,0 +1,177 @@ +From 15a4aec1e61d9b1e1ad212fc60058d9ee95620f7 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:25 +0100 +Subject: [PATCH 058/163] nbd/server: drop old-style negotiation + +RH-Author: John Snow +Message-id: <20190322032241.8111-13-jsnow@redhat.com> +Patchwork-id: 85110 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/28] nbd/server: drop old-style negotiation +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +After the previous commit, nbd_client_new's first parameter is always +NULL. Let's drop it with all corresponding old-style negotiation code +path which is unreachable now. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181003170228.95973-3-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: re-wrap short line] +Signed-off-by: Eric Blake +(cherry picked from commit 7f7dfe2a53446072c136d349e3150c84d322b2bc) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 3 +-- + include/block/nbd.h | 3 +-- + nbd/server.c | 53 +++++++++++++++-------------------------------------- + qemu-nbd.c | 2 +- + 4 files changed, 18 insertions(+), 43 deletions(-) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index 1ef1104..1d170c8 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -36,8 +36,7 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + gpointer opaque) + { + qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server"); +- nbd_client_new(NULL, cioc, +- nbd_server->tlscreds, NULL, ++ nbd_client_new(cioc, nbd_server->tlscreds, NULL, + nbd_blockdev_client_closed); + } + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index a53b0cf..6a5bfe5 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -310,8 +310,7 @@ void nbd_export_set_name(NBDExport *exp, const char *name); + void nbd_export_set_description(NBDExport *exp, const char *description); + void nbd_export_close_all(void); + +-void nbd_client_new(NBDExport *exp, +- QIOChannelSocket *sioc, ++void nbd_client_new(QIOChannelSocket *sioc, + QCryptoTLSCreds *tlscreds, + const char *tlsaclname, + void (*close_fn)(NBDClient *, bool)); +diff --git a/nbd/server.c b/nbd/server.c +index df76324..d414861 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1253,7 +1253,6 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) + const uint16_t myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM | + NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA | + NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_CACHE); +- bool oldStyle; + + /* Old style negotiation header, no room for options + [ 0 .. 7] passwd ("NBDMAGIC") +@@ -1274,33 +1273,19 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) + trace_nbd_negotiate_begin(); + memcpy(buf, "NBDMAGIC", 8); + +- oldStyle = client->exp != NULL && !client->tlscreds; +- if (oldStyle) { +- trace_nbd_negotiate_old_style(client->exp->size, +- client->exp->nbdflags | myflags); +- stq_be_p(buf + 8, NBD_CLIENT_MAGIC); +- stq_be_p(buf + 16, client->exp->size); +- stl_be_p(buf + 24, client->exp->nbdflags | myflags); ++ stq_be_p(buf + 8, NBD_OPTS_MAGIC); ++ stw_be_p(buf + 16, NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES); + +- if (nbd_write(client->ioc, buf, sizeof(buf), errp) < 0) { +- error_prepend(errp, "write failed: "); +- return -EINVAL; +- } +- } else { +- stq_be_p(buf + 8, NBD_OPTS_MAGIC); +- stw_be_p(buf + 16, NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES); +- +- if (nbd_write(client->ioc, buf, 18, errp) < 0) { +- error_prepend(errp, "write failed: "); +- return -EINVAL; +- } +- ret = nbd_negotiate_options(client, myflags, errp); +- if (ret != 0) { +- if (ret < 0) { +- error_prepend(errp, "option negotiation failed: "); +- } +- return ret; ++ if (nbd_write(client->ioc, buf, 18, errp) < 0) { ++ error_prepend(errp, "write failed: "); ++ return -EINVAL; ++ } ++ ret = nbd_negotiate_options(client, myflags, errp); ++ if (ret != 0) { ++ if (ret < 0) { ++ error_prepend(errp, "option negotiation failed: "); + } ++ return ret; + } + + assert(!client->optlen); +@@ -2396,13 +2381,8 @@ static void nbd_client_receive_next_request(NBDClient *client) + static coroutine_fn void nbd_co_client_start(void *opaque) + { + NBDClient *client = opaque; +- NBDExport *exp = client->exp; + Error *local_err = NULL; + +- if (exp) { +- nbd_export_get(exp); +- QTAILQ_INSERT_TAIL(&exp->clients, client, next); +- } + qemu_co_mutex_init(&client->send_lock); + + if (nbd_negotiate(client, &local_err)) { +@@ -2417,13 +2397,11 @@ static coroutine_fn void nbd_co_client_start(void *opaque) + } + + /* +- * Create a new client listener on the given export @exp, using the +- * given channel @sioc. Begin servicing it in a coroutine. When the +- * connection closes, call @close_fn with an indication of whether the +- * client completed negotiation. ++ * Create a new client listener using the given channel @sioc. ++ * Begin servicing it in a coroutine. When the connection closes, call ++ * @close_fn with an indication of whether the client completed negotiation. + */ +-void nbd_client_new(NBDExport *exp, +- QIOChannelSocket *sioc, ++void nbd_client_new(QIOChannelSocket *sioc, + QCryptoTLSCreds *tlscreds, + const char *tlsaclname, + void (*close_fn)(NBDClient *, bool)) +@@ -2433,7 +2411,6 @@ void nbd_client_new(NBDExport *exp, + + client = g_new0(NBDClient, 1); + client->refcount = 1; +- client->exp = exp; + client->tlscreds = tlscreds; + if (tlscreds) { + object_ref(OBJECT(client->tlscreds)); +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 6aaebe7..e76fe30 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -354,7 +354,7 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + + nb_fds++; + nbd_update_server_watch(); +- nbd_client_new(NULL, cioc, tlscreds, NULL, nbd_client_closed); ++ nbd_client_new(cioc, tlscreds, NULL, nbd_client_closed); + } + + static void nbd_update_server_watch(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-fix-NBD_CMD_CACHE.patch b/SOURCES/kvm-nbd-server-fix-NBD_CMD_CACHE.patch new file mode 100644 index 0000000..191abe1 --- /dev/null +++ b/SOURCES/kvm-nbd-server-fix-NBD_CMD_CACHE.patch @@ -0,0 +1,52 @@ +From 1abf2fdfb42f49715458e6b3c01b431c9522926a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 9 Oct 2018 22:14:31 +0200 +Subject: [PATCH 01/22] nbd/server: fix NBD_CMD_CACHE + +RH-Author: John Snow +Message-id: <20181009221432.18359-2-jsnow@redhat.com> +Patchwork-id: 82508 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] nbd/server: fix NBD_CMD_CACHE +Bugzilla: 1636148 +RH-Acked-by: Eric Blake +RH-Acked-by: Thomas Huth +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +We should not go to structured-read branch on CACHE command, fix that. + +Bug introduced in bc37b06a5cde24 "nbd/server: introduce NBD_CMD_CACHE" +with the whole feature and affects 3.0.0 release. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +CC: qemu-stable@nongnu.org +Message-Id: <20181003144738.70670-1-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: commit message typo fix] +Signed-off-by: Eric Blake +(cherry picked from commit 2f454defc23e1be78f2a96bad2877ce7829f61b4) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index ea5fe0e..1ce3f44 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -2135,7 +2135,8 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request, + } + + if (client->structured_reply && !(request->flags & NBD_CMD_FLAG_DF) && +- request->len) { ++ request->len && request->type != NBD_CMD_CACHE) ++ { + return nbd_co_send_sparse_read(client, request->handle, request->from, + data, request->len, errp); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-fix-bitmap-export.patch b/SOURCES/kvm-nbd-server-fix-bitmap-export.patch new file mode 100644 index 0000000..1952899 --- /dev/null +++ b/SOURCES/kvm-nbd-server-fix-bitmap-export.patch @@ -0,0 +1,91 @@ +From d7a0e8fc0484ef18c25e7396baea07dfd6520a30 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:20 +0100 +Subject: [PATCH 053/163] nbd/server: fix bitmap export + +RH-Author: John Snow +Message-id: <20190322032241.8111-8-jsnow@redhat.com> +Patchwork-id: 85094 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/28] nbd/server: fix bitmap export +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +bitmap_to_extents function is broken: it switches dirty variable after +every iteration, however it can process only part of dirty (or zero) +area during one iteration in case when this area is too large for one +extent. + +Fortunately, the bug doesn't produce wrong extent flags: it just inserts +a zero-length extent between sequential extents representing large dirty +(or zero) area. However, zero-length extents are forbidden by the NBD +protocol. So, a careful client should consider such a reply as a server +fault, while a less-careful will likely ignore zero-length extents. + +The bug can only be triggered by a client that requests block status +for nearly 4G at once (a request of 4G and larger is impossible per +the protocol, and requests smaller than 4G less the bitmap granularity +cause the loop to quit iterating rather than revisit the tail of the +large area); it also cannot trigger if the client used the +NBD_CMD_FLAG_REQ_ONE flag. Since qemu 3.0 as client (using the +x-dirty-bitmap extension) always passes the flag, it is immune; and +we are not aware of other open-source clients that know how to request +qemu:dirty-bitmap:FOO contexts. Clients that want to avoid the bug +could cap block status requests to a smaller length, such as 2G or 3G. + +Fix this by more careful handling of dirty variable. + +Bug was introduced in 3d068aff16 + "nbd/server: implement dirty bitmap export", with the whole function. +and is present in v3.0.0 release. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180914165116.23182-1-vsementsov@virtuozzo.com> +CC: qemu-stable@nongnu.org +Reviewed-by: Eric Blake +[eblake: improved commit message] +Signed-off-by: Eric Blake +(cherry picked from commit 6545916d528de7a6b784f4d10e7b236b30bfaced) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 0ab0dbd..a8ddc4a 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1951,6 +1951,8 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + + assert(begin < overall_end && nb_extents); + while (begin < overall_end && i < nb_extents) { ++ bool next_dirty = !dirty; ++ + if (dirty) { + end = bdrv_dirty_bitmap_next_zero(bitmap, begin, UINT64_MAX); + } else { +@@ -1962,6 +1964,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + end = MIN(bdrv_dirty_bitmap_size(bitmap), + begin + UINT32_MAX + 1 - + bdrv_dirty_bitmap_granularity(bitmap)); ++ next_dirty = dirty; + } + if (dont_fragment && end > overall_end) { + end = overall_end; +@@ -1971,7 +1974,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + extents[i].flags = cpu_to_be32(dirty ? NBD_STATE_DIRTY : 0); + i++; + begin = end; +- dirty = !dirty; ++ dirty = next_dirty; + } + + bdrv_dirty_iter_free(it); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-send-more-than-one-extent-of-base-allocat.patch b/SOURCES/kvm-nbd-server-send-more-than-one-extent-of-base-allocat.patch new file mode 100644 index 0000000..90a7fbe --- /dev/null +++ b/SOURCES/kvm-nbd-server-send-more-than-one-extent-of-base-allocat.patch @@ -0,0 +1,178 @@ +From 6f48ea5b06bd3f566d51996f447c205452c6ee70 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:21 +0100 +Subject: [PATCH 054/163] nbd/server: send more than one extent of + base:allocation context + +RH-Author: John Snow +Message-id: <20190322032241.8111-9-jsnow@redhat.com> +Patchwork-id: 85100 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/28] nbd/server: send more than one extent of base:allocation context +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +This is necessary for efficient block-status export, for clients which +support it. (qemu is not yet such a client, but could become one.) + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180704112302.471456-3-vsementsov@virtuozzo.com> +[eblake: grammar tweaks] +Signed-off-by: Eric Blake +(cherry picked from commit fb7afc797e071f2616e1ccc849b39fe43e7033bf) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 79 +++++++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 60 insertions(+), 19 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index a8ddc4a..a9fec45 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1844,37 +1844,68 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, + return ret; + } + +-static int blockstatus_to_extent_be(BlockDriverState *bs, uint64_t offset, +- uint64_t bytes, NBDExtent *extent) ++/* ++ * Populate @extents from block status. Update @bytes to be the actual ++ * length encoded (which may be smaller than the original), and update ++ * @nb_extents to the number of extents used. ++ * ++ * Returns zero on success and -errno on bdrv_block_status_above failure. ++ */ ++static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, ++ uint64_t *bytes, NBDExtent *extents, ++ unsigned int *nb_extents) + { +- uint64_t remaining_bytes = bytes; ++ uint64_t remaining_bytes = *bytes; ++ NBDExtent *extent = extents, *extents_end = extents + *nb_extents; ++ bool first_extent = true; + ++ assert(*nb_extents); + while (remaining_bytes) { + uint32_t flags; + int64_t num; + int ret = bdrv_block_status_above(bs, NULL, offset, remaining_bytes, + &num, NULL, NULL); ++ + if (ret < 0) { + return ret; + } + + flags = (ret & BDRV_BLOCK_ALLOCATED ? 0 : NBD_STATE_HOLE) | + (ret & BDRV_BLOCK_ZERO ? NBD_STATE_ZERO : 0); ++ offset += num; ++ remaining_bytes -= num; + +- if (remaining_bytes == bytes) { ++ if (first_extent) { + extent->flags = flags; ++ extent->length = num; ++ first_extent = false; ++ continue; + } + +- if (flags != extent->flags) { +- break; ++ if (flags == extent->flags) { ++ /* extend current extent */ ++ extent->length += num; ++ } else { ++ if (extent + 1 == extents_end) { ++ break; ++ } ++ ++ /* start new extent */ ++ extent++; ++ extent->flags = flags; ++ extent->length = num; + } ++ } + +- offset += num; +- remaining_bytes -= num; ++ extents_end = extent + 1; ++ ++ for (extent = extents; extent < extents_end; extent++) { ++ cpu_to_be32s(&extent->flags); ++ cpu_to_be32s(&extent->length); + } + +- cpu_to_be32s(&extent->flags); +- extent->length = cpu_to_be32(bytes - remaining_bytes); ++ *bytes -= remaining_bytes; ++ *nb_extents = extents_end - extents; + + return 0; + } +@@ -1910,21 +1941,29 @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, + /* Get block status from the exported device and send it to the client */ + static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, + BlockDriverState *bs, uint64_t offset, +- uint32_t length, bool last, +- uint32_t context_id, Error **errp) ++ uint32_t length, bool dont_fragment, ++ bool last, uint32_t context_id, ++ Error **errp) + { + int ret; +- NBDExtent extent; ++ unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BITMAP_EXTENTS; ++ NBDExtent *extents = g_new(NBDExtent, nb_extents); ++ uint64_t final_length = length; + +- ret = blockstatus_to_extent_be(bs, offset, length, &extent); ++ ret = blockstatus_to_extents(bs, offset, &final_length, extents, ++ &nb_extents); + if (ret < 0) { ++ g_free(extents); + return nbd_co_send_structured_error( + client, handle, -ret, "can't get block status", errp); + } + +- return nbd_co_send_extents(client, handle, &extent, 1, +- be32_to_cpu(extent.length), last, +- context_id, errp); ++ ret = nbd_co_send_extents(client, handle, extents, nb_extents, ++ final_length, last, context_id, errp); ++ ++ g_free(extents); ++ ++ return ret; + } + + /* +@@ -2232,10 +2271,12 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, + (client->export_meta.base_allocation || + client->export_meta.bitmap)) + { ++ bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE; ++ + if (client->export_meta.base_allocation) { + ret = nbd_co_send_block_status(client, request->handle, + blk_bs(exp->blk), request->from, +- request->len, ++ request->len, dont_fragment, + !client->export_meta.bitmap, + NBD_META_ID_BASE_ALLOCATION, + errp); +@@ -2248,7 +2289,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, + ret = nbd_co_send_bitmap(client, request->handle, + client->exp->export_bitmap, + request->from, request->len, +- request->flags & NBD_CMD_FLAG_REQ_ONE, ++ dont_fragment, + true, NBD_META_ID_DIRTY_BITMAP, errp); + if (ret < 0) { + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-net-drop-too-large-packet-early.patch b/SOURCES/kvm-net-drop-too-large-packet-early.patch new file mode 100644 index 0000000..ae44cb3 --- /dev/null +++ b/SOURCES/kvm-net-drop-too-large-packet-early.patch @@ -0,0 +1,149 @@ +From 4898198378a84fc6abd34adf5d0e297f4206b006 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Fri, 17 May 2019 07:29:37 +0200 +Subject: [PATCH 3/9] net: drop too large packet early + +RH-Author: Xiao Wang +Message-id: <1558078177-372-4-git-send-email-jasowang@redhat.com> +Patchwork-id: 88015 +O-Subject: [RHEL7.7 qemu-kvm-rhev PATCH 3/3] net: drop too large packet early +Bugzilla: 1636780 +RH-Acked-by: Thomas Huth +RH-Acked-by: Jens Freimann +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Michael S. Tsirkin + +Bugzilla: 1636779 + +We try to detect and drop too large packet (>INT_MAX) in 1592a9947036 +("net: ignore packet size greater than INT_MAX") during packet +delivering. Unfortunately, this is not sufficient as we may hit +another integer overflow when trying to queue such large packet in +qemu_net_queue_append_iov(): + +- size of the allocation may overflow on 32bit +- packet->size is integer which may overflow even on 64bit + +Fixing this by moving the check to qemu_sendv_packet_async() which is +the entrance of all networking codes and reduce the limit to +NET_BUFSIZE to be more conservative. This works since: + +- For the callers that call qemu_sendv_packet_async() directly, they + only care about if zero is returned to determine whether to prevent + the source from producing more packets. A callback will be triggered + if peer can accept more then source could be enabled. This is + usually used by high speed networking implementation like virtio-net + or netmap. +- For the callers that call qemu_sendv_packet() that calls + qemu_sendv_packet_async() indirectly, they often ignore the return + value. In this case qemu will just the drop packets if peer can't + receive. + +Qemu will copy the packet if it was queued. So it was safe for both +kinds of the callers to assume the packet was sent. + +Since we move the check from qemu_deliver_packet_iov() to +qemu_sendv_packet_async(), it would be safer to make +qemu_deliver_packet_iov() static to prevent any external user in the +future. + +This is a revised patch of CVE-2018-17963. + +Cc: qemu-stable@nongnu.org +Cc: Li Qiang +Fixes: 1592a9947036 ("net: ignore packet size greater than INT_MAX") +Reported-by: Li Qiang +Reviewed-by: Li Qiang +Signed-off-by: Jason Wang +Reviewed-by: Thomas Huth +Message-id: 20181204035347.6148-2-jasowang@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit 25c01bd19d0e4b66f357618aeefda1ef7a41e21a) +Signed-off-by: Miroslav Rezanina +--- + include/net/net.h | 6 ------ + net/net.c | 28 +++++++++++++++++----------- + 2 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/include/net/net.h b/include/net/net.h +index 1f7341e..df4df25 100644 +--- a/include/net/net.h ++++ b/include/net/net.h +@@ -170,12 +170,6 @@ void qemu_check_nic_model(NICInfo *nd, const char *model); + int qemu_find_nic_model(NICInfo *nd, const char * const *models, + const char *default_model); + +-ssize_t qemu_deliver_packet_iov(NetClientState *sender, +- unsigned flags, +- const struct iovec *iov, +- int iovcnt, +- void *opaque); +- + void print_net_client(Monitor *mon, NetClientState *nc); + void hmp_info_network(Monitor *mon, const QDict *qdict); + void net_socket_rs_init(SocketReadState *rs, +diff --git a/net/net.c b/net/net.c +index c991243..6e5c335 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -231,6 +231,11 @@ static void qemu_net_client_destructor(NetClientState *nc) + { + g_free(nc); + } ++static ssize_t qemu_deliver_packet_iov(NetClientState *sender, ++ unsigned flags, ++ const struct iovec *iov, ++ int iovcnt, ++ void *opaque); + + static void qemu_net_client_setup(NetClientState *nc, + NetClientInfo *info, +@@ -705,22 +710,18 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, + return ret; + } + +-ssize_t qemu_deliver_packet_iov(NetClientState *sender, +- unsigned flags, +- const struct iovec *iov, +- int iovcnt, +- void *opaque) ++static ssize_t qemu_deliver_packet_iov(NetClientState *sender, ++ unsigned flags, ++ const struct iovec *iov, ++ int iovcnt, ++ void *opaque) + { + NetClientState *nc = opaque; +- size_t size = iov_size(iov, iovcnt); + int ret; + +- if (size > INT_MAX) { +- return size; +- } + + if (nc->link_down) { +- return size; ++ return iov_size(iov, iovcnt); + } + + if (nc->receive_disabled) { +@@ -745,10 +746,15 @@ ssize_t qemu_sendv_packet_async(NetClientState *sender, + NetPacketSent *sent_cb) + { + NetQueue *queue; ++ size_t size = iov_size(iov, iovcnt); + int ret; + ++ if (size > NET_BUFSIZE) { ++ return size; ++ } ++ + if (sender->link_down || !sender->peer) { +- return iov_size(iov, iovcnt); ++ return size; + } + + /* Let filters handle the packet first */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-net-ignore-packet-size-greater-than-INT_MAX.patch b/SOURCES/kvm-net-ignore-packet-size-greater-than-INT_MAX.patch new file mode 100644 index 0000000..7a23f62 --- /dev/null +++ b/SOURCES/kvm-net-ignore-packet-size-greater-than-INT_MAX.patch @@ -0,0 +1,55 @@ +From 3abb574bc7328eab1f67a1e470ea44c595b0c0b5 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Fri, 17 May 2019 07:29:36 +0200 +Subject: [PATCH 2/9] net: ignore packet size greater than INT_MAX + +RH-Author: Xiao Wang +Message-id: <1558078177-372-3-git-send-email-jasowang@redhat.com> +Patchwork-id: 88014 +O-Subject: [RHEL7.7 qemu-kvm-rhev PATCH 2/3] net: ignore packet size greater than INT_MAX +Bugzilla: 1636780 +RH-Acked-by: Thomas Huth +RH-Acked-by: Jens Freimann +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Michael S. Tsirkin + +Bugzilla: 1636779 + +There should not be a reason for passing a packet size greater than +INT_MAX. It's usually a hint of bug somewhere, so ignore packet size +greater than INT_MAX in qemu_deliver_packet_iov() + +CC: qemu-stable@nongnu.org +Reported-by: Daniel Shapira +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +(cherry picked from commit 1592a9947036d60dde5404204a5d45975133caf5) +Signed-off-by: Miroslav Rezanina +--- + net/net.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/net.c b/net/net.c +index 29f8398..c991243 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -712,10 +712,15 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, + void *opaque) + { + NetClientState *nc = opaque; ++ size_t size = iov_size(iov, iovcnt); + int ret; + ++ if (size > INT_MAX) { ++ return size; ++ } ++ + if (nc->link_down) { +- return iov_size(iov, iovcnt); ++ return size; + } + + if (nc->receive_disabled) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nvdimm-no-need-to-overwrite-get_vmstate_memory_regio.patch b/SOURCES/kvm-nvdimm-no-need-to-overwrite-get_vmstate_memory_regio.patch new file mode 100644 index 0000000..b6da0ed --- /dev/null +++ b/SOURCES/kvm-nvdimm-no-need-to-overwrite-get_vmstate_memory_regio.patch @@ -0,0 +1,61 @@ +From cd99d0d882fc24428194547adb29399519ea09d5 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 29 Oct 2018 07:01:35 +0100 +Subject: [PATCH 05/22] nvdimm: no need to overwrite + get_vmstate_memory_region() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20181029070137.21196-2-armbru@redhat.com> +Patchwork-id: 82901 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] nvdimm: no need to overwrite get_vmstate_memory_region() +Bugzilla: 1620373 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Igor Mammedov +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau + +From: David Hildenbrand + +Our parent class (PC_DIMM) provides exactly the same function. + +Reviewed-by: David Gibson +Reviewed-by: Igor Mammedov +Signed-off-by: David Hildenbrand +Message-Id: <20180619134141.29478-7-david@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 4ab56d04ede6e0f979fc8e4a54b381e99cf0a255) +Signed-off-by: Miroslav Rezanina +--- + hw/mem/nvdimm.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c +index 0c962fd..5f1813d 100644 +--- a/hw/mem/nvdimm.c ++++ b/hw/mem/nvdimm.c +@@ -173,11 +173,6 @@ static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf, + memory_region_set_dirty(mr, backend_offset, size); + } + +-static MemoryRegion *nvdimm_get_vmstate_memory_region(PCDIMMDevice *dimm) +-{ +- return host_memory_backend_get_memory(dimm->hostmem, &error_abort); +-} +- + static void nvdimm_class_init(ObjectClass *oc, void *data) + { + PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); +@@ -185,7 +180,6 @@ static void nvdimm_class_init(ObjectClass *oc, void *data) + + ddc->realize = nvdimm_realize; + ddc->get_memory_region = nvdimm_get_memory_region; +- ddc->get_vmstate_memory_region = nvdimm_get_vmstate_memory_region; + + nvc->read_label_data = nvdimm_read_label_data; + nvc->write_label_data = nvdimm_write_label_data; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-Support-firmware-configuration-with-blockdev.patch b/SOURCES/kvm-pc-Support-firmware-configuration-with-blockdev.patch new file mode 100644 index 0000000..d01f708 --- /dev/null +++ b/SOURCES/kvm-pc-Support-firmware-configuration-with-blockdev.patch @@ -0,0 +1,447 @@ +From 056788975c5ebe651d8016ec714d6120da4bedc7 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:17 +0200 +Subject: [PATCH 50/53] pc: Support firmware configuration with -blockdev +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-29-armbru@redhat.com> +Patchwork-id: 87999 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 28/31] pc: Support firmware configuration with -blockdev +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +The PC machines put firmware in ROM by default. To get it put into +flash memory (required by OVMF), you have to use -drive +if=pflash,unit=0,... and optionally -drive if=pflash,unit=1,... + +Why two -drive? This permits setting up one part of the flash memory +read-only, and the other part read/write. It also makes upgrading +firmware on the host easier. Below the hood, it creates two separate +flash devices, because we were too lazy to improve our flash device +models to support sector protection. + +The problem at hand is to do the same with -blockdev somehow, as one +more step towards deprecating -drive. + +Mapping -drive if=none,... to -blockdev is a solved problem. With +if=T other than if=none, -drive additionally configures a block device +frontend. For non-onboard devices, that part maps to -device. Also a +solved problem. For onboard devices such as PC flash memory, we have +an unsolved problem. + +This is actually an instance of a wider problem: our general device +configuration interface doesn't cover onboard devices. Instead, we have +a zoo of ad hoc interfaces that are much more limited. One of them is +-drive, which we'd rather deprecate, but can't until we have suitable +replacements for all its uses. + +Sadly, I can't attack the wider problem today. So back to the narrow +problem. + +My first idea was to reduce it to its solved buddy by using pluggable +instead of onboard devices for the flash memory. Workable, but it +requires some extra smarts in firmware descriptors and libvirt. Paolo +had an idea that is simpler for libvirt: keep the devices onboard, and +add machine properties for their block backends. + +The implementation is less than straightforward, I'm afraid. + +First, block backend properties are *qdev* properties. Machines can't +have those, as they're not devices. I could duplicate these qdev +properties as QOM properties, but I hate that. + +More seriously, the properties do not belong to the machine, they +belong to the onboard flash devices. Adding them to the machine would +then require bad magic to somehow transfer them to the flash devices. +Fortunately, QOM provides the means to handle exactly this case: add +alias properties to the machine that forward to the onboard devices' +properties. + +Properties need to be created in .instance_init() methods. For PC +machines, that's pc_machine_initfn(). To make alias properties work, +we need to create the onboard flash devices there, too. Requires +several bug fixes, in the previous commits. We also have to realize +the devices. More on that below. + +If the user sets pflash0, firmware resides in flash memory. +pc_system_firmware_init() maps and realizes the flash devices. + +Else, firmware resides in ROM. The onboard flash devices aren't used +then. pc_system_firmware_init() destroys them unrealized, along with +the alias properties. + +The existing code to pick up drives defined with -drive if=pflash is +replaced by code to desugar into the machine properties. + +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael S. Tsirkin +Message-Id: <87ftrtux81.fsf@dusky.pond.sub.org> +(cherry picked from commit ebc29e1beab02646702c8cb9a1d29b68f72ad503) +[Conflict in hw/i386/pc.c due to lack of commit f5878b03811, and in +hw/i386/pc_sysfw.c due to lack of commit d471bf3ebba and due to the +part of downstream commit 84733200df4 that came from c3f813d2f53] + +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc.c | 2 + + hw/i386/pc_sysfw.c | 248 +++++++++++++++++++++++++++++++++------------------ + include/hw/i386/pc.h | 3 + + 3 files changed, 164 insertions(+), 89 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 86e9d43..1f55a28 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -2249,6 +2249,8 @@ static void pc_machine_initfn(Object *obj) + pcms->smbus = true; + pcms->sata = true; + pcms->pit = true; ++ ++ pc_system_flash_create(pcms); + } + + static void pc_machine_reset(void) +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index 2a0e18c..a120342 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -28,6 +28,7 @@ + #include "sysemu/block-backend.h" + #include "qemu/error-report.h" + #include "qemu/option.h" ++#include "qemu/units.h" + #include "hw/sysbus.h" + #include "hw/hw.h" + #include "hw/i386/pc.h" +@@ -39,6 +40,17 @@ + + #define BIOS_FILENAME "bios.bin" + ++/* ++ * We don't have a theoretically justifiable exact lower bound on the base ++ * address of any flash mapping. In practice, the IO-APIC MMIO range is ++ * [0xFEE00000..0xFEE01000] -- see IO_APIC_DEFAULT_ADDRESS --, leaving free ++ * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in ++ * size. ++ */ ++#define FLASH_SIZE_LIMIT (8 * MiB) ++ ++#define FLASH_SECTOR_SIZE 4096 ++ + static void pc_isa_bios_init(MemoryRegion *rom_memory, + MemoryRegion *flash_mem, + int ram_size) +@@ -70,96 +82,118 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory, + memory_region_set_readonly(isa_bios, true); + } + +-#define FLASH_MAP_UNIT_MAX 2 ++static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms, ++ const char *name, ++ const char *alias_prop_name) ++{ ++ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + +-/* We don't have a theoretically justifiable exact lower bound on the base +- * address of any flash mapping. In practice, the IO-APIC MMIO range is +- * [0xFEE00000..0xFEE01000[ -- see IO_APIC_DEFAULT_ADDRESS --, leaving free +- * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in +- * size. +- */ +-#define FLASH_MAP_BASE_MIN ((hwaddr)(0x100000000ULL - 8*1024*1024)) ++ qdev_prop_set_uint64(dev, "sector-length", FLASH_SECTOR_SIZE); ++ qdev_prop_set_uint8(dev, "width", 1); ++ qdev_prop_set_string(dev, "name", name); ++ object_property_add_child(OBJECT(pcms), name, OBJECT(dev), ++ &error_abort); ++ object_property_add_alias(OBJECT(pcms), alias_prop_name, ++ OBJECT(dev), "drive", &error_abort); ++ return PFLASH_CFI01(dev); ++} + +-/* This function maps flash drives from 4G downward, in order of their unit +- * numbers. The mapping starts at unit#0, with unit number increments of 1, and +- * stops before the first missing flash drive, or before +- * unit#FLASH_MAP_UNIT_MAX, whichever is reached first. +- * +- * Addressing within one flash drive is of course not reversed. +- * +- * An error message is printed and the process exits if: +- * - the size of the backing file for a flash drive is non-positive, or not a +- * multiple of the required sector size, or +- * - the current mapping's base address would fall below FLASH_MAP_BASE_MIN. ++void pc_system_flash_create(PCMachineState *pcms) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); ++ ++ if (pcmc->pci_enabled) { ++ pcms->flash[0] = pc_pflash_create(pcms, "system.flash0", ++ "pflash0"); ++ pcms->flash[1] = pc_pflash_create(pcms, "system.flash1", ++ "pflash1"); ++ } ++} ++ ++static void pc_system_flash_cleanup_unused(PCMachineState *pcms) ++{ ++ char *prop_name; ++ int i; ++ Object *dev_obj; ++ ++ assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled); ++ ++ for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) { ++ dev_obj = OBJECT(pcms->flash[i]); ++ if (!object_property_get_bool(dev_obj, "realized", &error_abort)) { ++ prop_name = g_strdup_printf("pflash%d", i); ++ object_property_del(OBJECT(pcms), prop_name, &error_abort); ++ g_free(prop_name); ++ object_unparent(dev_obj); ++ pcms->flash[i] = NULL; ++ } ++ } ++} ++ ++/* ++ * Map the pcms->flash[] from 4GiB downward, and realize. ++ * Map them in descending order, i.e. pcms->flash[0] at the top, ++ * without gaps. ++ * Stop at the first pcms->flash[0] lacking a block backend. ++ * Set each flash's size from its block backend. Fatal error if the ++ * size isn't a non-zero multiple of 4KiB, or the total size exceeds ++ * FLASH_SIZE_LIMIT. + * +- * The drive with unit#0 (if available) is mapped at the highest address, and +- * it is passed to pc_isa_bios_init(). Merging several drives for isa-bios is ++ * If pcms->flash[0] has a block backend, its memory is passed to ++ * pc_isa_bios_init(). Merging several flash devices for isa-bios is + * not supported. + */ +-static void pc_system_flash_init(MemoryRegion *rom_memory) ++static void pc_system_flash_map(PCMachineState *pcms, ++ MemoryRegion *rom_memory) + { +- int unit; +- DriveInfo *pflash_drv; ++ hwaddr total_size = 0; ++ int i; + BlockBackend *blk; + int64_t size; +- char *fatal_errmsg = NULL; +- hwaddr phys_addr = 0x100000000ULL; +- uint32_t sector_size = 4096; + PFlashCFI01 *system_flash; + MemoryRegion *flash_mem; +- char name[64]; + void *flash_ptr; + int ret, flash_size; + +- for (unit = 0; +- (unit < FLASH_MAP_UNIT_MAX && +- (pflash_drv = drive_get(IF_PFLASH, 0, unit)) != NULL); +- ++unit) { +- blk = blk_by_legacy_dinfo(pflash_drv); ++ assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled); ++ ++ for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) { ++ system_flash = pcms->flash[i]; ++ blk = pflash_cfi01_get_blk(system_flash); ++ if (!blk) { ++ break; ++ } + size = blk_getlength(blk); + if (size < 0) { +- fatal_errmsg = g_strdup_printf("failed to get backing file size"); +- } else if (size == 0) { +- fatal_errmsg = g_strdup_printf("PC system firmware (pflash) " +- "cannot have zero size"); +- } else if ((size % sector_size) != 0) { +- fatal_errmsg = g_strdup_printf("PC system firmware (pflash) " +- "must be a multiple of 0x%x", sector_size); +- } else if (phys_addr < size || phys_addr - size < FLASH_MAP_BASE_MIN) { +- fatal_errmsg = g_strdup_printf("oversized backing file, pflash " +- "segments cannot be mapped under " +- TARGET_FMT_plx, FLASH_MAP_BASE_MIN); ++ error_report("can't get size of block device %s: %s", ++ blk_name(blk), strerror(-size)); ++ exit(1); + } +- if (fatal_errmsg != NULL) { +- Location loc; +- +- /* push a new, "none" location on the location stack; overwrite its +- * contents with the location saved in the option; print the error +- * (includes location); pop the top +- */ +- loc_push_none(&loc); +- if (pflash_drv->opts != NULL) { +- qemu_opts_loc_restore(pflash_drv->opts); +- } +- error_report("%s", fatal_errmsg); +- loc_pop(&loc); +- g_free(fatal_errmsg); ++ if (size == 0 || size % FLASH_SECTOR_SIZE != 0) { ++ error_report("system firmware block device %s has invalid size " ++ "%" PRId64, ++ blk_name(blk), size); ++ info_report("its size must be a non-zero multiple of 0x%x", ++ FLASH_SECTOR_SIZE); ++ exit(1); ++ } ++ if ((hwaddr)size != size ++ || total_size > HWADDR_MAX - size ++ || total_size + size > FLASH_SIZE_LIMIT) { ++ error_report("combined size of system firmware exceeds " ++ "%" PRIu64 " bytes", ++ FLASH_SIZE_LIMIT); + exit(1); + } + +- phys_addr -= size; +- +- /* pflash_cfi01_register() creates a deep copy of the name */ +- snprintf(name, sizeof name, "system.flash%d", unit); +- system_flash = pflash_cfi01_register(phys_addr, name, +- size, blk, sector_size, +- 1 /* width */, +- 0x0000 /* id0 */, +- 0x0000 /* id1 */, +- 0x0000 /* id2 */, +- 0x0000 /* id3 */, +- 0 /* be */); +- if (unit == 0) { ++ total_size += size; ++ qdev_prop_set_uint32(DEVICE(system_flash), "num-blocks", ++ size / FLASH_SECTOR_SIZE); ++ qdev_init_nofail(DEVICE(system_flash)); ++ sysbus_mmio_map(SYS_BUS_DEVICE(system_flash), 0, ++ 0x100000000ULL - total_size); ++ ++ if (i == 0) { + flash_mem = pflash_cfi01_get_memory(system_flash); + pc_isa_bios_init(rom_memory, flash_mem, size); + +@@ -244,32 +278,68 @@ void pc_system_firmware_init(PCMachineState *pcms, + MemoryRegion *rom_memory) + { + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); +- bool isapc_ram_fw = !pcmc->pci_enabled; ++ int i; + DriveInfo *pflash_drv; ++ BlockBackend *pflash_blk[ARRAY_SIZE(pcms->flash)]; ++ Location loc; + +- pflash_drv = drive_get(IF_PFLASH, 0, 0); +- +- if (isapc_ram_fw || pflash_drv == NULL) { +- /* When a pflash drive is not found, use rom-mode */ +- old_pc_system_rom_init(rom_memory, isapc_ram_fw); ++ if (!pcmc->pci_enabled) { ++ old_pc_system_rom_init(rom_memory, true); + return; + } + +- if (shadow_bios_after_incoming) { +- MachineClass *mc; ++ /* Map legacy -drive if=pflash to machine properties */ ++ for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) { ++ pflash_blk[i] = pflash_cfi01_get_blk(pcms->flash[i]); ++ pflash_drv = drive_get(IF_PFLASH, 0, i); ++ if (!pflash_drv) { ++ continue; ++ } ++ loc_push_none(&loc); ++ qemu_opts_loc_restore(pflash_drv->opts); ++ if (pflash_blk[i]) { ++ error_report("clashes with -machine"); ++ exit(1); ++ } ++ pflash_blk[i] = blk_by_legacy_dinfo(pflash_drv); ++ qdev_prop_set_drive(DEVICE(pcms->flash[i]), ++ "drive", pflash_blk[i], &error_fatal); ++ loc_pop(&loc); ++ } + +- mc = MACHINE_GET_CLASS(current_machine); +- error_report("flash-based firmware is not supported by machine %s", +- mc->name); +- exit(1); ++ /* Reject gaps */ ++ for (i = 1; i < ARRAY_SIZE(pcms->flash); i++) { ++ if (pflash_blk[i] && !pflash_blk[i - 1]) { ++ error_report("pflash%d requires pflash%d", i, i - 1); ++ exit(1); ++ } + } + +- if (kvm_enabled() && !kvm_readonly_mem_enabled()) { +- /* Older KVM cannot execute from device memory. So, flash memory +- * cannot be used unless the readonly memory kvm capability is present. */ +- fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n"); +- exit(1); ++ if (!pflash_blk[0]) { ++ /* Machine property pflash0 not set, use ROM mode */ ++ old_pc_system_rom_init(rom_memory, false); ++ } else { ++ if (shadow_bios_after_incoming) { ++ MachineClass *mc; ++ ++ mc = MACHINE_GET_CLASS(current_machine); ++ error_report("flash-based firmware is not supported by machine %s", ++ mc->name); ++ exit(1); ++ } ++ ++ if (kvm_enabled() && !kvm_readonly_mem_enabled()) { ++ /* ++ * Older KVM cannot execute from device memory. So, flash ++ * memory cannot be used unless the readonly memory kvm ++ * capability is present. ++ */ ++ error_report("pflash with kvm requires KVM readonly memory support"); ++ exit(1); ++ } ++ ++ pc_system_flash_map(pcms, rom_memory); + } + +- pc_system_flash_init(rom_memory); ++ pc_system_flash_cleanup_unused(pcms); + } +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index 611e111..b91b95d 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -6,6 +6,7 @@ + #include "hw/boards.h" + #include "hw/isa/isa.h" + #include "hw/block/fdc.h" ++#include "hw/block/flash.h" + #include "net/net.h" + #include "hw/i386/ioapic.h" + +@@ -41,6 +42,7 @@ struct PCMachineState { + PCIBus *bus; + FWCfgState *fw_cfg; + qemu_irq *gsi; ++ PFlashCFI01 *flash[2]; + + /* Configuration options: */ + uint64_t max_ram_below_4g; +@@ -290,6 +292,7 @@ extern PCIDevice *piix4_dev; + int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); + + /* pc_sysfw.c */ ++void pc_system_flash_create(PCMachineState *pcms); + void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); + + /* acpi-build.c */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-dimm-turn-alignment-assert-into-check.patch b/SOURCES/kvm-pc-dimm-turn-alignment-assert-into-check.patch new file mode 100644 index 0000000..9b1025f --- /dev/null +++ b/SOURCES/kvm-pc-dimm-turn-alignment-assert-into-check.patch @@ -0,0 +1,76 @@ +From 84d49bc7469905877fc22f6faea1e53c8c0cbe1c Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Fri, 21 Sep 2018 09:19:39 +0200 +Subject: [PATCH 03/22] pc-dimm: turn alignment assert into check + +RH-Author: David Hildenbrand +Message-id: <20180921091939.4107-1-david@redhat.com> +Patchwork-id: 82227 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] pc-dimm: turn alignment assert into check +Bugzilla: 1629720 +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Igor Mammedov +RH-Acked-by: Paolo Bonzini + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1629720 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=18439425 +Upstream: 4d8938a05db15dea2c86c4ab9c5f872f160d2188 + +The start of the address space indicates which maximum alignment is +supported by our machine (e.g. ppc, x86 1GB). This is helpful to +catch fragmenting guest physical memory in strange fashions. + +Right now we can crash QEMU by e.g. (there might be easier examples) + +qemu-system-x86_64 -m 256M,maxmem=20G,slots=2 \ + -object memory-backend-file,id=mem0,size=8192M,mem-path=/dev/zero,align=8192M \ + -device pc-dimm,id=dimm1,memdev=mem0 + +Backport conflicts: + hw/mem/memory-device.c: The memory device refactoring is part of 3.0 + and probably not worth backporting to 7.X. + So fix it in previous pc-dimm code. +Note: The upstream patch missed a "x" (0% .. vs. 0x% ..), will fix that + upstream, too. + +Signed-off-by: David Hildenbrand +Message-Id: <20180607154705.6316-2-david@redhat.com> +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Igor Mammedov +Signed-off-by: Paolo Bonzini +(cherry picked from commit 4d8938a05db15dea2c86c4ab9c5f872f160d2188) +Signed-off-by: David Hildenbrand +Signed-off-by: Miroslav Rezanina +--- + hw/mem/pc-dimm.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c +index 51350d9..a9d7c51 100644 +--- a/hw/mem/pc-dimm.c ++++ b/hw/mem/pc-dimm.c +@@ -298,14 +298,19 @@ uint64_t pc_dimm_get_free_addr(uint64_t address_space_start, + uint64_t new_addr, ret = 0; + uint64_t address_space_end = address_space_start + address_space_size; + +- g_assert(QEMU_ALIGN_UP(address_space_start, align) == address_space_start); +- + if (!address_space_size) { + error_setg(errp, "memory hotplug is not enabled, " + "please add maxmem option"); + goto out; + } + ++ /* address_space_start indicates the maximum alignment we expect */ ++ if (QEMU_ALIGN_UP(address_space_start, align) != address_space_start) { ++ error_setg(errp, "the alignment (0x%" PRIx64 ") is not supported", ++ align); ++ goto out; ++ } ++ + if (hint && QEMU_ALIGN_UP(*hint, align) != *hint) { + error_setg(errp, "address must be aligned to 0x%" PRIx64 " bytes", + align); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc_sysfw-Pass-PCMachineState-to-pc_system_firmware_i.patch b/SOURCES/kvm-pc_sysfw-Pass-PCMachineState-to-pc_system_firmware_i.patch new file mode 100644 index 0000000..47c2168 --- /dev/null +++ b/SOURCES/kvm-pc_sysfw-Pass-PCMachineState-to-pc_system_firmware_i.patch @@ -0,0 +1,85 @@ +From 5991cbe99b2faf035522ec4910524421a34d9f14 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:16 +0200 +Subject: [PATCH 49/53] pc_sysfw: Pass PCMachineState to + pc_system_firmware_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-28-armbru@redhat.com> +Patchwork-id: 87988 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 27/31] pc_sysfw: Pass PCMachineState to pc_system_firmware_init() +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Philippe Mathieu-Daudé + +pc_system_firmware_init() parameter @isapc_ram_fw is PCMachineState +member pci_enabled negated. The next commit will need more of +PCMachineState. To prepare for that, pass a PCMachineState *, and +drop the now redundant parameter @isapc_ram_fw. + +Signed-off-by: Markus Armbruster +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Laszlo Ersek +Message-Id: <20190308131445.17502-11-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit 5e640a9e78ea61c50401a2b11fa144b5f0c217dc) +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc.c | 2 +- + hw/i386/pc_sysfw.c | 5 ++++- + include/hw/i386/pc.h | 3 +-- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 7160969..86e9d43 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1413,7 +1413,7 @@ void pc_memory_init(PCMachineState *pcms, + } + + /* Initialize PC system firmware */ +- pc_system_firmware_init(rom_memory, !pcmc->pci_enabled); ++ pc_system_firmware_init(pcms, rom_memory); + + option_rom_mr = g_malloc(sizeof(*option_rom_mr)); + memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index d40d727..2a0e18c 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -240,8 +240,11 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) + bios); + } + +-void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw) ++void pc_system_firmware_init(PCMachineState *pcms, ++ MemoryRegion *rom_memory) + { ++ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); ++ bool isapc_ram_fw = !pcmc->pci_enabled; + DriveInfo *pflash_drv; + + pflash_drv = drive_get(IF_PFLASH, 0, 0); +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index 1e9f252..611e111 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -290,8 +290,7 @@ extern PCIDevice *piix4_dev; + int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); + + /* pc_sysfw.c */ +-void pc_system_firmware_init(MemoryRegion *rom_memory, +- bool isapc_ram_fw); ++void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory); + + /* acpi-build.c */ + void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc_sysfw-Remove-unused-PcSysFwDevice.patch b/SOURCES/kvm-pc_sysfw-Remove-unused-PcSysFwDevice.patch new file mode 100644 index 0000000..e4d8009 --- /dev/null +++ b/SOURCES/kvm-pc_sysfw-Remove-unused-PcSysFwDevice.patch @@ -0,0 +1,51 @@ +From 546c38d9ecd455af7962cbe555c4304bb519f215 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:15 +0200 +Subject: [PATCH 48/53] pc_sysfw: Remove unused PcSysFwDevice +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-27-armbru@redhat.com> +Patchwork-id: 88010 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 26/31] pc_sysfw: Remove unused PcSysFwDevice +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Philippe Mathieu-Daudé + +This structure is not used since commit 6dd2a5c98a. + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Laszlo Ersek +Signed-off-by: Markus Armbruster +Message-Id: <20190308131445.17502-10-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit d6edbe91b98e3e6e0d0185a9c4c3d2e6d6bf0a6b) +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc_sysfw.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index 20eed89..d40d727 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -39,11 +39,6 @@ + + #define BIOS_FILENAME "bios.bin" + +-typedef struct PcSysFwDevice { +- SysBusDevice busdev; +- uint8_t isapc_ram_fw; +-} PcSysFwDevice; +- + static void pc_isa_bios_init(MemoryRegion *rom_memory, + MemoryRegion *flash_mem, + int ram_size) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash-Clean-up-after-commit-368a354f02b-part-1.patch b/SOURCES/kvm-pflash-Clean-up-after-commit-368a354f02b-part-1.patch new file mode 100644 index 0000000..ad5f352 --- /dev/null +++ b/SOURCES/kvm-pflash-Clean-up-after-commit-368a354f02b-part-1.patch @@ -0,0 +1,426 @@ +From 267bac031b2b6e5faf270f4af195b18820162ddb Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:05 +0200 +Subject: [PATCH 38/53] pflash: Clean up after commit 368a354f02b, part 1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-17-armbru@redhat.com> +Patchwork-id: 88000 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 16/31] pflash: Clean up after commit 368a354f02b, part 1 +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +QOMification left parameter @qdev unused in pflash_cfi01_register() +and pflash_cfi02_register(). All callers pass NULL. Remove. + +Signed-off-by: Markus Armbruster +Reviewed-by: Laszlo Ersek +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +Tested-by: Philippe Mathieu-Daudé +Message-Id: <20190308094610.21210-15-armbru@redhat.com> +(cherry picked from commit 940d5b132fab085bd8ec2bcfa5c1dd119785b217) +Signed-off-by: Miroslav Rezanina +--- + hw/arm/collie.c | 4 ++-- + hw/arm/digic_boards.c | 2 +- + hw/arm/gumstix.c | 4 ++-- + hw/arm/mainstone.c | 2 +- + hw/arm/musicpal.c | 4 ++-- + hw/arm/omap_sx1.c | 4 ++-- + hw/arm/versatilepb.c | 2 +- + hw/arm/xilinx_zynq.c | 2 +- + hw/arm/z2.c | 3 +-- + hw/block/pflash_cfi01.c | 2 +- + hw/block/pflash_cfi02.c | 2 +- + hw/i386/pc_sysfw.c | 2 +- + hw/lm32/lm32_boards.c | 4 ++-- + hw/lm32/milkymist.c | 2 +- + hw/microblaze/petalogix_ml605_mmu.c | 3 +-- + hw/microblaze/petalogix_s3adsp1800_mmu.c | 2 +- + hw/mips/mips_malta.c | 2 +- + hw/mips/mips_r4k.c | 2 +- + hw/ppc/ppc405_boards.c | 6 +++--- + hw/ppc/sam460ex.c | 2 +- + hw/ppc/virtex_ml507.c | 2 +- + hw/sh4/r2d.c | 2 +- + include/hw/block/flash.h | 4 ++-- + 23 files changed, 31 insertions(+), 33 deletions(-) + +diff --git a/hw/arm/collie.c b/hw/arm/collie.c +index f8c566e..9cf4538 100644 +--- a/hw/arm/collie.c ++++ b/hw/arm/collie.c +@@ -37,12 +37,12 @@ static void collie_init(MachineState *machine) + s = sa1110_init(sysmem, collie_binfo.ram_size, machine->cpu_type); + + dinfo = drive_get(IF_PFLASH, 0, 0); +- pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000, ++ pflash_cfi01_register(SA_CS0, "collie.fl1", 0x02000000, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + dinfo = drive_get(IF_PFLASH, 0, 1); +- pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000, ++ pflash_cfi01_register(SA_CS1, "collie.fl2", 0x02000000, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + +diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c +index 9f11dcd..15a00a1 100644 +--- a/hw/arm/digic_boards.c ++++ b/hw/arm/digic_boards.c +@@ -129,7 +129,7 @@ static void digic4_add_k8p3215uqb_rom(DigicBoardState *s, hwaddr addr, + #define FLASH_K8P3215UQB_SIZE (4 * 1024 * 1024) + #define FLASH_K8P3215UQB_SECTOR_SIZE (64 * 1024) + +- pflash_cfi02_register(addr, NULL, "pflash", FLASH_K8P3215UQB_SIZE, ++ pflash_cfi02_register(addr, "pflash", FLASH_K8P3215UQB_SIZE, + NULL, FLASH_K8P3215UQB_SECTOR_SIZE, + FLASH_K8P3215UQB_SIZE / FLASH_K8P3215UQB_SECTOR_SIZE, + DIGIC4_ROM_MAX_SIZE / FLASH_K8P3215UQB_SIZE, +diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c +index ea2a3c5..68a0376 100644 +--- a/hw/arm/gumstix.c ++++ b/hw/arm/gumstix.c +@@ -73,7 +73,7 @@ static void connex_init(MachineState *machine) + #else + be = 0; + #endif +- if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom, ++ if (!pflash_cfi01_register(0x00000000, "connext.rom", connex_rom, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + sector_len, connex_rom / sector_len, + 2, 0, 0, 0, 0, be)) { +@@ -110,7 +110,7 @@ static void verdex_init(MachineState *machine) + #else + be = 0; + #endif +- if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom, ++ if (!pflash_cfi01_register(0x00000000, "verdex.rom", verdex_rom, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + sector_len, verdex_rom / sector_len, + 2, 0, 0, 0, 0, be)) { +diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c +index 4215c02..cb1116b 100644 +--- a/hw/arm/mainstone.c ++++ b/hw/arm/mainstone.c +@@ -149,7 +149,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, + exit(1); + } + +- if (!pflash_cfi01_register(mainstone_flash_base[i], NULL, ++ if (!pflash_cfi01_register(mainstone_flash_base[i], + i ? "mainstone.flash1" : "mainstone.flash0", + MAINSTONE_FLASH, + blk_by_legacy_dinfo(dinfo), +diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c +index 38d7322..fd7a7a9 100644 +--- a/hw/arm/musicpal.c ++++ b/hw/arm/musicpal.c +@@ -1637,14 +1637,14 @@ static void musicpal_init(MachineState *machine) + * image is smaller than 32 MB. + */ + #ifdef TARGET_WORDS_BIGENDIAN +- pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, ++ pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, + "musicpal.flash", flash_size, + blk, 0x10000, (flash_size + 0xffff) >> 16, + MP_FLASH_SIZE_MAX / flash_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA, 1); + #else +- pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, ++ pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, + "musicpal.flash", flash_size, + blk, 0x10000, (flash_size + 0xffff) >> 16, + MP_FLASH_SIZE_MAX / flash_size, +diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c +index eccc19c..a7a3e7d 100644 +--- a/hw/arm/omap_sx1.c ++++ b/hw/arm/omap_sx1.c +@@ -153,7 +153,7 @@ static void sx1_init(MachineState *machine, const int version) + #endif + + if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { +- if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL, ++ if (!pflash_cfi01_register(OMAP_CS0_BASE, + "omap_sx1.flash0-1", flash_size, + blk_by_legacy_dinfo(dinfo), + sector_size, flash_size / sector_size, +@@ -177,7 +177,7 @@ static void sx1_init(MachineState *machine, const int version) + memory_region_add_subregion(address_space, + OMAP_CS1_BASE + flash1_size, &cs[1]); + +- if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL, ++ if (!pflash_cfi01_register(OMAP_CS1_BASE, + "omap_sx1.flash1-1", flash1_size, + blk_by_legacy_dinfo(dinfo), + sector_size, flash1_size / sector_size, +diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c +index 418792c..99d8ff9 100644 +--- a/hw/arm/versatilepb.c ++++ b/hw/arm/versatilepb.c +@@ -358,7 +358,7 @@ static void versatile_init(MachineState *machine, int board_id) + /* 0x34000000 NOR Flash */ + + dinfo = drive_get(IF_PFLASH, 0, 0); +- if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash", ++ if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, "versatile.flash", + VERSATILE_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + VERSATILE_FLASH_SECT_SIZE, +diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c +index 0f76333..4a05e1c 100644 +--- a/hw/arm/xilinx_zynq.c ++++ b/hw/arm/xilinx_zynq.c +@@ -206,7 +206,7 @@ static void zynq_init(MachineState *machine) + DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); + + /* AMD */ +- pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE, ++ pflash_cfi02_register(0xe2000000, "zynq.pflash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + FLASH_SECTOR_SIZE, + FLASH_SIZE/FLASH_SECTOR_SIZE, 1, +diff --git a/hw/arm/z2.c b/hw/arm/z2.c +index 730a539..f5f1903 100644 +--- a/hw/arm/z2.c ++++ b/hw/arm/z2.c +@@ -325,8 +325,7 @@ static void z2_init(MachineState *machine) + exit(1); + } + +- if (!pflash_cfi01_register(Z2_FLASH_BASE, +- NULL, "z2.flash0", Z2_FLASH_SIZE, ++ if (!pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + sector_len, Z2_FLASH_SIZE / sector_len, + 4, 0, 0, 0, 0, be)) { +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index dbd3b9d..31926e2 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -950,7 +950,7 @@ static void pflash_cfi01_register_types(void) + type_init(pflash_cfi01_register_types) + + PFlashCFI01 *pflash_cfi01_register(hwaddr base, +- DeviceState *qdev, const char *name, ++ const char *name, + hwaddr size, + BlockBackend *blk, + uint32_t sector_len, int nb_blocs, +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index b9e0448..8c6c6e1 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -786,7 +786,7 @@ static void pflash_cfi02_register_types(void) + type_init(pflash_cfi02_register_types) + + PFlashCFI02 *pflash_cfi02_register(hwaddr base, +- DeviceState *qdev, const char *name, ++ const char *name, + hwaddr size, + BlockBackend *blk, + uint32_t sector_len, int nb_blocs, +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index d8a98f3..721a867 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -159,7 +159,7 @@ static void pc_system_flash_init(MemoryRegion *rom_memory) + + /* pflash_cfi01_register() creates a deep copy of the name */ + snprintf(name, sizeof name, "system.flash%d", unit); +- system_flash = pflash_cfi01_register(phys_addr, NULL /* qdev */, name, ++ system_flash = pflash_cfi01_register(phys_addr, name, + size, blk, sector_size, + size >> sector_bits, + 1 /* width */, +diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c +index 527bcc2..0a1b6e9 100644 +--- a/hw/lm32/lm32_boards.c ++++ b/hw/lm32/lm32_boards.c +@@ -114,7 +114,7 @@ static void lm32_evr_init(MachineState *machine) + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Spansion S29NS128P */ +- pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size, ++ pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + flash_sector_size, flash_size / flash_sector_size, + 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); +@@ -206,7 +206,7 @@ static void lm32_uclinux_init(MachineState *machine) + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Spansion S29NS128P */ +- pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size, ++ pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + flash_sector_size, flash_size / flash_sector_size, + 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); +diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c +index 85d64fe..3e38313 100644 +--- a/hw/lm32/milkymist.c ++++ b/hw/lm32/milkymist.c +@@ -121,7 +121,7 @@ milkymist_init(MachineState *machine) + + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Numonyx JS28F256J3F105 */ +- pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size, ++ pflash_cfi01_register(flash_base, "milkymist.flash", flash_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + flash_sector_size, flash_size / flash_sector_size, + 2, 0x00, 0x89, 0x00, 0x1d, 1); +diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c +index b664dc0..a2bc9fc 100644 +--- a/hw/microblaze/petalogix_ml605_mmu.c ++++ b/hw/microblaze/petalogix_ml605_mmu.c +@@ -107,8 +107,7 @@ petalogix_ml605_init(MachineState *machine) + dinfo = drive_get(IF_PFLASH, 0, 0); + /* 5th parameter 2 means bank-width + * 10th paremeter 0 means little-endian */ +- pflash_cfi01_register(FLASH_BASEADDR, +- NULL, "petalogix_ml605.flash", FLASH_SIZE, ++ pflash_cfi01_register(FLASH_BASEADDR, "petalogix_ml605.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + (64 * 1024), FLASH_SIZE >> 16, + 2, 0x89, 0x18, 0x0000, 0x0, 0); +diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c +index 5cb4deb..37090c5 100644 +--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c ++++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c +@@ -86,7 +86,7 @@ petalogix_s3adsp1800_init(MachineState *machine) + + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(FLASH_BASEADDR, +- NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE, ++ "petalogix_s3adsp1800.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + (64 * 1024), FLASH_SIZE >> 16, + 1, 0x89, 0x18, 0x0000, 0x0, 1); +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index e46a252..6b09258 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -1062,7 +1062,7 @@ void mips_malta_init(MachineState *machine) + + /* Load firmware in flash / BIOS. */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); +- fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", ++ fl = pflash_cfi01_register(FLASH_ADDRESS, "mips_malta.bios", + FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 65536, FLASH_SIZE >> 16, +diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c +index aeadc4a..4ac5471 100644 +--- a/hw/mips/mips_r4k.c ++++ b/hw/mips/mips_r4k.c +@@ -234,7 +234,7 @@ void mips_r4k_init(MachineState *machine) + load_image_targphys(filename, 0x1fc00000, BIOS_SIZE); + } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) { + uint32_t mips_rom = 0x00400000; +- if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom, ++ if (!pflash_cfi01_register(0x1fc00000, "mips_r4k.bios", mips_rom, + blk_by_legacy_dinfo(dinfo), + sector_len, mips_rom / sector_len, + 4, 0, 0, 0, 0, be)) { +diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c +index bf32672..d2ad8cd 100644 +--- a/hw/ppc/ppc405_boards.c ++++ b/hw/ppc/ppc405_boards.c +@@ -229,7 +229,7 @@ static void ref405ep_init(MachineState *machine) + if (dinfo) { + bios_size = 8 * MiB; + pflash_cfi02_register((uint32_t)(-bios_size), +- NULL, "ef405ep.bios", bios_size, ++ "ef405ep.bios", bios_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 64 * KiB, bios_size / (64 * KiB), 1, + 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, +@@ -500,7 +500,7 @@ static void taihu_405ep_init(MachineState *machine) + if (dinfo) { + bios_size = 2 * MiB; + pflash_cfi02_register(0xFFE00000, +- NULL, "taihu_405ep.bios", bios_size, ++ "taihu_405ep.bios", bios_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 64 * KiB, bios_size / (64 * KiB), 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, +@@ -534,7 +534,7 @@ static void taihu_405ep_init(MachineState *machine) + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + if (dinfo) { + bios_size = 32 * MiB; +- pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size, ++ pflash_cfi02_register(0xfc000000, "taihu_405ep.flash", bios_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 64 * KiB, bios_size / (64 * KiB), 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, +diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c +index 83c6e90..0c1790f 100644 +--- a/hw/ppc/sam460ex.c ++++ b/hw/ppc/sam460ex.c +@@ -234,7 +234,7 @@ static int sam460ex_load_uboot(void) + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (!pflash_cfi01_register(FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32), +- NULL, "sam460ex.flash", FLASH_SIZE, ++ "sam460ex.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 64 * KiB, FLASH_SIZE / (64 * KiB), + 1, 0x89, 0x18, 0x0000, 0x0, 1)) { +diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c +index 77a1778..66fa766 100644 +--- a/hw/ppc/virtex_ml507.c ++++ b/hw/ppc/virtex_ml507.c +@@ -235,7 +235,7 @@ static void virtex_init(MachineState *machine) + memory_region_add_subregion(address_space_mem, ram_base, phys_ram); + + dinfo = drive_get(IF_PFLASH, 0, 0); +- pflash_cfi01_register(PFLASH_BASEADDR, NULL, "virtex.flash", FLASH_SIZE, ++ pflash_cfi01_register(PFLASH_BASEADDR, "virtex.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + (64 * 1024), FLASH_SIZE >> 16, + 1, 0x89, 0x18, 0x0000, 0x0, 1); +diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c +index befb582..7016d6f 100644 +--- a/hw/sh4/r2d.c ++++ b/hw/sh4/r2d.c +@@ -298,7 +298,7 @@ static void r2d_init(MachineState *machine) + * addressable in words of 16bit. + */ + dinfo = drive_get(IF_PFLASH, 0, 0); +- pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE, ++ pflash_cfi02_register(0x0, "r2d.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + 64 * KiB, FLASH_SIZE >> 16, + 1, 2, 0x0001, 0x227e, 0x2220, 0x2200, +diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h +index aeea3ca..3e48901 100644 +--- a/include/hw/block/flash.h ++++ b/include/hw/block/flash.h +@@ -14,7 +14,7 @@ + typedef struct PFlashCFI01 PFlashCFI01; + + PFlashCFI01 *pflash_cfi01_register(hwaddr base, +- DeviceState *qdev, const char *name, ++ const char *name, + hwaddr size, + BlockBackend *blk, + uint32_t sector_len, int nb_blocs, +@@ -33,7 +33,7 @@ MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl); + typedef struct PFlashCFI02 PFlashCFI02; + + PFlashCFI02 *pflash_cfi02_register(hwaddr base, +- DeviceState *qdev, const char *name, ++ const char *name, + hwaddr size, + BlockBackend *blk, + uint32_t sector_len, int nb_blocs, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash-Clean-up-after-commit-368a354f02b-part-2.patch b/SOURCES/kvm-pflash-Clean-up-after-commit-368a354f02b-part-2.patch new file mode 100644 index 0000000..f0f646a --- /dev/null +++ b/SOURCES/kvm-pflash-Clean-up-after-commit-368a354f02b-part-2.patch @@ -0,0 +1,504 @@ +From b64a99d86f7f10387f207b3fc52d04b6f1f0a818 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:06 +0200 +Subject: [PATCH 39/53] pflash: Clean up after commit 368a354f02b, part 2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-18-armbru@redhat.com> +Patchwork-id: 88006 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 17/31] pflash: Clean up after commit 368a354f02b, part 2 +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +Our pflash devices are simplistically modelled has having +"num-blocks" sectors of equal size "sector-length". Real hardware +commonly has sectors of different sizes. How our "sector-length" +property is related to the physical device's multiple sector sizes +is unclear. + +Helper functions pflash_cfi01_register() and pflash_cfi02_register() +create a pflash device, set properties including "sector-length" and +"num-blocks", and realize. They take parameters @size, @sector_len +and @nb_blocs. + +QOMification left parameter @size unused. Obviously, @size should +match @sector_len and @nb_blocs, i.e. size == sector_len * nb_blocs. +All callers satisfy this. + +Remove @nb_blocs and compute it from @size and @sector_len. + +Signed-off-by: Markus Armbruster +Reviewed-by: Laszlo Ersek +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-16-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit ce14710f4fdfca32123d7efd3ddcbee984ef0ae5) +[Trivial conflicts in hw/microblaze/petalogix_ml605_mmu.c, +hw/microblaze/petalogix_s3adsp1800_mmu.c, and hw/ppc/virtex_ml507.c +due to lack of commit ab3dd749241. Trivial conflict in +hw/ppc/sam460ex.c due to lack of commit 371b74e2215.] + +Signed-off-by: Miroslav Rezanina +--- + hw/arm/collie.c | 5 +++-- + hw/arm/digic_boards.c | 1 - + hw/arm/gumstix.c | 6 ++---- + hw/arm/mainstone.c | 3 +-- + hw/arm/musicpal.c | 4 ++-- + hw/arm/omap_sx1.c | 6 ++---- + hw/arm/versatilepb.c | 1 - + hw/arm/xilinx_zynq.c | 5 ++--- + hw/arm/z2.c | 3 +-- + hw/block/pflash_cfi01.c | 5 +++-- + hw/block/pflash_cfi02.c | 5 +++-- + hw/i386/pc_sysfw.c | 6 +----- + hw/lm32/lm32_boards.c | 4 ++-- + hw/lm32/milkymist.c | 3 +-- + hw/microblaze/petalogix_ml605_mmu.c | 3 +-- + hw/microblaze/petalogix_s3adsp1800_mmu.c | 3 +-- + hw/mips/mips_malta.c | 2 +- + hw/mips/mips_r4k.c | 3 +-- + hw/ppc/ppc405_boards.c | 6 +++--- + hw/ppc/sam460ex.c | 5 ++--- + hw/ppc/virtex_ml507.c | 3 +-- + hw/sh4/r2d.c | 3 +-- + include/hw/block/flash.h | 4 ++-- + 23 files changed, 36 insertions(+), 53 deletions(-) + +diff --git a/hw/arm/collie.c b/hw/arm/collie.c +index 9cf4538..29cacd8 100644 +--- a/hw/arm/collie.c ++++ b/hw/arm/collie.c +@@ -9,6 +9,7 @@ + * GNU GPL, version 2 or (at your option) any later version. + */ + #include "qemu/osdep.h" ++#include "qemu/units.h" + #include "hw/hw.h" + #include "hw/sysbus.h" + #include "hw/boards.h" +@@ -39,12 +40,12 @@ static void collie_init(MachineState *machine) + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(SA_CS0, "collie.fl1", 0x02000000, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0); ++ 64 * KiB, 4, 0x00, 0x00, 0x00, 0x00, 0); + + dinfo = drive_get(IF_PFLASH, 0, 1); + pflash_cfi01_register(SA_CS1, "collie.fl2", 0x02000000, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0); ++ 64 * KiB, 4, 0x00, 0x00, 0x00, 0x00, 0); + + sysbus_create_simple("scoop", 0x40800000, NULL); + +diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c +index 15a00a1..304e4d1 100644 +--- a/hw/arm/digic_boards.c ++++ b/hw/arm/digic_boards.c +@@ -131,7 +131,6 @@ static void digic4_add_k8p3215uqb_rom(DigicBoardState *s, hwaddr addr, + + pflash_cfi02_register(addr, "pflash", FLASH_K8P3215UQB_SIZE, + NULL, FLASH_K8P3215UQB_SECTOR_SIZE, +- FLASH_K8P3215UQB_SIZE / FLASH_K8P3215UQB_SECTOR_SIZE, + DIGIC4_ROM_MAX_SIZE / FLASH_K8P3215UQB_SIZE, + 4, + 0x00EC, 0x007E, 0x0003, 0x0001, +diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c +index 68a0376..03f6ef0 100644 +--- a/hw/arm/gumstix.c ++++ b/hw/arm/gumstix.c +@@ -75,8 +75,7 @@ static void connex_init(MachineState *machine) + #endif + if (!pflash_cfi01_register(0x00000000, "connext.rom", connex_rom, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- sector_len, connex_rom / sector_len, +- 2, 0, 0, 0, 0, be)) { ++ sector_len, 2, 0, 0, 0, 0, be)) { + error_report("Error registering flash memory"); + exit(1); + } +@@ -112,8 +111,7 @@ static void verdex_init(MachineState *machine) + #endif + if (!pflash_cfi01_register(0x00000000, "verdex.rom", verdex_rom, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- sector_len, verdex_rom / sector_len, +- 2, 0, 0, 0, 0, be)) { ++ sector_len, 2, 0, 0, 0, 0, be)) { + error_report("Error registering flash memory"); + exit(1); + } +diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c +index cb1116b..62cca6a 100644 +--- a/hw/arm/mainstone.c ++++ b/hw/arm/mainstone.c +@@ -153,8 +153,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, + i ? "mainstone.flash1" : "mainstone.flash0", + MAINSTONE_FLASH, + blk_by_legacy_dinfo(dinfo), +- sector_len, MAINSTONE_FLASH / sector_len, +- 4, 0, 0, 0, 0, be)) { ++ sector_len, 4, 0, 0, 0, 0, be)) { + error_report("Error registering flash memory"); + exit(1); + } +diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c +index fd7a7a9..bf8062b 100644 +--- a/hw/arm/musicpal.c ++++ b/hw/arm/musicpal.c +@@ -1639,14 +1639,14 @@ static void musicpal_init(MachineState *machine) + #ifdef TARGET_WORDS_BIGENDIAN + pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, + "musicpal.flash", flash_size, +- blk, 0x10000, (flash_size + 0xffff) >> 16, ++ blk, 0x10000, + MP_FLASH_SIZE_MAX / flash_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA, 1); + #else + pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, + "musicpal.flash", flash_size, +- blk, 0x10000, (flash_size + 0xffff) >> 16, ++ blk, 0x10000, + MP_FLASH_SIZE_MAX / flash_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA, 0); +diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c +index a7a3e7d..082d811 100644 +--- a/hw/arm/omap_sx1.c ++++ b/hw/arm/omap_sx1.c +@@ -156,8 +156,7 @@ static void sx1_init(MachineState *machine, const int version) + if (!pflash_cfi01_register(OMAP_CS0_BASE, + "omap_sx1.flash0-1", flash_size, + blk_by_legacy_dinfo(dinfo), +- sector_size, flash_size / sector_size, +- 4, 0, 0, 0, 0, be)) { ++ sector_size, 4, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory %d.\n", + fl_idx); + } +@@ -180,8 +179,7 @@ static void sx1_init(MachineState *machine, const int version) + if (!pflash_cfi01_register(OMAP_CS1_BASE, + "omap_sx1.flash1-1", flash1_size, + blk_by_legacy_dinfo(dinfo), +- sector_size, flash1_size / sector_size, +- 4, 0, 0, 0, 0, be)) { ++ sector_size, 4, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory %d.\n", + fl_idx); + } +diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c +index 99d8ff9..acb408d 100644 +--- a/hw/arm/versatilepb.c ++++ b/hw/arm/versatilepb.c +@@ -362,7 +362,6 @@ static void versatile_init(MachineState *machine, int board_id) + VERSATILE_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, + VERSATILE_FLASH_SECT_SIZE, +- VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE, + 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + } +diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c +index 4a05e1c..3234cf6 100644 +--- a/hw/arm/xilinx_zynq.c ++++ b/hw/arm/xilinx_zynq.c +@@ -208,10 +208,9 @@ static void zynq_init(MachineState *machine) + /* AMD */ + pflash_cfi02_register(0xe2000000, "zynq.pflash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- FLASH_SECTOR_SIZE, +- FLASH_SIZE/FLASH_SECTOR_SIZE, 1, ++ FLASH_SECTOR_SIZE, 1, + 1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa, +- 0); ++ 0); + + dev = qdev_create(NULL, "xilinx,zynq_slcr"); + qdev_init_nofail(dev); +diff --git a/hw/arm/z2.c b/hw/arm/z2.c +index f5f1903..394e7a8 100644 +--- a/hw/arm/z2.c ++++ b/hw/arm/z2.c +@@ -327,8 +327,7 @@ static void z2_init(MachineState *machine) + + if (!pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- sector_len, Z2_FLASH_SIZE / sector_len, +- 4, 0, 0, 0, 0, be)) { ++ sector_len, 4, 0, 0, 0, 0, be)) { + error_report("Error registering flash memory"); + exit(1); + } +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 31926e2..0101127 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -953,7 +953,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + const char *name, + hwaddr size, + BlockBackend *blk, +- uint32_t sector_len, int nb_blocs, ++ uint32_t sector_len, + int bank_width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, +@@ -964,7 +964,8 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + if (blk) { + qdev_prop_set_drive(dev, "drive", blk, &error_abort); + } +- qdev_prop_set_uint32(dev, "num-blocks", nb_blocs); ++ assert(size % sector_len == 0); ++ qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); + qdev_prop_set_uint64(dev, "sector-length", sector_len); + qdev_prop_set_uint8(dev, "width", bank_width); + qdev_prop_set_bit(dev, "big-endian", !!be); +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index 8c6c6e1..31b2e6c 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -789,7 +789,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, + const char *name, + hwaddr size, + BlockBackend *blk, +- uint32_t sector_len, int nb_blocs, ++ uint32_t sector_len, + int nb_mappings, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, +@@ -802,7 +802,8 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, + if (blk) { + qdev_prop_set_drive(dev, "drive", blk, &error_abort); + } +- qdev_prop_set_uint32(dev, "num-blocks", nb_blocs); ++ assert(size % sector_len == 0); ++ qdev_prop_set_uint32(dev, "num-blocks", size / sector_len); + qdev_prop_set_uint32(dev, "sector-length", sector_len); + qdev_prop_set_uint8(dev, "width", width); + qdev_prop_set_uint8(dev, "mappings", nb_mappings); +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index 721a867..20eed89 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -109,16 +109,13 @@ static void pc_system_flash_init(MemoryRegion *rom_memory) + int64_t size; + char *fatal_errmsg = NULL; + hwaddr phys_addr = 0x100000000ULL; +- int sector_bits, sector_size; ++ uint32_t sector_size = 4096; + PFlashCFI01 *system_flash; + MemoryRegion *flash_mem; + char name[64]; + void *flash_ptr; + int ret, flash_size; + +- sector_bits = 12; +- sector_size = 1 << sector_bits; +- + for (unit = 0; + (unit < FLASH_MAP_UNIT_MAX && + (pflash_drv = drive_get(IF_PFLASH, 0, unit)) != NULL); +@@ -161,7 +158,6 @@ static void pc_system_flash_init(MemoryRegion *rom_memory) + snprintf(name, sizeof name, "system.flash%d", unit); + system_flash = pflash_cfi01_register(phys_addr, name, + size, blk, sector_size, +- size >> sector_bits, + 1 /* width */, + 0x0000 /* id0 */, + 0x0000 /* id1 */, +diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c +index 0a1b6e9..92fe920 100644 +--- a/hw/lm32/lm32_boards.c ++++ b/hw/lm32/lm32_boards.c +@@ -116,7 +116,7 @@ static void lm32_evr_init(MachineState *machine) + /* Spansion S29NS128P */ + pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- flash_sector_size, flash_size / flash_sector_size, ++ flash_sector_size, + 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); + + /* create irq lines */ +@@ -208,7 +208,7 @@ static void lm32_uclinux_init(MachineState *machine) + /* Spansion S29NS128P */ + pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- flash_sector_size, flash_size / flash_sector_size, ++ flash_sector_size, + 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); + + /* create irq lines */ +diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c +index 3e38313..ac62a63 100644 +--- a/hw/lm32/milkymist.c ++++ b/hw/lm32/milkymist.c +@@ -123,8 +123,7 @@ milkymist_init(MachineState *machine) + /* Numonyx JS28F256J3F105 */ + pflash_cfi01_register(flash_base, "milkymist.flash", flash_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- flash_sector_size, flash_size / flash_sector_size, +- 2, 0x00, 0x89, 0x00, 0x1d, 1); ++ flash_sector_size, 2, 0x00, 0x89, 0x00, 0x1d, 1); + + /* create irq lines */ + env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0)); +diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c +index a2bc9fc..2a2c772 100644 +--- a/hw/microblaze/petalogix_ml605_mmu.c ++++ b/hw/microblaze/petalogix_ml605_mmu.c +@@ -109,8 +109,7 @@ petalogix_ml605_init(MachineState *machine) + * 10th paremeter 0 means little-endian */ + pflash_cfi01_register(FLASH_BASEADDR, "petalogix_ml605.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- (64 * 1024), FLASH_SIZE >> 16, +- 2, 0x89, 0x18, 0x0000, 0x0, 0); ++ 64 * KiB, 2, 0x89, 0x18, 0x0000, 0x0, 0); + + + dev = qdev_create(NULL, "xlnx.xps-intc"); +diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c +index 37090c5..eab6eb9 100644 +--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c ++++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c +@@ -88,8 +88,7 @@ petalogix_s3adsp1800_init(MachineState *machine) + pflash_cfi01_register(FLASH_BASEADDR, + "petalogix_s3adsp1800.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- (64 * 1024), FLASH_SIZE >> 16, +- 1, 0x89, 0x18, 0x0000, 0x0, 1); ++ 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1); + + dev = qdev_create(NULL, "xlnx.xps-intc"); + qdev_prop_set_uint32(dev, "kind-of-intr", +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index 6b09258..921eb22 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -1065,7 +1065,7 @@ void mips_malta_init(MachineState *machine) + fl = pflash_cfi01_register(FLASH_ADDRESS, "mips_malta.bios", + FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 65536, FLASH_SIZE >> 16, ++ 65536, + 4, 0x0000, 0x0000, 0x0000, 0x0000, be); + bios = pflash_cfi01_get_memory(fl); + fl_idx++; +diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c +index 4ac5471..0aca7f9 100644 +--- a/hw/mips/mips_r4k.c ++++ b/hw/mips/mips_r4k.c +@@ -236,8 +236,7 @@ void mips_r4k_init(MachineState *machine) + uint32_t mips_rom = 0x00400000; + if (!pflash_cfi01_register(0x1fc00000, "mips_r4k.bios", mips_rom, + blk_by_legacy_dinfo(dinfo), +- sector_len, mips_rom / sector_len, +- 4, 0, 0, 0, 0, be)) { ++ sector_len, 4, 0, 0, 0, 0, be)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + } + } else if (!qtest_enabled()) { +diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c +index d2ad8cd..4575043 100644 +--- a/hw/ppc/ppc405_boards.c ++++ b/hw/ppc/ppc405_boards.c +@@ -231,7 +231,7 @@ static void ref405ep_init(MachineState *machine) + pflash_cfi02_register((uint32_t)(-bios_size), + "ef405ep.bios", bios_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 64 * KiB, bios_size / (64 * KiB), 1, ++ 64 * KiB, 1, + 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + } else +@@ -502,7 +502,7 @@ static void taihu_405ep_init(MachineState *machine) + pflash_cfi02_register(0xFFE00000, + "taihu_405ep.bios", bios_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 64 * KiB, bios_size / (64 * KiB), 1, ++ 64 * KiB, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; +@@ -536,7 +536,7 @@ static void taihu_405ep_init(MachineState *machine) + bios_size = 32 * MiB; + pflash_cfi02_register(0xfc000000, "taihu_405ep.flash", bios_size, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 64 * KiB, bios_size / (64 * KiB), 1, ++ 64 * KiB, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; +diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c +index 0c1790f..4ec934f 100644 +--- a/hw/ppc/sam460ex.c ++++ b/hw/ppc/sam460ex.c +@@ -236,9 +236,8 @@ static int sam460ex_load_uboot(void) + if (!pflash_cfi01_register(FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32), + "sam460ex.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 64 * KiB, FLASH_SIZE / (64 * KiB), +- 1, 0x89, 0x18, 0x0000, 0x0, 1)) { +- error_report("qemu: Error registering flash memory."); ++ 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1)) { ++ error_report("Error registering flash memory"); + /* XXX: return an error instead? */ + exit(1); + } +diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c +index 66fa766..2fd8efe 100644 +--- a/hw/ppc/virtex_ml507.c ++++ b/hw/ppc/virtex_ml507.c +@@ -237,8 +237,7 @@ static void virtex_init(MachineState *machine) + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(PFLASH_BASEADDR, "virtex.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- (64 * 1024), FLASH_SIZE >> 16, +- 1, 0x89, 0x18, 0x0000, 0x0, 1); ++ 64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1); + + cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT]; + dev = qdev_create(NULL, "xlnx.xps-intc"); +diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c +index 7016d6f..d6e6515 100644 +--- a/hw/sh4/r2d.c ++++ b/hw/sh4/r2d.c +@@ -300,8 +300,7 @@ static void r2d_init(MachineState *machine) + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi02_register(0x0, "r2d.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- 64 * KiB, FLASH_SIZE >> 16, +- 1, 2, 0x0001, 0x227e, 0x2220, 0x2200, ++ 64 * KiB, 1, 2, 0x0001, 0x227e, 0x2220, 0x2200, + 0x555, 0x2aa, 0); + + /* NIC: rtl8139 on-board, and 2 slots. */ +diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h +index 3e48901..914932e 100644 +--- a/include/hw/block/flash.h ++++ b/include/hw/block/flash.h +@@ -17,7 +17,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + const char *name, + hwaddr size, + BlockBackend *blk, +- uint32_t sector_len, int nb_blocs, ++ uint32_t sector_len, + int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, +@@ -36,7 +36,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, + const char *name, + hwaddr size, + BlockBackend *blk, +- uint32_t sector_len, int nb_blocs, ++ uint32_t sector_len, + int nb_mappings, + int width, + uint16_t id0, uint16_t id1, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash-Rename-CFI_PFLASH-to-PFLASH_CFI.patch b/SOURCES/kvm-pflash-Rename-CFI_PFLASH-to-PFLASH_CFI.patch new file mode 100644 index 0000000..be8dfac --- /dev/null +++ b/SOURCES/kvm-pflash-Rename-CFI_PFLASH-to-PFLASH_CFI.patch @@ -0,0 +1,169 @@ +From 23f2d8fa204a3aa29a69e2e9d1efa5b7d22f3288 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:55 +0200 +Subject: [PATCH 28/53] pflash: Rename *CFI_PFLASH* to *PFLASH_CFI* +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-7-armbru@redhat.com> +Patchwork-id: 87993 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 06/31] pflash: Rename *CFI_PFLASH* to *PFLASH_CFI* +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +pflash_cfi01.c and pflash_cfi02.c start their identifiers with +pflash_cfi01_ and pflash_cfi02_ respectively, except for +CFI_PFLASH01(), TYPE_CFI_PFLASH01, CFI_PFLASH02(), TYPE_CFI_PFLASH02. +Rename for consistency. + +Suggested-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-5-armbru@redhat.com> +(cherry picked from commit e7b6274197c5f096860014ca750544d6aca0b9b9) +Signed-off-by: Miroslav Rezanina +--- + hw/block/pflash_cfi01.c | 12 ++++++------ + hw/block/pflash_cfi02.c | 14 +++++++------- + include/hw/block/flash.h | 4 ++-- + 3 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 3a6bd10..1ff4d25 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -59,8 +59,8 @@ do { \ + #define DPRINTF(fmt, ...) do { } while (0) + #endif + +-#define CFI_PFLASH01(obj) \ +- OBJECT_CHECK(PFlashCFI01, (obj), TYPE_CFI_PFLASH01) ++#define PFLASH_CFI01(obj) \ ++ OBJECT_CHECK(PFlashCFI01, (obj), TYPE_PFLASH_CFI01) + + #define PFLASH_BE 0 + #define PFLASH_SECURE 1 +@@ -711,7 +711,7 @@ static const MemoryRegionOps pflash_cfi01_ops = { + + static void pflash_cfi01_realize(DeviceState *dev, Error **errp) + { +- PFlashCFI01 *pfl = CFI_PFLASH01(dev); ++ PFlashCFI01 *pfl = PFLASH_CFI01(dev); + uint64_t total_len; + int ret; + uint64_t blocks_per_device, sector_len_per_device, device_len; +@@ -939,7 +939,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) + + + static const TypeInfo pflash_cfi01_info = { +- .name = TYPE_CFI_PFLASH01, ++ .name = TYPE_PFLASH_CFI01, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PFlashCFI01), + .class_init = pflash_cfi01_class_init, +@@ -962,7 +962,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + uint16_t id2, uint16_t id3, + int be) + { +- DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01); ++ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + + if (blk) { + qdev_prop_set_drive(dev, "drive", blk, &error_abort); +@@ -979,7 +979,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); +- return CFI_PFLASH01(dev); ++ return PFLASH_CFI01(dev); + } + + MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl) +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index 7fa02d2..2c0cbde 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -57,8 +57,8 @@ do { \ + + #define PFLASH_LAZY_ROMD_THRESHOLD 42 + +-#define CFI_PFLASH02(obj) \ +- OBJECT_CHECK(PFlashCFI02, (obj), TYPE_CFI_PFLASH02) ++#define PFLASH_CFI02(obj) \ ++ OBJECT_CHECK(PFlashCFI02, (obj), TYPE_PFLASH_CFI02) + + struct PFlashCFI02 { + /*< private >*/ +@@ -596,7 +596,7 @@ static const MemoryRegionOps pflash_cfi02_ops_le = { + + static void pflash_cfi02_realize(DeviceState *dev, Error **errp) + { +- PFlashCFI02 *pfl = CFI_PFLASH02(dev); ++ PFlashCFI02 *pfl = PFLASH_CFI02(dev); + uint32_t chip_len; + int ret; + Error *local_err = NULL; +@@ -760,7 +760,7 @@ static Property pflash_cfi02_properties[] = { + + static void pflash_cfi02_unrealize(DeviceState *dev, Error **errp) + { +- PFlashCFI02 *pfl = CFI_PFLASH02(dev); ++ PFlashCFI02 *pfl = PFLASH_CFI02(dev); + timer_del(&pfl->timer); + } + +@@ -775,7 +775,7 @@ static void pflash_cfi02_class_init(ObjectClass *klass, void *data) + } + + static const TypeInfo pflash_cfi02_info = { +- .name = TYPE_CFI_PFLASH02, ++ .name = TYPE_PFLASH_CFI02, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PFlashCFI02), + .class_init = pflash_cfi02_class_init, +@@ -800,7 +800,7 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, + uint16_t unlock_addr1, + int be) + { +- DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02); ++ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI02); + + if (blk) { + qdev_prop_set_drive(dev, "drive", blk, &error_abort); +@@ -820,5 +820,5 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); +- return CFI_PFLASH02(dev); ++ return PFLASH_CFI02(dev); + } +diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h +index 51d8f60..333005d 100644 +--- a/include/hw/block/flash.h ++++ b/include/hw/block/flash.h +@@ -7,7 +7,7 @@ + + /* pflash_cfi01.c */ + +-#define TYPE_CFI_PFLASH01 "cfi.pflash01" ++#define TYPE_PFLASH_CFI01 "cfi.pflash01" + + typedef struct PFlashCFI01 PFlashCFI01; + +@@ -24,7 +24,7 @@ MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl); + + /* pflash_cfi02.c */ + +-#define TYPE_CFI_PFLASH02 "cfi.pflash02" ++#define TYPE_PFLASH_CFI02 "cfi.pflash02" + + typedef struct PFlashCFI02 PFlashCFI02; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash-Rename-pflash_t-to-PFlashCFI01-PFlashCFI02.patch b/SOURCES/kvm-pflash-Rename-pflash_t-to-PFlashCFI01-PFlashCFI02.patch new file mode 100644 index 0000000..ac2a111 --- /dev/null +++ b/SOURCES/kvm-pflash-Rename-pflash_t-to-PFlashCFI01-PFlashCFI02.patch @@ -0,0 +1,607 @@ +From d8578dd73598ffaa42a9fc7aeaeec8bcba11df42 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:52 +0200 +Subject: [PATCH 25/53] pflash: Rename pflash_t to PFlashCFI01, PFlashCFI02 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-4-armbru@redhat.com> +Patchwork-id: 87982 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 03/31] pflash: Rename pflash_t to PFlashCFI01, PFlashCFI02 +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +flash.h's incomplete struct pflash_t is completed both in +pflash_cfi01.c and in pflash_cfi02.c. The complete types are +incompatible. This can hide type errors, such as passing a pflash_t +created with pflash_cfi02_register() to pflash_cfi01_get_memory(). + +Furthermore, POSIX reserves typedef names ending with _t. + +Rename the two structs to PFlashCFI01 and PFlashCFI02. + +Signed-off-by: Markus Armbruster +Reviewed-by: Alex Bennée +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +Message-Id: <20190308094610.21210-2-armbru@redhat.com> +(cherry picked from commit 1643406520f8ff6f4cc11062950f5f898b03b573) +Signed-off-by: Miroslav Rezanina +--- + hw/arm/vexpress.c | 8 ++--- + hw/block/pflash_cfi01.c | 89 +++++++++++++++++++++++++----------------------- + hw/block/pflash_cfi02.c | 73 ++++++++++++++++++++------------------- + hw/i386/pc_sysfw.c | 2 +- + hw/mips/mips_malta.c | 2 +- + hw/xtensa/xtfpga.c | 10 +++--- + include/hw/block/flash.h | 51 +++++++++++++++------------ + 7 files changed, 125 insertions(+), 110 deletions(-) + +diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c +index 9fad791..5cca371 100644 +--- a/hw/arm/vexpress.c ++++ b/hw/arm/vexpress.c +@@ -501,8 +501,8 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) + /* Open code a private version of pflash registration since we + * need to set non-default device width for VExpress platform. + */ +-static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, +- DriveInfo *di) ++static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, ++ DriveInfo *di) + { + DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); + +@@ -525,7 +525,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); +- return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01"); ++ return OBJECT_CHECK(PFlashCFI01, (dev), "cfi.pflash01"); + } + + static void vexpress_common_init(MachineState *machine) +@@ -537,7 +537,7 @@ static void vexpress_common_init(MachineState *machine) + qemu_irq pic[64]; + uint32_t sys_id; + DriveInfo *dinfo; +- pflash_t *pflash0; ++ PFlashCFI01 *pflash0; + I2CBus *i2c; + ram_addr_t vram_size, sram_size; + MemoryRegion *sysmem = get_system_memory(); +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 2e82840..389bc60 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -65,12 +65,13 @@ do { \ + #define DPRINTF(fmt, ...) do { } while (0) + #endif + +-#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01) ++#define CFI_PFLASH01(obj) \ ++ OBJECT_CHECK(PFlashCFI01, (obj), TYPE_CFI_PFLASH01) + + #define PFLASH_BE 0 + #define PFLASH_SECURE 1 + +-struct pflash_t { ++struct PFlashCFI01 { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ +@@ -109,17 +110,17 @@ static const VMStateDescription vmstate_pflash = { + .minimum_version_id = 1, + .post_load = pflash_post_load, + .fields = (VMStateField[]) { +- VMSTATE_UINT8(wcycle, pflash_t), +- VMSTATE_UINT8(cmd, pflash_t), +- VMSTATE_UINT8(status, pflash_t), +- VMSTATE_UINT64(counter, pflash_t), ++ VMSTATE_UINT8(wcycle, PFlashCFI01), ++ VMSTATE_UINT8(cmd, PFlashCFI01), ++ VMSTATE_UINT8(status, PFlashCFI01), ++ VMSTATE_UINT64(counter, PFlashCFI01), + VMSTATE_END_OF_LIST() + } + }; + + static void pflash_timer (void *opaque) + { +- pflash_t *pfl = opaque; ++ PFlashCFI01 *pfl = opaque; + + DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); + /* Reset flash */ +@@ -133,7 +134,7 @@ static void pflash_timer (void *opaque) + * If this code is called we know we have a device_width set for + * this flash. + */ +-static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset) ++static uint32_t pflash_cfi_query(PFlashCFI01 *pfl, hwaddr offset) + { + int i; + uint32_t resp = 0; +@@ -193,7 +194,7 @@ static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset) + + + /* Perform a device id query based on the bank width of the flash. */ +-static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset) ++static uint32_t pflash_devid_query(PFlashCFI01 *pfl, hwaddr offset) + { + int i; + uint32_t resp; +@@ -242,7 +243,7 @@ static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset) + return resp; + } + +-static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset, ++static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset, + int width, int be) + { + uint8_t *p; +@@ -288,8 +289,8 @@ static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset, + return ret; + } + +-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, +- int width, int be) ++static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, ++ int width, int be) + { + hwaddr boff; + uint32_t ret; +@@ -407,7 +408,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, + } + + /* update flash content on disk */ +-static void pflash_update(pflash_t *pfl, int offset, ++static void pflash_update(PFlashCFI01 *pfl, int offset, + int size) + { + int offset_end; +@@ -421,7 +422,7 @@ static void pflash_update(pflash_t *pfl, int offset, + } + } + +-static inline void pflash_data_write(pflash_t *pfl, hwaddr offset, ++static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset, + uint32_t value, int width, int be) + { + uint8_t *p = pfl->storage; +@@ -459,7 +460,7 @@ static inline void pflash_data_write(pflash_t *pfl, hwaddr offset, + + } + +-static void pflash_write(pflash_t *pfl, hwaddr offset, ++static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + uint32_t value, int width, int be) + { + uint8_t *p; +@@ -667,7 +668,7 @@ static void pflash_write(pflash_t *pfl, hwaddr offset, + static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value, + unsigned len, MemTxAttrs attrs) + { +- pflash_t *pfl = opaque; ++ PFlashCFI01 *pfl = opaque; + bool be = !!(pfl->features & (1 << PFLASH_BE)); + + if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) { +@@ -681,7 +682,7 @@ static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_ + static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value, + unsigned len, MemTxAttrs attrs) + { +- pflash_t *pfl = opaque; ++ PFlashCFI01 *pfl = opaque; + bool be = !!(pfl->features & (1 << PFLASH_BE)); + + if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) { +@@ -700,7 +701,7 @@ static const MemoryRegionOps pflash_cfi01_ops = { + + static void pflash_cfi01_realize(DeviceState *dev, Error **errp) + { +- pflash_t *pfl = CFI_PFLASH01(dev); ++ PFlashCFI01 *pfl = CFI_PFLASH01(dev); + uint64_t total_len; + int ret; + uint64_t blocks_per_device, sector_len_per_device, device_len; +@@ -877,14 +878,14 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) + } + + static Property pflash_cfi01_properties[] = { +- DEFINE_PROP_DRIVE("drive", struct pflash_t, blk), ++ DEFINE_PROP_DRIVE("drive", PFlashCFI01, blk), + /* num-blocks is the number of blocks actually visible to the guest, + * ie the total size of the device divided by the sector length. + * If we're emulating flash devices wired in parallel the actual + * number of blocks per indvidual device will differ. + */ +- DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0), +- DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0), ++ DEFINE_PROP_UINT32("num-blocks", PFlashCFI01, nb_blocs, 0), ++ DEFINE_PROP_UINT64("sector-length", PFlashCFI01, sector_len, 0), + /* width here is the overall width of this QEMU device in bytes. + * The QEMU device may be emulating a number of flash devices + * wired up in parallel; the width of each individual flash +@@ -901,17 +902,17 @@ static Property pflash_cfi01_properties[] = { + * 16 bit devices making up a 32 bit wide QEMU device. This + * is deprecated for new uses of this device. + */ +- DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0), +- DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0), +- DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0), +- DEFINE_PROP_BIT("big-endian", struct pflash_t, features, PFLASH_BE, 0), +- DEFINE_PROP_BIT("secure", struct pflash_t, features, PFLASH_SECURE, 0), +- DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0), +- DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0), +- DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0), +- DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0), +- DEFINE_PROP_STRING("name", struct pflash_t, name), +- DEFINE_PROP_BOOL("old-multiple-chip-handling", struct pflash_t, ++ DEFINE_PROP_UINT8("width", PFlashCFI01, bank_width, 0), ++ DEFINE_PROP_UINT8("device-width", PFlashCFI01, device_width, 0), ++ DEFINE_PROP_UINT8("max-device-width", PFlashCFI01, max_device_width, 0), ++ DEFINE_PROP_BIT("big-endian", PFlashCFI01, features, PFLASH_BE, 0), ++ DEFINE_PROP_BIT("secure", PFlashCFI01, features, PFLASH_SECURE, 0), ++ DEFINE_PROP_UINT16("id0", PFlashCFI01, ident0, 0), ++ DEFINE_PROP_UINT16("id1", PFlashCFI01, ident1, 0), ++ DEFINE_PROP_UINT16("id2", PFlashCFI01, ident2, 0), ++ DEFINE_PROP_UINT16("id3", PFlashCFI01, ident3, 0), ++ DEFINE_PROP_STRING("name", PFlashCFI01, name), ++ DEFINE_PROP_BOOL("old-multiple-chip-handling", PFlashCFI01, + old_multiple_chip_handling, false), + DEFINE_PROP_END_OF_LIST(), + }; +@@ -930,7 +931,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) + static const TypeInfo pflash_cfi01_info = { + .name = TYPE_CFI_PFLASH01, + .parent = TYPE_SYS_BUS_DEVICE, +- .instance_size = sizeof(struct pflash_t), ++ .instance_size = sizeof(PFlashCFI01), + .class_init = pflash_cfi01_class_init, + }; + +@@ -941,13 +942,15 @@ static void pflash_cfi01_register_types(void) + + type_init(pflash_cfi01_register_types) + +-pflash_t *pflash_cfi01_register(hwaddr base, +- DeviceState *qdev, const char *name, +- hwaddr size, +- BlockBackend *blk, +- uint32_t sector_len, int nb_blocs, +- int bank_width, uint16_t id0, uint16_t id1, +- uint16_t id2, uint16_t id3, int be) ++PFlashCFI01 *pflash_cfi01_register(hwaddr base, ++ DeviceState *qdev, const char *name, ++ hwaddr size, ++ BlockBackend *blk, ++ uint32_t sector_len, int nb_blocs, ++ int bank_width, ++ uint16_t id0, uint16_t id1, ++ uint16_t id2, uint16_t id3, ++ int be) + { + DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01); + +@@ -969,14 +972,14 @@ pflash_t *pflash_cfi01_register(hwaddr base, + return CFI_PFLASH01(dev); + } + +-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl) ++MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl) + { + return &fl->mem; + } + + static void postload_update_cb(void *opaque, int running, RunState state) + { +- pflash_t *pfl = opaque; ++ PFlashCFI01 *pfl = opaque; + + /* This is called after bdrv_invalidate_cache_all. */ + qemu_del_vm_change_state_handler(pfl->vmstate); +@@ -988,7 +991,7 @@ static void postload_update_cb(void *opaque, int running, RunState state) + + static int pflash_post_load(void *opaque, int version_id) + { +- pflash_t *pfl = opaque; ++ PFlashCFI01 *pfl = opaque; + + if (!pfl->ro) { + pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, +diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c +index cbc3d4d..7fa02d2 100644 +--- a/hw/block/pflash_cfi02.c ++++ b/hw/block/pflash_cfi02.c +@@ -57,9 +57,10 @@ do { \ + + #define PFLASH_LAZY_ROMD_THRESHOLD 42 + +-#define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02) ++#define CFI_PFLASH02(obj) \ ++ OBJECT_CHECK(PFlashCFI02, (obj), TYPE_CFI_PFLASH02) + +-struct pflash_t { ++struct PFlashCFI02 { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ +@@ -101,7 +102,7 @@ struct pflash_t { + /* + * Set up replicated mappings of the same region. + */ +-static void pflash_setup_mappings(pflash_t *pfl) ++static void pflash_setup_mappings(PFlashCFI02 *pfl) + { + unsigned i; + hwaddr size = memory_region_size(&pfl->orig_mem); +@@ -115,7 +116,7 @@ static void pflash_setup_mappings(pflash_t *pfl) + } + } + +-static void pflash_register_memory(pflash_t *pfl, int rom_mode) ++static void pflash_register_memory(PFlashCFI02 *pfl, int rom_mode) + { + memory_region_rom_device_set_romd(&pfl->orig_mem, rom_mode); + pfl->rom_mode = rom_mode; +@@ -123,7 +124,7 @@ static void pflash_register_memory(pflash_t *pfl, int rom_mode) + + static void pflash_timer (void *opaque) + { +- pflash_t *pfl = opaque; ++ PFlashCFI02 *pfl = opaque; + + DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); + /* Reset flash */ +@@ -137,8 +138,8 @@ static void pflash_timer (void *opaque) + pfl->cmd = 0; + } + +-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, +- int width, int be) ++static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset, ++ int width, int be) + { + hwaddr boff; + uint32_t ret; +@@ -246,7 +247,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, + } + + /* update flash content on disk */ +-static void pflash_update(pflash_t *pfl, int offset, ++static void pflash_update(PFlashCFI02 *pfl, int offset, + int size) + { + int offset_end; +@@ -260,8 +261,8 @@ static void pflash_update(pflash_t *pfl, int offset, + } + } + +-static void pflash_write (pflash_t *pfl, hwaddr offset, +- uint32_t value, int width, int be) ++static void pflash_write(PFlashCFI02 *pfl, hwaddr offset, ++ uint32_t value, int width, int be) + { + hwaddr boff; + uint8_t *p; +@@ -595,7 +596,7 @@ static const MemoryRegionOps pflash_cfi02_ops_le = { + + static void pflash_cfi02_realize(DeviceState *dev, Error **errp) + { +- pflash_t *pfl = CFI_PFLASH02(dev); ++ PFlashCFI02 *pfl = CFI_PFLASH02(dev); + uint32_t chip_len; + int ret; + Error *local_err = NULL; +@@ -741,25 +742,25 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) + } + + static Property pflash_cfi02_properties[] = { +- DEFINE_PROP_DRIVE("drive", struct pflash_t, blk), +- DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0), +- DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0), +- DEFINE_PROP_UINT8("width", struct pflash_t, width, 0), +- DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0), +- DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0), +- DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0), +- DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0), +- DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0), +- DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0), +- DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0), +- DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0), +- DEFINE_PROP_STRING("name", struct pflash_t, name), ++ DEFINE_PROP_DRIVE("drive", PFlashCFI02, blk), ++ DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, nb_blocs, 0), ++ DEFINE_PROP_UINT32("sector-length", PFlashCFI02, sector_len, 0), ++ DEFINE_PROP_UINT8("width", PFlashCFI02, width, 0), ++ DEFINE_PROP_UINT8("mappings", PFlashCFI02, mappings, 0), ++ DEFINE_PROP_UINT8("big-endian", PFlashCFI02, be, 0), ++ DEFINE_PROP_UINT16("id0", PFlashCFI02, ident0, 0), ++ DEFINE_PROP_UINT16("id1", PFlashCFI02, ident1, 0), ++ DEFINE_PROP_UINT16("id2", PFlashCFI02, ident2, 0), ++ DEFINE_PROP_UINT16("id3", PFlashCFI02, ident3, 0), ++ DEFINE_PROP_UINT16("unlock-addr0", PFlashCFI02, unlock_addr0, 0), ++ DEFINE_PROP_UINT16("unlock-addr1", PFlashCFI02, unlock_addr1, 0), ++ DEFINE_PROP_STRING("name", PFlashCFI02, name), + DEFINE_PROP_END_OF_LIST(), + }; + + static void pflash_cfi02_unrealize(DeviceState *dev, Error **errp) + { +- pflash_t *pfl = CFI_PFLASH02(dev); ++ PFlashCFI02 *pfl = CFI_PFLASH02(dev); + timer_del(&pfl->timer); + } + +@@ -776,7 +777,7 @@ static void pflash_cfi02_class_init(ObjectClass *klass, void *data) + static const TypeInfo pflash_cfi02_info = { + .name = TYPE_CFI_PFLASH02, + .parent = TYPE_SYS_BUS_DEVICE, +- .instance_size = sizeof(struct pflash_t), ++ .instance_size = sizeof(PFlashCFI02), + .class_init = pflash_cfi02_class_init, + }; + +@@ -787,15 +788,17 @@ static void pflash_cfi02_register_types(void) + + type_init(pflash_cfi02_register_types) + +-pflash_t *pflash_cfi02_register(hwaddr base, +- DeviceState *qdev, const char *name, +- hwaddr size, +- BlockBackend *blk, uint32_t sector_len, +- int nb_blocs, int nb_mappings, int width, +- uint16_t id0, uint16_t id1, +- uint16_t id2, uint16_t id3, +- uint16_t unlock_addr0, uint16_t unlock_addr1, +- int be) ++PFlashCFI02 *pflash_cfi02_register(hwaddr base, ++ DeviceState *qdev, const char *name, ++ hwaddr size, ++ BlockBackend *blk, ++ uint32_t sector_len, int nb_blocs, ++ int nb_mappings, int width, ++ uint16_t id0, uint16_t id1, ++ uint16_t id2, uint16_t id3, ++ uint16_t unlock_addr0, ++ uint16_t unlock_addr1, ++ int be) + { + DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02); + +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index 2a6de35..d8a98f3 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -110,7 +110,7 @@ static void pc_system_flash_init(MemoryRegion *rom_memory) + char *fatal_errmsg = NULL; + hwaddr phys_addr = 0x100000000ULL; + int sector_bits, sector_size; +- pflash_t *system_flash; ++ PFlashCFI01 *system_flash; + MemoryRegion *flash_mem; + char name[64]; + void *flash_ptr; +diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c +index f6513a4..88fd7d6 100644 +--- a/hw/mips/mips_malta.c ++++ b/hw/mips/mips_malta.c +@@ -986,7 +986,7 @@ void mips_malta_init(MachineState *machine) + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + char *filename; +- pflash_t *fl; ++ PFlashCFI01 *fl; + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *ram_high = g_new(MemoryRegion, 1); + MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1); +diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c +index 70686a2..8f8c0b9 100644 +--- a/hw/xtensa/xtfpga.c ++++ b/hw/xtensa/xtfpga.c +@@ -159,9 +159,9 @@ static void xtfpga_net_init(MemoryRegion *address_space, + memory_region_add_subregion(address_space, buffers, ram); + } + +-static pflash_t *xtfpga_flash_init(MemoryRegion *address_space, +- const XtfpgaBoardDesc *board, +- DriveInfo *dinfo, int be) ++static PFlashCFI01 *xtfpga_flash_init(MemoryRegion *address_space, ++ const XtfpgaBoardDesc *board, ++ DriveInfo *dinfo, int be) + { + SysBusDevice *s; + DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); +@@ -178,7 +178,7 @@ static pflash_t *xtfpga_flash_init(MemoryRegion *address_space, + s = SYS_BUS_DEVICE(dev); + memory_region_add_subregion(address_space, board->flash->base, + sysbus_mmio_get_region(s, 0)); +- return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01"); ++ return OBJECT_CHECK(PFlashCFI01, (dev), "cfi.pflash01"); + } + + static uint64_t translate_phys_addr(void *opaque, uint64_t addr) +@@ -224,7 +224,7 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine) + CPUXtensaState *env = NULL; + MemoryRegion *system_io; + DriveInfo *dinfo; +- pflash_t *flash = NULL; ++ PFlashCFI01 *flash = NULL; + QemuOpts *machine_opts = qemu_get_machine_opts(); + const char *kernel_filename = qemu_opt_get(machine_opts, "kernel"); + const char *kernel_cmdline = qemu_opt_get(machine_opts, "append"); +diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h +index 67c3aa3..51d8f60 100644 +--- a/include/hw/block/flash.h ++++ b/include/hw/block/flash.h +@@ -5,32 +5,41 @@ + + #include "exec/memory.h" + ++/* pflash_cfi01.c */ ++ + #define TYPE_CFI_PFLASH01 "cfi.pflash01" +-#define TYPE_CFI_PFLASH02 "cfi.pflash02" + +-typedef struct pflash_t pflash_t; ++typedef struct PFlashCFI01 PFlashCFI01; + +-/* pflash_cfi01.c */ +-pflash_t *pflash_cfi01_register(hwaddr base, +- DeviceState *qdev, const char *name, +- hwaddr size, +- BlockBackend *blk, +- uint32_t sector_len, int nb_blocs, int width, +- uint16_t id0, uint16_t id1, +- uint16_t id2, uint16_t id3, int be); ++PFlashCFI01 *pflash_cfi01_register(hwaddr base, ++ DeviceState *qdev, const char *name, ++ hwaddr size, ++ BlockBackend *blk, ++ uint32_t sector_len, int nb_blocs, ++ int width, ++ uint16_t id0, uint16_t id1, ++ uint16_t id2, uint16_t id3, ++ int be); ++MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl); + + /* pflash_cfi02.c */ +-pflash_t *pflash_cfi02_register(hwaddr base, +- DeviceState *qdev, const char *name, +- hwaddr size, +- BlockBackend *blk, uint32_t sector_len, +- int nb_blocs, int nb_mappings, int width, +- uint16_t id0, uint16_t id1, +- uint16_t id2, uint16_t id3, +- uint16_t unlock_addr0, uint16_t unlock_addr1, +- int be); +- +-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl); ++ ++#define TYPE_CFI_PFLASH02 "cfi.pflash02" ++ ++typedef struct PFlashCFI02 PFlashCFI02; ++ ++PFlashCFI02 *pflash_cfi02_register(hwaddr base, ++ DeviceState *qdev, const char *name, ++ hwaddr size, ++ BlockBackend *blk, ++ uint32_t sector_len, int nb_blocs, ++ int nb_mappings, ++ int width, ++ uint16_t id0, uint16_t id1, ++ uint16_t id2, uint16_t id3, ++ uint16_t unlock_addr0, ++ uint16_t unlock_addr1, ++ int be); + + /* nand.c */ + DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash_cfi01-Add-pflash_cfi01_get_blk-helper.patch b/SOURCES/kvm-pflash_cfi01-Add-pflash_cfi01_get_blk-helper.patch new file mode 100644 index 0000000..8ff67be --- /dev/null +++ b/SOURCES/kvm-pflash_cfi01-Add-pflash_cfi01_get_blk-helper.patch @@ -0,0 +1,64 @@ +From 8486c0843637f5822dbfcc1eed561d640ff14fe9 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:14 +0200 +Subject: [PATCH 47/53] pflash_cfi01: Add pflash_cfi01_get_blk() helper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-26-armbru@redhat.com> +Patchwork-id: 87983 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 25/31] pflash_cfi01: Add pflash_cfi01_get_blk() helper +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Philippe Mathieu-Daudé + +Add an helper to access the opaque struct PFlashCFI01. + +Signed-off-by: Markus Armbruster +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Laszlo Ersek +Message-Id: <20190308131445.17502-9-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit e60cf76549a628d63f865fb6faeb1c7c0f390d0b) +Signed-off-by: Miroslav Rezanina +--- + hw/block/pflash_cfi01.c | 5 +++++ + include/hw/block/flash.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 0101127..7a25051 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -980,6 +980,11 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + return PFLASH_CFI01(dev); + } + ++BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl) ++{ ++ return fl->blk; ++} ++ + MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl) + { + return &fl->mem; +diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h +index 914932e..a0f4887 100644 +--- a/include/hw/block/flash.h ++++ b/include/hw/block/flash.h +@@ -22,6 +22,7 @@ PFlashCFI01 *pflash_cfi01_register(hwaddr base, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, + int be); ++BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl); + MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl); + + /* pflash_cfi02.c */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash_cfi01-Do-not-exit-on-guest-aborting-write-to-.patch b/SOURCES/kvm-pflash_cfi01-Do-not-exit-on-guest-aborting-write-to-.patch new file mode 100644 index 0000000..87d4bc9 --- /dev/null +++ b/SOURCES/kvm-pflash_cfi01-Do-not-exit-on-guest-aborting-write-to-.patch @@ -0,0 +1,70 @@ +From f72f8a75f6b29f02a2226324901e35dbb07ae932 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:53 +0200 +Subject: [PATCH 26/53] pflash_cfi01: Do not exit() on guest aborting "write to + buffer" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-5-armbru@redhat.com> +Patchwork-id: 87986 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 04/31] pflash_cfi01: Do not exit() on guest aborting "write to buffer" +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +When a guest tries to abort "write to buffer" (command 0xE8), we print +"PFLASH: Possible BUG - Write block confirm", then exit(1). Letting +the guest terminate QEMU is not a good idea. Instead, LOG_UNIMP we +screwed up, then reset the device. + +Macro PFLASH_BUG() is now unused; delete it. + +Suggested-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-3-armbru@redhat.com> +(cherry picked from commit 2d93bebf81520ccebeb9a3ea9bd051ce088854ea) +Signed-off-by: Miroslav Rezanina +--- + hw/block/pflash_cfi01.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index 389bc60..c565db1 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -49,12 +49,6 @@ + #include "hw/sysbus.h" + #include "sysemu/sysemu.h" + +-#define PFLASH_BUG(fmt, ...) \ +-do { \ +- fprintf(stderr, "PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \ +- exit(1); \ +-} while(0) +- + /* #define PFLASH_DEBUG */ + #ifdef PFLASH_DEBUG + #define DPRINTF(fmt, ...) \ +@@ -636,8 +630,11 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + pfl->wcycle = 0; + pfl->status |= 0x80; + } else { +- DPRINTF("%s: unknown command for \"write block\"\n", __func__); +- PFLASH_BUG("Write block confirm"); ++ qemu_log_mask(LOG_UNIMP, ++ "%s: Aborting write to buffer not implemented," ++ " the data is already written to storage!\n" ++ "Flash device reset into READ mode.\n", ++ __func__); + goto reset_flash; + } + break; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pflash_cfi01-Log-use-of-flawed-write-to-buffer.patch b/SOURCES/kvm-pflash_cfi01-Log-use-of-flawed-write-to-buffer.patch new file mode 100644 index 0000000..35c3aeb --- /dev/null +++ b/SOURCES/kvm-pflash_cfi01-Log-use-of-flawed-write-to-buffer.patch @@ -0,0 +1,86 @@ +From d35903b0e772c0cdcd3f685dbee81ffbd110a24a Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:54 +0200 +Subject: [PATCH 27/53] pflash_cfi01: Log use of flawed "write to buffer" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-6-armbru@redhat.com> +Patchwork-id: 87990 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 05/31] pflash_cfi01: Log use of flawed "write to buffer" +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +Our implementation of "write to buffer" (command 0xE8) is flawed. +LOG_UNIMP its use, and add some FIXME comments. + +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-4-armbru@redhat.com> +(cherry picked from commit 4dbda935e054600667f9e57095fa97e2ce5936f9) +Signed-off-by: Miroslav Rezanina +--- + hw/block/pflash_cfi01.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c +index c565db1..3a6bd10 100644 +--- a/hw/block/pflash_cfi01.c ++++ b/hw/block/pflash_cfi01.c +@@ -515,6 +515,10 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + break; + case 0xe8: /* Write to buffer */ + DPRINTF("%s: Write to buffer\n", __func__); ++ /* FIXME should save @offset, @width for case 1+ */ ++ qemu_log_mask(LOG_UNIMP, ++ "%s: Write to buffer emulation is flawed\n", ++ __func__); + pfl->status |= 0x80; /* Ready! */ + break; + case 0xf0: /* Probe for AMD flash */ +@@ -558,6 +562,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + /* Mask writeblock size based on device width, or bank width if + * device width not specified. + */ ++ /* FIXME check @offset, @width */ + if (pfl->device_width) { + value = extract32(value, 0, pfl->device_width * 8); + } else { +@@ -595,7 +600,13 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + case 2: + switch (pfl->cmd) { + case 0xe8: /* Block write */ ++ /* FIXME check @offset, @width */ + if (!pfl->ro) { ++ /* ++ * FIXME writing straight to memory is *wrong*. We ++ * should write to a buffer, and flush it to memory ++ * only on confirm command (see below). ++ */ + pflash_data_write(pfl, offset, value, width, be); + } else { + pfl->status |= 0x10; /* Programming error */ +@@ -611,6 +622,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + pfl->wcycle++; + if (!pfl->ro) { + /* Flush the entire write buffer onto backing storage. */ ++ /* FIXME premature! */ + pflash_update(pfl, offset & mask, pfl->writeblock_size); + } else { + pfl->status |= 0x10; /* Programming error */ +@@ -627,6 +639,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, + switch (pfl->cmd) { + case 0xe8: /* Block write */ + if (cmd == 0xd0) { ++ /* FIXME this is where we should write out the buffer */ + pfl->wcycle = 0; + pfl->status |= 0x80; + } else { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-postcopy-Synchronize-usage-of-the-balloon-inhibitor.patch b/SOURCES/kvm-postcopy-Synchronize-usage-of-the-balloon-inhibitor.patch new file mode 100644 index 0000000..2519940 --- /dev/null +++ b/SOURCES/kvm-postcopy-Synchronize-usage-of-the-balloon-inhibitor.patch @@ -0,0 +1,81 @@ +From 4c1361e2dfac092c94077a20610087871c7878f4 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:54:25 +0100 +Subject: [PATCH 24/34] postcopy: Synchronize usage of the balloon inhibitor + +RH-Author: Alex Williamson +Message-id: <154387406568.26945.10032109321234466443.stgit@gimli.home> +Patchwork-id: 83233 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 7/7] postcopy: Synchronize usage of the balloon inhibitor +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +While the qemu_balloon_inhibit() interface appears rather general purpose, +postcopy uses it in a last-caller-wins approach with no guarantee of balanced +inhibits and de-inhibits. Wrap postcopy's usage of the inhibitor to give it +one vote overall, using the same last-caller-wins approach as previously +implemented at the balloon level. + +Fixes: 01ccbec7bdf6 ("balloon: Allow multiple inhibit users") +Reported-by: Christian Borntraeger +Tested-by: Christian Borntraeger +Reviewed-by: Cornelia Huck +Reviewed-by: Juan Quintela +Signed-off-by: Alex Williamson +(cherry picked from commit 154304cd6e99e4222ed762976f9d9aca33c094d3) +Signed-off-by: Miroslav Rezanina +--- + migration/postcopy-ram.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c +index 001b041..4b65ff9 100644 +--- a/migration/postcopy-ram.c ++++ b/migration/postcopy-ram.c +@@ -400,6 +400,20 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages) + } + + /* ++ * Manage a single vote to the QEMU balloon inhibitor for all postcopy usage, ++ * last caller wins. ++ */ ++static void postcopy_balloon_inhibit(bool state) ++{ ++ static bool cur_state = false; ++ ++ if (state != cur_state) { ++ qemu_balloon_inhibit(state); ++ cur_state = state; ++ } ++} ++ ++/* + * At the end of a migration where postcopy_ram_incoming_init was called. + */ + int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) +@@ -429,7 +443,7 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) + mis->have_fault_thread = false; + } + +- qemu_balloon_inhibit(false); ++ postcopy_balloon_inhibit(false); + + if (enable_mlock) { + if (os_mlock() < 0) { +@@ -801,7 +815,7 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) + * Ballooning can mark pages as absent while we're postcopying + * that would cause false userfaults. + */ +- qemu_balloon_inhibit(true); ++ postcopy_balloon_inhibit(true); + + trace_postcopy_ram_enable_notify(); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ppc405_boards-Delete-stale-disabled-DEBUG_BOARD_INIT.patch b/SOURCES/kvm-ppc405_boards-Delete-stale-disabled-DEBUG_BOARD_INIT.patch new file mode 100644 index 0000000..7443f66 --- /dev/null +++ b/SOURCES/kvm-ppc405_boards-Delete-stale-disabled-DEBUG_BOARD_INIT.patch @@ -0,0 +1,208 @@ +From 9844bbde0f1586645b1d8b148452270984ae85e5 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:58 +0200 +Subject: [PATCH 31/53] ppc405_boards: Delete stale, disabled DEBUG_BOARD_INIT + code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-10-armbru@redhat.com> +Patchwork-id: 88005 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 09/31] ppc405_boards: Delete stale, disabled DEBUG_BOARD_INIT code +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +The disabled DEBUG_BOARD_INIT code goes back to the initial commit +1a6c0886203, and has since seen only mechanical updates. It sure +feels like useless clutter now. Delete it. + +Suggested-by: Alex Bennée +Signed-off-by: Markus Armbruster +Message-Id: <20190308094610.21210-8-armbru@redhat.com> +Reviewed-by: Alex Bennée +(cherry picked from commit 886db7c55c72246e3810628d735f5e25eceb8c45) +[Trivial conflict in hw/ppc/ppc405_boards.c due to lack of +commit ab3dd749241] + +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/ppc405_boards.c | 62 +------------------------------------------------- + 1 file changed, 1 insertion(+), 61 deletions(-) + +diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c +index 0b65893..2c23e8b 100644 +--- a/hw/ppc/ppc405_boards.c ++++ b/hw/ppc/ppc405_boards.c +@@ -48,8 +48,6 @@ + + #define USE_FLASH_BIOS + +-//#define DEBUG_BOARD_INIT +- + /*****************************************************************************/ + /* PPC405EP reference board (IBM) */ + /* Standalone board with: +@@ -217,10 +215,7 @@ static void ref405ep_init(MachineState *machine) + memory_region_init(&ram_memories[1], NULL, "ef405ep.ram1", 0); + ram_bases[1] = 0x00000000; + ram_sizes[1] = 0x00000000; +- ram_size = 128 * 1024 * 1024; +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register cpu\n", __func__); +-#endif ++ ram_size = 128 * MiB; + env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, + 33333333, &pic, kernel_filename == NULL ? 0 : 1); + /* allocate SRAM */ +@@ -229,9 +224,6 @@ static void ref405ep_init(MachineState *machine) + &error_fatal); + memory_region_add_subregion(sysmem, 0xFFF00000, sram); + /* allocate and load BIOS */ +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register BIOS\n", __func__); +-#endif + fl_idx = 0; + #ifdef USE_FLASH_BIOS + dinfo = drive_get(IF_PFLASH, 0, fl_idx); +@@ -240,12 +232,6 @@ static void ref405ep_init(MachineState *machine) + + bios_size = blk_getlength(blk); + fl_sectors = (bios_size + 65535) >> 16; +-#ifdef DEBUG_BOARD_INIT +- printf("Register parallel flash %d size %lx" +- " at addr %lx '%s' %d\n", +- fl_idx, bios_size, -bios_size, +- blk_name(blk), fl_sectors); +-#endif + pflash_cfi02_register((uint32_t)(-bios_size), + NULL, "ef405ep.bios", bios_size, + blk, 65536, fl_sectors, 1, +@@ -255,9 +241,6 @@ static void ref405ep_init(MachineState *machine) + } else + #endif + { +-#ifdef DEBUG_BOARD_INIT +- printf("Load BIOS from file\n"); +-#endif + bios = g_new(MemoryRegion, 1); + memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE, + &error_fatal); +@@ -284,21 +267,12 @@ static void ref405ep_init(MachineState *machine) + memory_region_set_readonly(bios, true); + } + /* Register FPGA */ +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register FPGA\n", __func__); +-#endif + ref405ep_fpga_init(sysmem, 0xF0300000); + /* Register NVRAM */ +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register NVRAM\n", __func__); +-#endif + m48t59_init(NULL, 0xF0000000, 0, 8192, 1968, 8); + /* Load kernel */ + linux_boot = (kernel_filename != NULL); + if (linux_boot) { +-#ifdef DEBUG_BOARD_INIT +- printf("%s: load kernel\n", __func__); +-#endif + memset(&bd, 0, sizeof(bd)); + bd.bi_memstart = 0x00000000; + bd.bi_memsize = ram_size; +@@ -370,10 +344,6 @@ static void ref405ep_init(MachineState *machine) + initrd_size = 0; + bdloc = 0; + } +-#ifdef DEBUG_BOARD_INIT +- printf("bdloc " RAM_ADDR_FMT "\n", bdloc); +- printf("%s: Done\n", __func__); +-#endif + } + + static void ref405ep_class_init(ObjectClass *oc, void *data) +@@ -525,15 +495,9 @@ static void taihu_405ep_init(MachineState *machine) + memory_region_init_alias(&ram_memories[1], NULL, + "taihu_405ep.ram-1", ram, ram_bases[1], + ram_sizes[1]); +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register cpu\n", __func__); +-#endif + ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes, + 33333333, &pic, kernel_filename == NULL ? 0 : 1); + /* allocate and load BIOS */ +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register BIOS\n", __func__); +-#endif + fl_idx = 0; + #if defined(USE_FLASH_BIOS) + dinfo = drive_get(IF_PFLASH, 0, fl_idx); +@@ -544,12 +508,6 @@ static void taihu_405ep_init(MachineState *machine) + /* XXX: should check that size is 2MB */ + // bios_size = 2 * 1024 * 1024; + fl_sectors = (bios_size + 65535) >> 16; +-#ifdef DEBUG_BOARD_INIT +- printf("Register parallel flash %d size %lx" +- " at addr %lx '%s' %d\n", +- fl_idx, bios_size, -bios_size, +- blk_name(blk), fl_sectors); +-#endif + pflash_cfi02_register((uint32_t)(-bios_size), + NULL, "taihu_405ep.bios", bios_size, + blk, 65536, fl_sectors, 1, +@@ -559,9 +517,6 @@ static void taihu_405ep_init(MachineState *machine) + } else + #endif + { +-#ifdef DEBUG_BOARD_INIT +- printf("Load BIOS from file\n"); +-#endif + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + bios = g_new(MemoryRegion, 1); +@@ -592,12 +547,6 @@ static void taihu_405ep_init(MachineState *machine) + /* XXX: should check that size is 32MB */ + bios_size = 32 * 1024 * 1024; + fl_sectors = (bios_size + 65535) >> 16; +-#ifdef DEBUG_BOARD_INIT +- printf("Register parallel flash %d size %lx" +- " at addr " TARGET_FMT_lx " '%s'\n", +- fl_idx, bios_size, (target_ulong)0xfc000000, +- blk_name(blk)); +-#endif + pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size, + blk, 65536, fl_sectors, 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, +@@ -605,16 +554,10 @@ static void taihu_405ep_init(MachineState *machine) + fl_idx++; + } + /* Register CLPD & LCD display */ +-#ifdef DEBUG_BOARD_INIT +- printf("%s: register CPLD\n", __func__); +-#endif + taihu_cpld_init(sysmem, 0x50100000); + /* Load kernel */ + linux_boot = (kernel_filename != NULL); + if (linux_boot) { +-#ifdef DEBUG_BOARD_INIT +- printf("%s: load kernel\n", __func__); +-#endif + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image_targphys(kernel_filename, kernel_base, +@@ -643,9 +586,6 @@ static void taihu_405ep_init(MachineState *machine) + initrd_base = 0; + initrd_size = 0; + } +-#ifdef DEBUG_BOARD_INIT +- printf("%s: Done\n", __func__); +-#endif + } + + static void taihu_class_init(ObjectClass *oc, void *data) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ppc405_boards-Don-t-size-flash-memory-to-match-backi.patch b/SOURCES/kvm-ppc405_boards-Don-t-size-flash-memory-to-match-backi.patch new file mode 100644 index 0000000..842d7b9 --- /dev/null +++ b/SOURCES/kvm-ppc405_boards-Don-t-size-flash-memory-to-match-backi.patch @@ -0,0 +1,145 @@ +From fc257e52fc251e4db6cd7ad604391941a2592556 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:59 +0200 +Subject: [PATCH 32/53] ppc405_boards: Don't size flash memory to match backing + image +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-11-armbru@redhat.com> +Patchwork-id: 88004 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 10/31] ppc405_boards: Don't size flash memory to match backing image +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +Machine "ref405ep" maps its flash memory at address 2^32 - image size. +Image size is rounded up to the next multiple of 64KiB. Useless, +because pflash_cfi02_realize() fails with "failed to read the initial +flash content" unless the rounding is a no-op. + +If the image size exceeds 0x80000 Bytes, we overlap first SRAM, then +other stuff. No idea how that would play out, but useful outcomes +seem unlikely. + +Map the flash memory at fixed address 0xFFF80000 with size 512KiB, +regardless of image size, to match the physical hardware. + +Machine "taihu" maps its boot flash memory similarly. The code even +has a comment /* XXX: should check that size is 2MB */, followed by +disabled code to adjust the size to 2MiB regardless of image size. + +Its code to map its application flash memory looks the same, except +there the XXX comment asks for 32MiB, and the code to adjust the size +isn't disabled. Note that pflash_cfi02_realize() fails with "failed +to read the initial flash content" for images smaller than 32MiB. + +Map the boot flash memory at fixed address 0xFFE00000 with size 2MiB, +to match the physical hardware. Delete dead code from application +flash mapping, and simplify some. + +Cc: David Gibson +Signed-off-by: Markus Armbruster +Acked-by: David Gibson +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-9-armbru@redhat.com> +(cherry picked from commit dd59bcae7687df4b2ba8e5292607724996e00892) +[Trivial conflict in hw/ppc/ppc405_boards.c due to lack of +commit ab3dd749241] + +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/ppc405_boards.c | 38 +++++++++++++------------------------- + 1 file changed, 13 insertions(+), 25 deletions(-) + +diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c +index 2c23e8b..bf32672 100644 +--- a/hw/ppc/ppc405_boards.c ++++ b/hw/ppc/ppc405_boards.c +@@ -196,7 +196,7 @@ static void ref405ep_init(MachineState *machine) + target_ulong kernel_base, initrd_base; + long kernel_size, initrd_size; + int linux_boot; +- int fl_idx, fl_sectors, len; ++ int len; + DriveInfo *dinfo; + MemoryRegion *sysmem = get_system_memory(); + +@@ -224,20 +224,16 @@ static void ref405ep_init(MachineState *machine) + &error_fatal); + memory_region_add_subregion(sysmem, 0xFFF00000, sram); + /* allocate and load BIOS */ +- fl_idx = 0; + #ifdef USE_FLASH_BIOS +- dinfo = drive_get(IF_PFLASH, 0, fl_idx); ++ dinfo = drive_get(IF_PFLASH, 0, 0); + if (dinfo) { +- BlockBackend *blk = blk_by_legacy_dinfo(dinfo); +- +- bios_size = blk_getlength(blk); +- fl_sectors = (bios_size + 65535) >> 16; ++ bios_size = 8 * MiB; + pflash_cfi02_register((uint32_t)(-bios_size), + NULL, "ef405ep.bios", bios_size, +- blk, 65536, fl_sectors, 1, ++ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, ++ 64 * KiB, bios_size / (64 * KiB), 1, + 2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); +- fl_idx++; + } else + #endif + { +@@ -470,7 +466,7 @@ static void taihu_405ep_init(MachineState *machine) + target_ulong kernel_base, initrd_base; + long kernel_size, initrd_size; + int linux_boot; +- int fl_idx, fl_sectors; ++ int fl_idx; + DriveInfo *dinfo; + + #ifdef TARGET_PPCEMB +@@ -502,15 +498,11 @@ static void taihu_405ep_init(MachineState *machine) + #if defined(USE_FLASH_BIOS) + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + if (dinfo) { +- BlockBackend *blk = blk_by_legacy_dinfo(dinfo); +- +- bios_size = blk_getlength(blk); +- /* XXX: should check that size is 2MB */ +- // bios_size = 2 * 1024 * 1024; +- fl_sectors = (bios_size + 65535) >> 16; +- pflash_cfi02_register((uint32_t)(-bios_size), ++ bios_size = 2 * MiB; ++ pflash_cfi02_register(0xFFE00000, + NULL, "taihu_405ep.bios", bios_size, +- blk, 65536, fl_sectors, 1, ++ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, ++ 64 * KiB, bios_size / (64 * KiB), 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; +@@ -541,14 +533,10 @@ static void taihu_405ep_init(MachineState *machine) + /* Register Linux flash */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); + if (dinfo) { +- BlockBackend *blk = blk_by_legacy_dinfo(dinfo); +- +- bios_size = blk_getlength(blk); +- /* XXX: should check that size is 32MB */ +- bios_size = 32 * 1024 * 1024; +- fl_sectors = (bios_size + 65535) >> 16; ++ bios_size = 32 * MiB; + pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size, +- blk, 65536, fl_sectors, 1, ++ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, ++ 64 * KiB, bios_size / (64 * KiB), 1, + 4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA, + 1); + fl_idx++; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-Add-rendernode-display-option-for-egl-headless.patch b/SOURCES/kvm-qapi-Add-rendernode-display-option-for-egl-headless.patch new file mode 100644 index 0000000..893a3d4 --- /dev/null +++ b/SOURCES/kvm-qapi-Add-rendernode-display-option-for-egl-headless.patch @@ -0,0 +1,69 @@ +From c6a95857cb076ed085b2620009da4c0e108cd8ed Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 5 Mar 2019 08:26:14 +0100 +Subject: [PATCH 6/9] qapi: Add "rendernode" display option for egl-headless +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190305082617.14614-2-kraxel@redhat.com> +Patchwork-id: 84796 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/4] qapi: Add "rendernode" display option for egl-headless +Bugzilla: 1648236 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Marc-André Lureau +RH-Acked-by: John Snow +RH-Acked-by: Erik Skultety + +From: Erik Skultety + +Unlike SPICE, egl-headless doesn't offer a way of specifying the DRM +node used for OpenGL, hence QEMU always selecting the first one that is +available. Thus, add the 'rendernode' option for egl-headless to QAPI. + +Signed-off-by: Erik Skultety +Message-id: 7658e15eca72d520e7a5fb1c2e724702d83d4f7f.1542362949.git.eskultet@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit d4dc4ab133b5d7b066aa14036f297ed20398dd32) +Signed-off-by: Miroslav Rezanina +--- + qapi/ui.json | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/qapi/ui.json b/qapi/ui.json +index 5d01ad4..3e8aeee 100644 +--- a/qapi/ui.json ++++ b/qapi/ui.json +@@ -1020,6 +1020,20 @@ + 'data' : { '*grab-on-hover' : 'bool' } } + + ## ++# @DisplayEGLHeadless: ++# ++# EGL headless display options. ++# ++# @rendernode: Which DRM render node should be used. Default is the first ++# available node on the host. ++# ++# Since: 3.1 ++# ++## ++{ 'struct' : 'DisplayEGLHeadless', ++ 'data' : { '*rendernode' : 'str' } } ++ ++## + # @DisplayType: + # + # Display (user interface) type. +@@ -1054,6 +1068,6 @@ + 'none' : 'DisplayNoOpts', + 'gtk' : 'DisplayGTK', + 'sdl' : 'DisplayNoOpts', +- 'egl-headless' : 'DisplayNoOpts', ++ 'egl-headless' : 'DisplayEGLHeadless', + 'curses' : 'DisplayNoOpts', + 'cocoa' : 'DisplayNoOpts' } } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-add-SysEmuTarget-to-common.json.patch b/SOURCES/kvm-qapi-add-SysEmuTarget-to-common.json.patch new file mode 100644 index 0000000..dd02be1 --- /dev/null +++ b/SOURCES/kvm-qapi-add-SysEmuTarget-to-common.json.patch @@ -0,0 +1,95 @@ +From f156a5a4d6e4afbe88e0485771f87db2a17aa75e Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 13 Nov 2018 18:16:35 +0100 +Subject: [PATCH 16/22] qapi: add SysEmuTarget to "common.json" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laszlo Ersek +Message-id: <20181113181639.4999-3-lersek@redhat.com> +Patchwork-id: 83008 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/6] qapi: add SysEmuTarget to "common.json" +Bugzilla: 1607406 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Markus Armbruster + +We'll soon need an enumeration type that lists all the softmmu targets +that QEMU (the project) supports. Introduce @SysEmuTarget to +"common.json". + +The enum constant @x86_64 doesn't match the QAPI convention of preferring +hyphen ("-") over underscore ("_"). This is intentional; the @SysEmuTarget +constants are supposed to produce QEMU executable names when stringified +and appended to the "qemu-system-" prefix. Put differently, the +replacement text of the TARGET_NAME preprocessor macro must be possible to +look up in the list of (stringified) enum constants. + +Like other enum types, @SysEmuTarget too can be used for discriminator +fields in unions. For the @i386 constant, a C-language union member called +"i386" would be generated. On mingw build hosts, "i386" is a macro +however. Add "i386" to "polluted_words" at once. + +Cc: "Daniel P. Berrange" +Cc: Eric Blake +Cc: Markus Armbruster +Signed-off-by: Laszlo Ersek +Message-Id: <20180427192852.15013-3-lersek@redhat.com> +Reviewed-by: Eric Blake +Reviewed-by: Markus Armbruster +Signed-off-by: Markus Armbruster +(cherry picked from commit 9a801c7d6c8fd927df915f2ac3eacd306e8fc334) +Signed-off-by: Miroslav Rezanina +--- + qapi/common.json | 23 +++++++++++++++++++++++ + scripts/qapi/common.py | 2 +- + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/qapi/common.json b/qapi/common.json +index d9b14dd..c811d04 100644 +--- a/qapi/common.json ++++ b/qapi/common.json +@@ -126,3 +126,26 @@ + ## + { 'enum': 'OffAutoPCIBAR', + 'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] } ++ ++## ++# @SysEmuTarget: ++# ++# The comprehensive enumeration of QEMU system emulation ("softmmu") ++# targets. Run "./configure --help" in the project root directory, and ++# look for the *-softmmu targets near the "--target-list" option. The ++# individual target constants are not documented here, for the time ++# being. ++# ++# Notes: The resulting QMP strings can be appended to the "qemu-system-" ++# prefix to produce the corresponding QEMU executable name. This ++# is true even for "qemu-system-x86_64". ++# ++# Since: 2.13 ++## ++{ 'enum' : 'SysEmuTarget', ++ 'data' : [ 'aarch64', 'alpha', 'arm', 'cris', 'hppa', 'i386', 'lm32', ++ 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', ++ 'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc', ++ 'ppc64', 'ppcemb', 'riscv32', 'riscv64', 's390x', 'sh4', ++ 'sh4eb', 'sparc', 'sparc64', 'tricore', 'unicore32', ++ 'x86_64', 'xtensa', 'xtensaeb' ] } +diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py +index 3e14bc4..a032cec 100644 +--- a/scripts/qapi/common.py ++++ b/scripts/qapi/common.py +@@ -1822,7 +1822,7 @@ def c_name(name, protect=True): + 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', + 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq']) + # namespace pollution: +- polluted_words = set(['unix', 'errno', 'mips', 'sparc']) ++ polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386']) + name = name.translate(c_name_trans) + if protect and (name in c89_words | c99_words | c11_words | gcc_words + | cpp_words | polluted_words): +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-add-query-display-options-command.patch b/SOURCES/kvm-qapi-add-query-display-options-command.patch new file mode 100644 index 0000000..b5101c6 --- /dev/null +++ b/SOURCES/kvm-qapi-add-query-display-options-command.patch @@ -0,0 +1,95 @@ +From 8c923259c0880336125c05adb5b7e8001776cd79 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 5 Mar 2019 08:26:16 +0100 +Subject: [PATCH 8/9] qapi: add query-display-options command +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190305082617.14614-4-kraxel@redhat.com> +Patchwork-id: 84795 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/4] qapi: add query-display-options command +Bugzilla: 1648236 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Marc-André Lureau +RH-Acked-by: John Snow +RH-Acked-by: Erik Skultety + +Add query-display-options command, which allows querying the qemu +display configuration. This isn't particularly useful, except it +exposes QAPI type DisplayOptions in query-qmp-schema, so that libvirt +can discover recently added -display parameter rendernode (commit +d4dc4ab133b). Works around lack of sufficiently powerful command line +introspection. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Eric Blake +Tested-by: Eric Blake +Tested-by: Erik Skultety +Message-id: 20181122071613.2889-1-kraxel@redhat.com + +[ kraxel: reworded commit message as suggested by armbru ] + +(cherry picked from commit e1ca8f7e1915496148f6e0ce1f7c2309af013312) + +[ kraxel: No QAPI_CLONE() in rhel-7. So do a manual clone of the + one essential field: DisplayOptions->type ] + +Signed-off-by: Miroslav Rezanina +--- + qapi/ui.json | 13 +++++++++++++ + vl.c | 9 +++++++++ + 2 files changed, 22 insertions(+) + +diff --git a/qapi/ui.json b/qapi/ui.json +index 3e8aeee..1475867 100644 +--- a/qapi/ui.json ++++ b/qapi/ui.json +@@ -1071,3 +1071,16 @@ + 'egl-headless' : 'DisplayEGLHeadless', + 'curses' : 'DisplayNoOpts', + 'cocoa' : 'DisplayNoOpts' } } ++ ++## ++# @query-display-options: ++# ++# Returns information about display configuration ++# ++# Returns: @DisplayOptions ++# ++# Since: 3.1 ++# ++## ++{ 'command': 'query-display-options', ++ 'returns': 'DisplayOptions' } +diff --git a/vl.c b/vl.c +index 713f899..8b79eb9 100644 +--- a/vl.c ++++ b/vl.c +@@ -129,6 +129,7 @@ int main(int argc, char **argv) + #include "qapi/qapi-commands-block-core.h" + #include "qapi/qapi-commands-misc.h" + #include "qapi/qapi-commands-run-state.h" ++#include "qapi/qapi-commands-ui.h" + #include "qapi/qmp/qerror.h" + #include "sysemu/iothread.h" + +@@ -2119,6 +2120,14 @@ static void select_vgahw(const char *p) + } + } + ++DisplayOptions *qmp_query_display_options(Error **errp) ++{ ++ DisplayOptions *r = g_new0(DisplayOptions, 1); ++ ++ r->type = dpy.type; ++ return r; ++} ++ + static void parse_display(const char *p) + { + const char *opts; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-add-transaction-support-for-x-block-dirty-bitma.patch b/SOURCES/kvm-qapi-add-transaction-support-for-x-block-dirty-bitma.patch new file mode 100644 index 0000000..7965bbd --- /dev/null +++ b/SOURCES/kvm-qapi-add-transaction-support-for-x-block-dirty-bitma.patch @@ -0,0 +1,107 @@ +From f678429fca4701bda6a4631722e99c57a977846f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:30 +0100 +Subject: [PATCH 20/33] qapi: add transaction support for + x-block-dirty-bitmap-merge + +RH-Author: John Snow +Message-id: <20190206221243.7407-11-jsnow@redhat.com> +Patchwork-id: 84270 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 10/23] qapi: add transaction support for x-block-dirty-bitmap-merge +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +New action is like clean action: do the whole thing in .prepare and +undo in .abort. This behavior for bitmap-changing actions is needed +because backup job actions use bitmap in .prepare. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: John Snow +(cherry picked from commit 6fd2e40789ef7389b17c5fff93b0bf82d4352cb3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 35 +++++++++++++++++++++++++++++++++++ + qapi/transaction.json | 2 ++ + 2 files changed, 37 insertions(+) + +diff --git a/blockdev.c b/blockdev.c +index 853dd0e..df0cbe2 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2264,6 +2264,35 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common) + } + } + ++static void block_dirty_bitmap_merge_prepare(BlkActionState *common, ++ Error **errp) ++{ ++ BlockDirtyBitmapMerge *action; ++ BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, ++ common, common); ++ BdrvDirtyBitmap *merge_source; ++ ++ if (action_check_completion_mode(common, errp) < 0) { ++ return; ++ } ++ ++ action = common->action->u.x_block_dirty_bitmap_merge.data; ++ state->bitmap = block_dirty_bitmap_lookup(action->node, ++ action->dst_name, ++ &state->bs, ++ errp); ++ if (!state->bitmap) { ++ return; ++ } ++ ++ merge_source = bdrv_find_dirty_bitmap(state->bs, action->src_name); ++ if (!merge_source) { ++ return; ++ } ++ ++ bdrv_merge_dirty_bitmap(state->bitmap, merge_source, &state->backup, errp); ++} ++ + static void abort_prepare(BlkActionState *common, Error **errp) + { + error_setg(errp, "Transaction aborted using Abort action"); +@@ -2335,6 +2364,12 @@ static const BlkActionOps actions[] = { + .prepare = block_dirty_bitmap_disable_prepare, + .abort = block_dirty_bitmap_disable_abort, + }, ++ [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_MERGE] = { ++ .instance_size = sizeof(BlockDirtyBitmapState), ++ .prepare = block_dirty_bitmap_merge_prepare, ++ .commit = block_dirty_bitmap_free_backup, ++ .abort = block_dirty_bitmap_restore, ++ }, + /* Where are transactions for MIRROR, COMMIT and STREAM? + * Although these blockjobs use transaction callbacks like the backup job, + * these jobs do not necessarily adhere to transaction semantics. +diff --git a/qapi/transaction.json b/qapi/transaction.json +index d7e4274..5875cdb 100644 +--- a/qapi/transaction.json ++++ b/qapi/transaction.json +@@ -48,6 +48,7 @@ + # - @block-dirty-bitmap-clear: since 2.5 + # - @x-block-dirty-bitmap-enable: since 3.0 + # - @x-block-dirty-bitmap-disable: since 3.0 ++# - @x-block-dirty-bitmap-merge: since 3.1 + # - @blockdev-backup: since 2.3 + # - @blockdev-snapshot: since 2.5 + # - @blockdev-snapshot-internal-sync: since 1.7 +@@ -63,6 +64,7 @@ + 'block-dirty-bitmap-clear': 'BlockDirtyBitmap', + 'x-block-dirty-bitmap-enable': 'BlockDirtyBitmap', + 'x-block-dirty-bitmap-disable': 'BlockDirtyBitmap', ++ 'x-block-dirty-bitmap-merge': 'BlockDirtyBitmapMerge', + 'blockdev-backup': 'BlockdevBackup', + 'blockdev-snapshot': 'BlockdevSnapshot', + 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal', +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-bitmap-merge-document-name-change.patch b/SOURCES/kvm-qapi-bitmap-merge-document-name-change.patch new file mode 100644 index 0000000..9be3350 --- /dev/null +++ b/SOURCES/kvm-qapi-bitmap-merge-document-name-change.patch @@ -0,0 +1,52 @@ +From 31ed4da2c4cecaeff9ebdf7bfe8c911b8411b624 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 16:16:13 +0100 +Subject: [PATCH 015/163] qapi: bitmap-merge: document name change + +RH-Author: John Snow +Message-id: <20190320161631.14841-2-jsnow@redhat.com> +Patchwork-id: 84947 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/19] qapi: bitmap-merge: document name change +Bugzilla: 1668956 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +We named these using underscores instead of the preferred dash, +document this nearby so we cannot possibly forget to rectify this +when we remove the 'x-' prefixes when the feature becomes stable. + +We do not implement the change ahead of time to avoid more work +for libvirt to do in order to figure out how to use the beta version +of the API needlessly. + +Reported-by: Eric Blake +Signed-off-by: John Snow +Message-Id: <20180919190934.16284-1-jsnow@redhat.com> +Reviewed-by: Eric Blake +[eblake: typo fix] +Signed-off-by: Eric Blake +(cherry picked from commit cb9f871e80fe630422e0962751a6f9fb1795fe02) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + qapi/block-core.json | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 9c8c9ff..0960449 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1923,6 +1923,8 @@ + ## + # @x-block-dirty-bitmap-merge: + # ++# FIXME: Rename @src_name and @dst_name to src-name and dst-name. ++# + # Merge @src_name dirty bitmap to @dst_name dirty bitmap. @src_name dirty + # bitmap is unchanged. On error, @dst_name is unchanged. + # +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-change-the-type-of-TargetInfo.arch-from-string-.patch b/SOURCES/kvm-qapi-change-the-type-of-TargetInfo.arch-from-string-.patch new file mode 100644 index 0000000..6eadf4b --- /dev/null +++ b/SOURCES/kvm-qapi-change-the-type-of-TargetInfo.arch-from-string-.patch @@ -0,0 +1,89 @@ +From 27de7538bc01f788b4b2b652e96817b3c80e760c Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 13 Nov 2018 18:16:36 +0100 +Subject: [PATCH 17/22] qapi: change the type of TargetInfo.arch from string to + enum SysEmuTarget +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laszlo Ersek +Message-id: <20181113181639.4999-4-lersek@redhat.com> +Patchwork-id: 83004 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/6] qapi: change the type of TargetInfo.arch from string to enum SysEmuTarget +Bugzilla: 1607406 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Markus Armbruster + +Now that we have @SysEmuTarget, it makes sense to restrict +@TargetInfo.@arch to valid sysemu targets at the schema level. + +Cc: "Daniel P. Berrange" +Cc: Eric Blake +Cc: Markus Armbruster +Signed-off-by: Laszlo Ersek +Reviewed-by: Markus Armbruster +Reviewed-by: Eric Blake +Message-Id: <20180427192852.15013-4-lersek@redhat.com> +Signed-off-by: Markus Armbruster +(cherry picked from commit b47aa7b3d44dcedf7bf541563f70704f82f500d0) +Signed-off-by: Miroslav Rezanina +--- + arch_init.c | 4 +++- + qapi/misc.json | 6 ++++-- + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 6ee0747..9597218 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -29,6 +29,7 @@ + #include "hw/pci/pci.h" + #include "hw/audio/soundhw.h" + #include "qapi/qapi-commands-misc.h" ++#include "qapi/error.h" + #include "qemu/config-file.h" + #include "qemu/error-report.h" + #include "hw/acpi/acpi.h" +@@ -112,7 +113,8 @@ TargetInfo *qmp_query_target(Error **errp) + { + TargetInfo *info = g_malloc0(sizeof(*info)); + +- info->arch = g_strdup(TARGET_NAME); ++ info->arch = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME, -1, ++ &error_abort); + + return info; + } +diff --git a/qapi/misc.json b/qapi/misc.json +index 8b28270..7cf4fbc 100644 +--- a/qapi/misc.json ++++ b/qapi/misc.json +@@ -5,6 +5,8 @@ + # = Miscellanea + ## + ++{ 'include': 'common.json' } ++ + ## + # @qmp_capabilities: + # +@@ -2471,12 +2473,12 @@ + # + # Information describing the QEMU target. + # +-# @arch: the target architecture (eg "x86_64", "i386", etc) ++# @arch: the target architecture + # + # Since: 1.2.0 + ## + { 'struct': 'TargetInfo', +- 'data': { 'arch': 'str' } } ++ 'data': { 'arch': 'SysEmuTarget' } } + + ## + # @query-target: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-deprecate-CpuInfoFast.arch.patch b/SOURCES/kvm-qapi-deprecate-CpuInfoFast.arch.patch new file mode 100644 index 0000000..211cd34 --- /dev/null +++ b/SOURCES/kvm-qapi-deprecate-CpuInfoFast.arch.patch @@ -0,0 +1,84 @@ +From 1d06e4e316610a2ffc805d8cc122dab5494bb8e5 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 13 Nov 2018 18:16:38 +0100 +Subject: [PATCH 19/22] qapi: deprecate CpuInfoFast.arch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laszlo Ersek +Message-id: <20181113181639.4999-6-lersek@redhat.com> +Patchwork-id: 83006 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 5/6] qapi: deprecate CpuInfoFast.arch +Bugzilla: 1607406 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Markus Armbruster + +The TARGET_BASE_ARCH values from "configure" don't all map to the +@CpuInfoArch enum constants; in particular "s390x" from the former does +not match @s390 in the latter. Clients are known to rely on the @s390 +constant specifically, so we can't change it silently. Instead, deprecate +the @CpuInfoFast.@arch member (in favor of @CpuInfoFast.@target) using the +regular deprecation process. + +(No deprecation reminder is added to sysemu_target_to_cpuinfo_arch(): once +@CpuInfoFast.@arch is removed, the assignment expression that calls +sysemu_target_to_cpuinfo_arch() from qmp_query_cpus_fast() will have to +disappear; in turn the static function left without callers will also +break the build, thus it'll have to go.) + +Cc: "Daniel P. Berrange" +Cc: Eric Blake +Cc: Markus Armbruster +Signed-off-by: Laszlo Ersek +Message-Id: <20180427192852.15013-6-lersek@redhat.com> +Reviewed-by: Eric Blake +Reviewed-by: Markus Armbruster +Signed-off-by: Markus Armbruster +(cherry picked from commit 6ffa3ab453b431ec047ff1fc87120059b5266014) +Signed-off-by: Miroslav Rezanina +--- + qapi/misc.json | 8 ++++---- + qemu-doc.texi | 5 +++++ + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/qapi/misc.json b/qapi/misc.json +index d7fd8bd..e6291fd 100644 +--- a/qapi/misc.json ++++ b/qapi/misc.json +@@ -558,11 +558,11 @@ + # @props: properties describing to which node/socket/core/thread + # virtual CPU belongs to, provided if supported by board + # +-# @arch: base architecture of the cpu ++# @arch: base architecture of the cpu; deprecated since 2.13.0 in favor ++# of @target + # +-# @target: the QEMU system emulation target, which is more specific than +-# @arch and determines which additional fields will be listed +-# (since 2.13) ++# @target: the QEMU system emulation target, which determines which ++# additional fields will be listed (since 2.13) + # + # Since: 2.12 + # +diff --git a/qemu-doc.texi b/qemu-doc.texi +index 985e0f2..88358be 100644 +--- a/qemu-doc.texi ++++ b/qemu-doc.texi +@@ -2955,6 +2955,11 @@ from qcow2 images. + + The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command. + ++@subsection query-cpus-fast "arch" output member (since 2.13.0) ++ ++The ``arch'' output member of the ``query-cpus-fast'' command is ++replaced by the ``target'' output member. ++ + @section System emulator devices + + @subsection ivshmem (since 2.6.0) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-discriminate-CpuInfoFast-on-SysEmuTarget-not-Cp.patch b/SOURCES/kvm-qapi-discriminate-CpuInfoFast-on-SysEmuTarget-not-Cp.patch new file mode 100644 index 0000000..7501e53 --- /dev/null +++ b/SOURCES/kvm-qapi-discriminate-CpuInfoFast-on-SysEmuTarget-not-Cp.patch @@ -0,0 +1,246 @@ +From 17a1d383393e879c43e2aa8f2b264cb001cbca78 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 13 Nov 2018 18:16:37 +0100 +Subject: [PATCH 18/22] qapi: discriminate CpuInfoFast on SysEmuTarget, not + CpuInfoArch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laszlo Ersek +Message-id: <20181113181639.4999-5-lersek@redhat.com> +Patchwork-id: 83005 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/6] qapi: discriminate CpuInfoFast on SysEmuTarget, not CpuInfoArch +Bugzilla: 1607406 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Markus Armbruster + +Add a new field @target (of type @SysEmuTarget) to the output of the +@query-cpus-fast command, which provides more information about the +emulation target than the field @arch (of type @CpuInfoArch). Make @target +the new discriminator for the @CpuInfoFast return structure. Keep @arch +for compatibility. + +Cc: "Daniel P. Berrange" +Cc: Eric Blake +Cc: Markus Armbruster +Signed-off-by: Laszlo Ersek +Reviewed-by: Eric Blake +Message-Id: <20180427192852.15013-5-lersek@redhat.com> +Reviewed-by: Markus Armbruster +Signed-off-by: Markus Armbruster +(cherry picked from commit daa9d2bc6d73618bc230787ddfa821a6a6560fc2) +Signed-off-by: Miroslav Rezanina +--- + cpus.c | 87 ++++++++++++++++++++++++++++++++++++++++++---------------- + qapi/misc.json | 62 +++++++++++++++++++++++++++++++---------- + 2 files changed, 110 insertions(+), 39 deletions(-) + +diff --git a/cpus.c b/cpus.c +index 4f83f16..be3a4eb 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -2187,6 +2187,59 @@ CpuInfoList *qmp_query_cpus(Error **errp) + return head; + } + ++static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target) ++{ ++ /* ++ * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the ++ * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script. ++ */ ++ switch (target) { ++ case SYS_EMU_TARGET_I386: ++ case SYS_EMU_TARGET_X86_64: ++ return CPU_INFO_ARCH_X86; ++ ++ case SYS_EMU_TARGET_PPC: ++ case SYS_EMU_TARGET_PPCEMB: ++ case SYS_EMU_TARGET_PPC64: ++ return CPU_INFO_ARCH_PPC; ++ ++ case SYS_EMU_TARGET_SPARC: ++ case SYS_EMU_TARGET_SPARC64: ++ return CPU_INFO_ARCH_SPARC; ++ ++ case SYS_EMU_TARGET_MIPS: ++ case SYS_EMU_TARGET_MIPSEL: ++ case SYS_EMU_TARGET_MIPS64: ++ case SYS_EMU_TARGET_MIPS64EL: ++ return CPU_INFO_ARCH_MIPS; ++ ++ case SYS_EMU_TARGET_TRICORE: ++ return CPU_INFO_ARCH_TRICORE; ++ ++ case SYS_EMU_TARGET_S390X: ++ return CPU_INFO_ARCH_S390; ++ ++ case SYS_EMU_TARGET_RISCV32: ++ case SYS_EMU_TARGET_RISCV64: ++ return CPU_INFO_ARCH_RISCV; ++ ++ default: ++ return CPU_INFO_ARCH_OTHER; ++ } ++} ++ ++static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu) ++{ ++#ifdef TARGET_S390X ++ S390CPU *s390_cpu = S390_CPU(cpu); ++ CPUS390XState *env = &s390_cpu->env; ++ ++ info->cpu_state = env->cpu_state; ++#else ++ abort(); ++#endif ++} ++ + /* + * fast means: we NEVER interrupt vCPU threads to retrieve + * information from KVM. +@@ -2196,11 +2249,9 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp) + MachineState *ms = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(ms); + CpuInfoFastList *head = NULL, *cur_item = NULL; ++ SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME, ++ -1, &error_abort); + CPUState *cpu; +-#if defined(TARGET_S390X) +- S390CPU *s390_cpu; +- CPUS390XState *env; +-#endif + + CPU_FOREACH(cpu) { + CpuInfoFastList *info = g_malloc0(sizeof(*info)); +@@ -2218,26 +2269,14 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp) + info->value->props = props; + } + +-#if defined(TARGET_I386) +- info->value->arch = CPU_INFO_ARCH_X86; +-#elif defined(TARGET_PPC) +- info->value->arch = CPU_INFO_ARCH_PPC; +-#elif defined(TARGET_SPARC) +- info->value->arch = CPU_INFO_ARCH_SPARC; +-#elif defined(TARGET_MIPS) +- info->value->arch = CPU_INFO_ARCH_MIPS; +-#elif defined(TARGET_TRICORE) +- info->value->arch = CPU_INFO_ARCH_TRICORE; +-#elif defined(TARGET_S390X) +- s390_cpu = S390_CPU(cpu); +- env = &s390_cpu->env; +- info->value->arch = CPU_INFO_ARCH_S390; +- info->value->u.s390.cpu_state = env->cpu_state; +-#elif defined(TARGET_RISCV) +- info->value->arch = CPU_INFO_ARCH_RISCV; +-#else +- info->value->arch = CPU_INFO_ARCH_OTHER; +-#endif ++ info->value->arch = sysemu_target_to_cpuinfo_arch(target); ++ info->value->target = target; ++ if (target == SYS_EMU_TARGET_S390X) { ++ cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu); ++ } else { ++ /* do nothing for @CpuInfoOther */ ++ } ++ + if (!cur_item) { + head = cur_item = info; + } else { +diff --git a/qapi/misc.json b/qapi/misc.json +index 7cf4fbc..d7fd8bd 100644 +--- a/qapi/misc.json ++++ b/qapi/misc.json +@@ -558,25 +558,55 @@ + # @props: properties describing to which node/socket/core/thread + # virtual CPU belongs to, provided if supported by board + # +-# @arch: architecture of the cpu, which determines which additional fields +-# will be listed ++# @arch: base architecture of the cpu ++# ++# @target: the QEMU system emulation target, which is more specific than ++# @arch and determines which additional fields will be listed ++# (since 2.13) + # + # Since: 2.12 + # + ## +-{ 'union': 'CpuInfoFast', +- 'base': {'cpu-index': 'int', 'qom-path': 'str', +- 'thread-id': 'int', '*props': 'CpuInstanceProperties', +- 'arch': 'CpuInfoArch' }, +- 'discriminator': 'arch', +- 'data': { 'x86': 'CpuInfoOther', +- 'sparc': 'CpuInfoOther', +- 'ppc': 'CpuInfoOther', +- 'mips': 'CpuInfoOther', +- 'tricore': 'CpuInfoOther', +- 's390': 'CpuInfoS390', +- 'riscv': 'CpuInfoOther', +- 'other': 'CpuInfoOther' } } ++{ 'union' : 'CpuInfoFast', ++ 'base' : { 'cpu-index' : 'int', ++ 'qom-path' : 'str', ++ 'thread-id' : 'int', ++ '*props' : 'CpuInstanceProperties', ++ 'arch' : 'CpuInfoArch', ++ 'target' : 'SysEmuTarget' }, ++ 'discriminator' : 'target', ++ 'data' : { 'aarch64' : 'CpuInfoOther', ++ 'alpha' : 'CpuInfoOther', ++ 'arm' : 'CpuInfoOther', ++ 'cris' : 'CpuInfoOther', ++ 'hppa' : 'CpuInfoOther', ++ 'i386' : 'CpuInfoOther', ++ 'lm32' : 'CpuInfoOther', ++ 'm68k' : 'CpuInfoOther', ++ 'microblaze' : 'CpuInfoOther', ++ 'microblazeel' : 'CpuInfoOther', ++ 'mips' : 'CpuInfoOther', ++ 'mips64' : 'CpuInfoOther', ++ 'mips64el' : 'CpuInfoOther', ++ 'mipsel' : 'CpuInfoOther', ++ 'moxie' : 'CpuInfoOther', ++ 'nios2' : 'CpuInfoOther', ++ 'or1k' : 'CpuInfoOther', ++ 'ppc' : 'CpuInfoOther', ++ 'ppc64' : 'CpuInfoOther', ++ 'ppcemb' : 'CpuInfoOther', ++ 'riscv32' : 'CpuInfoOther', ++ 'riscv64' : 'CpuInfoOther', ++ 's390x' : 'CpuInfoS390', ++ 'sh4' : 'CpuInfoOther', ++ 'sh4eb' : 'CpuInfoOther', ++ 'sparc' : 'CpuInfoOther', ++ 'sparc64' : 'CpuInfoOther', ++ 'tricore' : 'CpuInfoOther', ++ 'unicore32' : 'CpuInfoOther', ++ 'x86_64' : 'CpuInfoOther', ++ 'xtensa' : 'CpuInfoOther', ++ 'xtensaeb' : 'CpuInfoOther' } } + + ## + # @query-cpus-fast: +@@ -602,6 +632,7 @@ + # }, + # "qom-path": "/machine/unattached/device[0]", + # "arch":"x86", ++# "target":"x86_64", + # "cpu-index": 0 + # }, + # { +@@ -613,6 +644,7 @@ + # }, + # "qom-path": "/machine/unattached/device[2]", + # "arch":"x86", ++# "target":"x86_64", + # "cpu-index": 1 + # } + # ] +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-fill-in-CpuInfoFast.arch-in-query-cpus-fast.patch b/SOURCES/kvm-qapi-fill-in-CpuInfoFast.arch-in-query-cpus-fast.patch new file mode 100644 index 0000000..6acbe7a --- /dev/null +++ b/SOURCES/kvm-qapi-fill-in-CpuInfoFast.arch-in-query-cpus-fast.patch @@ -0,0 +1,116 @@ +From 06441913a6b0832d545bb40b1c4969cca99059a7 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 13 Nov 2018 18:16:34 +0100 +Subject: [PATCH 15/22] qapi: fill in CpuInfoFast.arch in query-cpus-fast +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laszlo Ersek +Message-id: <20181113181639.4999-2-lersek@redhat.com> +Patchwork-id: 83003 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/6] qapi: fill in CpuInfoFast.arch in query-cpus-fast +Bugzilla: 1607406 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Markus Armbruster + +* Commit ca230ff33f89 added the @arch field to @CpuInfoFast, but it failed + to set the new field in qmp_query_cpus_fast(), when TARGET_S390X was not + defined. The updated @query-cpus-fast example in "qapi-schema.json" + showed "arch":"x86" only because qmp_query_cpus_fast() calls g_malloc0() + to allocate @CpuInfoFast, and the CPU_INFO_ARCH_X86 enum constant is + generated with value 0. + + All @arch values other than @s390 implied the @CpuInfoOther sub-struct + for @CpuInfoFast -- at the time of writing the patch --, thus no fields + other than @arch needed to be set when TARGET_S390X was not defined. Set + @arch now, by copying the corresponding assignments from + qmp_query_cpus(). + +* Commit 25fa194b7b11 added the @riscv enum constant to @CpuInfoArch (used + in both @CpuInfo and @CpuInfoFast -- the return types of the @query-cpus + and @query-cpus-fast commands, respectively), and assigned, in both + return structures, the @CpuInfoRISCV sub-structure to the new enum + value. + + However, qmp_query_cpus_fast() would not populate either the @arch field + or the @CpuInfoRISCV sub-structure, when TARGET_RISCV was defined; only + qmp_query_cpus() would. + + Assign @CpuInfoOther to the @riscv enum constant in @CpuInfoFast, and + populate only the @arch field in qmp_query_cpus_fast(). Getting CPU + state without interrupting KVM is an exceptional thing that only S390X + does currently. Quoting Cornelia Huck , "s390x is + exceptional in that it has state in QEMU that is actually interesting + for upper layers and can be retrieved without performance penalty". See + also + . + +Cc: Cornelia Huck +Cc: Eric Blake +Cc: Markus Armbruster +Cc: Viktor VM Mihajlovski +Cc: qemu-stable@nongnu.org +Fixes: ca230ff33f89bf7102cbfbc2328716da6750aaed +Fixes: 25fa194b7b11901561532e435beb83d046899f7a +Signed-off-by: Laszlo Ersek +Reviewed-by: Eric Blake +Reviewed-by: Cornelia Huck +Reviewed-by: Markus Armbruster +Message-Id: <20180427192852.15013-2-lersek@redhat.com> +Signed-off-by: Markus Armbruster +(cherry picked from commit 96054f56396eaa0b9b5c681fc3e42a0004b17ade) +Signed-off-by: Miroslav Rezanina +--- + cpus.c | 16 +++++++++++++++- + qapi/misc.json | 2 +- + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/cpus.c b/cpus.c +index 398392b..4f83f16 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -2218,11 +2218,25 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp) + info->value->props = props; + } + +-#if defined(TARGET_S390X) ++#if defined(TARGET_I386) ++ info->value->arch = CPU_INFO_ARCH_X86; ++#elif defined(TARGET_PPC) ++ info->value->arch = CPU_INFO_ARCH_PPC; ++#elif defined(TARGET_SPARC) ++ info->value->arch = CPU_INFO_ARCH_SPARC; ++#elif defined(TARGET_MIPS) ++ info->value->arch = CPU_INFO_ARCH_MIPS; ++#elif defined(TARGET_TRICORE) ++ info->value->arch = CPU_INFO_ARCH_TRICORE; ++#elif defined(TARGET_S390X) + s390_cpu = S390_CPU(cpu); + env = &s390_cpu->env; + info->value->arch = CPU_INFO_ARCH_S390; + info->value->u.s390.cpu_state = env->cpu_state; ++#elif defined(TARGET_RISCV) ++ info->value->arch = CPU_INFO_ARCH_RISCV; ++#else ++ info->value->arch = CPU_INFO_ARCH_OTHER; + #endif + if (!cur_item) { + head = cur_item = info; +diff --git a/qapi/misc.json b/qapi/misc.json +index 045eb7c..8b28270 100644 +--- a/qapi/misc.json ++++ b/qapi/misc.json +@@ -573,7 +573,7 @@ + 'mips': 'CpuInfoOther', + 'tricore': 'CpuInfoOther', + 's390': 'CpuInfoS390', +- 'riscv': 'CpuInfoRISCV', ++ 'riscv': 'CpuInfoOther', + 'other': 'CpuInfoOther' } } + + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Add-list-of-bitmaps-to-ImageInfoSpecificQCow2.patch b/SOURCES/kvm-qcow2-Add-list-of-bitmaps-to-ImageInfoSpecificQCow2.patch new file mode 100644 index 0000000..d5df57c --- /dev/null +++ b/SOURCES/kvm-qcow2-Add-list-of-bitmaps-to-ImageInfoSpecificQCow2.patch @@ -0,0 +1,264 @@ +From bc648c67692348f9fa8cb091f5949c608dbc7565 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:37 +0100 +Subject: [PATCH 044/163] qcow2: Add list of bitmaps to ImageInfoSpecificQCow2 + +RH-Author: John Snow +Message-id: <20190320214838.22027-10-jsnow@redhat.com> +Patchwork-id: 85000 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/10] qcow2: Add list of bitmaps to ImageInfoSpecificQCow2 +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Andrey Shinkevich + +In the 'Format specific information' section of the 'qemu-img info' +command output, the supplemental information about existing QCOW2 +bitmaps will be shown, such as a bitmap name, flags and granularity: + +image: /vz/vmprivate/VM1/harddisk.hdd +file format: qcow2 +virtual size: 64G (68719476736 bytes) +disk size: 3.0M +cluster_size: 1048576 +Format specific information: + compat: 1.1 + lazy refcounts: true + bitmaps: + [0]: + flags: + [0]: in-use + [1]: auto + name: back-up1 + granularity: 65536 + [1]: + flags: + [0]: in-use + [1]: auto + name: back-up2 + granularity: 65536 + refcount bits: 16 + corrupt: false + +Signed-off-by: Andrey Shinkevich +Reviewed-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <1549638368-530182-3-git-send-email-andrey.shinkevich@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit b8968c875f4030dd6924d6971bb3d92dfa3d2f65) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-bitmap.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + block/qcow2.c | 11 +++++++- + block/qcow2.h | 2 ++ + qapi/block-core.json | 41 +++++++++++++++++++++++++++- + 4 files changed, 128 insertions(+), 2 deletions(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index a36773c..4899719 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -1008,6 +1008,82 @@ fail: + return false; + } + ++ ++static Qcow2BitmapInfoFlagsList *get_bitmap_info_flags(uint32_t flags) ++{ ++ Qcow2BitmapInfoFlagsList *list = NULL; ++ Qcow2BitmapInfoFlagsList **plist = &list; ++ int i; ++ ++ static const struct { ++ int bme; /* Bitmap directory entry flags */ ++ int info; /* The flags to report to the user */ ++ } map[] = { ++ { BME_FLAG_IN_USE, QCOW2_BITMAP_INFO_FLAGS_IN_USE }, ++ { BME_FLAG_AUTO, QCOW2_BITMAP_INFO_FLAGS_AUTO }, ++ }; ++ ++ int map_size = ARRAY_SIZE(map); ++ ++ for (i = 0; i < map_size; ++i) { ++ if (flags & map[i].bme) { ++ Qcow2BitmapInfoFlagsList *entry = ++ g_new0(Qcow2BitmapInfoFlagsList, 1); ++ entry->value = map[i].info; ++ *plist = entry; ++ plist = &entry->next; ++ flags &= ~map[i].bme; ++ } ++ } ++ /* Check if the BME_* mapping above is complete */ ++ assert(!flags); ++ ++ return list; ++} ++ ++/* ++ * qcow2_get_bitmap_info_list() ++ * Returns a list of QCOW2 bitmap details. ++ * In case of no bitmaps, the function returns NULL and ++ * the @errp parameter is not set. ++ * When bitmap information can not be obtained, the function returns ++ * NULL and the @errp parameter is set. ++ */ ++Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs, ++ Error **errp) ++{ ++ BDRVQcow2State *s = bs->opaque; ++ Qcow2BitmapList *bm_list; ++ Qcow2Bitmap *bm; ++ Qcow2BitmapInfoList *list = NULL; ++ Qcow2BitmapInfoList **plist = &list; ++ ++ if (s->nb_bitmaps == 0) { ++ return NULL; ++ } ++ ++ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, ++ s->bitmap_directory_size, errp); ++ if (bm_list == NULL) { ++ return NULL; ++ } ++ ++ QSIMPLEQ_FOREACH(bm, bm_list, entry) { ++ Qcow2BitmapInfo *info = g_new0(Qcow2BitmapInfo, 1); ++ Qcow2BitmapInfoList *obj = g_new0(Qcow2BitmapInfoList, 1); ++ info->granularity = 1U << bm->granularity_bits; ++ info->name = g_strdup(bm->name); ++ info->flags = get_bitmap_info_flags(bm->flags & ~BME_RESERVED_FLAGS); ++ obj->value = info; ++ *plist = obj; ++ plist = &obj->next; ++ } ++ ++ bitmap_list_free(bm_list); ++ ++ return list; ++} ++ + int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp) + { +diff --git a/block/qcow2.c b/block/qcow2.c +index de9872f..21f7556 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -4185,7 +4185,7 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, + spec_info = g_new(ImageInfoSpecific, 1); + *spec_info = (ImageInfoSpecific){ + .type = IMAGE_INFO_SPECIFIC_KIND_QCOW2, +- .u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1), ++ .u.qcow2.data = g_new0(ImageInfoSpecificQCow2, 1), + }; + if (s->qcow_version == 2) { + *spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){ +@@ -4193,6 +4193,13 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, + .refcount_bits = s->refcount_bits, + }; + } else if (s->qcow_version == 3) { ++ Qcow2BitmapInfoList *bitmaps; ++ bitmaps = qcow2_get_bitmap_info_list(bs, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ qapi_free_ImageInfoSpecific(spec_info); ++ return NULL; ++ } + *spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){ + .compat = g_strdup("1.1"), + .lazy_refcounts = s->compatible_features & +@@ -4202,6 +4209,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, + QCOW2_INCOMPAT_CORRUPT, + .has_corrupt = true, + .refcount_bits = s->refcount_bits, ++ .has_bitmaps = !!bitmaps, ++ .bitmaps = bitmaps, + }; + } else { + /* if this assertion fails, this probably means a new version was +diff --git a/block/qcow2.h b/block/qcow2.h +index 29b041c..2633e33 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -676,6 +676,8 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, + void **refcount_table, + int64_t *refcount_table_size); + bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp); ++Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs, ++ Error **errp); + int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp); + int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 176c04e..5d6bb14 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -70,6 +70,8 @@ + # @encrypt: details about encryption parameters; only set if image + # is encrypted (since 2.10) + # ++# @bitmaps: A list of qcow2 bitmap details (since 4.0) ++# + # Since: 1.7 + ## + { 'struct': 'ImageInfoSpecificQCow2', +@@ -78,7 +80,8 @@ + '*lazy-refcounts': 'bool', + '*corrupt': 'bool', + 'refcount-bits': 'int', +- '*encrypt': 'ImageInfoSpecificQCow2Encryption' ++ '*encrypt': 'ImageInfoSpecificQCow2Encryption', ++ '*bitmaps': ['Qcow2BitmapInfo'] + } } + + ## +@@ -455,6 +458,42 @@ + 'status': 'DirtyBitmapStatus'} } + + ## ++# @Qcow2BitmapInfoFlags: ++# ++# An enumeration of flags that a bitmap can report to the user. ++# ++# @in-use: This flag is set by any process actively modifying the qcow2 file, ++# and cleared when the updated bitmap is flushed to the qcow2 image. ++# The presence of this flag in an offline image means that the bitmap ++# was not saved correctly after its last usage, and may contain ++# inconsistent data. ++# ++# @auto: The bitmap must reflect all changes of the virtual disk by any ++# application that would write to this qcow2 file. ++# ++# Since: 4.0 ++## ++{ 'enum': 'Qcow2BitmapInfoFlags', ++ 'data': ['in-use', 'auto'] } ++ ++## ++# @Qcow2BitmapInfo: ++# ++# Qcow2 bitmap information. ++# ++# @name: the name of the bitmap ++# ++# @granularity: granularity of the bitmap in bytes ++# ++# @flags: flags of the bitmap ++# ++# Since: 4.0 ++## ++{ 'struct': 'Qcow2BitmapInfo', ++ 'data': {'name': 'str', 'granularity': 'uint32', ++ 'flags': ['Qcow2BitmapInfoFlags'] } } ++ ++## + # @BlockLatencyHistogramInfo: + # + # Block latency histogram. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Assign-the-L2-cache-relatively-to-the-image-si.patch b/SOURCES/kvm-qcow2-Assign-the-L2-cache-relatively-to-the-image-si.patch new file mode 100644 index 0000000..c03d9d2 --- /dev/null +++ b/SOURCES/kvm-qcow2-Assign-the-L2-cache-relatively-to-the-image-si.patch @@ -0,0 +1,231 @@ +From 2790e1d1df870d455bbd493dc7c342e34df6e4dd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:18 +0100 +Subject: [PATCH 17/23] qcow2: Assign the L2 cache relatively to the image size + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-9-kwolf@redhat.com> +Patchwork-id: 84548 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 08/13] qcow2: Assign the L2 cache relatively to the image size +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +Sufficient L2 cache can noticeably improve the performance when using +large images with frequent I/O. + +Previously, unless 'cache-size' was specified and was large enough, the +L2 cache was set to a certain size without taking the virtual image size +into account. + +Now, the L2 cache assignment is aware of the virtual size of the image, +and will cover the entire image, unless the cache size needed for that is +larger than a certain maximum. This maximum is set to 1 MB by default +(enough to cover an 8 GB image with the default cluster size) but can +be increased or decreased using the 'l2-cache-size' option. This option +was previously documented as the *maximum* L2 cache size, and this patch +makes it behave as such, instead of as a constant size. Also, the +existing option 'cache-size' can limit the sum of both L2 and refcount +caches, as previously. + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit b749562d9822d14ef69c9eaa5f85903010b86c30) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 21 +++++++++------------ + block/qcow2.h | 4 +--- + docs/qcow2-cache.txt | 15 ++++++++++----- + qemu-options.hx | 6 +++--- + tests/qemu-iotests/137 | 8 +++++++- + tests/qemu-iotests/137.out | 4 +++- + 6 files changed, 33 insertions(+), 25 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index f3b2860..fc6bddd 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -773,29 +773,35 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + uint64_t *refcount_cache_size, Error **errp) + { + BDRVQcow2State *s = bs->opaque; +- uint64_t combined_cache_size; ++ uint64_t combined_cache_size, l2_cache_max_setting; + bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set; + int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; ++ uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; ++ uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); + + combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE); + l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE); + refcount_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_REFCOUNT_CACHE_SIZE); + + combined_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_CACHE_SIZE, 0); +- *l2_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE, 0); ++ l2_cache_max_setting = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE, ++ DEFAULT_L2_CACHE_MAX_SIZE); + *refcount_cache_size = qemu_opt_get_size(opts, + QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0); + + *l2_cache_entry_size = qemu_opt_get_size( + opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE, s->cluster_size); + ++ *l2_cache_size = MIN(max_l2_cache, l2_cache_max_setting); ++ + if (combined_cache_size_set) { + if (l2_cache_size_set && refcount_cache_size_set) { + error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE + " and " QCOW2_OPT_REFCOUNT_CACHE_SIZE " may not be set " + "the same time"); + return; +- } else if (*l2_cache_size > combined_cache_size) { ++ } else if (l2_cache_size_set && ++ (l2_cache_max_setting > combined_cache_size)) { + error_setg(errp, QCOW2_OPT_L2_CACHE_SIZE " may not exceed " + QCOW2_OPT_CACHE_SIZE); + return; +@@ -810,9 +816,6 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + } else if (refcount_cache_size_set) { + *l2_cache_size = combined_cache_size - *refcount_cache_size; + } else { +- uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; +- uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); +- + /* Assign as much memory as possible to the L2 cache, and + * use the remainder for the refcount cache */ + if (combined_cache_size >= max_l2_cache + min_refcount_cache) { +@@ -824,12 +827,6 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + *l2_cache_size = combined_cache_size - *refcount_cache_size; + } + } +- } else { +- if (!l2_cache_size_set) { +- *l2_cache_size = MAX(DEFAULT_L2_CACHE_SIZE, +- (uint64_t)DEFAULT_L2_CACHE_CLUSTERS +- * s->cluster_size); +- } + } + /* l2_cache_size and refcount_cache_size are ensured to have at least + * their minimum values in qcow2_update_options_prepare() */ +diff --git a/block/qcow2.h b/block/qcow2.h +index f73a48a..d0dd4a2 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -74,9 +74,7 @@ + /* Must be at least 4 to cover all cases of refcount table growth */ + #define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */ + +-/* Whichever is more */ +-#define DEFAULT_L2_CACHE_CLUSTERS 8 /* clusters */ +-#define DEFAULT_L2_CACHE_SIZE S_1MiB ++#define DEFAULT_L2_CACHE_MAX_SIZE S_1MiB + + #define DEFAULT_CLUSTER_SIZE S_64KiB + +diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt +index 7e28b41..750447e 100644 +--- a/docs/qcow2-cache.txt ++++ b/docs/qcow2-cache.txt +@@ -125,8 +125,12 @@ There are a few things that need to be taken into account: + - Both caches must have a size that is a multiple of the cluster size + (or the cache entry size: see "Using smaller cache sizes" below). + +- - The default L2 cache size is 8 clusters or 1MB (whichever is more), +- and the minimum is 2 clusters (or 2 cache entries, see below). ++ - The maximum L2 cache size is 1 MB by default (enough for full coverage ++ of 8 GB images, with the default cluster size). This value can be ++ modified using the "l2-cache-size" option. QEMU will not use more memory ++ than needed to hold all of the image's L2 tables, regardless of this max. ++ value. The minimal L2 cache size is 2 clusters (or 2 cache entries, see ++ below). + + - The default (and minimum) refcount cache size is 4 clusters. + +@@ -184,9 +188,10 @@ Some things to take into account: + always uses the cluster size as the entry size. + + - If the L2 cache is big enough to hold all of the image's L2 tables +- (as explained in the "Choosing the right cache sizes" section +- earlier in this document) then none of this is necessary and you +- can omit the "l2-cache-entry-size" parameter altogether. ++ (as explained in the "Choosing the right cache sizes" and "How to ++ configure the cache sizes" sections in this document) then none of ++ this is necessary and you can omit the "l2-cache-entry-size" ++ parameter altogether. + + + Reducing the memory usage +diff --git a/qemu-options.hx b/qemu-options.hx +index 3308b94..e1fbc5b 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -756,9 +756,9 @@ The maximum total size of the L2 table and refcount block caches in bytes + + @item l2-cache-size + The maximum size of the L2 table cache in bytes +-(default: if cache-size is not defined - 1048576 bytes or 8 clusters, whichever +-is larger; otherwise, as large as possible or needed within the cache-size, +-while permitting the requested or the minimal refcount cache size) ++(default: if cache-size is not specified - 1M; otherwise, as large as possible ++within the cache-size, while permitting the requested or the minimal refcount ++cache size) + + @item refcount-cache-size + The maximum size of the refcount block cache in bytes +diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137 +index 8796562..19e8597 100755 +--- a/tests/qemu-iotests/137 ++++ b/tests/qemu-iotests/137 +@@ -109,7 +109,6 @@ $QEMU_IO \ + -c "reopen -o cache-size=1M,l2-cache-size=64k,refcount-cache-size=64k" \ + -c "reopen -o cache-size=1M,l2-cache-size=2M" \ + -c "reopen -o cache-size=1M,refcount-cache-size=2M" \ +- -c "reopen -o l2-cache-size=256T" \ + -c "reopen -o l2-cache-entry-size=33k" \ + -c "reopen -o l2-cache-entry-size=128k" \ + -c "reopen -o refcount-cache-size=256T" \ +@@ -119,6 +118,13 @@ $QEMU_IO \ + -c "reopen -o cache-clean-interval=-1" \ + "$TEST_IMG" | _filter_qemu_io + ++IMGOPTS="cluster_size=256k" _make_test_img 32P ++$QEMU_IO \ ++ -c "reopen -o l2-cache-entry-size=512,l2-cache-size=1T" \ ++ "$TEST_IMG" | _filter_qemu_io ++ ++_make_test_img 64M ++ + echo + echo === Test transaction semantics === + echo +diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out +index 96724a6..afcc000 100644 +--- a/tests/qemu-iotests/137.out ++++ b/tests/qemu-iotests/137.out +@@ -19,7 +19,6 @@ Parameter 'lazy-refcounts' expects 'on' or 'off' + cache-size, l2-cache-size and refcount-cache-size may not be set the same time + l2-cache-size may not exceed cache-size + refcount-cache-size may not exceed cache-size +-L2 cache size too big + L2 cache entry size must be a power of two between 512 and the cluster size (65536) + L2 cache entry size must be a power of two between 512 and the cluster size (65536) + Refcount cache size too big +@@ -27,6 +26,9 @@ Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-c + Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all + Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all + Cache clean interval too big ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=36028797018963968 ++L2 cache size too big ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + + === Test transaction semantics === + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Avoid-duplication-in-setting-the-refcount-cach.patch b/SOURCES/kvm-qcow2-Avoid-duplication-in-setting-the-refcount-cach.patch new file mode 100644 index 0000000..8736442 --- /dev/null +++ b/SOURCES/kvm-qcow2-Avoid-duplication-in-setting-the-refcount-cach.patch @@ -0,0 +1,52 @@ +From 7eca8ae696c2f3be102eef0a0e1bd0e6f24129cb Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:17 +0100 +Subject: [PATCH 16/23] qcow2: Avoid duplication in setting the refcount cache + size + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-8-kwolf@redhat.com> +Patchwork-id: 84547 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/13] qcow2: Avoid duplication in setting the refcount cache size +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +The refcount cache size does not need to be set to its minimum value in +read_cache_sizes(), as it is set to at least its minimum value in +qcow2_update_options_prepare(). + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 657ada52abb85140e56949f522ecec527b256450) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 3859112..f3b2860 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -830,10 +830,9 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + (uint64_t)DEFAULT_L2_CACHE_CLUSTERS + * s->cluster_size); + } +- if (!refcount_cache_size_set) { +- *refcount_cache_size = min_refcount_cache; +- } + } ++ /* l2_cache_size and refcount_cache_size are ensured to have at least ++ * their minimum values in qcow2_update_options_prepare() */ + + if (*l2_cache_entry_size < (1 << MIN_CLUSTER_BITS) || + *l2_cache_entry_size > s->cluster_size || +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Explicit-number-replaced-by-a-constant.patch b/SOURCES/kvm-qcow2-Explicit-number-replaced-by-a-constant.patch new file mode 100644 index 0000000..288affa --- /dev/null +++ b/SOURCES/kvm-qcow2-Explicit-number-replaced-by-a-constant.patch @@ -0,0 +1,52 @@ +From 01cb24169e6f707daea28e19dbb9cbc59180023c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:22 +0100 +Subject: [PATCH 21/23] qcow2: Explicit number replaced by a constant + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-13-kwolf@redhat.com> +Patchwork-id: 84551 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/13] qcow2: Explicit number replaced by a constant +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit bd016b912cc68c6f6c68cd5acb2e13126bd9e05c) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index acd076c..114dcdd 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1321,7 +1321,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, + /* 2^(s->refcount_order - 3) is the refcount width in bytes */ + s->refcount_block_bits = s->cluster_bits - (s->refcount_order - 3); + s->refcount_block_size = 1 << s->refcount_block_bits; +- bs->total_sectors = header.size / 512; ++ bs->total_sectors = header.size / BDRV_SECTOR_SIZE; + s->csize_shift = (62 - (s->cluster_bits - 8)); + s->csize_mask = (1 << (s->cluster_bits - 8)) - 1; + s->cluster_offset_mask = (1LL << s->csize_shift) - 1; +@@ -3494,7 +3494,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, + goto fail; + } + +- old_length = bs->total_sectors * 512; ++ old_length = bs->total_sectors * BDRV_SECTOR_SIZE; + new_l1_size = size_to_l1(s, offset); + + if (offset < old_length) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Fix-Coverity-warning-when-calculating-the-refc.patch b/SOURCES/kvm-qcow2-Fix-Coverity-warning-when-calculating-the-refc.patch new file mode 100644 index 0000000..9cd8c8f --- /dev/null +++ b/SOURCES/kvm-qcow2-Fix-Coverity-warning-when-calculating-the-refc.patch @@ -0,0 +1,75 @@ +From 5a43aa56f4a0435e9e36884088673513444b8129 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:13 +0100 +Subject: [PATCH 12/23] qcow2: Fix Coverity warning when calculating the + refcount cache size + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-4-kwolf@redhat.com> +Patchwork-id: 84543 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 03/13] qcow2: Fix Coverity warning when calculating the refcount cache size +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Alberto Garcia + +MIN_REFCOUNT_CACHE_SIZE is 4 and the cluster size is guaranteed to be +at most 2MB, so the minimum refcount cache size (in bytes) is always +going to fit in a 32-bit integer. + +Coverity doesn't know that, and since we're storing the result in a +uint64_t (*refcount_cache_size) it thinks that we need the 64 bits and +that we probably want to do a 64-bit multiplication to prevent the +result from being truncated. + +This is a false positive in this case, but it's a fair warning. +We could do a 64-bit multiplication to get rid of it, but since we +know that a 32-bit variable is enough to store this value let's simply +reuse min_refcount_cache, make it a normal int and stop doing casts. + +Reported-by: Peter Maydell +Signed-off-by: Alberto Garcia +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit 7af5eea9b34ffb7a9a9fc25ba71998a02b76e159) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 4b65e4c..a0f7234 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -775,6 +775,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + BDRVQcow2State *s = bs->opaque; + uint64_t combined_cache_size; + bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set; ++ int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; + + combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE); + l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE); +@@ -811,8 +812,6 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + } else { + uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; + uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); +- uint64_t min_refcount_cache = +- (uint64_t) MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; + + /* Assign as much memory as possible to the L2 cache, and + * use the remainder for the refcount cache */ +@@ -832,7 +831,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + * s->cluster_size); + } + if (!refcount_cache_size_set) { +- *refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; ++ *refcount_cache_size = min_refcount_cache; + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Fix-cache-clean-interval-documentation.patch b/SOURCES/kvm-qcow2-Fix-cache-clean-interval-documentation.patch new file mode 100644 index 0000000..4e31c2c --- /dev/null +++ b/SOURCES/kvm-qcow2-Fix-cache-clean-interval-documentation.patch @@ -0,0 +1,94 @@ +From c51af90d479b6fb65a64be78c94b38726f4d466b Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:23 +0100 +Subject: [PATCH 22/23] qcow2: Fix cache-clean-interval documentation + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-14-kwolf@redhat.com> +Patchwork-id: 84552 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/13] qcow2: Fix cache-clean-interval documentation +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +Fixing cache-clean-interval documentation following the recent change to +a default of 600 seconds on supported plarforms (only Linux currently). + +Signed-off-by: Leonid Bloch +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit e3a7b4556ee33feba2b396769a9c8354be06b024) +Signed-off-by: Miroslav Rezanina +--- + docs/qcow2-cache.txt | 20 ++++++++++---------- + qapi/block-core.json | 3 ++- + qemu-options.hx | 3 ++- + 3 files changed, 14 insertions(+), 12 deletions(-) + +diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt +index 59358b8..c459bf5 100644 +--- a/docs/qcow2-cache.txt ++++ b/docs/qcow2-cache.txt +@@ -202,18 +202,18 @@ Reducing the memory usage + It is possible to clean unused cache entries in order to reduce the + memory usage during periods of low I/O activity. + +-The parameter "cache-clean-interval" defines an interval (in seconds). +-All cache entries that haven't been accessed during that interval are +-removed from memory. ++The parameter "cache-clean-interval" defines an interval (in seconds), ++after which all the cache entries that haven't been accessed during the ++interval are removed from memory. Setting this parameter to 0 disables this ++feature. + +-This example removes all unused cache entries every 15 minutes: ++The following example removes all unused cache entries every 15 minutes: + + -drive file=hd.qcow2,cache-clean-interval=900 + +-If unset, the default value for this parameter is 600. Setting it to 0 +-disables this feature. ++If unset, the default value for this parameter is 600 on platforms which ++support this functionality, and is 0 (disabled) on other platforms. + +-Note that this functionality currently relies on the MADV_DONTNEED +-argument for madvise() to actually free the memory. This is a +-Linux-specific feature, so cache-clean-interval is not supported in +-other systems. ++This functionality currently relies on the MADV_DONTNEED argument for ++madvise() to actually free the memory. This is a Linux-specific feature, ++so cache-clean-interval is not supported on other systems. +diff --git a/qapi/block-core.json b/qapi/block-core.json +index f43124e..9c8c9ff 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2873,7 +2873,8 @@ + # + # @cache-clean-interval: clean unused entries in the L2 and refcount + # caches. The interval is in seconds. The default value +-# is 600, and 0 disables this feature. (since 2.5) ++# is 600 on supporting platforms, and 0 on other ++# platforms. 0 disables this feature. (since 2.5) + # + # @encrypt: Image decryption options. Mandatory for + # encrypted images, except when doing a metadata-only +diff --git a/qemu-options.hx b/qemu-options.hx +index f7c9e23..e1ac8ae 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -767,7 +767,8 @@ it which is not used for the L2 cache) + + @item cache-clean-interval + Clean unused entries in the L2 and refcount caches. The interval is in seconds. +-The default value is 600. Setting it to 0 disables this feature. ++The default value is 600 on supporting platforms, and 0 on other platforms. ++Setting it to 0 disables this feature. + + @item pass-discard-request + Whether discard requests to the qcow2 device should be forwarded to the data +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Give-the-refcount-cache-the-minimum-possible-s.patch b/SOURCES/kvm-qcow2-Give-the-refcount-cache-the-minimum-possible-s.patch new file mode 100644 index 0000000..9a04caf --- /dev/null +++ b/SOURCES/kvm-qcow2-Give-the-refcount-cache-the-minimum-possible-s.patch @@ -0,0 +1,152 @@ +From f212cada55593c16cbfdfce2eee75ccd7b375e38 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:11 +0100 +Subject: [PATCH 10/23] qcow2: Give the refcount cache the minimum possible + size by default + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-2-kwolf@redhat.com> +Patchwork-id: 84541 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/13] qcow2: Give the refcount cache the minimum possible size by default +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Alberto Garcia + +The L2 and refcount caches have default sizes that can be overridden +using the l2-cache-size and refcount-cache-size (an additional +parameter named cache-size sets the combined size of both caches). + +Unless forced by one of the aforementioned parameters, QEMU will set +the unspecified sizes so that the L2 cache is 4 times larger than the +refcount cache. + +This is based on the premise that the refcount metadata needs to be +only a fourth of the L2 metadata to cover the same amount of disk +space. This is incorrect for two reasons: + + a) The amount of disk covered by an L2 table depends solely on the + cluster size, but in the case of a refcount block it depends on + the cluster size *and* the width of each refcount entry. + The 4/1 ratio is only valid with 16-bit entries (the default). + + b) When we talk about disk space and L2 tables we are talking about + guest space (L2 tables map guest clusters to host clusters), + whereas refcount blocks are used for host clusters (including + L1/L2 tables and the refcount blocks themselves). On a fully + populated (and uncompressed) qcow2 file, image size > virtual size + so there are more refcount entries than L2 entries. + +Problem (a) could be fixed by adjusting the algorithm to take into +account the refcount entry width. Problem (b) could be fixed by +increasing a bit the refcount cache size to account for the clusters +used for qcow2 metadata. + +However this patch takes a completely different approach and instead +of keeping a ratio between both cache sizes it assigns as much as +possible to the L2 cache and the remainder to the refcount cache. + +The reason is that L2 tables are used for every single I/O request +from the guest and the effect of increasing the cache is significant +and clearly measurable. Refcount blocks are however only used for +cluster allocation and internal snapshots and in practice are accessed +sequentially in most cases, so the effect of increasing the cache is +negligible (even when doing random writes from the guest). + +So, make the refcount cache as small as possible unless the user +explicitly asks for a larger one. + +Signed-off-by: Alberto Garcia +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Message-id: 9695182c2eb11b77cb319689a1ebaa4e7c9d6591.1523968389.git.berto@igalia.com +Signed-off-by: Max Reitz +(cherry picked from commit 52253998ec3e523c9e20ae81e2a6431d8ff733ba) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 31 +++++++++++++++++++------------ + block/qcow2.h | 4 ---- + tests/qemu-iotests/137.out | 2 +- + 3 files changed, 20 insertions(+), 17 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 36d1152..4b65e4c 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -809,23 +809,30 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + } else if (refcount_cache_size_set) { + *l2_cache_size = combined_cache_size - *refcount_cache_size; + } else { +- *refcount_cache_size = combined_cache_size +- / (DEFAULT_L2_REFCOUNT_SIZE_RATIO + 1); +- *l2_cache_size = combined_cache_size - *refcount_cache_size; ++ uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; ++ uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); ++ uint64_t min_refcount_cache = ++ (uint64_t) MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; ++ ++ /* Assign as much memory as possible to the L2 cache, and ++ * use the remainder for the refcount cache */ ++ if (combined_cache_size >= max_l2_cache + min_refcount_cache) { ++ *l2_cache_size = max_l2_cache; ++ *refcount_cache_size = combined_cache_size - *l2_cache_size; ++ } else { ++ *refcount_cache_size = ++ MIN(combined_cache_size, min_refcount_cache); ++ *l2_cache_size = combined_cache_size - *refcount_cache_size; ++ } + } + } else { +- if (!l2_cache_size_set && !refcount_cache_size_set) { ++ if (!l2_cache_size_set) { + *l2_cache_size = MAX(DEFAULT_L2_CACHE_BYTE_SIZE, + (uint64_t)DEFAULT_L2_CACHE_CLUSTERS + * s->cluster_size); +- *refcount_cache_size = *l2_cache_size +- / DEFAULT_L2_REFCOUNT_SIZE_RATIO; +- } else if (!l2_cache_size_set) { +- *l2_cache_size = *refcount_cache_size +- * DEFAULT_L2_REFCOUNT_SIZE_RATIO; +- } else if (!refcount_cache_size_set) { +- *refcount_cache_size = *l2_cache_size +- / DEFAULT_L2_REFCOUNT_SIZE_RATIO; ++ } ++ if (!refcount_cache_size_set) { ++ *refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; + } + } + +diff --git a/block/qcow2.h b/block/qcow2.h +index 43163b2..3d92cdb 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -77,10 +77,6 @@ + #define DEFAULT_L2_CACHE_CLUSTERS 8 /* clusters */ + #define DEFAULT_L2_CACHE_BYTE_SIZE 1048576 /* bytes */ + +-/* The refblock cache needs only a fourth of the L2 cache size to cover as many +- * clusters */ +-#define DEFAULT_L2_REFCOUNT_SIZE_RATIO 4 +- + #define DEFAULT_CLUSTER_SIZE 65536 + + +diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out +index e28e1ea..96724a6 100644 +--- a/tests/qemu-iotests/137.out ++++ b/tests/qemu-iotests/137.out +@@ -22,7 +22,7 @@ refcount-cache-size may not exceed cache-size + L2 cache size too big + L2 cache entry size must be a power of two between 512 and the cluster size (65536) + L2 cache entry size must be a power of two between 512 and the cluster size (65536) +-L2 cache size too big ++Refcount cache size too big + Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all') + Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all + Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Increase-the-default-upper-limit-on-the-L2-cac.patch b/SOURCES/kvm-qcow2-Increase-the-default-upper-limit-on-the-L2-cac.patch new file mode 100644 index 0000000..d6d5db8 --- /dev/null +++ b/SOURCES/kvm-qcow2-Increase-the-default-upper-limit-on-the-L2-cac.patch @@ -0,0 +1,104 @@ +From fac45a82432d342bf8cf86fab57af88ba54fb0f4 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:19 +0100 +Subject: [PATCH 18/23] qcow2: Increase the default upper limit on the L2 cache + size + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-10-kwolf@redhat.com> +Patchwork-id: 84549 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 09/13] qcow2: Increase the default upper limit on the L2 cache size +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +The upper limit on the L2 cache size is increased from 1 MB to 32 MB +on Linux platforms, and to 8 MB on other platforms (this difference is +caused by the ability to set intervals for cache cleaning on Linux +platforms only). + +This is done in order to allow default full coverage with the L2 cache +for images of up to 256 GB in size (was 8 GB). Note, that only the +needed amount to cover the full image is allocated. The value which is +changed here is just the upper limit on the L2 cache size, beyond which +it will not grow, even if the size of the image will require it to. + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 80668d0fb735f0839a46278a7d42116089b82816) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.h | 6 +++++- + docs/qcow2-cache.txt | 15 +++++++++------ + qemu-options.hx | 6 +++--- + 3 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/block/qcow2.h b/block/qcow2.h +index d0dd4a2..6c6c742 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -74,7 +74,11 @@ + /* Must be at least 4 to cover all cases of refcount table growth */ + #define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */ + +-#define DEFAULT_L2_CACHE_MAX_SIZE S_1MiB ++#ifdef CONFIG_LINUX ++#define DEFAULT_L2_CACHE_MAX_SIZE S_32MiB ++#else ++#define DEFAULT_L2_CACHE_MAX_SIZE S_8MiB ++#endif + + #define DEFAULT_CLUSTER_SIZE S_64KiB + +diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt +index 750447e..1fcc065 100644 +--- a/docs/qcow2-cache.txt ++++ b/docs/qcow2-cache.txt +@@ -125,12 +125,15 @@ There are a few things that need to be taken into account: + - Both caches must have a size that is a multiple of the cluster size + (or the cache entry size: see "Using smaller cache sizes" below). + +- - The maximum L2 cache size is 1 MB by default (enough for full coverage +- of 8 GB images, with the default cluster size). This value can be +- modified using the "l2-cache-size" option. QEMU will not use more memory +- than needed to hold all of the image's L2 tables, regardless of this max. +- value. The minimal L2 cache size is 2 clusters (or 2 cache entries, see +- below). ++ - The maximum L2 cache size is 32 MB by default on Linux platforms (enough ++ for full coverage of 256 GB images, with the default cluster size). This ++ value can be modified using the "l2-cache-size" option. QEMU will not use ++ more memory than needed to hold all of the image's L2 tables, regardless ++ of this max. value. ++ On non-Linux platforms the maximal value is smaller by default (8 MB) and ++ this difference stems from the fact that on Linux the cache can be cleared ++ periodically if needed, using the "cache-clean-interval" option (see below). ++ The minimal L2 cache size is 2 clusters (or 2 cache entries, see below). + + - The default (and minimum) refcount cache size is 4 clusters. + +diff --git a/qemu-options.hx b/qemu-options.hx +index e1fbc5b..3580d16 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -756,9 +756,9 @@ The maximum total size of the L2 table and refcount block caches in bytes + + @item l2-cache-size + The maximum size of the L2 table cache in bytes +-(default: if cache-size is not specified - 1M; otherwise, as large as possible +-within the cache-size, while permitting the requested or the minimal refcount +-cache size) ++(default: if cache-size is not specified - 32M on Linux platforms, and 8M on ++non-Linux platforms; otherwise, as large as possible within the cache-size, ++while permitting the requested or the minimal refcount cache size) + + @item refcount-cache-size + The maximum size of the refcount block cache in bytes +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Make-sizes-more-humanly-readable.patch b/SOURCES/kvm-qcow2-Make-sizes-more-humanly-readable.patch new file mode 100644 index 0000000..dc7b37b --- /dev/null +++ b/SOURCES/kvm-qcow2-Make-sizes-more-humanly-readable.patch @@ -0,0 +1,82 @@ +From 320903cac23bb449df8c2e9cf737e16b3f94d684 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:16 +0100 +Subject: [PATCH 15/23] qcow2: Make sizes more humanly readable + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-7-kwolf@redhat.com> +Patchwork-id: 84546 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 06/13] qcow2: Make sizes more humanly readable +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit b6a95c6d10075bb540ce50198bbe22fc0a4392c7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 2 +- + block/qcow2.h | 9 +++++---- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index a0f7234..3859112 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -826,7 +826,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, + } + } else { + if (!l2_cache_size_set) { +- *l2_cache_size = MAX(DEFAULT_L2_CACHE_BYTE_SIZE, ++ *l2_cache_size = MAX(DEFAULT_L2_CACHE_SIZE, + (uint64_t)DEFAULT_L2_CACHE_CLUSTERS + * s->cluster_size); + } +diff --git a/block/qcow2.h b/block/qcow2.h +index 3d92cdb..f73a48a 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -27,6 +27,7 @@ + + #include "crypto/block.h" + #include "qemu/coroutine.h" ++#include "qemu/units.h" + + //#define DEBUG_ALLOC + //#define DEBUG_ALLOC2 +@@ -43,11 +44,11 @@ + + /* 8 MB refcount table is enough for 2 PB images at 64k cluster size + * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ +-#define QCOW_MAX_REFTABLE_SIZE 0x800000 ++#define QCOW_MAX_REFTABLE_SIZE S_8MiB + + /* 32 MB L1 table is enough for 2 PB images at 64k cluster size + * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ +-#define QCOW_MAX_L1_SIZE 0x2000000 ++#define QCOW_MAX_L1_SIZE S_32MiB + + /* Allow for an average of 1k per snapshot table entry, should be plenty of + * space for snapshot names and IDs */ +@@ -75,9 +76,9 @@ + + /* Whichever is more */ + #define DEFAULT_L2_CACHE_CLUSTERS 8 /* clusters */ +-#define DEFAULT_L2_CACHE_BYTE_SIZE 1048576 /* bytes */ ++#define DEFAULT_L2_CACHE_SIZE S_1MiB + +-#define DEFAULT_CLUSTER_SIZE 65536 ++#define DEFAULT_CLUSTER_SIZE S_64KiB + + + #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Options-documentation-fixes.patch b/SOURCES/kvm-qcow2-Options-documentation-fixes.patch new file mode 100644 index 0000000..ab7ddfe --- /dev/null +++ b/SOURCES/kvm-qcow2-Options-documentation-fixes.patch @@ -0,0 +1,110 @@ +From 4ae8e237a43188fd01c057a336d06942a53bc04f Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:14 +0100 +Subject: [PATCH 13/23] qcow2: Options' documentation fixes + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-5-kwolf@redhat.com> +Patchwork-id: 84544 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/13] qcow2: Options' documentation fixes +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 40fb215d483ce510e211b843352288894eb13285) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + docs/qcow2-cache.txt | 21 ++++++++++++++------- + qemu-options.hx | 9 ++++++--- + 2 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt +index 8a09a5c..7e28b41 100644 +--- a/docs/qcow2-cache.txt ++++ b/docs/qcow2-cache.txt +@@ -79,14 +79,14 @@ Choosing the right cache sizes + In order to choose the cache sizes we need to know how they relate to + the amount of allocated space. + +-The amount of virtual disk that can be mapped by the L2 and refcount ++The part of the virtual disk that can be mapped by the L2 and refcount + caches (in bytes) is: + + disk_size = l2_cache_size * cluster_size / 8 + disk_size = refcount_cache_size * cluster_size * 8 / refcount_bits + + With the default values for cluster_size (64KB) and refcount_bits +-(16), that is ++(16), this becomes: + + disk_size = l2_cache_size * 8192 + disk_size = refcount_cache_size * 32768 +@@ -97,12 +97,16 @@ need: + l2_cache_size = disk_size_GB * 131072 + refcount_cache_size = disk_size_GB * 32768 + +-QEMU has a default L2 cache of 1MB (1048576 bytes) and a refcount +-cache of 256KB (262144 bytes), so using the formulas we've just seen +-we have ++For example, 1MB of L2 cache is needed to cover every 8 GB of the virtual ++image size (given that the default cluster size is used): + +- 1048576 / 131072 = 8 GB of virtual disk covered by that cache +- 262144 / 32768 = 8 GB ++ 8 GB / 8192 = 1 MB ++ ++The refcount cache is 4 times the cluster size by default. With the default ++cluster size of 64 KB, it is 256 KB (262144 bytes). This is sufficient for ++8 GB of image size: ++ ++ 262144 * 32768 = 8 GB + + + How to configure the cache sizes +@@ -130,6 +134,9 @@ There are a few things that need to be taken into account: + memory as possible to the L2 cache before increasing the refcount + cache size. + ++ - At most two of "l2-cache-size", "refcount-cache-size", and "cache-size" ++ can be set simultaneously. ++ + Unlike L2 tables, refcount blocks are not used during normal I/O but + only during allocations and internal snapshots. In most cases they are + accessed sequentially (even during random guest I/O) so increasing the +diff --git a/qemu-options.hx b/qemu-options.hx +index 5c58760..3308b94 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -752,15 +752,18 @@ image file) + + @item cache-size + The maximum total size of the L2 table and refcount block caches in bytes +-(default: 1048576 bytes or 8 clusters, whichever is larger) ++(default: the sum of l2-cache-size and refcount-cache-size) + + @item l2-cache-size + The maximum size of the L2 table cache in bytes +-(default: 4/5 of the total cache size) ++(default: if cache-size is not defined - 1048576 bytes or 8 clusters, whichever ++is larger; otherwise, as large as possible or needed within the cache-size, ++while permitting the requested or the minimal refcount cache size) + + @item refcount-cache-size + The maximum size of the refcount block cache in bytes +-(default: 1/5 of the total cache size) ++(default: 4 times the cluster size; or if cache-size is specified, the part of ++it which is not used for the L2 cache) + + @item cache-clean-interval + Clean unused entries in the L2 and refcount caches. The interval is in seconds. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Resize-the-cache-upon-image-resizing.patch b/SOURCES/kvm-qcow2-Resize-the-cache-upon-image-resizing.patch new file mode 100644 index 0000000..7ddbdc3 --- /dev/null +++ b/SOURCES/kvm-qcow2-Resize-the-cache-upon-image-resizing.patch @@ -0,0 +1,70 @@ +From 25829686076eac2d3d6216145377ecca8f92d6bd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:20 +0100 +Subject: [PATCH 19/23] qcow2: Resize the cache upon image resizing + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-11-kwolf@redhat.com> +Patchwork-id: 84553 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/13] qcow2: Resize the cache upon image resizing +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +The caches are now recalculated upon image resizing. This is done +because the new default behavior of assigning L2 cache relatively to +the image size, implies that the cache will be adapted accordingly +after an image resize. + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 45b4949c7bcdcd998cb42f5c517e80a2657cfd33) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/block/qcow2.c b/block/qcow2.c +index fc6bddd..72f1ea8 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3462,6 +3462,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, + uint64_t old_length; + int64_t new_l1_size; + int ret; ++ QDict *options; + + if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_METADATA && + prealloc != PREALLOC_MODE_FALLOC && prealloc != PREALLOC_MODE_FULL) +@@ -3686,6 +3687,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, + } + } + ++ bs->total_sectors = offset / BDRV_SECTOR_SIZE; ++ + /* write updated header.size */ + offset = cpu_to_be64(offset); + ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), +@@ -3696,6 +3699,14 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, + } + + s->l1_vm_state_index = new_l1_size; ++ ++ /* Update cache sizes */ ++ options = qdict_clone_shallow(bs->options); ++ ret = qcow2_update_options(bs, options, s->flags, errp); ++ qobject_unref(options); ++ if (ret < 0) { ++ goto fail; ++ } + ret = 0; + fail: + qemu_co_mutex_unlock(&s->lock); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Set-the-default-cache-clean-interval-to-10-min.patch b/SOURCES/kvm-qcow2-Set-the-default-cache-clean-interval-to-10-min.patch new file mode 100644 index 0000000..49a136c --- /dev/null +++ b/SOURCES/kvm-qcow2-Set-the-default-cache-clean-interval-to-10-min.patch @@ -0,0 +1,118 @@ +From 098468977d64b1c8f63ae6fb312e24698d368c74 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 19 Feb 2019 17:00:21 +0100 +Subject: [PATCH 20/23] qcow2: Set the default cache-clean-interval to 10 + minutes + +RH-Author: Kevin Wolf +Message-id: <20190219170023.27826-12-kwolf@redhat.com> +Patchwork-id: 84550 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/13] qcow2: Set the default cache-clean-interval to 10 minutes +Bugzilla: 1656913 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Leonid Bloch + +The default cache-clean-interval is set to 10 minutes, in order to lower +the overhead of the qcow2 caches (before the default was 0, i.e. +disabled). + +* For non-Linux platforms the default is kept at 0, because + cache-clean-interval is not supported there yet. + +Signed-off-by: Leonid Bloch +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit e957b50b8daecfc39a1ac09855b0eacb6edfd328) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 2 +- + block/qcow2.h | 4 +++- + docs/qcow2-cache.txt | 4 ++-- + qapi/block-core.json | 3 ++- + qemu-options.hx | 2 +- + 5 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 72f1ea8..acd076c 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -940,7 +940,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, + /* New interval for cache cleanup timer */ + r->cache_clean_interval = + qemu_opt_get_number(opts, QCOW2_OPT_CACHE_CLEAN_INTERVAL, +- s->cache_clean_interval); ++ DEFAULT_CACHE_CLEAN_INTERVAL); + #ifndef CONFIG_LINUX + if (r->cache_clean_interval != 0) { + error_setg(errp, QCOW2_OPT_CACHE_CLEAN_INTERVAL +diff --git a/block/qcow2.h b/block/qcow2.h +index 6c6c742..29b041c 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -76,13 +76,15 @@ + + #ifdef CONFIG_LINUX + #define DEFAULT_L2_CACHE_MAX_SIZE S_32MiB ++#define DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */ + #else + #define DEFAULT_L2_CACHE_MAX_SIZE S_8MiB ++/* Cache clean interval is currently available only on Linux, so must be 0 */ ++#define DEFAULT_CACHE_CLEAN_INTERVAL 0 + #endif + + #define DEFAULT_CLUSTER_SIZE S_64KiB + +- + #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" + #define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" + #define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot" +diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt +index 1fcc065..59358b8 100644 +--- a/docs/qcow2-cache.txt ++++ b/docs/qcow2-cache.txt +@@ -210,8 +210,8 @@ This example removes all unused cache entries every 15 minutes: + + -drive file=hd.qcow2,cache-clean-interval=900 + +-If unset, the default value for this parameter is 0 and it disables +-this feature. ++If unset, the default value for this parameter is 600. Setting it to 0 ++disables this feature. + + Note that this functionality currently relies on the MADV_DONTNEED + argument for madvise() to actually free the memory. This is a +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 9741555..f43124e 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2873,7 +2873,8 @@ + # + # @cache-clean-interval: clean unused entries in the L2 and refcount + # caches. The interval is in seconds. The default value +-# is 0 and it disables this feature (since 2.5) ++# is 600, and 0 disables this feature. (since 2.5) ++# + # @encrypt: Image decryption options. Mandatory for + # encrypted images, except when doing a metadata-only + # probe of the image. (since 2.10) +diff --git a/qemu-options.hx b/qemu-options.hx +index 3580d16..f7c9e23 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -767,7 +767,7 @@ it which is not used for the L2 cache) + + @item cache-clean-interval + Clean unused entries in the L2 and refcount caches. The interval is in seconds. +-The default value is 0 and it disables this feature. ++The default value is 600. Setting it to 0 disables this feature. + + @item pass-discard-request + Whether discard requests to the qcow2 device should be forwarded to the data +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-list-of-bitmaps-new-test-242.patch b/SOURCES/kvm-qcow2-list-of-bitmaps-new-test-242.patch new file mode 100644 index 0000000..d00bdb9 --- /dev/null +++ b/SOURCES/kvm-qcow2-list-of-bitmaps-new-test-242.patch @@ -0,0 +1,332 @@ +From 171b297adccba187047045e533213ff1adad7173 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:38 +0100 +Subject: [PATCH 045/163] qcow2: list of bitmaps new test 242 + +RH-Author: John Snow +Message-id: <20190320214838.22027-11-jsnow@redhat.com> +Patchwork-id: 85001 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/10] qcow2: list of bitmaps new test 242 +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Andrey Shinkevich + +A new test file 242 added to the qemu-iotests set. It checks +the format of qcow2 specific information for the new added +section that lists details of bitmaps. + +Signed-off-by: Andrey Shinkevich +Message-Id: <1549638368-530182-4-git-send-email-andrey.shinkevich@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: pep8 compliance, avoid trailing blank line] +Reviewed-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake +(cherry picked from commit ddd113beedd22908e676d53803843d2f85bf91ab) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/242 | 104 ++++++++++++++++++++++++++++ + tests/qemu-iotests/242.out | 166 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 271 insertions(+) + create mode 100755 tests/qemu-iotests/242 + create mode 100644 tests/qemu-iotests/242.out + +diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242 +new file mode 100755 +index 0000000..16c65ed +--- /dev/null ++++ b/tests/qemu-iotests/242 +@@ -0,0 +1,104 @@ ++#!/usr/bin/env python ++# ++# Test for qcow2 bitmap printed information ++# ++# Copyright (c) 2019 Virtuozzo International GmbH ++# ++# 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 iotests ++import json ++from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \ ++ file_path, img_info_log, log, filter_qemu_io ++ ++iotests.verify_image_format(supported_fmts=['qcow2']) ++ ++disk = file_path('disk') ++chunk = 256 * 1024 ++bitmap_flag_unknown = 1 << 2 ++# flag_offset = 5*cluster_size + flag_offset_in_bitmap_directory_entry ++flag_offset = 0x5000f ++ ++ ++def print_bitmap(extra_args): ++ log('qemu-img info dump:\n') ++ img_info_log(disk, extra_args=extra_args) ++ result = json.loads(qemu_img_pipe('info', '--force-share', ++ '--output=json', disk)) ++ if 'bitmaps' in result['format-specific']['data']: ++ bitmaps = result['format-specific']['data']['bitmaps'] ++ log('The same bitmaps in JSON format:') ++ log(bitmaps, indent=2) ++ else: ++ log('No bitmap in JSON format output') ++ ++ ++def add_bitmap(bitmap_number, persistent, disabled): ++ granularity = 1 << (13 + bitmap_number) ++ bitmap_name = 'bitmap-' + str(bitmap_number-1) ++ vm = iotests.VM().add_drive(disk) ++ vm.launch() ++ vm.qmp_log('block-dirty-bitmap-add', node='drive0', name=bitmap_name, ++ granularity=granularity, persistent=persistent, ++ disabled=disabled) ++ vm.shutdown() ++ ++ ++def write_to_disk(offset, size): ++ write = 'write {} {}'.format(offset, size) ++ log(qemu_io('-c', write, disk), filters=[filter_qemu_io]) ++ ++ ++def toggle_flag(offset): ++ with open(disk, "r+b") as f: ++ f.seek(offset, 0) ++ c = f.read(1) ++ toggled = chr(ord(c) ^ bitmap_flag_unknown) ++ f.seek(-1, 1) ++ f.write(toggled) ++ ++ ++qemu_img_create('-f', iotests.imgfmt, disk, '1M') ++ ++for num in range(1, 4): ++ disabled = False ++ if num == 2: ++ disabled = True ++ log('Test {}'.format(num)) ++ add_bitmap(num, num > 1, disabled) ++ write_to_disk((num-1) * chunk, chunk) ++ print_bitmap([]) ++ log('') ++ ++vm = iotests.VM().add_drive(disk) ++vm.launch() ++num += 1 ++log('Test {}\nChecking "in-use" flag...'.format(num)) ++print_bitmap(['--force-share']) ++vm.shutdown() ++ ++num += 1 ++log('\nTest {}'.format(num)) ++qemu_img_create('-f', iotests.imgfmt, disk, '1M') ++add_bitmap(1, True, False) ++log('Write an unknown bitmap flag \'{}\' into a new QCOW2 image at offset {}' ++ .format(hex(bitmap_flag_unknown), flag_offset)) ++toggle_flag(flag_offset) ++img_info_log(disk) ++toggle_flag(flag_offset) ++log('Unset the unknown bitmap flag \'{}\' in the bitmap directory entry:\n' ++ .format(hex(bitmap_flag_unknown))) ++img_info_log(disk) ++log('Test complete') +diff --git a/tests/qemu-iotests/242.out b/tests/qemu-iotests/242.out +new file mode 100644 +index 0000000..fbe05d7 +--- /dev/null ++++ b/tests/qemu-iotests/242.out +@@ -0,0 +1,166 @@ ++Test 1 ++{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": false, "granularity": 16384, "name": "bitmap-0", "node": "drive0", "persistent": false}} ++{"return": {}} ++wrote 262144/262144 bytes at offset 0 ++256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++qemu-img info dump: ++ ++image: TEST_IMG ++file format: IMGFMT ++virtual size: 1.0M (1048576 bytes) ++cluster_size: 65536 ++Format specific information: ++ compat: 1.1 ++ lazy refcounts: false ++ refcount bits: 16 ++ corrupt: false ++ ++No bitmap in JSON format output ++ ++Test 2 ++{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": true, "granularity": 32768, "name": "bitmap-1", "node": "drive0", "persistent": true}} ++{"return": {}} ++wrote 262144/262144 bytes at offset 262144 ++256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++qemu-img info dump: ++ ++image: TEST_IMG ++file format: IMGFMT ++virtual size: 1.0M (1048576 bytes) ++cluster_size: 65536 ++Format specific information: ++ compat: 1.1 ++ lazy refcounts: false ++ bitmaps: ++ [0]: ++ flags: ++ name: bitmap-1 ++ granularity: 32768 ++ refcount bits: 16 ++ corrupt: false ++ ++The same bitmaps in JSON format: ++[ ++ { ++ "flags": [], ++ "granularity": 32768, ++ "name": "bitmap-1" ++ } ++] ++ ++Test 3 ++{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": false, "granularity": 65536, "name": "bitmap-2", "node": "drive0", "persistent": true}} ++{"return": {}} ++wrote 262144/262144 bytes at offset 524288 ++256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++qemu-img info dump: ++ ++image: TEST_IMG ++file format: IMGFMT ++virtual size: 1.0M (1048576 bytes) ++cluster_size: 65536 ++Format specific information: ++ compat: 1.1 ++ lazy refcounts: false ++ bitmaps: ++ [0]: ++ flags: ++ name: bitmap-1 ++ granularity: 32768 ++ [1]: ++ flags: ++ [0]: auto ++ name: bitmap-2 ++ granularity: 65536 ++ refcount bits: 16 ++ corrupt: false ++ ++The same bitmaps in JSON format: ++[ ++ { ++ "flags": [], ++ "granularity": 32768, ++ "name": "bitmap-1" ++ }, ++ { ++ "flags": [ ++ "auto" ++ ], ++ "granularity": 65536, ++ "name": "bitmap-2" ++ } ++] ++ ++Test 4 ++Checking "in-use" flag... ++qemu-img info dump: ++ ++image: TEST_IMG ++file format: IMGFMT ++virtual size: 1.0M (1048576 bytes) ++cluster_size: 65536 ++Format specific information: ++ compat: 1.1 ++ lazy refcounts: false ++ bitmaps: ++ [0]: ++ flags: ++ [0]: in-use ++ name: bitmap-1 ++ granularity: 32768 ++ [1]: ++ flags: ++ [0]: in-use ++ [1]: auto ++ name: bitmap-2 ++ granularity: 65536 ++ refcount bits: 16 ++ corrupt: false ++ ++The same bitmaps in JSON format: ++[ ++ { ++ "flags": [ ++ "in-use" ++ ], ++ "granularity": 32768, ++ "name": "bitmap-1" ++ }, ++ { ++ "flags": [ ++ "in-use", ++ "auto" ++ ], ++ "granularity": 65536, ++ "name": "bitmap-2" ++ } ++] ++ ++Test 5 ++{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": false, "granularity": 16384, "name": "bitmap-0", "node": "drive0", "persistent": true}} ++{"return": {}} ++Write an unknown bitmap flag '0x4' into a new QCOW2 image at offset 327695 ++qemu-img: Could not open 'TEST_IMG': Bitmap 'bitmap-0' doesn't satisfy the constraints ++ ++Unset the unknown bitmap flag '0x4' in the bitmap directory entry: ++ ++image: TEST_IMG ++file format: IMGFMT ++virtual size: 1.0M (1048576 bytes) ++cluster_size: 65536 ++Format specific information: ++ compat: 1.1 ++ lazy refcounts: false ++ bitmaps: ++ [0]: ++ flags: ++ [0]: auto ++ name: bitmap-0 ++ granularity: 16384 ++ refcount bits: 16 ++ corrupt: false ++ ++Test complete +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 8662839..bee2855 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -228,3 +228,4 @@ + 232 auto quick + 234 auto quick migration + 236 auto quick ++242 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qdev-Loosen-coupling-between-compat-and-other-global.patch b/SOURCES/kvm-qdev-Loosen-coupling-between-compat-and-other-global.patch new file mode 100644 index 0000000..2667323 --- /dev/null +++ b/SOURCES/kvm-qdev-Loosen-coupling-between-compat-and-other-global.patch @@ -0,0 +1,158 @@ +From a3a904263d8b2c2cb91be8f9dfb048239fc2b1e2 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:07 +0200 +Subject: [PATCH 40/53] qdev: Loosen coupling between compat and other global + properties +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-19-armbru@redhat.com> +Patchwork-id: 88002 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 18/31] qdev: Loosen coupling between compat and other global properties +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +The (upstream) patch after next creates global properties before +compat properties rather than after. That's fine upstream, because +compat properties have been divorced from global properties there, in +merge commit 31ed41889e6. Downstream, changing creation order that +way would break overriding compat properties with -global. + +Since backporting the upstream work is rather invasive, this commit +loosens the coupling between the two just enough to permit the +reordering: collect accelerator and machine compat properties in +separate lists @accel_compat_props and @machine_compat_props rather +than stuffing them all into @global_props, and apply the three lists +order @accel_compat_props, @machine_compat_props, @global_props. This +matches the order before the patch, thus no functional change. + +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + accel/accel.c | 2 +- + hw/core/machine.c | 2 +- + hw/core/qdev-properties.c | 34 +++++++++++++++++++++++++++------- + include/hw/qdev-properties.h | 9 +++------ + 4 files changed, 32 insertions(+), 15 deletions(-) + +diff --git a/accel/accel.c b/accel/accel.c +index 5f3d73f..124f957 100644 +--- a/accel/accel.c ++++ b/accel/accel.c +@@ -123,7 +123,7 @@ void configure_accelerator(MachineState *ms) + void accel_register_compat_props(AccelState *accel) + { + AccelClass *class = ACCEL_GET_CLASS(accel); +- register_compat_props_array(class->global_props); ++ register_accel_compat_props(class->global_props); + } + + static void register_accel_types(void) +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 2040177..b4804e9 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -853,7 +853,7 @@ void machine_register_compat_props(MachineState *machine) + p = g_array_index(mc->compat_props, GlobalProperty *, i); + /* Machine compat_props must never cause errors: */ + p->errp = &error_abort; +- qdev_prop_register_global(p); ++ register_machine_compat_prop(p); + } + } + +diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c +index f3a83a3..5fd6d11 100644 +--- a/hw/core/qdev-properties.c ++++ b/hw/core/qdev-properties.c +@@ -1174,6 +1174,14 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) + *ptr = value; + } + ++static GList *machine_compat_props; ++static GList *accel_compat_props; ++ ++void register_machine_compat_prop(GlobalProperty *prop) ++{ ++ machine_compat_props = g_list_append(machine_compat_props, prop); ++} ++ + static GList *global_props; + + void qdev_prop_register_global(GlobalProperty *prop) +@@ -1195,10 +1203,17 @@ void register_compat_prop(const char *driver, + qdev_prop_register_global(p); + } + +-void register_compat_props_array(GlobalProperty *prop) ++void register_accel_compat_props(GlobalProperty *props) + { +- for (; prop && prop->driver; prop++) { +- register_compat_prop(prop->driver, prop->property, prop->value); ++ GlobalProperty *p, *prop; ++ ++ for (p = props; p && p->driver; p++) { ++ prop = g_new0(GlobalProperty, 1); ++ prop->errp = &error_abort; ++ prop->driver = p->driver; ++ prop->property = p->property; ++ prop->value = p->value; ++ accel_compat_props = g_list_append(accel_compat_props, prop); + } + } + +@@ -1245,11 +1260,9 @@ int qdev_prop_check_globals(void) + return ret; + } + +-void qdev_prop_set_globals(DeviceState *dev) ++static void qdev_prop_set_globals_1(DeviceState *dev, GList *l) + { +- GList *l; +- +- for (l = global_props; l; l = l->next) { ++ for (; l; l = l->next) { + GlobalProperty *prop = l->data; + Error *err = NULL; + +@@ -1271,6 +1284,13 @@ void qdev_prop_set_globals(DeviceState *dev) + } + } + ++void qdev_prop_set_globals(DeviceState *dev) ++{ ++ qdev_prop_set_globals_1(dev, accel_compat_props); ++ qdev_prop_set_globals_1(dev, machine_compat_props); ++ qdev_prop_set_globals_1(dev, global_props); ++} ++ + /* --- 64bit unsigned int 'size' type --- */ + + static void get_size(Object *obj, Visitor *v, const char *name, void *opaque, +diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h +index b2ad8e9..19ad0ae 100644 +--- a/include/hw/qdev-properties.h ++++ b/include/hw/qdev-properties.h +@@ -280,12 +280,9 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, + */ + void register_compat_prop(const char *driver, const char *property, + const char *value); +-/* +- * register_compat_props_array(): using register_compat_prop(), which +- * only registers internal global properties (which has lower priority +- * than user-provided global properties) +- */ +-void register_compat_props_array(GlobalProperty *prop); ++ ++void register_accel_compat_props(GlobalProperty *props); ++void register_machine_compat_prop(GlobalProperty *prop); + + /** + * qdev_property_add_static: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-error-introduce-error-warn-_report_once.patch b/SOURCES/kvm-qemu-error-introduce-error-warn-_report_once.patch new file mode 100644 index 0000000..aaba848 --- /dev/null +++ b/SOURCES/kvm-qemu-error-introduce-error-warn-_report_once.patch @@ -0,0 +1,102 @@ +From 22b617c9f567f65f72a29fff454a40f4ed67b45d Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 8 Nov 2018 05:37:15 +0100 +Subject: [PATCH 08/22] qemu-error: introduce {error|warn}_report_once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Peter Xu +Message-id: <20181108053721.13162-2-peterx@redhat.com> +Patchwork-id: 82951 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/7] qemu-error: introduce {error|warn}_report_once +Bugzilla: 1627272 +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Philippe Mathieu-Daudé + +There are many error_report()s that can be used in frequently called +functions, especially on IO paths. That can be unideal in that +malicious guest can try to trigger the error tons of time which might +use up the log space on the host (e.g., libvirt can capture the stderr +of QEMU and put it persistently onto disk). In VT-d emulation code, we +have trace_vtd_error() tracer. AFAIU all those places can be replaced +by something like error_report() but trace points are mostly used to +avoid the DDOS attack that mentioned above. However using trace points +mean that errors are not dumped if trace not enabled. + +It's not a big deal in most modern server managements since we have +things like logrotate to maintain the logs and make sure the quota is +expected. However it'll still be nice that we just provide another way +to restrict message generations. In most cases, this kind of +error_report()s will only provide valid information on the first message +sent, and all the rest of similar messages will be mostly talking about +the same thing. This patch introduces *_report_once() helpers to allow +a message to be dumped only once during one QEMU process's life cycle. +It will make sure: (1) it's on by deffault, so we can even get something +without turning the trace on and reproducing, and (2) it won't be +affected by DDOS attack. + +To implement it, I stole the printk_once() macro from Linux. + +CC: Eric Blake +CC: Markus Armbruster +Signed-off-by: Peter Xu +Message-Id: <20180815095328.32414-2-peterx@redhat.com> +Reviewed-by: Markus Armbruster +[Whitespace adjusted, comments improved] +Signed-off-by: Markus Armbruster +(cherry picked from commit bc6a69dd4bfa41ae56235dcbb9a28a56e12a7dc6) +Signed-off-by: Peter Xu + +Signed-off-by: Miroslav Rezanina +--- + include/qemu/error-report.h | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h +index e1c8ae1..72fab2b 100644 +--- a/include/qemu/error-report.h ++++ b/include/qemu/error-report.h +@@ -44,6 +44,38 @@ void error_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); + void warn_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); + void info_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); + ++/* ++ * Similar to error_report(), except it prints the message just once. ++ * Return true when it prints, false otherwise. ++ */ ++#define error_report_once(fmt, ...) \ ++ ({ \ ++ static bool print_once_; \ ++ bool ret_print_once_ = !print_once_; \ ++ \ ++ if (!print_once_) { \ ++ print_once_ = true; \ ++ error_report(fmt, ##__VA_ARGS__); \ ++ } \ ++ unlikely(ret_print_once_); \ ++ }) ++ ++/* ++ * Similar to warn_report(), except it prints the message just once. ++ * Return true when it prints, false otherwise. ++ */ ++#define warn_report_once(fmt, ...) \ ++ ({ \ ++ static bool print_once_; \ ++ bool ret_print_once_ = !print_once_; \ ++ \ ++ if (!print_once_) { \ ++ print_once_ = true; \ ++ warn_report(fmt, ##__VA_ARGS__); \ ++ } \ ++ unlikely(ret_print_once_); \ ++ }) ++ + const char *error_get_progname(void); + extern bool enable_timestamp_msg; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Gracefully-shutdown-when-map-can-t-finish.patch b/SOURCES/kvm-qemu-img-Gracefully-shutdown-when-map-can-t-finish.patch new file mode 100644 index 0000000..d392d4b --- /dev/null +++ b/SOURCES/kvm-qemu-img-Gracefully-shutdown-when-map-can-t-finish.patch @@ -0,0 +1,91 @@ +From f93730ef94f17043f240950d40d4661629b89aa3 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:15 +0200 +Subject: [PATCH 05/53] qemu-img: Gracefully shutdown when map can't finish + +RH-Author: John Snow +Message-id: <20190506175629.11079-6-jsnow@redhat.com> +Patchwork-id: 87190 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 05/19] qemu-img: Gracefully shutdown when map can't finish +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +Trying 'qemu-img map -f raw nbd://localhost:10809' causes the +NBD server to output a scary message: + +qemu-nbd: Disconnect client, due to: Failed to read request: Unexpected end-of-file before all bytes were read + +This is because the NBD client, being remote, has no way to expose a +human-readable map (the --output=json data is fine, however). But +because we exit(1) right after the message, causing the client to +bypass all block cleanup, the server sees the abrupt exit and warns, +whereas it would be silent had the client had a chance to send +NBD_CMD_DISC. Other protocols may have similar cleanup issues, where +failure to blk_unref() could cause unintended effects. + +Signed-off-by: Eric Blake +Message-Id: <20190326184043.7544-1-eblake@redhat.com> +Reviewed-by: John Snow +Reviewed-by: Kevin Wolf +(cherry picked from commit 30065d142443981924786da72828ba683da35e8f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 096e844..5be2abf 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2713,14 +2713,14 @@ static int img_info(int argc, char **argv) + return 0; + } + +-static void dump_map_entry(OutputFormat output_format, MapEntry *e, +- MapEntry *next) ++static int dump_map_entry(OutputFormat output_format, MapEntry *e, ++ MapEntry *next) + { + switch (output_format) { + case OFORMAT_HUMAN: + if (e->data && !e->has_offset) { + error_report("File contains external, encrypted or compressed clusters."); +- exit(1); ++ return -1; + } + if (e->data && !e->zero) { + printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n", +@@ -2753,6 +2753,7 @@ static void dump_map_entry(OutputFormat output_format, MapEntry *e, + } + break; + } ++ return 0; + } + + static int get_block_status(BlockDriverState *bs, int64_t offset, +@@ -2939,12 +2940,15 @@ static int img_map(int argc, char **argv) + } + + if (curr.length > 0) { +- dump_map_entry(output_format, &curr, &next); ++ ret = dump_map_entry(output_format, &curr, &next); ++ if (ret < 0) { ++ goto out; ++ } + } + curr = next; + } + +- dump_map_entry(output_format, &curr, NULL); ++ ret = dump_map_entry(output_format, &curr, NULL); + + out: + blk_unref(blk); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Report-bdrv_block_status-failures.patch b/SOURCES/kvm-qemu-img-Report-bdrv_block_status-failures.patch new file mode 100644 index 0000000..528e422 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Report-bdrv_block_status-failures.patch @@ -0,0 +1,57 @@ +From 1df02b6de7da262eb8349560f27f6c41d85953cd Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 6 May 2019 17:56:11 +0200 +Subject: [PATCH 01/53] qemu-img: Report bdrv_block_status failures + +RH-Author: John Snow +Message-id: <20190506175629.11079-2-jsnow@redhat.com> +Patchwork-id: 87181 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/19] qemu-img: Report bdrv_block_status failures +Bugzilla: 1692018 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Thomas Huth + +From: Eric Blake + +If bdrv_block_status_above() fails, we are aborting the convert +process but failing to print an error message. Broken in commit +690c7301 (v2.4) when rewriting convert's logic. + +Discovered when teaching nbdkit to support NBD_CMD_BLOCK_STATUS, and +accidentally violating the protocol by returning more than one extent +in spite of qemu asking for NBD_CMD_FLAG_REQ_ONE. The qemu NBD code +should probably handle the server's non-compliance more gracefully +than failing with EINVAL, but qemu-img shouldn't be silently +squelching any block status failures. It doesn't help that qemu 3.1 +masks the qemu-img bug with extra noise that the nbd code is dumping +to stderr (that noise was cleaned up in d8b4bad8). + +Reported-by: Richard W.M. Jones +Signed-off-by: Eric Blake +Message-Id: <20190323212639.579-2-eblake@redhat.com> +Reviewed-by: Kevin Wolf +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 2058c2ad261de7f58fae01d63d3d0efa484caf2a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qemu-img.c b/qemu-img.c +index 3b147ca..096e844 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -1607,6 +1607,8 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) + count, &count, NULL, NULL); + } + if (ret < 0) { ++ error_report("error while reading block status of sector %" PRId64 ++ ": %s", sector_num, strerror(-ret)); + return ret; + } + n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-fix-error-reporting-for-object.patch b/SOURCES/kvm-qemu-img-fix-error-reporting-for-object.patch new file mode 100644 index 0000000..a710d19 --- /dev/null +++ b/SOURCES/kvm-qemu-img-fix-error-reporting-for-object.patch @@ -0,0 +1,168 @@ +From 021b459bdd231286b9029da55fc7847cd338d66e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 5 Apr 2019 21:41:02 +0200 +Subject: [PATCH 096/163] qemu-img: fix error reporting for -object +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190405214102.17467-1-jsnow@redhat.com> +Patchwork-id: 85467 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 21.5/55] qemu-img: fix error reporting for -object +Bugzilla: 1691009 +RH-Acked-by: Max Reitz +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +Error reporting for user_creatable_add_opts_foreach was changed so that +it no longer called 'error_report_err' in: + + commit 7e1e0c11127bde81cff260fc6859690435c509d6 + Author: Markus Armbruster + Date: Wed Oct 17 10:26:43 2018 +0200 + + qom: Clean up error reporting in user_creatable_add_opts_foreach() + +Some callers were updated to pass in "&error_fatal" but all the ones in +qemu-img were left passing NULL. As a result all errors went to +/dev/null instead of being reported to the user. + +Signed-off-by: Daniel P. Berrangé +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Markus Armbruster +Reviewed-by: Stefano Garzarella +Signed-off-by: Kevin Wolf +(cherry picked from commit 334c43e2c342e878311c66b4e62343f0a7c2c6be) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index fa0cbd7..3b147ca 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -505,7 +505,7 @@ static int img_create(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + goto fail; + } + +@@ -755,7 +755,7 @@ static int img_check(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -968,7 +968,7 @@ static int img_commit(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -1327,7 +1327,7 @@ static int img_compare(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + ret = 2; + goto out4; + } +@@ -2132,7 +2132,7 @@ static int img_convert(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + goto fail_getopt; + } + +@@ -2684,7 +2684,7 @@ static int img_info(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -2903,7 +2903,7 @@ static int img_map(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -3052,7 +3052,7 @@ static int img_snapshot(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -3212,7 +3212,7 @@ static int img_rebase(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -3592,7 +3592,7 @@ static int img_resize(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + return 1; + } + +@@ -3836,7 +3836,7 @@ static int img_amend(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + ret = -1; + goto out_no_progress; + } +@@ -4480,7 +4480,7 @@ static int img_dd(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + ret = -1; + goto out; + } +@@ -4757,7 +4757,7 @@ static int img_measure(int argc, char **argv) + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, +- NULL, NULL)) { ++ NULL, &error_fatal)) { + goto out; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Modern-shell-scripting-use-instead-of.patch b/SOURCES/kvm-qemu-iotests-Modern-shell-scripting-use-instead-of.patch new file mode 100644 index 0000000..87a6334 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Modern-shell-scripting-use-instead-of.patch @@ -0,0 +1,249 @@ +From 551c981778ea501b674fb4f6ae2cb5e86d9f5354 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:28 +0100 +Subject: [PATCH 061/163] qemu-iotests: Modern shell scripting (use $() instead + of ``) + +RH-Author: John Snow +Message-id: <20190322032241.8111-16-jsnow@redhat.com> +Patchwork-id: 85098 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 15/28] qemu-iotests: Modern shell scripting (use $() instead of ``) +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Mao Zhongyi + +Various shell files contain a mix between obsolete `` +and modern $(); It would be nice to convert to using +$() everywhere. For now, just do the qemu-iotests directory. + +Cc: kwolf@redhat.com +Cc: mreitz@redhat.com +Cc: eblake@redhat.com +Suggested-by: Eric Blake +Signed-off-by: Mao Zhongyi +Message-Id: <20181024094051.4470-4-maozhongyi@cmss.chinamobile.com> +Reviewed-by: Eric Blake +[eblake: tweak commit message] +Signed-off-by: Eric Blake +(cherry picked from commit 4a9e751f61522991c2fa94a4da8feda6a4d09c70) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/check | 60 ++++++++++++++++++++-------------------- + tests/qemu-iotests/common.config | 4 +-- + 2 files changed, 32 insertions(+), 32 deletions(-) + +diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check +index b377132..89ed275 100755 +--- a/tests/qemu-iotests/check ++++ b/tests/qemu-iotests/check +@@ -80,17 +80,17 @@ _full_imgfmt_details() + + _full_platform_details() + { +- os=`uname -s` +- host=`hostname -s` +- kernel=`uname -r` +- platform=`uname -m` ++ os=$(uname -s) ++ host=$(hostname -s) ++ kernel=$(uname -r) ++ platform=$(uname -m) + echo "$os/$platform $host $kernel" + } + + # $1 = prog to look for + set_prog_path() + { +- p=`command -v $1 2> /dev/null` ++ p=$(command -v $1 2> /dev/null) + if [ -n "$p" -a -x "$p" ]; then + type -p "$p" + else +@@ -147,9 +147,9 @@ do + if $group + then + # arg after -g +- group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ ++ group_list=$(sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ + s/ .*//p +-}'` ++}') + if [ -z "$group_list" ] + then + echo "Group \"$r\" is empty or not defined?" +@@ -173,9 +173,9 @@ s/ .*//p + # arg after -x + # Populate $tmp.list with all tests + awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null +- group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ ++ group_list=$(sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ + s/ .*//p +-}'` ++}') + if [ -z "$group_list" ] + then + echo "Group \"$r\" is empty or not defined?" +@@ -193,7 +193,7 @@ s/ .*//p + rm -f $tmp.sed + fi + echo "/^$t\$/d" >>$tmp.sed +- numsed=`expr $numsed + 1` ++ numsed=$(expr $numsed + 1) + done + sed -f $tmp.sed <$tmp.list >$tmp.tmp + mv $tmp.tmp $tmp.list +@@ -433,12 +433,12 @@ testlist options + ;; + + [0-9]*-[0-9]*) +- eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'` ++ eval $(echo $r | sed -e 's/^/start=/' -e 's/-/ end=/') + ;; + + [0-9]*-) +- eval `echo $r | sed -e 's/^/start=/' -e 's/-//'` +- end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'` ++ eval $(echo $r | sed -e 's/^/start=/' -e 's/-//') ++ end=$(echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //') + if [ -z "$end" ] + then + echo "No tests in range \"$r\"?" +@@ -455,8 +455,8 @@ testlist options + esac + + # get rid of leading 0s as can be interpreted as octal +- start=`echo $start | sed 's/^0*//'` +- end=`echo $end | sed 's/^0*//'` ++ start=$(echo $start | sed 's/^0*//') ++ end=$(echo $end | sed 's/^0*//') + + if $xpand + then +@@ -531,7 +531,7 @@ fi + # should be sort -n, but this did not work for Linux when this + # was ported from IRIX + # +-list=`sort $tmp.list` ++list=$(sort $tmp.list) + rm -f $tmp.list $tmp.tmp $tmp.sed + + if [ -z "$QEMU_PROG" ] +@@ -590,7 +590,7 @@ fi + export QEMU_NBD_PROG="$(type -p "$QEMU_NBD_PROG")" + + if [ -z "$QEMU_VXHS_PROG" ]; then +- export QEMU_VXHS_PROG="`set_prog_path qnio_server`" ++ export QEMU_VXHS_PROG="$(set_prog_path qnio_server)" + fi + + if [ -x "$build_iotests/socket_scm_helper" ] +@@ -616,7 +616,7 @@ _wallclock() + + _timestamp() + { +- now=`date "+%T"` ++ now=$(date "+%T") + printf %s " [$now]" + } + +@@ -642,9 +642,9 @@ END { if (NR > 0) { + + if [ -f $tmp.expunged ] + then +- notrun=`wc -l <$tmp.expunged | sed -e 's/ *//g'` +- try=`expr $try - $notrun` +- list=`echo "$list" | sed -f $tmp.expunged` ++ notrun=$(wc -l <$tmp.expunged | sed -e 's/ *//g') ++ try=$(expr $try - $notrun) ++ list=$(echo "$list" | sed -f $tmp.expunged) + fi + + echo "" >>check.log +@@ -682,8 +682,8 @@ trap "_wrapup; exit \$status" 0 1 2 3 15 + + [ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE + +-FULL_IMGFMT_DETAILS=`_full_imgfmt_details` +-FULL_HOST_DETAILS=`_full_platform_details` ++FULL_IMGFMT_DETAILS=$(_full_imgfmt_details) ++FULL_HOST_DETAILS=$(_full_platform_details) + + cat <>$tmp.time ++ echo "$seq $(expr $stop - $start)" >>$tmp.time + fi + else + echo " - output mismatch (see $seq.out.bad)" +@@ -824,14 +824,14 @@ do + if $err + then + bad="$bad $seq" +- n_bad=`expr $n_bad + 1` ++ n_bad=$(expr $n_bad + 1) + quick=false + fi +- [ -f $seq.notrun ] || try=`expr $try + 1` ++ [ -f $seq.notrun ] || try=$(expr $try + 1) + + seq="after_$seq" + done + + interrupt=false +-status=`expr $n_bad` ++status=$(expr $n_bad) + exit +diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config +index 3cda0fe..9f460f2 100644 +--- a/tests/qemu-iotests/common.config ++++ b/tests/qemu-iotests/common.config +@@ -21,8 +21,8 @@ export LANG=C + + PATH=".:$PATH" + +-HOSTOS=`uname -s` +-arch=`uname -m` ++HOSTOS=$(uname -s) ++arch=$(uname -m) + [[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" + + # make sure we have a standard umask +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Test-auto-read-only-with-drive-and-bloc.patch b/SOURCES/kvm-qemu-iotests-Test-auto-read-only-with-drive-and-bloc.patch new file mode 100644 index 0000000..90912f3 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Test-auto-read-only-with-drive-and-bloc.patch @@ -0,0 +1,259 @@ +From 64dfcbf0230040e118a00ac921ba2b39d99bb094 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:53 +0100 +Subject: [PATCH 12/34] qemu-iotests: Test auto-read-only with -drive and + -blockdev + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-12-kwolf@redhat.com> +Patchwork-id: 83119 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 11/12] qemu-iotests: Test auto-read-only with -drive and -blockdev +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 36f808fa15f85a894c2f6cce9df46d27e8f0f129) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/232 | 147 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/232.out | 59 ++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 207 insertions(+) + create mode 100755 tests/qemu-iotests/232 + create mode 100644 tests/qemu-iotests/232.out + +diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 +new file mode 100755 +index 0000000..bc2972d +--- /dev/null ++++ b/tests/qemu-iotests/232 +@@ -0,0 +1,147 @@ ++#!/bin/bash ++# ++# Test for auto-read-only ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# 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 . ++# ++ ++# creator ++owner=kwolf@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++here=`pwd` ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++ rm -f $TEST_IMG.snap ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt generic ++_supported_proto file ++_supported_os Linux ++ ++function do_run_qemu() ++{ ++ echo Testing: "$@" ++ ( ++ if ! test -t 0; then ++ while read cmd; do ++ echo $cmd ++ done ++ fi ++ echo quit ++ ) | $QEMU -nographic -monitor stdio -nodefaults "$@" ++ echo ++} ++ ++function run_qemu() ++{ ++ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp | ++ _filter_generated_node_ids | _filter_imgfmt ++} ++ ++function run_qemu_info_block() ++{ ++ echo "info block -n" | run_qemu "$@" | grep -e "(file" -e "QEMU_PROG" ++} ++ ++size=128M ++ ++_make_test_img $size ++ ++echo ++echo "=== -drive with read-write image: read-only/auto-read-only combinations ===" ++echo ++ ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on ++echo ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off ++echo ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none ++ ++echo ++echo "=== -drive with read-only image: read-only/auto-read-only combinations ===" ++echo ++ ++chmod a-w $TEST_IMG ++ ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on ++echo ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off ++echo ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on ++run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none ++ ++echo ++echo "=== -blockdev with read-write image: read-only/auto-read-only combinations ===" ++echo ++ ++chmod a+w $TEST_IMG ++ ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on ++echo ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off ++echo ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0 ++ ++echo ++echo "=== -blockdev with read-only image: read-only/auto-read-only combinations ===" ++echo ++ ++chmod a-w $TEST_IMG ++ ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on ++echo ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off ++echo ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on ++run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0 ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out +new file mode 100644 +index 0000000..dcb683a +--- /dev/null ++++ b/tests/qemu-iotests/232.out +@@ -0,0 +1,59 @@ ++QA output created by 232 ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 ++ ++=== -drive with read-write image: read-only/auto-read-only combinations === ++ ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++ ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++ ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++NODE_NAME: TEST_DIR/t.IMGFMT (file) ++ ++=== -drive with read-only image: read-only/auto-read-only combinations === ++ ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++ ++QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++ ++QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only) ++ ++=== -blockdev with read-write image: read-only/auto-read-only combinations === ++ ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++ ++node0: TEST_DIR/t.IMGFMT (file) ++node0: TEST_DIR/t.IMGFMT (file) ++node0: TEST_DIR/t.IMGFMT (file) ++ ++node0: TEST_DIR/t.IMGFMT (file) ++node0: TEST_DIR/t.IMGFMT (file) ++node0: TEST_DIR/t.IMGFMT (file) ++ ++=== -blockdev with read-only image: read-only/auto-read-only combinations === ++ ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++ ++QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied ++ ++QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied ++node0: TEST_DIR/t.IMGFMT (file, read-only) ++QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 06a7107..fcbf3f3 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -225,3 +225,4 @@ + 227 auto quick + 229 auto quick + 231 auto quick ++232 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Test-snapshot-on-with-nonexistent-TMPDI.patch b/SOURCES/kvm-qemu-iotests-Test-snapshot-on-with-nonexistent-TMPDI.patch new file mode 100644 index 0000000..6f59f9d --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Test-snapshot-on-with-nonexistent-TMPDI.patch @@ -0,0 +1,73 @@ +From f7de511ab11650d017d75a73a3492fe964ec3f95 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:10:03 +0100 +Subject: [PATCH 007/163] qemu-iotests: Test snapshot=on with nonexistent + TMPDIR + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-8-kwolf@redhat.com> +Patchwork-id: 84884 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/14] qemu-iotests: Test snapshot=on with nonexistent TMPDIR +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Alberto Garcia + +We just fixed a bug that was causing a use-after-free when QEMU was +unable to create a temporary snapshot. This is a test case for this +scenario. + +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 6a7014ef22ad3cf9110ca0e178f73a67a6483e00) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/051 | 3 +++ + tests/qemu-iotests/051.out | 3 +++ + tests/qemu-iotests/051.pc.out | 3 +++ + 3 files changed, 9 insertions(+) + +diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 +index c5cc0ee..4899f84 100755 +--- a/tests/qemu-iotests/051 ++++ b/tests/qemu-iotests/051 +@@ -354,6 +354,9 @@ printf %b "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id\n" | + + $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io + ++# Using snapshot=on with a non-existent TMPDIR ++TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out +index b727350..793af2a 100644 +--- a/tests/qemu-iotests/051.out ++++ b/tests/qemu-iotests/051.out +@@ -455,4 +455,7 @@ wrote 4096/4096 bytes at offset 0 + + read 4096/4096 bytes at offset 0 + 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Testing: -drive driver=null-co,snapshot=on ++QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory ++ + *** done +diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out +index e9257fe..ca64eda 100644 +--- a/tests/qemu-iotests/051.pc.out ++++ b/tests/qemu-iotests/051.pc.out +@@ -527,4 +527,7 @@ wrote 4096/4096 bytes at offset 0 + + read 4096/4096 bytes at offset 0 + 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Testing: -drive driver=null-co,snapshot=on ++QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory ++ + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-convert-pwd-and-pwd-to-PWD.patch b/SOURCES/kvm-qemu-iotests-convert-pwd-and-pwd-to-PWD.patch new file mode 100644 index 0000000..b4fcc19 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-convert-pwd-and-pwd-to-PWD.patch @@ -0,0 +1,135 @@ +From 2da89bf5ccc55e0535fecc5b507bacac5c6ad3b4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:27 +0100 +Subject: [PATCH 060/163] qemu-iotests: convert `pwd` and $(pwd) to $PWD + +RH-Author: John Snow +Message-id: <20190322032241.8111-15-jsnow@redhat.com> +Patchwork-id: 85097 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 14/28] qemu-iotests: convert `pwd` and $(pwd) to $PWD +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Mao Zhongyi + +POSIX requires $PWD to be reliable, and we expect all +shells used by qemu scripts to be relatively close to +POSIX. Thus, it is smarter to avoid forking the pwd +executable for something that is already available in +the environment. + +So replace it with the following: + +sed -i 's/\(`pwd`\|\$(pwd)\)/$PWD/g' $(git grep -l pwd) + +Then delete a pointless line assigning PWD to itself. + +Cc: kwolf@redhat.com +Cc: mreitz@redhat.com +Cc: eblake@redhat.com +Suggested-by: Eric Blake +Signed-off-by: Mao Zhongyi +Message-Id: <20181024094051.4470-2-maozhongyi@cmss.chinamobile.com> +Reviewed-by: Eric Blake +[eblake: touch up commit message, reorder series, tweak a couple more files] +Signed-off-by: Eric Blake +(cherry picked from commit e8d81a61e1b9e28267164f751dee5b9b59444e71) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + configure | 2 +- + scripts/coccinelle/tcg_gen_extract.cocci | 2 +- + tests/check-block.sh | 6 +++--- + tests/qemu-iotests/check | 2 +- + tests/qemu-iotests/common.config | 2 -- + tests/qemu-iotests/common.rc | 2 +- + 6 files changed, 7 insertions(+), 9 deletions(-) + +diff --git a/configure b/configure +index f9c8365..285fd47 100755 +--- a/configure ++++ b/configure +@@ -821,7 +821,7 @@ Linux) + vhost_crypto="yes" + vhost_scsi="yes" + vhost_vsock="yes" +- QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES" ++ QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$PWD/linux-headers $QEMU_INCLUDES" + supported_os="yes" + ;; + esac +diff --git a/scripts/coccinelle/tcg_gen_extract.cocci b/scripts/coccinelle/tcg_gen_extract.cocci +index 81e66a3..c10c863 100644 +--- a/scripts/coccinelle/tcg_gen_extract.cocci ++++ b/scripts/coccinelle/tcg_gen_extract.cocci +@@ -17,7 +17,7 @@ + // --keep-comments --in-place \ + // --use-gitgrep --dir target + // +-// $ docker run --rm -v `pwd`:`pwd` -w `pwd` philmd/coccinelle \ ++// $ docker run --rm -v $PWD:$PWD -w $PWD philmd/coccinelle \ + // --macro-file scripts/cocci-macro-file.h \ + // --sp-file scripts/coccinelle/tcg_gen_extract.cocci \ + // --keep-comments --in-place \ +diff --git a/tests/check-block.sh b/tests/check-block.sh +index c3de378..f3d12fd 100755 +--- a/tests/check-block.sh ++++ b/tests/check-block.sh +@@ -5,9 +5,9 @@ if [ "$#" -ne 0 ]; then + FORMAT_LIST="$@" + fi + +-export QEMU_PROG="$(pwd)/x86_64-softmmu/qemu-system-x86_64" +-export QEMU_IMG_PROG="$(pwd)/qemu-img" +-export QEMU_IO_PROG="$(pwd)/qemu-io" ++export QEMU_PROG="$PWD/x86_64-softmmu/qemu-system-x86_64" ++export QEMU_IMG_PROG="$PWD/qemu-img" ++export QEMU_IO_PROG="$PWD/qemu-io" + + if [ ! -x $QEMU_PROG ]; then + echo "'make check-block' requires qemu-system-x86_64" +diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check +index aa94c6c..b377132 100755 +--- a/tests/qemu-iotests/check ++++ b/tests/qemu-iotests/check +@@ -99,7 +99,7 @@ set_prog_path() + } + + if [ -z "$TEST_DIR" ]; then +- TEST_DIR=`pwd`/scratch ++ TEST_DIR=$PWD/scratch + fi + + if [ ! -e "$TEST_DIR" ]; then +diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config +index 102aa68..3cda0fe 100644 +--- a/tests/qemu-iotests/common.config ++++ b/tests/qemu-iotests/common.config +@@ -25,8 +25,6 @@ HOSTOS=`uname -s` + arch=`uname -m` + [[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" + +-export PWD=`pwd` +- + # make sure we have a standard umask + umask 022 + +diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc +index 1e567b0..bb03a4b 100644 +--- a/tests/qemu-iotests/common.rc ++++ b/tests/qemu-iotests/common.rc +@@ -159,7 +159,7 @@ fi + ORIG_TEST_IMG="$TEST_IMG" + + if [ -z "$TEST_DIR" ]; then +- TEST_DIR=`pwd`/scratch ++ TEST_DIR=$PWD/scratch + fi + + QEMU_TEST_DIR="${TEST_DIR}" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-remove-unused-variable-here.patch b/SOURCES/kvm-qemu-iotests-remove-unused-variable-here.patch new file mode 100644 index 0000000..8ae8120 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-remove-unused-variable-here.patch @@ -0,0 +1,2242 @@ +From 7a29e3639569a4fd765bf293b40caa465786fddc Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:26 +0100 +Subject: [PATCH 059/163] qemu-iotests: remove unused variable 'here' + +RH-Author: John Snow +Message-id: <20190322032241.8111-14-jsnow@redhat.com> +Patchwork-id: 85101 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/28] qemu-iotests: remove unused variable 'here' +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Mao Zhongyi + +Running +git grep '\$here' tests/qemu-iotests + +has 0 hits, which means we are setting a variable that has +no use. It appears that commit e8f8624d removed the last +use. So execute the following cmd to remove all of +the 'here=...' lines as dead code. + +sed -i '/^here=/d' $(git grep -l '^here=' tests/qemu-iotests) + +Cc: kwolf@redhat.com +Cc: mreitz@redhat.com +Cc: eblake@redhat.com +Suggested-by: Eric Blake +Signed-off-by: Mao Zhongyi +Message-Id: <20181024094051.4470-3-maozhongyi@cmss.chinamobile.com> +Reviewed-by: Eric Blake +[eblake: touch up commit message, reorder series, rebase to master] +Signed-off-by: Eric Blake +(cherry picked from commit bf22957309369cf6f642e715ff6c470671920e7e) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/001 | 1 - + tests/qemu-iotests/002 | 1 - + tests/qemu-iotests/003 | 1 - + tests/qemu-iotests/004 | 1 - + tests/qemu-iotests/005 | 1 - + tests/qemu-iotests/007 | 1 - + tests/qemu-iotests/008 | 1 - + tests/qemu-iotests/009 | 1 - + tests/qemu-iotests/010 | 1 - + tests/qemu-iotests/011 | 1 - + tests/qemu-iotests/012 | 1 - + tests/qemu-iotests/013 | 1 - + tests/qemu-iotests/014 | 1 - + tests/qemu-iotests/015 | 1 - + tests/qemu-iotests/017 | 1 - + tests/qemu-iotests/018 | 1 - + tests/qemu-iotests/019 | 1 - + tests/qemu-iotests/020 | 1 - + tests/qemu-iotests/021 | 1 - + tests/qemu-iotests/022 | 1 - + tests/qemu-iotests/023 | 1 - + tests/qemu-iotests/024 | 1 - + tests/qemu-iotests/025 | 1 - + tests/qemu-iotests/026 | 1 - + tests/qemu-iotests/027 | 1 - + tests/qemu-iotests/028 | 1 - + tests/qemu-iotests/029 | 1 - + tests/qemu-iotests/031 | 1 - + tests/qemu-iotests/032 | 1 - + tests/qemu-iotests/033 | 1 - + tests/qemu-iotests/034 | 1 - + tests/qemu-iotests/035 | 1 - + tests/qemu-iotests/036 | 1 - + tests/qemu-iotests/037 | 1 - + tests/qemu-iotests/038 | 1 - + tests/qemu-iotests/039 | 1 - + tests/qemu-iotests/042 | 1 - + tests/qemu-iotests/043 | 1 - + tests/qemu-iotests/046 | 1 - + tests/qemu-iotests/047 | 1 - + tests/qemu-iotests/049 | 1 - + tests/qemu-iotests/050 | 1 - + tests/qemu-iotests/051 | 1 - + tests/qemu-iotests/052 | 1 - + tests/qemu-iotests/053 | 1 - + tests/qemu-iotests/054 | 1 - + tests/qemu-iotests/058 | 1 - + tests/qemu-iotests/059 | 1 - + tests/qemu-iotests/060 | 1 - + tests/qemu-iotests/061 | 1 - + tests/qemu-iotests/062 | 1 - + tests/qemu-iotests/063 | 1 - + tests/qemu-iotests/064 | 1 - + tests/qemu-iotests/066 | 1 - + tests/qemu-iotests/067 | 1 - + tests/qemu-iotests/068 | 1 - + tests/qemu-iotests/069 | 1 - + tests/qemu-iotests/070 | 1 - + tests/qemu-iotests/071 | 1 - + tests/qemu-iotests/072 | 1 - + tests/qemu-iotests/073 | 1 - + tests/qemu-iotests/075 | 1 - + tests/qemu-iotests/076 | 1 - + tests/qemu-iotests/077 | 1 - + tests/qemu-iotests/078 | 1 - + tests/qemu-iotests/079 | 1 - + tests/qemu-iotests/080 | 1 - + tests/qemu-iotests/081 | 1 - + tests/qemu-iotests/082 | 1 - + tests/qemu-iotests/083 | 1 - + tests/qemu-iotests/084 | 1 - + tests/qemu-iotests/085 | 1 - + tests/qemu-iotests/086 | 1 - + tests/qemu-iotests/087 | 1 - + tests/qemu-iotests/088 | 1 - + tests/qemu-iotests/089 | 1 - + tests/qemu-iotests/090 | 1 - + tests/qemu-iotests/091 | 1 - + tests/qemu-iotests/092 | 1 - + tests/qemu-iotests/094 | 1 - + tests/qemu-iotests/095 | 1 - + tests/qemu-iotests/097 | 1 - + tests/qemu-iotests/098 | 1 - + tests/qemu-iotests/099 | 1 - + tests/qemu-iotests/101 | 1 - + tests/qemu-iotests/102 | 1 - + tests/qemu-iotests/103 | 1 - + tests/qemu-iotests/104 | 1 - + tests/qemu-iotests/105 | 1 - + tests/qemu-iotests/106 | 1 - + tests/qemu-iotests/107 | 1 - + tests/qemu-iotests/108 | 1 - + tests/qemu-iotests/109 | 1 - + tests/qemu-iotests/110 | 1 - + tests/qemu-iotests/111 | 1 - + tests/qemu-iotests/112 | 1 - + tests/qemu-iotests/113 | 1 - + tests/qemu-iotests/114 | 1 - + tests/qemu-iotests/115 | 1 - + tests/qemu-iotests/116 | 1 - + tests/qemu-iotests/117 | 1 - + tests/qemu-iotests/119 | 1 - + tests/qemu-iotests/120 | 1 - + tests/qemu-iotests/121 | 1 - + tests/qemu-iotests/122 | 1 - + tests/qemu-iotests/123 | 1 - + tests/qemu-iotests/125 | 1 - + tests/qemu-iotests/126 | 1 - + tests/qemu-iotests/127 | 1 - + tests/qemu-iotests/128 | 1 - + tests/qemu-iotests/130 | 1 - + tests/qemu-iotests/131 | 1 - + tests/qemu-iotests/133 | 1 - + tests/qemu-iotests/134 | 1 - + tests/qemu-iotests/135 | 1 - + tests/qemu-iotests/137 | 1 - + tests/qemu-iotests/138 | 1 - + tests/qemu-iotests/140 | 1 - + tests/qemu-iotests/141 | 1 - + tests/qemu-iotests/142 | 1 - + tests/qemu-iotests/143 | 1 - + tests/qemu-iotests/144 | 1 - + tests/qemu-iotests/145 | 1 - + tests/qemu-iotests/146 | 1 - + tests/qemu-iotests/150 | 1 - + tests/qemu-iotests/153 | 1 - + tests/qemu-iotests/154 | 1 - + tests/qemu-iotests/156 | 1 - + tests/qemu-iotests/157 | 1 - + tests/qemu-iotests/158 | 1 - + tests/qemu-iotests/159 | 1 - + tests/qemu-iotests/160 | 1 - + tests/qemu-iotests/162 | 1 - + tests/qemu-iotests/170 | 1 - + tests/qemu-iotests/171 | 1 - + tests/qemu-iotests/172 | 1 - + tests/qemu-iotests/173 | 1 - + tests/qemu-iotests/174 | 1 - + tests/qemu-iotests/175 | 1 - + tests/qemu-iotests/176 | 1 - + tests/qemu-iotests/177 | 1 - + tests/qemu-iotests/178 | 1 - + tests/qemu-iotests/179 | 1 - + tests/qemu-iotests/181 | 1 - + tests/qemu-iotests/182 | 1 - + tests/qemu-iotests/183 | 1 - + tests/qemu-iotests/184 | 1 - + tests/qemu-iotests/185 | 1 - + tests/qemu-iotests/186 | 1 - + tests/qemu-iotests/187 | 1 - + tests/qemu-iotests/188 | 1 - + tests/qemu-iotests/189 | 1 - + tests/qemu-iotests/190 | 1 - + tests/qemu-iotests/191 | 1 - + tests/qemu-iotests/192 | 1 - + tests/qemu-iotests/195 | 1 - + tests/qemu-iotests/197 | 1 - + tests/qemu-iotests/198 | 1 - + tests/qemu-iotests/200 | 1 - + tests/qemu-iotests/204 | 1 - + tests/qemu-iotests/214 | 1 - + tests/qemu-iotests/215 | 1 - + tests/qemu-iotests/221 | 1 - + tests/qemu-iotests/223 | 1 - + tests/qemu-iotests/226 | 1 - + tests/qemu-iotests/227 | 1 - + tests/qemu-iotests/229 | 1 - + tests/qemu-iotests/231 | 1 - + tests/qemu-iotests/232 | 1 - + 169 files changed, 169 deletions(-) + +diff --git a/tests/qemu-iotests/001 b/tests/qemu-iotests/001 +index ffd14e2..55dcbb7 100755 +--- a/tests/qemu-iotests/001 ++++ b/tests/qemu-iotests/001 +@@ -24,7 +24,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002 +index d4f8e91..74572b4 100755 +--- a/tests/qemu-iotests/002 ++++ b/tests/qemu-iotests/002 +@@ -24,7 +24,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003 +index 19889b9..bf25955 100755 +--- a/tests/qemu-iotests/003 ++++ b/tests/qemu-iotests/003 +@@ -24,7 +24,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/004 b/tests/qemu-iotests/004 +index 6f2aa3d..841b15d 100755 +--- a/tests/qemu-iotests/004 ++++ b/tests/qemu-iotests/004 +@@ -24,7 +24,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005 +index 4447377..8aa4283 100755 +--- a/tests/qemu-iotests/005 ++++ b/tests/qemu-iotests/005 +@@ -27,7 +27,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007 +index fa543ee..b983022 100755 +--- a/tests/qemu-iotests/007 ++++ b/tests/qemu-iotests/007 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/008 b/tests/qemu-iotests/008 +index 8e89d74..8dfa10b 100755 +--- a/tests/qemu-iotests/008 ++++ b/tests/qemu-iotests/008 +@@ -24,7 +24,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009 +index 16e4475..73ae09d 100755 +--- a/tests/qemu-iotests/009 ++++ b/tests/qemu-iotests/009 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010 +index 151dac2..751aca9 100755 +--- a/tests/qemu-iotests/010 ++++ b/tests/qemu-iotests/010 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011 +index f8d044e..3590956 100755 +--- a/tests/qemu-iotests/011 ++++ b/tests/qemu-iotests/011 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/012 b/tests/qemu-iotests/012 +index 01a770d..de9a5fb 100755 +--- a/tests/qemu-iotests/012 ++++ b/tests/qemu-iotests/012 +@@ -26,7 +26,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013 +index d013f87..5e1efce 100755 +--- a/tests/qemu-iotests/013 ++++ b/tests/qemu-iotests/013 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014 +index 2ea79e8..9ade571 100755 +--- a/tests/qemu-iotests/014 ++++ b/tests/qemu-iotests/014 +@@ -26,7 +26,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015 +index aaf9c3f..21f7d42 100755 +--- a/tests/qemu-iotests/015 ++++ b/tests/qemu-iotests/015 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 +index 4f9302d..1ac6f74 100755 +--- a/tests/qemu-iotests/017 ++++ b/tests/qemu-iotests/017 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018 +index 1d39d35..bba30a1 100755 +--- a/tests/qemu-iotests/018 ++++ b/tests/qemu-iotests/018 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 +index 24a789a..8f911a7 100755 +--- a/tests/qemu-iotests/019 ++++ b/tests/qemu-iotests/019 +@@ -26,7 +26,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 +index eac5080..6b972d0 100755 +--- a/tests/qemu-iotests/020 ++++ b/tests/qemu-iotests/020 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/021 b/tests/qemu-iotests/021 +index 11e8ed7..c15ebf9 100755 +--- a/tests/qemu-iotests/021 ++++ b/tests/qemu-iotests/021 +@@ -24,7 +24,6 @@ owner=hch@lst.de + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/022 b/tests/qemu-iotests/022 +index 2452a9f..44765c7 100755 +--- a/tests/qemu-iotests/022 ++++ b/tests/qemu-iotests/022 +@@ -26,7 +26,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/023 b/tests/qemu-iotests/023 +index 497ae1e..c8e1b9a 100755 +--- a/tests/qemu-iotests/023 ++++ b/tests/qemu-iotests/023 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024 +index 4071ed6..428b5c8 100755 +--- a/tests/qemu-iotests/024 ++++ b/tests/qemu-iotests/024 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025 +index 70dd5f1..fcd4d97 100755 +--- a/tests/qemu-iotests/025 ++++ b/tests/qemu-iotests/025 +@@ -24,7 +24,6 @@ owner=stefanha@linux.vnet.ibm.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 +index 582d254..31276d9 100755 +--- a/tests/qemu-iotests/026 ++++ b/tests/qemu-iotests/026 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027 +index 08593da..2c46ae1 100755 +--- a/tests/qemu-iotests/027 ++++ b/tests/qemu-iotests/027 +@@ -24,7 +24,6 @@ owner=stefanha@linux.vnet.ibm.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 +index 97a8869..a2a7c93 100755 +--- a/tests/qemu-iotests/028 ++++ b/tests/qemu-iotests/028 +@@ -27,7 +27,6 @@ owner=stefanha@linux.vnet.ibm.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029 +index 30bab24..51fd0d4 100755 +--- a/tests/qemu-iotests/029 ++++ b/tests/qemu-iotests/029 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031 +index 1e08abc..ac0dfae 100755 +--- a/tests/qemu-iotests/031 ++++ b/tests/qemu-iotests/031 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032 +index 24bcb52..3e86bb0 100755 +--- a/tests/qemu-iotests/032 ++++ b/tests/qemu-iotests/032 +@@ -26,7 +26,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 +index ee8a133..46b9138 100755 +--- a/tests/qemu-iotests/033 ++++ b/tests/qemu-iotests/033 +@@ -24,7 +24,6 @@ owner=pbonzini@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034 +index 1b28bda..62812cd 100755 +--- a/tests/qemu-iotests/034 ++++ b/tests/qemu-iotests/034 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035 +index efc38e4..a5716ca 100755 +--- a/tests/qemu-iotests/035 ++++ b/tests/qemu-iotests/035 +@@ -25,7 +25,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 +index ce638d6..4e76602 100755 +--- a/tests/qemu-iotests/036 ++++ b/tests/qemu-iotests/036 +@@ -27,7 +27,6 @@ owner=stefanha@linux.vnet.ibm.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 +index c476b82..2e43b19 100755 +--- a/tests/qemu-iotests/037 ++++ b/tests/qemu-iotests/037 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038 +index d99a150..4e03976 100755 +--- a/tests/qemu-iotests/038 ++++ b/tests/qemu-iotests/038 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 +index 1f48339..b3c344c 100755 +--- a/tests/qemu-iotests/039 ++++ b/tests/qemu-iotests/039 +@@ -27,7 +27,6 @@ owner=stefanha@linux.vnet.ibm.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042 +index a53e7cb..beaa339 100755 +--- a/tests/qemu-iotests/042 ++++ b/tests/qemu-iotests/042 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043 +index 1c6c22d..fc9005b 100755 +--- a/tests/qemu-iotests/043 ++++ b/tests/qemu-iotests/043 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 +index f2ebecf..01c0de6 100755 +--- a/tests/qemu-iotests/046 ++++ b/tests/qemu-iotests/046 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047 +index 1b8f3d4..c168373 100755 +--- a/tests/qemu-iotests/047 ++++ b/tests/qemu-iotests/047 +@@ -25,7 +25,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049 +index df35b6d..4d0ad5c 100755 +--- a/tests/qemu-iotests/049 ++++ b/tests/qemu-iotests/049 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050 +index 03b4a5d..963a0db 100755 +--- a/tests/qemu-iotests/050 ++++ b/tests/qemu-iotests/050 +@@ -24,7 +24,6 @@ owner=pbonzini@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 +index 23f9678..4f20265 100755 +--- a/tests/qemu-iotests/051 ++++ b/tests/qemu-iotests/051 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 +index 842eace..b992adf 100755 +--- a/tests/qemu-iotests/052 ++++ b/tests/qemu-iotests/052 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053 +index 2a04f5f..afa109c 100755 +--- a/tests/qemu-iotests/053 ++++ b/tests/qemu-iotests/053 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054 +index bf47ef9..cf88a7c 100755 +--- a/tests/qemu-iotests/054 ++++ b/tests/qemu-iotests/054 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 +index 5eb8784..0d741a7 100755 +--- a/tests/qemu-iotests/058 ++++ b/tests/qemu-iotests/058 +@@ -26,7 +26,6 @@ owner=xiawenc@linux.vnet.ibm.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket +diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 +index 530bbbe..54d5567 100755 +--- a/tests/qemu-iotests/059 ++++ b/tests/qemu-iotests/059 +@@ -24,7 +24,6 @@ owner=famz@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 +index 7bdf609..890617b 100755 +--- a/tests/qemu-iotests/060 ++++ b/tests/qemu-iotests/060 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 +index 911b6f2..1a50163 100755 +--- a/tests/qemu-iotests/061 ++++ b/tests/qemu-iotests/061 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062 +index 051fb9f..985fbef 100755 +--- a/tests/qemu-iotests/062 ++++ b/tests/qemu-iotests/062 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 +index adc037c..041fb5c 100755 +--- a/tests/qemu-iotests/063 ++++ b/tests/qemu-iotests/063 +@@ -25,7 +25,6 @@ owner=alex@alex.org.uk + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/064 b/tests/qemu-iotests/064 +index 5792fbb..f55ff37 100755 +--- a/tests/qemu-iotests/064 ++++ b/tests/qemu-iotests/064 +@@ -24,7 +24,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066 +index 8638217..26c0437 100755 +--- a/tests/qemu-iotests/066 ++++ b/tests/qemu-iotests/066 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 +index fe259f6..f8d584f 100755 +--- a/tests/qemu-iotests/067 ++++ b/tests/qemu-iotests/067 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + # get standard environment, filters and checks +diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 +index e7fca6a..f0583d5 100755 +--- a/tests/qemu-iotests/068 ++++ b/tests/qemu-iotests/068 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069 +index 96e55ef..fdee121 100755 +--- a/tests/qemu-iotests/069 ++++ b/tests/qemu-iotests/069 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070 +index 8d08d74..78e0390 100755 +--- a/tests/qemu-iotests/070 ++++ b/tests/qemu-iotests/070 +@@ -25,7 +25,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 +index 48b4955..6448e9e 100755 +--- a/tests/qemu-iotests/071 ++++ b/tests/qemu-iotests/071 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072 +index aa027c7..08ef29f 100755 +--- a/tests/qemu-iotests/072 ++++ b/tests/qemu-iotests/072 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073 +index 40f85b1..5e7f76c 100755 +--- a/tests/qemu-iotests/073 ++++ b/tests/qemu-iotests/073 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/075 b/tests/qemu-iotests/075 +index caa30d4..45b8901 100755 +--- a/tests/qemu-iotests/075 ++++ b/tests/qemu-iotests/075 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076 +index ef9e6a4..3b5ab3f 100755 +--- a/tests/qemu-iotests/076 ++++ b/tests/qemu-iotests/076 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 +index b3c6fb1..a40f319 100755 +--- a/tests/qemu-iotests/077 ++++ b/tests/qemu-iotests/077 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/078 b/tests/qemu-iotests/078 +index a106c26..68d0ea8 100755 +--- a/tests/qemu-iotests/078 ++++ b/tests/qemu-iotests/078 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079 +index b2e3f74..fca2f77 100755 +--- a/tests/qemu-iotests/079 ++++ b/tests/qemu-iotests/079 +@@ -24,7 +24,6 @@ owner=hutao@cn.fujitsu.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080 +index 4dbe68e..8d56089 100755 +--- a/tests/qemu-iotests/080 ++++ b/tests/qemu-iotests/080 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 +index da3fb09..c5d4616 100755 +--- a/tests/qemu-iotests/081 ++++ b/tests/qemu-iotests/081 +@@ -24,7 +24,6 @@ owner=benoit@irqsave.net + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 +index 3e605d5..14f6631 100755 +--- a/tests/qemu-iotests/082 ++++ b/tests/qemu-iotests/082 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 +index 3c1adbf..982adec 100755 +--- a/tests/qemu-iotests/083 ++++ b/tests/qemu-iotests/083 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/084 b/tests/qemu-iotests/084 +index 04f2aa9..e131fa9 100755 +--- a/tests/qemu-iotests/084 ++++ b/tests/qemu-iotests/084 +@@ -25,7 +25,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 +index 5c7668c..2ef8407 100755 +--- a/tests/qemu-iotests/085 ++++ b/tests/qemu-iotests/085 +@@ -29,7 +29,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + snapshot_virt0="snapshot-v0.qcow2" +diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086 +index cd4494a..f9e4722 100755 +--- a/tests/qemu-iotests/086 ++++ b/tests/qemu-iotests/086 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 +index 2561a14..109cdf5 100755 +--- a/tests/qemu-iotests/087 ++++ b/tests/qemu-iotests/087 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + # get standard environment, filters and checks +diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088 +index b8076f2..c5e9ab4 100755 +--- a/tests/qemu-iotests/088 ++++ b/tests/qemu-iotests/088 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089 +index aa1ba4a..3165d79 100755 +--- a/tests/qemu-iotests/089 ++++ b/tests/qemu-iotests/089 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090 +index 7380503..1450993 100755 +--- a/tests/qemu-iotests/090 ++++ b/tests/qemu-iotests/090 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 +index 10ac4a8..2f2f98e 100755 +--- a/tests/qemu-iotests/091 ++++ b/tests/qemu-iotests/091 +@@ -26,7 +26,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + MIG_FIFO="${TEST_DIR}/migrate" +diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 +index 5bbdd07..8e318f1 100755 +--- a/tests/qemu-iotests/092 ++++ b/tests/qemu-iotests/092 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094 +index 9aa01e3..7adc9b9 100755 +--- a/tests/qemu-iotests/094 ++++ b/tests/qemu-iotests/094 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 +index 72ecc22..9fc47f6 100755 +--- a/tests/qemu-iotests/095 ++++ b/tests/qemu-iotests/095 +@@ -27,7 +27,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/097 b/tests/qemu-iotests/097 +index e22670c..7234b16 100755 +--- a/tests/qemu-iotests/097 ++++ b/tests/qemu-iotests/097 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098 +index b002e96..c7977da 100755 +--- a/tests/qemu-iotests/098 ++++ b/tests/qemu-iotests/098 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099 +index caaf58e..4a6275d 100755 +--- a/tests/qemu-iotests/099 ++++ b/tests/qemu-iotests/099 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/101 b/tests/qemu-iotests/101 +index ea53f8b..3001ba3 100755 +--- a/tests/qemu-iotests/101 ++++ b/tests/qemu-iotests/101 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102 +index 04b3f28..29a6a94 100755 +--- a/tests/qemu-iotests/102 ++++ b/tests/qemu-iotests/102 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq=$(basename $0) + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103 +index 2841318..66f8167 100755 +--- a/tests/qemu-iotests/103 ++++ b/tests/qemu-iotests/103 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq=$(basename $0) + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/104 b/tests/qemu-iotests/104 +index 726d467..34bb0d2 100755 +--- a/tests/qemu-iotests/104 ++++ b/tests/qemu-iotests/104 +@@ -24,7 +24,6 @@ owner=hutao@cn.fujitsu.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + trap "exit \$status" 0 1 2 3 15 +diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105 +index 3db4ce3..943bda2 100755 +--- a/tests/qemu-iotests/105 ++++ b/tests/qemu-iotests/105 +@@ -24,7 +24,6 @@ owner=famz@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 +index 5e51f88..4129fee 100755 +--- a/tests/qemu-iotests/106 ++++ b/tests/qemu-iotests/106 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq=$(basename $0) + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/107 b/tests/qemu-iotests/107 +index d7222dc..5d70ad2 100755 +--- a/tests/qemu-iotests/107 ++++ b/tests/qemu-iotests/107 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108 +index 2355d98..58e8ad7 100755 +--- a/tests/qemu-iotests/108 ++++ b/tests/qemu-iotests/108 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 +index acbd079..90bdae4 100755 +--- a/tests/qemu-iotests/109 ++++ b/tests/qemu-iotests/109 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 +index 9de7369..b64b3b2 100755 +--- a/tests/qemu-iotests/110 ++++ b/tests/qemu-iotests/110 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111 +index a1c152d..e15e66a 100755 +--- a/tests/qemu-iotests/111 ++++ b/tests/qemu-iotests/111 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112 +index 28eb9aa..fba2965 100755 +--- a/tests/qemu-iotests/112 ++++ b/tests/qemu-iotests/112 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113 +index 4e09810..d8d78c4 100755 +--- a/tests/qemu-iotests/113 ++++ b/tests/qemu-iotests/113 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 +index 5b7dc54..e17fb51 100755 +--- a/tests/qemu-iotests/114 ++++ b/tests/qemu-iotests/114 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115 +index 665c2ea..0581e03 100755 +--- a/tests/qemu-iotests/115 ++++ b/tests/qemu-iotests/115 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/116 b/tests/qemu-iotests/116 +index df0172f..f8a27b9 100755 +--- a/tests/qemu-iotests/116 ++++ b/tests/qemu-iotests/116 +@@ -27,7 +27,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117 +index 6c83461..e533e23 100755 +--- a/tests/qemu-iotests/117 ++++ b/tests/qemu-iotests/117 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119 +index 4f34fb4..32810d5 100755 +--- a/tests/qemu-iotests/119 ++++ b/tests/qemu-iotests/119 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 +index f40b97d..76afdf4 100755 +--- a/tests/qemu-iotests/120 ++++ b/tests/qemu-iotests/120 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121 +index 6d6f55a..d2885c7 100755 +--- a/tests/qemu-iotests/121 ++++ b/tests/qemu-iotests/121 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 +index d8c8ad7..eab3399 100755 +--- a/tests/qemu-iotests/122 ++++ b/tests/qemu-iotests/122 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123 +index b18e3fc..168b985 100755 +--- a/tests/qemu-iotests/123 ++++ b/tests/qemu-iotests/123 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 +index c20c715..778c874 100755 +--- a/tests/qemu-iotests/125 ++++ b/tests/qemu-iotests/125 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq=$(basename $0) + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 +index a2d4d6c..9114838 100755 +--- a/tests/qemu-iotests/126 ++++ b/tests/qemu-iotests/126 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + # get standard environment, filters and checks +diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127 +index 9e0d7d3..c9139ed 100755 +--- a/tests/qemu-iotests/127 ++++ b/tests/qemu-iotests/127 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq=$(basename $0) + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/128 b/tests/qemu-iotests/128 +index 0976a18..925f5c7 100755 +--- a/tests/qemu-iotests/128 ++++ b/tests/qemu-iotests/128 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + devname="eiodev$$" +diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 +index 2c4b94d..f2f2706 100755 +--- a/tests/qemu-iotests/130 ++++ b/tests/qemu-iotests/130 +@@ -26,7 +26,6 @@ owner=kwolf@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131 +index 94a9ae7..58c25f7 100755 +--- a/tests/qemu-iotests/131 ++++ b/tests/qemu-iotests/131 +@@ -24,7 +24,6 @@ owner=den@openvz.org + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133 +index af6b3e1..a9a47a3 100755 +--- a/tests/qemu-iotests/133 ++++ b/tests/qemu-iotests/133 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 +index 9914415..cacabcd 100755 +--- a/tests/qemu-iotests/134 ++++ b/tests/qemu-iotests/134 +@@ -24,7 +24,6 @@ owner=berrange@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/135 b/tests/qemu-iotests/135 +index ce60831..a18a0c7 100755 +--- a/tests/qemu-iotests/135 ++++ b/tests/qemu-iotests/135 +@@ -24,7 +24,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137 +index 19e8597..09cd445 100755 +--- a/tests/qemu-iotests/137 ++++ b/tests/qemu-iotests/137 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138 +index 21650d8..eccbcae 100755 +--- a/tests/qemu-iotests/138 ++++ b/tests/qemu-iotests/138 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 +index a8fc951..d4623b5 100755 +--- a/tests/qemu-iotests/140 ++++ b/tests/qemu-iotests/140 +@@ -28,7 +28,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 +index 4246d38..e2408c7 100755 +--- a/tests/qemu-iotests/141 ++++ b/tests/qemu-iotests/141 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 +index 1639c83..c7c360d 100755 +--- a/tests/qemu-iotests/142 ++++ b/tests/qemu-iotests/142 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143 +index 5ff1944..d6302cc 100755 +--- a/tests/qemu-iotests/143 ++++ b/tests/qemu-iotests/143 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144 +index 4b91571..118c099 100755 +--- a/tests/qemu-iotests/144 ++++ b/tests/qemu-iotests/144 +@@ -26,7 +26,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + TMP_SNAP1=${TEST_DIR}/tmp.qcow2 +diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 +index c371b3c..6ce8a46 100755 +--- a/tests/qemu-iotests/145 ++++ b/tests/qemu-iotests/145 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/146 b/tests/qemu-iotests/146 +index 043711b..3f61351 100755 +--- a/tests/qemu-iotests/146 ++++ b/tests/qemu-iotests/146 +@@ -24,7 +24,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/150 b/tests/qemu-iotests/150 +index ee8f637..955b877 100755 +--- a/tests/qemu-iotests/150 ++++ b/tests/qemu-iotests/150 +@@ -24,7 +24,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 +index 0daeb1b..00092b8 100755 +--- a/tests/qemu-iotests/153 ++++ b/tests/qemu-iotests/153 +@@ -24,7 +24,6 @@ owner=famz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + tmp=/tmp/$$ + status=1 # failure is the default! + +diff --git a/tests/qemu-iotests/154 b/tests/qemu-iotests/154 +index fde03b0..4a4abf0 100755 +--- a/tests/qemu-iotests/154 ++++ b/tests/qemu-iotests/154 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 +index 0a9a098..f97f96f 100755 +--- a/tests/qemu-iotests/156 ++++ b/tests/qemu-iotests/156 +@@ -32,7 +32,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 +index 2bf02be..c3231b7 100755 +--- a/tests/qemu-iotests/157 ++++ b/tests/qemu-iotests/157 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 +index 24ac600..d277ddc 100755 +--- a/tests/qemu-iotests/158 ++++ b/tests/qemu-iotests/158 +@@ -24,7 +24,6 @@ owner=berrange@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 +index 9b0e1ec..e74b273 100755 +--- a/tests/qemu-iotests/159 ++++ b/tests/qemu-iotests/159 +@@ -23,7 +23,6 @@ owner=fullmanet@gmail.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 + + _cleanup() +diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160 +index 5c910e5..92fff45 100755 +--- a/tests/qemu-iotests/160 ++++ b/tests/qemu-iotests/160 +@@ -23,7 +23,6 @@ owner=fullmanet@gmail.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 + + _cleanup() +diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162 +index 477a806..ef02d84 100755 +--- a/tests/qemu-iotests/162 ++++ b/tests/qemu-iotests/162 +@@ -25,7 +25,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 +index b79359f..861eabf 100755 +--- a/tests/qemu-iotests/170 ++++ b/tests/qemu-iotests/170 +@@ -23,7 +23,6 @@ owner=fullmanet@gmail.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 + + _cleanup() +diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 +index bcfaaf1..5b46069 100755 +--- a/tests/qemu-iotests/171 ++++ b/tests/qemu-iotests/171 +@@ -25,7 +25,6 @@ owner=tgolembi@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 +index 02c5f79..c5ee33e 100755 +--- a/tests/qemu-iotests/172 ++++ b/tests/qemu-iotests/172 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173 +index bdaa092..1fe8c5d 100755 +--- a/tests/qemu-iotests/173 ++++ b/tests/qemu-iotests/173 +@@ -24,7 +24,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174 +index 552879d..d8bb05c 100755 +--- a/tests/qemu-iotests/174 ++++ b/tests/qemu-iotests/174 +@@ -24,7 +24,6 @@ owner=nirsof@gmail.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 +index ca56e82..ebbeb6e 100755 +--- a/tests/qemu-iotests/175 ++++ b/tests/qemu-iotests/175 +@@ -24,7 +24,6 @@ owner=nirsof@gmail.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176 +index 32baa11..c091d0b 100755 +--- a/tests/qemu-iotests/176 ++++ b/tests/qemu-iotests/176 +@@ -29,7 +29,6 @@ owner=mreitz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 +index 396986d..7bf8e1d 100755 +--- a/tests/qemu-iotests/177 ++++ b/tests/qemu-iotests/177 +@@ -24,7 +24,6 @@ owner=eblake@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 +index 6af52c6..3f4b4a4 100755 +--- a/tests/qemu-iotests/178 ++++ b/tests/qemu-iotests/178 +@@ -24,7 +24,6 @@ owner=stefanha@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179 +index 115944a..3040631 100755 +--- a/tests/qemu-iotests/179 ++++ b/tests/qemu-iotests/179 +@@ -24,7 +24,6 @@ owner=eblake@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 +index 5e767c6..e0ae965 100755 +--- a/tests/qemu-iotests/181 ++++ b/tests/qemu-iotests/181 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + MIG_SOCKET="${TEST_DIR}/migrate" +diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182 +index 3b7689c..9e078c5 100755 +--- a/tests/qemu-iotests/182 ++++ b/tests/qemu-iotests/182 +@@ -24,7 +24,6 @@ owner=famz@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + tmp=/tmp/$$ + status=1 # failure is the default! + +diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183 +index c49e1ad..ebb5e30 100755 +--- a/tests/qemu-iotests/183 ++++ b/tests/qemu-iotests/183 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + MIG_SOCKET="${TEST_DIR}/migrate" +diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184 +index 2b68284..2f3259d 100755 +--- a/tests/qemu-iotests/184 ++++ b/tests/qemu-iotests/184 +@@ -24,7 +24,6 @@ owner="Manos Pitsidianakis" + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + trap "exit \$status" 0 1 2 3 15 +diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 +index 567ba67..dacfcb5 100755 +--- a/tests/qemu-iotests/185 ++++ b/tests/qemu-iotests/185 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + MIG_SOCKET="${TEST_DIR}/migrate" +diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 +index 0aa4395..29681bf 100755 +--- a/tests/qemu-iotests/186 ++++ b/tests/qemu-iotests/186 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187 +index 7bb7833..1feddca 100755 +--- a/tests/qemu-iotests/187 ++++ b/tests/qemu-iotests/187 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 +index 83ed03e..af40e49 100755 +--- a/tests/qemu-iotests/188 ++++ b/tests/qemu-iotests/188 +@@ -24,7 +24,6 @@ owner=berrange@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 +index e695475..222bec1 100755 +--- a/tests/qemu-iotests/189 ++++ b/tests/qemu-iotests/189 +@@ -24,7 +24,6 @@ owner=berrange@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190 +index 8f808fe..95ba06d 100755 +--- a/tests/qemu-iotests/190 ++++ b/tests/qemu-iotests/190 +@@ -24,7 +24,6 @@ owner=eblake@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191 +index b3629ff..ff0fdec 100755 +--- a/tests/qemu-iotests/191 ++++ b/tests/qemu-iotests/191 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + MIG_SOCKET="${TEST_DIR}/migrate" +diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192 +index 595f0d7..415c706 100755 +--- a/tests/qemu-iotests/192 ++++ b/tests/qemu-iotests/192 +@@ -25,7 +25,6 @@ owner=famz@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 +index e7a403d..f56f255 100755 +--- a/tests/qemu-iotests/195 ++++ b/tests/qemu-iotests/195 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 +index 0369aa5..8170f5d 100755 +--- a/tests/qemu-iotests/197 ++++ b/tests/qemu-iotests/197 +@@ -24,7 +24,6 @@ owner=eblake@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + # get standard environment, filters and checks +diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198 +index 54eaaf5..4d961f4 100755 +--- a/tests/qemu-iotests/198 ++++ b/tests/qemu-iotests/198 +@@ -24,7 +24,6 @@ owner=berrange@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200 +index ddbdedc..b9ebd5a 100755 +--- a/tests/qemu-iotests/200 ++++ b/tests/qemu-iotests/200 +@@ -26,7 +26,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204 +index feb69d2..57f3afe 100755 +--- a/tests/qemu-iotests/204 ++++ b/tests/qemu-iotests/204 +@@ -24,7 +24,6 @@ owner=eblake@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 +index c46ca2a..7a2d539 100755 +--- a/tests/qemu-iotests/214 ++++ b/tests/qemu-iotests/214 +@@ -22,7 +22,6 @@ + seq=$(basename "$0") + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215 +index 2e616ed..230fd25 100755 +--- a/tests/qemu-iotests/215 ++++ b/tests/qemu-iotests/215 +@@ -21,7 +21,6 @@ + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + # get standard environment, filters and checks +diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221 +index 41c4e4b..06f48f1 100755 +--- a/tests/qemu-iotests/221 ++++ b/tests/qemu-iotests/221 +@@ -21,7 +21,6 @@ + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index d011b3e..29e1951 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -21,7 +21,6 @@ + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226 +index 0bc227f..687a182 100755 +--- a/tests/qemu-iotests/226 ++++ b/tests/qemu-iotests/226 +@@ -25,7 +25,6 @@ owner=jsnow@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227 +index 9a5f7f9..43f2323 100755 +--- a/tests/qemu-iotests/227 ++++ b/tests/qemu-iotests/227 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=$(basename $0) + echo "QA output created by $seq" + +-here=$PWD + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 +index ff851ec..8660243 100755 +--- a/tests/qemu-iotests/229 ++++ b/tests/qemu-iotests/229 +@@ -25,7 +25,6 @@ owner=jcody@redhat.com + seq="$(basename $0)" + echo "QA output created by $seq" + +-here="$PWD" + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231 +index 3e28370..e9f8aaa 100755 +--- a/tests/qemu-iotests/231 ++++ b/tests/qemu-iotests/231 +@@ -26,7 +26,6 @@ owner=jcody@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 +index 2ed39d2..ae63f13 100755 +--- a/tests/qemu-iotests/232 ++++ b/tests/qemu-iotests/232 +@@ -24,7 +24,6 @@ owner=kwolf@redhat.com + seq=`basename $0` + echo "QA output created by $seq" + +-here=`pwd` + status=1 # failure is the default! + + _cleanup() +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Add-bitmap-NAME-option.patch b/SOURCES/kvm-qemu-nbd-Add-bitmap-NAME-option.patch new file mode 100644 index 0000000..761478d --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Add-bitmap-NAME-option.patch @@ -0,0 +1,189 @@ +From 608c35120c7e8026232a2c2b7083648fca20144d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:33 +0100 +Subject: [PATCH 094/163] qemu-nbd: Add --bitmap=NAME option + +RH-Author: John Snow +Message-id: <20190327172308.31077-21-jsnow@redhat.com> +Patchwork-id: 85200 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 20/55] qemu-nbd: Add --bitmap=NAME option +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Having to fire up qemu, then use QMP commands for nbd-server-start +and nbd-server-add, just to expose a persistent dirty bitmap, is +rather tedious. Make it possible to expose a dirty bitmap using +just qemu-nbd (of course, for now this only works when qemu-nbd is +visiting a BDS formatted as qcow2). + +Of course, any good feature also needs unit testing, so expand +iotest 223 to cover it. + +Signed-off-by: Eric Blake +Message-Id: <20190111194720.15671-9-eblake@redhat.com> +(cherry picked from commit 636192c4b6052820ea126a5287c58a8f53f3c84f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 10 ++++++++-- + qemu-nbd.texi | 4 ++++ + tests/qemu-iotests/223 | 18 +++++++++++++++++- + tests/qemu-iotests/223.out | 12 +++++++++++- + 4 files changed, 40 insertions(+), 4 deletions(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index ac4c958..0c92f62 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -95,6 +95,7 @@ static void usage(const char *name) + "Exposing part of the image:\n" + " -o, --offset=OFFSET offset into the image\n" + " -P, --partition=NUM only expose partition NUM\n" ++" -B, --bitmap=NAME expose a persistent dirty bitmap\n" + "\n" + "General purpose options:\n" + " --object type,id=ID,... define an object such as 'secret' for providing\n" +@@ -509,7 +510,7 @@ int main(int argc, char **argv) + off_t fd_size; + QemuOpts *sn_opts = NULL; + const char *sn_id_or_name = NULL; +- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:"; ++ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:"; + struct option lopt[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, +@@ -519,6 +520,7 @@ int main(int argc, char **argv) + { "offset", required_argument, NULL, 'o' }, + { "read-only", no_argument, NULL, 'r' }, + { "partition", required_argument, NULL, 'P' }, ++ { "bitmap", required_argument, NULL, 'B' }, + { "connect", required_argument, NULL, 'c' }, + { "disconnect", no_argument, NULL, 'd' }, + { "snapshot", no_argument, NULL, 's' }, +@@ -558,6 +560,7 @@ int main(int argc, char **argv) + QDict *options = NULL; + const char *export_name = ""; /* Default export name */ + const char *export_description = NULL; ++ const char *bitmap = NULL; + const char *tlscredsid = NULL; + bool imageOpts = false; + bool writethrough = true; +@@ -695,6 +698,9 @@ int main(int argc, char **argv) + exit(EXIT_FAILURE); + } + break; ++ case 'B': ++ bitmap = optarg; ++ break; + case 'k': + sockpath = optarg; + if (sockpath[0] != '/') { +@@ -1018,7 +1024,7 @@ int main(int argc, char **argv) + } + + export = nbd_export_new(bs, dev_offset, fd_size, export_name, +- export_description, NULL, nbdflags, ++ export_description, bitmap, nbdflags, + nbd_export_closed, writethrough, NULL, + &error_fatal); + +diff --git a/qemu-nbd.texi b/qemu-nbd.texi +index 9a84e81..96b1546 100644 +--- a/qemu-nbd.texi ++++ b/qemu-nbd.texi +@@ -45,6 +45,10 @@ auto-detecting + Export the disk as read-only + @item -P, --partition=@var{num} + Only expose partition @var{num} ++@item -B, --bitmap=@var{name} ++If @var{filename} has a qcow2 persistent bitmap @var{name}, expose ++that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context ++accessible through NBD_OPT_SET_META_CONTEXT. + @item -s, --snapshot + Use @var{filename} as an external snapshot, create a temporary + file with backing_file=@var{filename}, redirect the write to +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +index 0bcc98a..773892d 100755 +--- a/tests/qemu-iotests/223 ++++ b/tests/qemu-iotests/223 +@@ -25,6 +25,7 @@ status=1 # failure is the default! + + _cleanup() + { ++ nbd_server_stop + _cleanup_test_img + _cleanup_qemu + rm -f "$TEST_DIR/nbd" +@@ -35,6 +36,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 + . ./common.rc + . ./common.filter + . ./common.qemu ++. ./common.nbd + + _supported_fmt qcow2 + _supported_proto file # uses NBD as well +@@ -163,7 +165,7 @@ $QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map + + echo +-echo "=== End NBD server ===" ++echo "=== End qemu NBD server ===" + echo + + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", +@@ -176,6 +178,20 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "error" # Again + _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" + ++echo ++echo "=== Use qemu-nbd as server ===" ++echo ++ ++nbd_server_start_unix_socket -r -f $IMGFMT -B b "$TEST_IMG" ++IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket" ++$QEMU_IMG map --output=json --image-opts \ ++ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map ++ ++nbd_server_start_unix_socket -f $IMGFMT -B b2 "$TEST_IMG" ++IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket" ++$QEMU_IMG map --output=json --image-opts \ ++ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map ++ + # success, all done + echo '*** done' + rm -f $seq.full +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +index a0c2dec..4012bb0 100644 +--- a/tests/qemu-iotests/223.out ++++ b/tests/qemu-iotests/223.out +@@ -61,7 +61,7 @@ read 2097152/2097152 bytes at offset 2097152 + { "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true}, + { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + +-=== End NBD server === ++=== End qemu NBD server === + + {"return": {}} + {"return": {}} +@@ -69,4 +69,14 @@ read 2097152/2097152 bytes at offset 2097152 + {"return": {}} + {"error": {"class": "GenericError", "desc": "NBD server not running"}} + {"return": {}} ++ ++=== Use qemu-nbd as server === ++ ++[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, ++{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true}, ++{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] ++[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true}, ++{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, ++{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true}, ++{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Add-list-option.patch b/SOURCES/kvm-qemu-nbd-Add-list-option.patch new file mode 100644 index 0000000..7878644 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Add-list-option.patch @@ -0,0 +1,440 @@ +From 7d72cea18905a4b635ac75997d5ce719ebc5ffb3 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:53 +0100 +Subject: [PATCH 115/163] qemu-nbd: Add --list option + +RH-Author: John Snow +Message-id: <20190327172308.31077-41-jsnow@redhat.com> +Patchwork-id: 85204 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 40/55] qemu-nbd: Add --list option +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +We want to be able to detect whether a given qemu NBD server is +exposing the right export(s) and dirty bitmaps, at least for +regression testing. We could use 'nbd-client -l' from the upstream +NBD project to list exports, but it's annoying to rely on +out-of-tree binaries; furthermore, nbd-client doesn't necessarily +know about all of the qemu NBD extensions. Thus, it is time to add +a new mode to qemu-nbd that merely sniffs all possible information +from the server during handshake phase, then disconnects and dumps +the information. + +This patch actually implements --list/-L, while reusing other +options such as --tls-creds for now designating how to connect +as the client (rather than their non-list usage of how to operate +as the server). + +I debated about adding this functionality to something akin to +'qemu-img info' - but that tool does not readily lend itself +to connecting to an arbitrary NBD server without also tying to +a specific export (I may, however, still add ImageInfoSpecificNBD +for reporting the bitmaps available when connecting to a single +export). And, while it may feel a bit odd that normally +qemu-nbd is a server but 'qemu-nbd -L' is a client, we are not +really making the qemu-nbd binary that much larger, because +'qemu-nbd -c' has to operate as both server and client +simultaneously across two threads when feeding the kernel module +for /dev/nbdN access. + +Sample output: +$ qemu-nbd -L +exports available: 1 + export: '' + size: 65536 + flags: 0x4ed ( flush fua trim zeroes df cache ) + min block: 512 + opt block: 4096 + max block: 33554432 + available meta contexts: 1 + base:allocation + +Note that the output only lists sizes if the server sent +NBD_FLAG_HAS_FLAGS, because a newstyle server does not give +the size otherwise. It has the side effect that for really +old servers that did not send any flags, the size is not +output even though it was available. However, I'm not too +concerned about that - oldstyle servers are (rightfully) +getting less common to encounter (qemu 3.0 was the last +version where we even serve it), and most existing servers +that still even offer oldstyle negotiation (such as nbdkit) +still send flags (since that was added to the NBD protocol +in 2007 to permit read-only connections). + +Not done here, but maybe worth future experiments: capture +the meat of NBDExportInfo into a QAPI struct, and use the +generated QAPI pretty-printers instead of hand-rolling our +output loop. It would also permit us to add a JSON output +mode for machine parsing. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-20-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 68b96f15838d309ef791cb83b5eec1bd7da271c2) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- + qemu-nbd.texi | 29 +++++++++-- + 2 files changed, 167 insertions(+), 17 deletions(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 3c53870..1f7b2a0 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -76,7 +76,8 @@ static void usage(const char *name) + { + (printf) ( + "Usage: %s [OPTIONS] FILE\n" +-"QEMU Disk Network Block Device Server\n" ++" or: %s -L [OPTIONS]\n" ++"QEMU Disk Network Block Device Utility\n" + "\n" + " -h, --help display this help and exit\n" + " -V, --version output version information and exit\n" +@@ -98,6 +99,7 @@ static void usage(const char *name) + " -B, --bitmap=NAME expose a persistent dirty bitmap\n" + "\n" + "General purpose options:\n" ++" -L, --list list exports available from another NBD server\n" + " --object type,id=ID,... define an object such as 'secret' for providing\n" + " passwords and/or encryption keys\n" + " --tls-creds=ID use id of an earlier --object to provide TLS\n" +@@ -131,7 +133,7 @@ static void usage(const char *name) + " --image-opts treat FILE as a full set of image options\n" + "\n" + QEMU_HELP_BOTTOM "\n" +- , name, NBD_DEFAULT_PORT, "DEVICE"); ++ , name, name, NBD_DEFAULT_PORT, "DEVICE"); + } + + static void version(const char *name) +@@ -243,6 +245,91 @@ static void termsig_handler(int signum) + } + + ++static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls, ++ const char *hostname) ++{ ++ int ret = EXIT_FAILURE; ++ int rc; ++ Error *err = NULL; ++ QIOChannelSocket *sioc; ++ NBDExportInfo *list; ++ int i, j; ++ ++ sioc = qio_channel_socket_new(); ++ if (qio_channel_socket_connect_sync(sioc, saddr, &err) < 0) { ++ error_report_err(err); ++ return EXIT_FAILURE; ++ } ++ rc = nbd_receive_export_list(QIO_CHANNEL(sioc), tls, hostname, &list, ++ &err); ++ if (rc < 0) { ++ if (err) { ++ error_report_err(err); ++ } ++ goto out; ++ } ++ printf("exports available: %d\n", rc); ++ for (i = 0; i < rc; i++) { ++ printf(" export: '%s'\n", list[i].name); ++ if (list[i].description && *list[i].description) { ++ printf(" description: %s\n", list[i].description); ++ } ++ if (list[i].flags & NBD_FLAG_HAS_FLAGS) { ++ printf(" size: %" PRIu64 "\n", list[i].size); ++ printf(" flags: 0x%x (", list[i].flags); ++ if (list[i].flags & NBD_FLAG_READ_ONLY) { ++ printf(" readonly"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_FLUSH) { ++ printf(" flush"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_FUA) { ++ printf(" fua"); ++ } ++ if (list[i].flags & NBD_FLAG_ROTATIONAL) { ++ printf(" rotational"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_TRIM) { ++ printf(" trim"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_WRITE_ZEROES) { ++ printf(" zeroes"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_DF) { ++ printf(" df"); ++ } ++ if (list[i].flags & NBD_FLAG_CAN_MULTI_CONN) { ++ printf(" multi"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_RESIZE) { ++ printf(" resize"); ++ } ++ if (list[i].flags & NBD_FLAG_SEND_CACHE) { ++ printf(" cache"); ++ } ++ printf(" )\n"); ++ } ++ if (list[i].min_block) { ++ printf(" min block: %u\n", list[i].min_block); ++ printf(" opt block: %u\n", list[i].opt_block); ++ printf(" max block: %u\n", list[i].max_block); ++ } ++ if (list[i].n_contexts) { ++ printf(" available meta contexts: %d\n", list[i].n_contexts); ++ for (j = 0; j < list[i].n_contexts; j++) { ++ printf(" %s\n", list[i].contexts[j]); ++ } ++ } ++ } ++ nbd_free_export_list(list, rc); ++ ++ ret = EXIT_SUCCESS; ++ out: ++ object_unref(OBJECT(sioc)); ++ return ret; ++} ++ ++ + #if HAVE_NBD_DEVICE + static void *show_parts(void *arg) + { +@@ -425,7 +512,8 @@ static QemuOptsList qemu_object_opts = { + + + +-static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) ++static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, bool list, ++ Error **errp) + { + Object *obj; + QCryptoTLSCreds *creds; +@@ -445,10 +533,18 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) + return NULL; + } + +- if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { +- error_setg(errp, +- "Expecting TLS credentials with a server endpoint"); +- return NULL; ++ if (list) { ++ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { ++ error_setg(errp, ++ "Expecting TLS credentials with a client endpoint"); ++ return NULL; ++ } ++ } else { ++ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { ++ error_setg(errp, ++ "Expecting TLS credentials with a server endpoint"); ++ return NULL; ++ } + } + object_ref(obj); + return creds; +@@ -471,7 +567,8 @@ static void setup_address_and_port(const char **address, const char **port) + static const char *socket_activation_validate_opts(const char *device, + const char *sockpath, + const char *address, +- const char *port) ++ const char *port, ++ bool list) + { + if (device != NULL) { + return "NBD device can't be set when using socket activation"; +@@ -489,6 +586,10 @@ static const char *socket_activation_validate_opts(const char *device, + return "TCP port number can't be set when using socket activation"; + } + ++ if (list) { ++ return "List mode is incompatible with socket activation"; ++ } ++ + return NULL; + } + +@@ -512,7 +613,7 @@ int main(int argc, char **argv) + int64_t fd_size; + QemuOpts *sn_opts = NULL; + const char *sn_id_or_name = NULL; +- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:"; ++ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:L"; + struct option lopt[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, +@@ -525,6 +626,7 @@ int main(int argc, char **argv) + { "bitmap", required_argument, NULL, 'B' }, + { "connect", required_argument, NULL, 'c' }, + { "disconnect", no_argument, NULL, 'd' }, ++ { "list", no_argument, NULL, 'L' }, + { "snapshot", no_argument, NULL, 's' }, + { "load-snapshot", required_argument, NULL, 'l' }, + { "nocache", no_argument, NULL, 'n' }, +@@ -559,7 +661,7 @@ int main(int argc, char **argv) + Error *local_err = NULL; + BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; + QDict *options = NULL; +- const char *export_name = ""; /* Default export name */ ++ const char *export_name = NULL; /* defaults to "" later for server mode */ + const char *export_description = NULL; + const char *bitmap = NULL; + const char *tlscredsid = NULL; +@@ -567,6 +669,7 @@ int main(int argc, char **argv) + bool writethrough = true; + char *trace_file = NULL; + bool fork_process = false; ++ bool list = false; + int old_stderr = -1; + unsigned socket_activation; + +@@ -760,13 +863,33 @@ int main(int argc, char **argv) + case QEMU_NBD_OPT_FORK: + fork_process = true; + break; ++ case 'L': ++ list = true; ++ break; + } + } + +- if ((argc - optind) != 1) { ++ if (list) { ++ if (argc != optind) { ++ error_report("List mode is incompatible with a file name"); ++ exit(EXIT_FAILURE); ++ } ++ if (export_name || export_description || dev_offset || partition || ++ device || disconnect || fmt || sn_id_or_name || bitmap || ++ seen_aio || seen_discard || seen_cache) { ++ error_report("List mode is incompatible with per-device settings"); ++ exit(EXIT_FAILURE); ++ } ++ if (fork_process) { ++ error_report("List mode is incompatible with forking"); ++ exit(EXIT_FAILURE); ++ } ++ } else if ((argc - optind) != 1) { + error_report("Invalid number of arguments"); + error_printf("Try `%s --help' for more information.\n", argv[0]); + exit(EXIT_FAILURE); ++ } else if (!export_name) { ++ export_name = ""; + } + + qemu_opts_foreach(&qemu_object_opts, +@@ -785,7 +908,8 @@ int main(int argc, char **argv) + } else { + /* Using socket activation - check user didn't use -p etc. */ + const char *err_msg = socket_activation_validate_opts(device, sockpath, +- bindto, port); ++ bindto, port, ++ list); + if (err_msg != NULL) { + error_report("%s", err_msg); + exit(EXIT_FAILURE); +@@ -808,7 +932,7 @@ int main(int argc, char **argv) + error_report("TLS is not supported with a host device"); + exit(EXIT_FAILURE); + } +- tlscreds = nbd_get_tls_creds(tlscredsid, &local_err); ++ tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err); + if (local_err) { + error_report("Failed to get TLS creds %s", + error_get_pretty(local_err)); +@@ -816,6 +940,11 @@ int main(int argc, char **argv) + } + } + ++ if (list) { ++ saddr = nbd_build_socket_address(sockpath, bindto, port); ++ return qemu_nbd_client_list(saddr, tlscreds, bindto); ++ } ++ + #if !HAVE_NBD_DEVICE + if (disconnect || device) { + error_report("Kernel /dev/nbdN support not available"); +diff --git a/qemu-nbd.texi b/qemu-nbd.texi +index f218291..386bece 100644 +--- a/qemu-nbd.texi ++++ b/qemu-nbd.texi +@@ -2,6 +2,8 @@ + @c man begin SYNOPSIS + @command{qemu-nbd} [OPTION]... @var{filename} + ++@command{qemu-nbd} @option{-L} [OPTION]... ++ + @command{qemu-nbd} @option{-d} @var{dev} + @c man end + @end example +@@ -14,6 +16,8 @@ Other uses: + @itemize + @item + Bind a /dev/nbdX block device to a QEMU server (on Linux). ++@item ++As a client to query exports of a remote NBD server. + @end itemize + + @c man end +@@ -31,13 +35,15 @@ See the @code{qemu(1)} manual page for full details of the properties + supported. The common object types that it makes sense to define are the + @code{secret} object, which is used to supply passwords and/or encryption + keys, and the @code{tls-creds} object, which is used to supply TLS +-credentials for the qemu-nbd server. ++credentials for the qemu-nbd server or client. + @item -p, --port=@var{port} +-The TCP port to listen on (default @samp{10809}). ++The TCP port to listen on as a server, or connect to as a client ++(default @samp{10809}). + @item -o, --offset=@var{offset} + The offset into the image. + @item -b, --bind=@var{iface} +-The interface to bind to (default @samp{0.0.0.0}). ++The interface to bind to as a server, or connect to as a client ++(default @samp{0.0.0.0}). + @item -k, --socket=@var{path} + Use a unix socket with path @var{path}. + @item --image-opts +@@ -97,10 +103,16 @@ Set the NBD volume export name (default of a zero-length string). + @item -D, --description=@var{description} + Set the NBD volume export description, as a human-readable + string. ++@item -L, --list ++Connect as a client and list all details about the exports exposed by ++a remote NBD server. This enables list mode, and is incompatible ++with options that change behavior related to a specific export (such as ++@option{--export-name}, @option{--offset}, ...). + @item --tls-creds=ID + Enable mandatory TLS encryption for the server by setting the ID + of the TLS credentials object previously created with the --object +-option. ++option; or provide the credentials needed for connecting as a client ++in list mode. + @item --fork + Fork off the server process and exit the parent once the server is running. + @item -v, --verbose +@@ -162,6 +174,15 @@ qemu-nbd -c /dev/nbd0 -f qcow2 file.qcow2 + qemu-nbd -d /dev/nbd0 + @end example + ++Query a remote server to see details about what export(s) it is ++serving on port 10809, and authenticating via PSK: ++ ++@example ++qemu-nbd \ ++ --object tls-creds-psk,id=tls0,dir=/tmp/keys,username=eblake,endpoint=client \ ++ --tls-creds tls0 -L -b remote.example.com ++@end example ++ + @c man end + + @ignore +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Avoid-strtol-open-coding.patch b/SOURCES/kvm-qemu-nbd-Avoid-strtol-open-coding.patch new file mode 100644 index 0000000..c0766b6 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Avoid-strtol-open-coding.patch @@ -0,0 +1,112 @@ +From 0a0c3e3e1453856848ff9ee25ecc98045f89e194 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:41 +0100 +Subject: [PATCH 103/163] qemu-nbd: Avoid strtol open-coding + +RH-Author: John Snow +Message-id: <20190327172308.31077-29-jsnow@redhat.com> +Patchwork-id: 85191 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 28/55] qemu-nbd: Avoid strtol open-coding +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Our copy-and-pasted open-coding of strtol handling forgot to +handle overflow conditions. Use qemu_strto*() instead. + +In the case of --partition, since we insist on a user-supplied +partition to be non-zero, we can use 0 rather than -1 for our +initial value to distinguish when a partition is not being +served, for slightly more optimal code. + +The error messages for out-of-bounds values are less specific, +but should not be a terrible loss in quality. + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-8-eblake@redhat.com> +(cherry picked from commit 43b510113bb2c6393c98a31dae9b57022a9c5636) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 28 +++++++++------------------- + 1 file changed, 9 insertions(+), 19 deletions(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 598caa6..efca0e4 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -546,9 +546,8 @@ int main(int argc, char **argv) + }; + int ch; + int opt_ind = 0; +- char *end; + int flags = BDRV_O_RDWR; +- int partition = -1; ++ int partition = 0; + int ret = 0; + bool seen_cache = false; + bool seen_discard = false; +@@ -660,9 +659,8 @@ int main(int argc, char **argv) + port = optarg; + break; + case 'o': +- dev_offset = strtoll (optarg, &end, 0); +- if (*end) { +- error_report("Invalid offset `%s'", optarg); ++ if (qemu_strtou64(optarg, NULL, 0, &dev_offset) < 0) { ++ error_report("Invalid offset '%s'", optarg); + exit(EXIT_FAILURE); + } + break; +@@ -684,13 +682,9 @@ int main(int argc, char **argv) + flags &= ~BDRV_O_RDWR; + break; + case 'P': +- partition = strtol(optarg, &end, 0); +- if (*end) { +- error_report("Invalid partition `%s'", optarg); +- exit(EXIT_FAILURE); +- } +- if (partition < 1 || partition > 8) { +- error_report("Invalid partition %d", partition); ++ if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 || ++ partition < 1 || partition > 8) { ++ error_report("Invalid partition '%s'", optarg); + exit(EXIT_FAILURE); + } + break; +@@ -711,15 +705,11 @@ int main(int argc, char **argv) + device = optarg; + break; + case 'e': +- shared = strtol(optarg, &end, 0); +- if (*end) { ++ if (qemu_strtoi(optarg, NULL, 0, &shared) < 0 || ++ shared < 1) { + error_report("Invalid shared device number '%s'", optarg); + exit(EXIT_FAILURE); + } +- if (shared < 1) { +- error_report("Shared device number must be greater than 0"); +- exit(EXIT_FAILURE); +- } + break; + case 'f': + fmt = optarg; +@@ -1007,7 +997,7 @@ int main(int argc, char **argv) + } + fd_size -= dev_offset; + +- if (partition != -1) { ++ if (partition) { + uint64_t limit; + + if (dev_offset) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Deprecate-qemu-nbd-partition.patch b/SOURCES/kvm-qemu-nbd-Deprecate-qemu-nbd-partition.patch new file mode 100644 index 0000000..e962d6f --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Deprecate-qemu-nbd-partition.patch @@ -0,0 +1,129 @@ +From f9d66802239e15434d7d0c01a8bc11afb2708a75 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:56 +0100 +Subject: [PATCH 118/163] qemu-nbd: Deprecate qemu-nbd --partition + +RH-Author: John Snow +Message-id: <20190327172308.31077-44-jsnow@redhat.com> +Patchwork-id: 85223 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 43/55] qemu-nbd: Deprecate qemu-nbd --partition +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +The existing qemu-nbd --partition code claims to handle logical +partitions up to 8, since its introduction in 2008 (commit 7a5ca86). +However, the implementation is bogus (actual MBR logical partitions +form a sort of linked list, with one partition per extended table +entry, rather than four logical partitions in a single extended +table), making the code unlikely to work for anything beyond -P5 on +actual guest images. What's more, the code does not support GPT +partitions, which are becoming more popular, and maintaining device +subsetting in both NBD and the raw device is unnecessary duplication +of effort (even if it is not too difficult). + +Note that obtaining the offsets of a partition (MBR or GPT) can be +learned by using 'qemu-nbd -c /dev/nbd0 file.qcow2 && sfdisk --dump +/dev/nbd0', but by the time you've done that, you might as well +just mount /dev/nbd0p1 that the kernel creates for you instead of +bothering with qemu exporting a subset. Or, keeping to just +user-space code, use nbdkit's partition filter, which has already +known both GPT and primary MBR partitions for a while, and was +just recently enhanced to support arbitrary logical MBR parititions. + +Start the clock on the deprecation cycle, with examples of how +to accomplish device subsetting without using -P. + +Signed-off-by: Eric Blake +Message-Id: <20190125234837.2272-1-eblake@redhat.com> +Reviewed-by: Richard W.M. Jones +Reviewed-by: Stefano Garzarella +(cherry picked from commit 0ae2d54645eb2888af6dc7f701bc02ca18e4e656) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-doc.texi | 33 +++++++++++++++++++++++++++++++++ + qemu-nbd.c | 2 ++ + qemu-nbd.texi | 6 ++++-- + 3 files changed, 39 insertions(+), 2 deletions(-) + +diff --git a/qemu-doc.texi b/qemu-doc.texi +index 88358be..2acbec5 100644 +--- a/qemu-doc.texi ++++ b/qemu-doc.texi +@@ -2987,6 +2987,39 @@ The ``xlnx-zcu102'' machine has the same features and capabilites in QEMU. + In order to prevent QEMU from automatically opening an image's backing + chain, use ``"backing": null'' instead. + ++@section Related binaries ++ ++@subsection qemu-nbd --partition (since 4.0.0) ++ ++The ``qemu-nbd --partition $digit'' code (also spelled @option{-P}) ++can only handle MBR partitions, and has never correctly handled ++logical partitions beyond partition 5. If you know the offset and ++length of the partition (perhaps by using @code{sfdisk} within the ++guest), you can achieve the effect of exporting just that subset of ++the disk by use of the @option{--image-opts} option with a raw ++blockdev using the @code{offset} and @code{size} parameters layered on ++top of any other existing blockdev. For example, if partition 1 is ++100MiB long starting at 1MiB, the old command: ++ ++@code{qemu-nbd -t -P 1 -f qcow2 file.qcow2} ++ ++can be rewritten as: ++ ++@code{qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.backing.driver=file,file.backing.filename=file.qcow2} ++ ++Alternatively, the @code{nbdkit} project provides a more powerful ++partition filter on top of its nbd plugin, which can be used to select ++an arbitrary MBR or GPT partition on top of any other full-image NBD ++export. Using this to rewrite the above example results in: ++ ++@code{qemu-nbd -t -k /tmp/sock -f qcow2 file.qcow2 &} ++@code{nbdkit -f --filter=partition nbd socket=/tmp/sock partition=1} ++ ++Note that if you are exposing the export via /dev/nbd0, it is easier ++to just export the entire image and then mount only /dev/nbd0p1 than ++it is to reinvoke @command{qemu-nbd -c /dev/nbd0} limited to just a ++subset of the image. ++ + @node License + @appendix License + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 1f7b2a0..00c07fd 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -787,6 +787,8 @@ int main(int argc, char **argv) + flags &= ~BDRV_O_RDWR; + break; + case 'P': ++ warn_report("The '-P' option is deprecated; use --image-opts with " ++ "a raw device wrapper for subset exports instead"); + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 || + partition < 1 || partition > 8) { + error_report("Invalid partition '%s'", optarg); +diff --git a/qemu-nbd.texi b/qemu-nbd.texi +index 386bece..d0c5182 100644 +--- a/qemu-nbd.texi ++++ b/qemu-nbd.texi +@@ -56,8 +56,10 @@ auto-detecting. + @item -r, --read-only + Export the disk as read-only. + @item -P, --partition=@var{num} +-Only expose MBR partition @var{num}. Understands physical partitions +-1-4 and logical partitions 5-8. ++Deprecated: Only expose MBR partition @var{num}. Understands physical ++partitions 1-4 and logical partition 5. New code should instead use ++@option{--image-opts} with the raw driver wrapping a subset of the ++original image. + @item -B, --bitmap=@var{name} + If @var{filename} has a qcow2 persistent bitmap @var{name}, expose + that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Document-tls-creds.patch b/SOURCES/kvm-qemu-nbd-Document-tls-creds.patch new file mode 100644 index 0000000..ad26030 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Document-tls-creds.patch @@ -0,0 +1,44 @@ +From 38e564acf5939c83ded3e324091a1e00631a12f8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:23 +0100 +Subject: [PATCH 056/163] qemu-nbd: Document --tls-creds + +RH-Author: John Snow +Message-id: <20190322032241.8111-11-jsnow@redhat.com> +Patchwork-id: 85103 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/28] qemu-nbd: Document --tls-creds +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Commit 145614a1 introduced --tls-creds and documented it in +qemu-nbd.texi, but forgot to document it in 'qemu-nbd --help'. + +Signed-off-by: Eric Blake +Message-Id: <20181003180426.602765-1-eblake@redhat.com> +Reviewed-by: John Snow +(cherry picked from commit f7812df77d7830c6b375066a4e656f3b79232c13) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 51b9d38..66e023f 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -94,6 +94,7 @@ static void usage(const char *name) + "General purpose options:\n" + " --object type,id=ID,... define an object such as 'secret' for providing\n" + " passwords and/or encryption keys\n" ++" --tls-creds=ID use id of an earlier --object to provide TLS\n" + " -T, --trace [[enable=]][,events=][,file=]\n" + " specify tracing options\n" + " --fork fork off the server process and exit the parent\n" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Enhance-man-page.patch b/SOURCES/kvm-qemu-nbd-Enhance-man-page.patch new file mode 100644 index 0000000..38af71b --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Enhance-man-page.patch @@ -0,0 +1,199 @@ +From 649cb3fdd8a60caa687452be84fb06de78fead9b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:37 +0100 +Subject: [PATCH 099/163] qemu-nbd: Enhance man page + +RH-Author: John Snow +Message-id: <20190327172308.31077-25-jsnow@redhat.com> +Patchwork-id: 85186 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 24/55] qemu-nbd: Enhance man page +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Document some useful qemu-nbd command lines. Mention some restrictions +on particular options, like -p being only for MBR images, or -c/-d +being Linux-only. Update some text given the recent change to no +longer serve oldstyle protocol (missed in commit 7f7dfe2a). Also, +consistently use trailing '.' in describing options. + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-4-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 86b7f6771f0cd1552791d1bfc2bdebd65cf967a3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.texi | 94 +++++++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 75 insertions(+), 19 deletions(-) + +diff --git a/qemu-nbd.texi b/qemu-nbd.texi +index 96b1546..f218291 100644 +--- a/qemu-nbd.texi ++++ b/qemu-nbd.texi +@@ -10,11 +10,17 @@ + + Export a QEMU disk image using the NBD protocol. + ++Other uses: ++@itemize ++@item ++Bind a /dev/nbdX block device to a QEMU server (on Linux). ++@end itemize ++ + @c man end + + @c man begin OPTIONS + @var{filename} is a disk image filename, or a set of block +-driver options if @var{--image-opts} is specified. ++driver options if @option{--image-opts} is specified. + + @var{dev} is an NBD device. + +@@ -27,24 +33,25 @@ supported. The common object types that it makes sense to define are the + keys, and the @code{tls-creds} object, which is used to supply TLS + credentials for the qemu-nbd server. + @item -p, --port=@var{port} +-The TCP port to listen on (default @samp{10809}) ++The TCP port to listen on (default @samp{10809}). + @item -o, --offset=@var{offset} +-The offset into the image ++The offset into the image. + @item -b, --bind=@var{iface} +-The interface to bind to (default @samp{0.0.0.0}) ++The interface to bind to (default @samp{0.0.0.0}). + @item -k, --socket=@var{path} +-Use a unix socket with path @var{path} ++Use a unix socket with path @var{path}. + @item --image-opts + Treat @var{filename} as a set of image options, instead of a plain + filename. If this flag is specified, the @var{-f} flag should + not be used, instead the '@code{format=}' option should be set. + @item -f, --format=@var{fmt} + Force the use of the block driver for format @var{fmt} instead of +-auto-detecting ++auto-detecting. + @item -r, --read-only +-Export the disk as read-only ++Export the disk as read-only. + @item -P, --partition=@var{num} +-Only expose partition @var{num} ++Only expose MBR partition @var{num}. Understands physical partitions ++1-4 and logical partitions 5-8. + @item -B, --bitmap=@var{name} + If @var{filename} has a qcow2 persistent bitmap @var{name}, expose + that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context +@@ -52,7 +59,7 @@ accessible through NBD_OPT_SET_META_CONTEXT. + @item -s, --snapshot + Use @var{filename} as an external snapshot, create a temporary + file with backing_file=@var{filename}, redirect the write to +-the temporary one ++the temporary one. + @item -l, --load-snapshot=@var{snapshot_param} + Load an internal snapshot inside @var{filename} and export it + as an read-only device, @var{snapshot_param} format is +@@ -76,19 +83,20 @@ driver-specific optimized zero write commands. @var{detect-zeroes} is one of + converts a zero write to an unmap operation and can only be used if + @var{discard} is set to @samp{unmap}. The default is @samp{off}. + @item -c, --connect=@var{dev} +-Connect @var{filename} to NBD device @var{dev} ++Connect @var{filename} to NBD device @var{dev} (Linux only). + @item -d, --disconnect +-Disconnect the device @var{dev} ++Disconnect the device @var{dev} (Linux only). + @item -e, --shared=@var{num} +-Allow up to @var{num} clients to share the device (default @samp{1}) ++Allow up to @var{num} clients to share the device (default ++@samp{1}). Safe for readers, but for now, consistency is not ++guaranteed between multiple writers. + @item -t, --persistent +-Don't exit on the last connection ++Don't exit on the last connection. + @item -x, --export-name=@var{name} +-Set the NBD volume export name. This switches the server to use +-the new style NBD protocol negotiation ++Set the NBD volume export name (default of a zero-length string). + @item -D, --description=@var{description} + Set the NBD volume export description, as a human-readable +-string. Requires the use of @option{-x} ++string. + @item --tls-creds=ID + Enable mandatory TLS encryption for the server by setting the ID + of the TLS credentials object previously created with the --object +@@ -96,11 +104,11 @@ option. + @item --fork + Fork off the server process and exit the parent once the server is running. + @item -v, --verbose +-Display extra debugging information ++Display extra debugging information. + @item -h, --help +-Display this help and exit ++Display this help and exit. + @item -V, --version +-Display version information and exit ++Display version information and exit. + @item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}] + @findex --trace + @include qemu-option-trace.texi +@@ -108,6 +116,54 @@ Display version information and exit + + @c man end + ++@c man begin EXAMPLES ++Start a server listening on port 10809 that exposes only the ++guest-visible contents of a qcow2 file, with no TLS encryption, and ++with the default export name (an empty string). The command is ++one-shot, and will block until the first successful client ++disconnects: ++ ++@example ++qemu-nbd -f qcow2 file.qcow2 ++@end example ++ ++Start a long-running server listening with encryption on port 10810, ++and require clients to have a correct X.509 certificate to connect to ++a 1 megabyte subset of a raw file, using the export name 'subset': ++ ++@example ++qemu-nbd \ ++ --object tls-creds-x509,id=tls0,endpoint=server,dir=/path/to/qemutls \ ++ --tls-creds tls0 -t -x subset -p 10810 \ ++ --image-opts driver=raw,offset=1M,size=1M,file.driver=file,file.filename=file.raw ++@end example ++ ++Serve a read-only copy of just the first MBR partition of a guest ++image over a Unix socket with as many as 5 simultaneous readers, with ++a persistent process forked as a daemon: ++ ++@example ++qemu-nbd --fork --persistent --shared=5 --socket=/path/to/sock \ ++ --partition=1 --read-only --format=qcow2 file.qcow2 ++@end example ++ ++Expose the guest-visible contents of a qcow2 file via a block device ++/dev/nbd0 (and possibly creating /dev/nbd0p1 and friends for ++partitions found within), then disconnect the device when done. ++Access to bind qemu-nbd to an /dev/nbd device generally requires root ++privileges, and may also require the execution of @code{modprobe nbd} ++to enable the kernel NBD client module. @emph{CAUTION}: Do not use ++this method to mount filesystems from an untrusted guest image - a ++malicious guest may have prepared the image to attempt to trigger ++kernel bugs in partition probing or file system mounting. ++ ++@example ++qemu-nbd -c /dev/nbd0 -f qcow2 file.qcow2 ++qemu-nbd -d /dev/nbd0 ++@end example ++ ++@c man end ++ + @ignore + + @setfilename qemu-nbd +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Fail-earlier-for-c-d-on-non-linux.patch b/SOURCES/kvm-qemu-nbd-Fail-earlier-for-c-d-on-non-linux.patch new file mode 100644 index 0000000..8302113 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Fail-earlier-for-c-d-on-non-linux.patch @@ -0,0 +1,158 @@ +From fd123e372472179657da738e52e87897d0508812 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:23 +0100 +Subject: [PATCH 084/163] qemu-nbd: Fail earlier for -c/-d on non-linux + +RH-Author: John Snow +Message-id: <20190327172308.31077-11-jsnow@redhat.com> +Patchwork-id: 85173 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 10/55] qemu-nbd: Fail earlier for -c/-d on non-linux +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Connecting to a /dev/nbdN device is a Linux-specific action. +We were already masking -c and -d from 'qemu-nbd --help' on +non-linux. However, while -d fails with a sensible error +message, it took hunting through a couple of files to prove +that. What's more, the code for -c doesn't fail until after +it has created a pthread and tried to open a device - possibly +even printing an error message with %m on a non-Linux platform +in spite of the comment that %m is glibc-specific. Make the +failure happen sooner, then get rid of stubs that are no +longer needed because of the early exits. + +While at it: tweak the blank newlines in --help output to be +consistent, whether or not built on Linux. + +Signed-off-by: Eric Blake +Message-Id: <20181215135324.152629-7-eblake@redhat.com> +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit 3c1fa35d74aabe9c3ab642d2591b087e53d7a616) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 18 +----------------- + qemu-nbd.c | 21 +++++++++++++++++++-- + 2 files changed, 20 insertions(+), 19 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index e774147..5a03a84 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -1031,23 +1031,7 @@ int nbd_disconnect(int fd) + return 0; + } + +-#else +-int nbd_init(int fd, QIOChannelSocket *ioc, NBDExportInfo *info, +- Error **errp) +-{ +- error_setg(errp, "nbd_init is only supported on Linux"); +- return -ENOTSUP; +-} +- +-int nbd_client(int fd) +-{ +- return -ENOTSUP; +-} +-int nbd_disconnect(int fd) +-{ +- return -ENOTSUP; +-} +-#endif ++#endif /* __linux__ */ + + int nbd_send_request(QIOChannel *ioc, NBDRequest *request) + { +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 7f078b2..652199c 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -43,6 +43,12 @@ + #include "trace/control.h" + #include "qemu-version.h" + ++#ifdef __linux__ ++#define HAVE_NBD_DEVICE 1 ++#else ++#define HAVE_NBD_DEVICE 0 ++#endif ++ + #define SOCKET_PATH "/var/lock/qemu-nbd-%s" + #define QEMU_NBD_OPT_CACHE 256 + #define QEMU_NBD_OPT_AIO 257 +@@ -98,11 +104,11 @@ static void usage(const char *name) + " specify tracing options\n" + " --fork fork off the server process and exit the parent\n" + " once the server is running\n" +-#ifdef __linux__ ++#if HAVE_NBD_DEVICE ++"\n" + "Kernel NBD client support:\n" + " -c, --connect=DEV connect FILE to the local NBD device DEV\n" + " -d, --disconnect disconnect the specified device\n" +-"\n" + #endif + "\n" + "Block device options:\n" +@@ -236,6 +242,7 @@ static void termsig_handler(int signum) + } + + ++#if HAVE_NBD_DEVICE + static void *show_parts(void *arg) + { + char *device = arg; +@@ -321,6 +328,7 @@ out: + kill(getpid(), SIGTERM); + return (void *) EXIT_FAILURE; + } ++#endif /* HAVE_NBD_DEVICE */ + + static int nbd_can_accept(void) + { +@@ -816,6 +824,12 @@ int main(int argc, char **argv) + } + } + ++#if !HAVE_NBD_DEVICE ++ if (disconnect || device) { ++ error_report("Kernel /dev/nbdN support not available"); ++ exit(EXIT_FAILURE); ++ } ++#else /* HAVE_NBD_DEVICE */ + if (disconnect) { + int nbdfd = open(argv[optind], O_RDWR); + if (nbdfd < 0) { +@@ -831,6 +845,7 @@ int main(int argc, char **argv) + + return 0; + } ++#endif + + if ((device && !verbose) || fork_process) { + int stderr_fd[2]; +@@ -1012,6 +1027,7 @@ int main(int argc, char **argv) + nbd_export_set_description(exp, export_description); + + if (device) { ++#if HAVE_NBD_DEVICE + int ret; + + ret = pthread_create(&client_thread, NULL, nbd_client_thread, device); +@@ -1019,6 +1035,7 @@ int main(int argc, char **argv) + error_report("Failed to create client thread: %s", strerror(ret)); + exit(EXIT_FAILURE); + } ++#endif + } else { + /* Shut up GCC warnings. */ + memset(&client_thread, 0, sizeof(client_thread)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Rename-exp-variable-clashing-with-math-exp-.patch b/SOURCES/kvm-qemu-nbd-Rename-exp-variable-clashing-with-math-exp-.patch new file mode 100644 index 0000000..0b34ad8 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Rename-exp-variable-clashing-with-math-exp-.patch @@ -0,0 +1,106 @@ +From b7bec5a423cc8bb7792e231e3d81d015d9278d91 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:25 +0100 +Subject: [PATCH 086/163] qemu-nbd: Rename 'exp' variable clashing with + math::exp() symbol +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190327172308.31077-13-jsnow@redhat.com> +Patchwork-id: 85184 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 12/55] qemu-nbd: Rename 'exp' variable clashing with math::exp() symbol +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Philippe Mathieu-Daudé + +The use of a variable named 'exp' prevents includes to import . + +Rename it to avoid: + + qemu-nbd.c:64:19: error: ‘exp’ redeclared as different kind of symbol + static NBDExport *exp; + ^~~ + In file included from /usr/include/features.h:428, + from /usr/include/bits/libc-header-start.h:33, + from /usr/include/stdint.h:26, + from /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:9, + from /source/qemu/include/qemu/osdep.h:80, + from /source/qemu/qemu-nbd.c:19: + /usr/include/bits/mathcalls.h:95:1: note: previous declaration of ‘exp’ was here + __MATHCALL_VEC (exp,, (_Mdouble_ __x)); + ^~~~~~~~~~~~~~ + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Eric Blake +Message-Id: <20190111163519.11457-1-philmd@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 9d97658020db922b68da05faadcdd61f49fbbdc7) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 652199c..c37defb 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -61,7 +61,7 @@ + + #define MBR_SIZE 512 + +-static NBDExport *exp; ++static NBDExport *export; + static int verbose; + static char *srcpath; + static SocketAddress *saddr; +@@ -335,7 +335,7 @@ static int nbd_can_accept(void) + return state == RUNNING && nb_fds < shared; + } + +-static void nbd_export_closed(NBDExport *exp) ++static void nbd_export_closed(NBDExport *export) + { + assert(state == TERMINATING); + state = TERMINATED; +@@ -1017,14 +1017,11 @@ int main(int argc, char **argv) + } + } + +- exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, nbd_export_closed, +- writethrough, NULL, &local_err); +- if (!exp) { +- error_report_err(local_err); +- exit(EXIT_FAILURE); +- } +- nbd_export_set_name(exp, export_name); +- nbd_export_set_description(exp, export_description); ++ export = nbd_export_new(bs, dev_offset, fd_size, nbdflags, ++ nbd_export_closed, writethrough, ++ NULL, &error_fatal); ++ nbd_export_set_name(export, export_name); ++ nbd_export_set_description(export, export_description); + + if (device) { + #if HAVE_NBD_DEVICE +@@ -1061,9 +1058,9 @@ int main(int argc, char **argv) + main_loop_wait(false); + if (state == TERMINATE) { + state = TERMINATING; +- nbd_export_close(exp); +- nbd_export_put(exp); +- exp = NULL; ++ nbd_export_close(export); ++ nbd_export_put(export); ++ export = NULL; + } + } while (state != TERMINATED); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Sanity-check-partition-bounds.patch b/SOURCES/kvm-qemu-nbd-Sanity-check-partition-bounds.patch new file mode 100644 index 0000000..60b8229 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Sanity-check-partition-bounds.patch @@ -0,0 +1,110 @@ +From 58096dddd1682a83fb782a49d80199da9a117ef9 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:38 +0100 +Subject: [PATCH 100/163] qemu-nbd: Sanity check partition bounds + +RH-Author: John Snow +Message-id: <20190327172308.31077-26-jsnow@redhat.com> +Patchwork-id: 85207 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 25/55] qemu-nbd: Sanity check partition bounds +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +When the user requests a partition, we were using data read +from the disk as disk offsets without a bounds check. We got +lucky that even when computed offsets are out-of-bounds, +blk_pread() will gracefully catch the error later (so I don't +think a malicious image can crash or exploit qemu-nbd, and am +not treating this as a security flaw), but it's better to +flag the problem up front than to risk permanent EIO death of +the block device down the road. The new bounds check adds +an assertion that will never fail, but rather exists to help +the compiler see that adding two positive 41-bit values +(given MBR constraints) can't overflow 64-bit off_t. + +Using off_t to represent a partition length is a bit of a +misnomer; a later patch will update to saner types, but it +is left separate in case the bounds check needs to be +backported in isolation. + +Also, note that the partition code blindly overwrites any +non-zero offset passed in by the user; so for now, make the +-o/-P combo an error for less confusion. In the future, we +may let -o and -P work together (selecting a subset of a +partition); so it is okay that an explicit '-o 0' behaves +no differently from omitting -o. + +This can be tested with nbdkit: +$ echo hi > file +$ nbdkit -fv --filter=truncate partitioning file truncate=64k + +Pre-patch: +$ qemu-nbd -p 10810 -P 1 -f raw nbd://localhost:10809 & +$ qemu-io -f raw nbd://localhost:10810 +qemu-io> r -v 0 1 +Disconnect client, due to: Failed to send reply: reading from file failed: Input/output error +Connection closed +read failed: Input/output error +qemu-io> q +[1]+ Done qemu-nbd -p 10810 -P 1 -f raw nbd://localhost:10809 + +Post-patch: +$ qemu-nbd -p 10810 -P 1 -f raw nbd://localhost:10809 +qemu-nbd: Discovered partition 1 at offset 1048576 size 512, but size exceeds file length 65536 + +Signed-off-by: Eric Blake +Reviewed-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Richard W.M. Jones +Message-Id: <20190117193658.16413-5-eblake@redhat.com> +(cherry picked from commit 4485936b6de20afa38138e9d1e8ffed88cf0be73) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 51b55f2..5c90c5e 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -1013,12 +1013,32 @@ int main(int argc, char **argv) + fd_size -= dev_offset; + + if (partition != -1) { +- ret = find_partition(blk, partition, &dev_offset, &fd_size); ++ off_t limit; ++ ++ if (dev_offset) { ++ error_report("Cannot request partition and offset together"); ++ exit(EXIT_FAILURE); ++ } ++ ret = find_partition(blk, partition, &dev_offset, &limit); + if (ret < 0) { + error_report("Could not find partition %d: %s", partition, + strerror(-ret)); + exit(EXIT_FAILURE); + } ++ /* ++ * MBR partition limits are (32-bit << 9); this assert lets ++ * the compiler know that we have two positive values that ++ * can't overflow 64 bits. ++ */ ++ assert(dev_offset >= 0 && dev_offset + limit >= dev_offset); ++ if (dev_offset + limit > fd_size) { ++ error_report("Discovered partition %d at offset %lld size %lld, " ++ "but size exceeds file length %lld", partition, ++ (long long int) dev_offset, (long long int) limit, ++ (long long int) fd_size); ++ exit(EXIT_FAILURE); ++ } ++ fd_size = limit; + } + + export = nbd_export_new(bs, dev_offset, fd_size, export_name, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-Use-program-name-in-error-messages.patch b/SOURCES/kvm-qemu-nbd-Use-program-name-in-error-messages.patch new file mode 100644 index 0000000..a112ce0 --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-Use-program-name-in-error-messages.patch @@ -0,0 +1,69 @@ +From 9a2c829fe94fb3bb241cf9f22cd206c4392b87f3 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:20 +0100 +Subject: [PATCH 081/163] qemu-nbd: Use program name in error messages + +RH-Author: John Snow +Message-id: <20190327172308.31077-8-jsnow@redhat.com> +Patchwork-id: 85174 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 07/55] qemu-nbd: Use program name in error messages +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +This changes output from: + +$ qemu-nbd nosuch +Failed to blk_new_open 'nosuch': Could not open 'nosuch': No such file or directory + +to something more consistent with qemu-img and qemu: + +$ qemu-nbd nosuch +qemu-nbd: Failed to blk_new_open 'nosuch': Could not open 'nosuch': No such file or directory + +Update the lone affected test to match. (Hmm - is it sad that we don't +do much testing of expected failures?) + +Signed-off-by: Eric Blake +Reviewed-by: Richard W.M. Jones +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181215135324.152629-2-eblake@redhat.com> +(cherry picked from commit 3ba1b7baf4b2518e8efdbe50175d909b79c21596) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 1 + + tests/qemu-iotests/233.out | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index e76fe30..7f078b2 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -571,6 +571,7 @@ int main(int argc, char **argv) + #endif + + module_call_init(MODULE_INIT_TRACE); ++ error_set_progname(argv[0]); + qcrypto_init(&error_fatal); + + module_call_init(MODULE_INIT_QOM); +diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out +index 94acd9b..5f41672 100644 +--- a/tests/qemu-iotests/233.out ++++ b/tests/qemu-iotests/233.out +@@ -27,7 +27,7 @@ virtual size: 64M (67108864 bytes) + disk size: unavailable + + == check TLS with different CA fails == +-option negotiation failed: Verify failed: No certificate was found. ++qemu-nbd: option negotiation failed: Verify failed: No certificate was found. + qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer + + == perform I/O over TLS == +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-nbd-drop-old-style-negotiation.patch b/SOURCES/kvm-qemu-nbd-drop-old-style-negotiation.patch new file mode 100644 index 0000000..e5ebb7e --- /dev/null +++ b/SOURCES/kvm-qemu-nbd-drop-old-style-negotiation.patch @@ -0,0 +1,121 @@ +From e7b2b502ad9b10b852c507447e34e3212a274cee Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:24 +0100 +Subject: [PATCH 057/163] qemu-nbd: drop old-style negotiation + +RH-Author: John Snow +Message-id: <20190322032241.8111-12-jsnow@redhat.com> +Patchwork-id: 85096 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 11/28] qemu-nbd: drop old-style negotiation +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Use new-style negotiation always, with default "" (empty) export name +if it is not specified with '-x' option. + +qemu as client can manage either style since 2.6.0, commit 69b49502d8 + +For comparison: + +nbd 3.10 dropped oldstyle long ago (Mar 2015): +https://github.com/NetworkBlockDevice/nbd/commit/36940193 + +nbdkit 1.3 switched its default to newstyle (Jan 2018): +https://github.com/libguestfs/nbdkit/commit/b2a8aecc +https://github.com/libguestfs/nbdkit/commit/8158e773 + +Furthermore, if a client that only speaks oldstyle still needs to +communicate to qemu, nbdkit remains available to perform the +translation between the two protocols. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20181003170228.95973-2-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: enhance commit message] +Signed-off-by: Eric Blake +(cherry picked from commit f5cd0bb5174dcd6e8c160d7992fb89f09f264ef0) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + qemu-nbd.c | 25 ++++++------------------- + 1 file changed, 6 insertions(+), 19 deletions(-) + +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 66e023f..6aaebe7 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -56,7 +56,6 @@ + #define MBR_SIZE 512 + + static NBDExport *exp; +-static bool newproto; + static int verbose; + static char *srcpath; + static SocketAddress *saddr; +@@ -84,8 +83,8 @@ static void usage(const char *name) + " -e, --shared=NUM device can be shared by NUM clients (default '1')\n" + " -t, --persistent don't exit on the last connection\n" + " -v, --verbose display extra debugging information\n" +-" -x, --export-name=NAME expose export by name\n" +-" -D, --description=TEXT with -x, also export a human-readable description\n" ++" -x, --export-name=NAME expose export by name (default is empty string)\n" ++" -D, --description=TEXT export a human-readable description\n" + "\n" + "Exposing part of the image:\n" + " -o, --offset=OFFSET offset into the image\n" +@@ -355,8 +354,7 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + + nb_fds++; + nbd_update_server_watch(); +- nbd_client_new(newproto ? NULL : exp, cioc, +- tlscreds, NULL, nbd_client_closed); ++ nbd_client_new(NULL, cioc, tlscreds, NULL, nbd_client_closed); + } + + static void nbd_update_server_watch(void) +@@ -550,7 +548,7 @@ int main(int argc, char **argv) + Error *local_err = NULL; + BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; + QDict *options = NULL; +- const char *export_name = NULL; ++ const char *export_name = ""; /* Default export name */ + const char *export_description = NULL; + const char *tlscredsid = NULL; + bool imageOpts = false; +@@ -809,11 +807,6 @@ int main(int argc, char **argv) + error_report("TLS is not supported with a host device"); + exit(EXIT_FAILURE); + } +- if (!export_name) { +- /* Set the default NBD protocol export name, since +- * we *must* use new style protocol for TLS */ +- export_name = ""; +- } + tlscreds = nbd_get_tls_creds(tlscredsid, &local_err); + if (local_err) { + error_report("Failed to get TLS creds %s", +@@ -1014,14 +1007,8 @@ int main(int argc, char **argv) + error_report_err(local_err); + exit(EXIT_FAILURE); + } +- if (export_name) { +- nbd_export_set_name(exp, export_name); +- nbd_export_set_description(exp, export_description); +- newproto = true; +- } else if (export_description) { +- error_report("Export description requires an export name"); +- exit(EXIT_FAILURE); +- } ++ nbd_export_set_name(exp, export_name); ++ nbd_export_set_description(exp, export_description); + + if (device) { + int ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qom-Clean-up-error-reporting-in-user_creatable_add_o.patch b/SOURCES/kvm-qom-Clean-up-error-reporting-in-user_creatable_add_o.patch new file mode 100644 index 0000000..72cf31c --- /dev/null +++ b/SOURCES/kvm-qom-Clean-up-error-reporting-in-user_creatable_add_o.patch @@ -0,0 +1,138 @@ +From 2070eac10c75c262e8f803b3654f512c55c261c1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 27 Mar 2019 17:22:34 +0100 +Subject: [PATCH 095/163] qom: Clean up error reporting in + user_creatable_add_opts_foreach() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190327172308.31077-22-jsnow@redhat.com> +Patchwork-id: 85216 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 21/55] qom: Clean up error reporting in user_creatable_add_opts_foreach() +Bugzilla: 1691009 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Markus Armbruster + +Calling error_report() in a function that takes an Error ** argument +is suspicious. user_creatable_add_opts_foreach() does that, and then +fails without setting an error. Its caller main(), via +qemu_opts_foreach(), is fine with it, but clean it up anyway. + +Cc: Daniel P. Berrangé +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +Reviewed-by: Marc-André Lureau +Message-Id: <20181017082702.5581-20-armbru@redhat.com> +(cherry picked from commit 7e1e0c11127bde81cff260fc6859690435c509d6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-io.c | 8 +++----- + qemu-nbd.c | 8 +++----- + qom/object_interfaces.c | 4 +--- + vl.c | 16 ++++++---------- + 4 files changed, 13 insertions(+), 23 deletions(-) + +diff --git a/qemu-io.c b/qemu-io.c +index 13829f5..6df7731 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -620,11 +620,9 @@ int main(int argc, char **argv) + exit(1); + } + +- if (qemu_opts_foreach(&qemu_object_opts, +- user_creatable_add_opts_foreach, +- NULL, NULL)) { +- exit(1); +- } ++ qemu_opts_foreach(&qemu_object_opts, ++ user_creatable_add_opts_foreach, ++ NULL, &error_fatal); + + if (!trace_init_backends()) { + exit(1); +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 0c92f62..51b55f2 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -781,11 +781,9 @@ int main(int argc, char **argv) + exit(EXIT_FAILURE); + } + +- if (qemu_opts_foreach(&qemu_object_opts, +- user_creatable_add_opts_foreach, +- NULL, NULL)) { +- exit(EXIT_FAILURE); +- } ++ qemu_opts_foreach(&qemu_object_opts, ++ user_creatable_add_opts_foreach, ++ NULL, &error_fatal); + + if (!trace_init_backends()) { + exit(1); +diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c +index 980ffc2..7491c69 100644 +--- a/qom/object_interfaces.c ++++ b/qom/object_interfaces.c +@@ -149,7 +149,6 @@ int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) + { + bool (*type_predicate)(const char *) = opaque; + Object *obj = NULL; +- Error *err = NULL; + const char *type; + + type = qemu_opt_get(opts, "qom-type"); +@@ -158,9 +157,8 @@ int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) + return 0; + } + +- obj = user_creatable_add_opts(opts, &err); ++ obj = user_creatable_add_opts(opts, errp); + if (!obj) { +- error_report_err(err); + return -1; + } + object_unref(obj); +diff --git a/vl.c b/vl.c +index dfe261d..92a98ab 100644 +--- a/vl.c ++++ b/vl.c +@@ -4407,11 +4407,9 @@ int main(int argc, char **argv, char **envp) + page_size_init(); + socket_init(); + +- if (qemu_opts_foreach(qemu_find_opts("object"), +- user_creatable_add_opts_foreach, +- object_create_initial, NULL)) { +- exit(1); +- } ++ qemu_opts_foreach(qemu_find_opts("object"), ++ user_creatable_add_opts_foreach, ++ object_create_initial, &error_fatal); + + if (qemu_opts_foreach(qemu_find_opts("chardev"), + chardev_init_func, NULL, NULL)) { +@@ -4537,11 +4535,9 @@ int main(int argc, char **argv, char **envp) + exit(1); + } + +- if (qemu_opts_foreach(qemu_find_opts("object"), +- user_creatable_add_opts_foreach, +- object_create_delayed, NULL)) { +- exit(1); +- } ++ qemu_opts_foreach(qemu_find_opts("object"), ++ user_creatable_add_opts_foreach, ++ object_create_delayed, &error_fatal); + + if (tpm_init() < 0) { + exit(1); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-r2d-Fix-flash-memory-size-sector-size-width-device-I.patch b/SOURCES/kvm-r2d-Fix-flash-memory-size-sector-size-width-device-I.patch new file mode 100644 index 0000000..5f711b7 --- /dev/null +++ b/SOURCES/kvm-r2d-Fix-flash-memory-size-sector-size-width-device-I.patch @@ -0,0 +1,86 @@ +From e164d03a365ec6457a09acefdda7e6fe50e068af Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:00 +0200 +Subject: [PATCH 33/53] r2d: Fix flash memory size, sector size, width, device + ID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-12-armbru@redhat.com> +Patchwork-id: 87987 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 11/31] r2d: Fix flash memory size, sector size, width, device ID +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +pflash_cfi02_register() takes a size in bytes, a block size in bytes +and a number of blocks. r2d_init() passes FLASH_SIZE, 16 * KiB, +FLASH_SIZE >> 16. Does not compute: size doesn't match block size * +number of blocks. The latter happens to win: FLASH_SIZE / 4, +i.e. 8MiB. + +The best information we have on the physical hardware lists a Cypress +S29PL127J60TFI130 128MiBit NOR flash addressable in words of 16 bits, +in sectors of 4 and 32 Kibiwords. We don't model multiple sector +sizes. + +Fix the flash size from 8 to 16MiB, and adjust the sector size from 16 +to 64KiB. Fix the width from 4 to 2. While there, supply the real +device IDs 0x0001, 0x227e, 0x2220, 0x2200 instead of zeros. + +Cc: Magnus Damm +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20190308094610.21210-10-armbru@redhat.com> +Tested-by: Philippe Mathieu-Daudé +(cherry picked from commit 8468713412b1eb0d24d605bf97d159a9b01d4b02) +[Trivial conflict in hw/sh4/r2d.c due to lack of commit ab3dd749241] + +Signed-off-by: Miroslav Rezanina +--- + hw/sh4/r2d.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c +index 458ed83..befb582 100644 +--- a/hw/sh4/r2d.c ++++ b/hw/sh4/r2d.c +@@ -44,7 +44,7 @@ + #include "exec/address-spaces.h" + + #define FLASH_BASE 0x00000000 +-#define FLASH_SIZE 0x02000000 ++#define FLASH_SIZE (16 * MiB) + + #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ + #define SDRAM_SIZE 0x04000000 +@@ -288,12 +288,20 @@ static void r2d_init(MachineState *machine) + sysbus_mmio_map(busdev, 1, 0x1400080c); + mmio_ide_init_drives(dev, dinfo, NULL); + +- /* onboard flash memory */ ++ /* ++ * Onboard flash memory ++ * According to the old board user document in Japanese (under ++ * NDA) what is referred to as FROM (Area0) is connected via a ++ * 32-bit bus and CS0 to CN8. The docs mention a Cypress ++ * S29PL127J60TFI130 chipsset. Per the 'S29PL-J 002-00615 ++ * Rev. *E' datasheet, it is a 128Mbit NOR parallel flash ++ * addressable in words of 16bit. ++ */ + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE, + dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, +- (16 * 1024), FLASH_SIZE >> 16, +- 1, 4, 0x0000, 0x0000, 0x0000, 0x0000, ++ 64 * KiB, FLASH_SIZE >> 16, ++ 1, 2, 0x0001, 0x227e, 0x2220, 0x2200, + 0x555, 0x2aa, 0); + + /* NIC: rtl8139 on-board, and 2 slots. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rbd-Close-image-in-qemu_rbd_open-error-path.patch b/SOURCES/kvm-rbd-Close-image-in-qemu_rbd_open-error-path.patch new file mode 100644 index 0000000..47f3de4 --- /dev/null +++ b/SOURCES/kvm-rbd-Close-image-in-qemu_rbd_open-error-path.patch @@ -0,0 +1,46 @@ +From 65f966b512842ad7654eb80a4b98cbfff7437751 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 23 Nov 2018 10:41:45 +0100 +Subject: [PATCH 04/34] rbd: Close image in qemu_rbd_open() error path + +RH-Author: Kevin Wolf +Message-id: <20181123104154.13541-4-kwolf@redhat.com> +Patchwork-id: 83113 +O-Subject: [RHEL-7.7/7.6.z qemu-kvm-rhev PATCH v2 03/12] rbd: Close image in qemu_rbd_open() error path +Bugzilla: 1623986 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow + +Commit e2b8247a322 introduced an error path in qemu_rbd_open() after +calling rbd_open(), but neglected to close the image again in this error +path. The error path should contain everything that the regular close +function qemu_rbd_close() contains. + +This adds the missing rbd_close() call. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit a51b9c4862c29f427931f45ee1d39ac1663ba859) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/rbd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/rbd.c b/block/rbd.c +index 8f81fbc..8ce68c8 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -779,6 +779,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + "automatically marking the image read-only."); + r = bdrv_set_read_only(bs, true, &local_err); + if (r < 0) { ++ rbd_close(s->image); + error_propagate(errp, local_err); + goto failed_open; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rhel-Set-host-phys-bits-limit-48-on-rhel-machine-typ.patch b/SOURCES/kvm-rhel-Set-host-phys-bits-limit-48-on-rhel-machine-typ.patch new file mode 100644 index 0000000..f89ae06 --- /dev/null +++ b/SOURCES/kvm-rhel-Set-host-phys-bits-limit-48-on-rhel-machine-typ.patch @@ -0,0 +1,53 @@ +From a402e015f9945358215e63b00d9efae44693ccd5 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 11 Apr 2019 21:48:46 +0200 +Subject: [PATCH 160/163] rhel: Set host-phys-bits-limit=48 on rhel + machine-types + +RH-Author: Eduardo Habkost +Message-id: <20190411214846.8816-3-ehabkost@redhat.com> +Patchwork-id: 85609 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/2] rhel: Set host-phys-bits-limit=48 on rhel machine-types +Bugzilla: 1691519 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Dr. David Alan Gilbert + +Upstream status: not applicable + +Currently we use the host physical address size by default on +VMs. This was a good default on most cases, but this is not the +case on host CPUs supporting 5-level EPT. On those cases, we +want VMs to use 4-level EPT by default. + +Ensure VMs will use 4-level EPT by default, by limiting physical +address bits to 48. + +Not applicable upstream because upstream doesn't set +host-phys-bits=on by default. + +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + include/hw/i386/pc.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index 88e5a92..1e9f252 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -963,6 +963,11 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); + .property = "host-phys-bits",\ + .value = "on",\ + },\ ++ { /* PC_RHEL_COMPAT */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "host-phys-bits-limit",\ ++ .value = "48",\ ++ },\ + { /* PC_RHEL_COMPAT bz 1508330 */ \ + .driver = "vfio-pci",\ + .property = "x-no-geforce-quirks",\ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rtl8139-fix-possible-out-of-bound-access.patch b/SOURCES/kvm-rtl8139-fix-possible-out-of-bound-access.patch new file mode 100644 index 0000000..a9a7252 --- /dev/null +++ b/SOURCES/kvm-rtl8139-fix-possible-out-of-bound-access.patch @@ -0,0 +1,78 @@ +From 72e7bb00aef5e81d870d44e3697d0a247a3bb3af Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Fri, 17 May 2019 07:29:35 +0200 +Subject: [PATCH 1/9] rtl8139: fix possible out of bound access + +RH-Author: Xiao Wang +Message-id: <1558078177-372-2-git-send-email-jasowang@redhat.com> +Patchwork-id: 88013 +O-Subject: [RHEL7.7 qemu-kvm-rhev PATCH 1/3] rtl8139: fix possible out of bound access +Bugzilla: 1636780 +RH-Acked-by: Thomas Huth +RH-Acked-by: Jens Freimann +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Michael S. Tsirkin + +Bugzilla: 1636727 + +In rtl8139_do_receive(), we try to assign size_ to size which converts +from size_t to integer. This will cause troubles when size_ is greater +INT_MAX, this will lead a negative value in size and it can then pass +the check of size < MIN_BUF_SIZE which may lead out of bound access of +for both buf and buf1. + +Fixing by converting the type of size to size_t. + +CC: qemu-stable@nongnu.org +Reported-by: Daniel Shapira +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +(cherry picked from commit 1a326646fef38782e5542280040ec3ea23e4a730) +Signed-off-by: Miroslav Rezanina +--- + hw/net/rtl8139.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c +index bc37326..d343fb9 100644 +--- a/hw/net/rtl8139.c ++++ b/hw/net/rtl8139.c +@@ -817,7 +817,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + RTL8139State *s = qemu_get_nic_opaque(nc); + PCIDevice *d = PCI_DEVICE(s); + /* size is the length of the buffer passed to the driver */ +- int size = size_; ++ size_t size = size_; + const uint8_t *dot1q_buf = NULL; + + uint32_t packet_header = 0; +@@ -826,7 +826,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + static const uint8_t broadcast_macaddr[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +- DPRINTF(">>> received len=%d\n", size); ++ DPRINTF(">>> received len=%zu\n", size); + + /* test if board clock is stopped */ + if (!s->clock_enabled) +@@ -1035,7 +1035,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + + if (size+4 > rx_space) + { +- DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n", ++ DPRINTF("C+ Rx mode : descriptor %d size %d received %zu + 4\n", + descriptor, rx_space, size); + + s->IntrStatus |= RxOverflow; +@@ -1148,7 +1148,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + if (avail != 0 && RX_ALIGN(size + 8) >= avail) + { + DPRINTF("rx overflow: rx buffer length %d head 0x%04x " +- "read 0x%04x === available 0x%04x need 0x%04x\n", ++ "read 0x%04x === available 0x%04x need 0x%04zx\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); + + s->IntrStatus |= RxOverflow; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-Return-specification-exception-for-unimplement.patch b/SOURCES/kvm-s390x-Return-specification-exception-for-unimplement.patch deleted file mode 100644 index b29f78f..0000000 --- a/SOURCES/kvm-s390x-Return-specification-exception-for-unimplement.patch +++ /dev/null @@ -1,54 +0,0 @@ -From f6f56692227952864edcb0dc841cde6238470cf8 Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Mon, 21 Jan 2019 17:05:59 +0100 -Subject: [PATCH 14/14] s390x: Return specification exception for unimplemented - diag 308 subcodes - -RH-Author: Cornelia Huck -Message-id: <20190121170559.19471-1-cohuck@redhat.com> -Patchwork-id: 84074 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH] s390x: Return specification exception for unimplemented diag 308 subcodes -Bugzilla: 1668424 -RH-Acked-by: Thomas Huth -RH-Acked-by: David Hildenbrand -RH-Acked-by: John Snow - -From: Janosch Frank - -The architecture specifies specification exceptions for all -unavailable subcodes. - -The presence of subcodes is indicated by checking some query subcode. -For example 6 will indicate that 3-6 are available. So future systems -might call new subcodes to check for new features. This should not -trigger a hw error, instead we return the architectured specification -exception. - -Signed-off-by: Janosch Frank -Cc: qemu-stable@nongnu.org -Message-Id: <20190111113657.66195-3-frankja@linux.ibm.com> -Reviewed-by: Christian Borntraeger -Reviewed-by: David Hildenbrand -Signed-off-by: Cornelia Huck -(cherry picked from commit 37dbd1f4d4805edcd18d94eb202bb3461b3cd52d) -Signed-off-by: Miroslav Rezanina ---- - target/s390x/diag.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/s390x/diag.c b/target/s390x/diag.c -index a755837..50b58df 100644 ---- a/target/s390x/diag.c -+++ b/target/s390x/diag.c -@@ -182,7 +182,7 @@ out: - } - return; - default: -- hw_error("Unhandled diag308 subcode %" PRIx64, subcode); -+ s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); - break; - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-cpumodel-ignore-csske-for-expansion.patch b/SOURCES/kvm-s390x-cpumodel-ignore-csske-for-expansion.patch deleted file mode 100644 index 1a2a8a7..0000000 --- a/SOURCES/kvm-s390x-cpumodel-ignore-csske-for-expansion.patch +++ /dev/null @@ -1,46 +0,0 @@ -From f2ac185797ae7e260a99dae91a6a9adf89538d49 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Thu, 13 Jun 2019 08:07:26 +0200 -Subject: [PATCH] s390x/cpumodel: ignore csske for expansion - -RH-Author: David Hildenbrand -Message-id: <20190613080726.13089-1-david@redhat.com> -Patchwork-id: 88658 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH] s390x/cpumodel: ignore csske for expansion -Bugzilla: 1720262 -RH-Acked-by: Jens Freimann -RH-Acked-by: Cornelia Huck -RH-Acked-by: Laurent Vivier -RH-Acked-by: Eduardo Habkost - -csske will be removed in a future machine. Ignore it for expanding the -cpu model. Otherwise qemu falls back to z9. - -Signed-off-by: Christian Borntraeger -Cc: qemu-stable@nongnu.org -Reviewed-by: David Hildenbrand -Message-Id: <20190429090250.7648-3-borntraeger@de.ibm.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit eaf6f642abf1d4d24791b70728d4068428fc4658) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu_models.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c -index 0b5d271..ed06498 100644 ---- a/target/s390x/cpu_models.c -+++ b/target/s390x/cpu_models.c -@@ -1259,6 +1259,8 @@ static void init_ignored_base_feat(void) - S390_FEAT_KM_TDEA_192, - S390_FEAT_KIMD_SHA_1, - S390_FEAT_KLMD_SHA_1, -+ /* CSSKE is deprecated on newer generations */ -+ S390_FEAT_CONDITIONAL_SSKE, - }; - int i; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-kvm-pass-values-instead-of-pointers-to-kvm_s39.patch b/SOURCES/kvm-s390x-kvm-pass-values-instead-of-pointers-to-kvm_s39.patch deleted file mode 100644 index 6fbf7b2..0000000 --- a/SOURCES/kvm-s390x-kvm-pass-values-instead-of-pointers-to-kvm_s39.patch +++ /dev/null @@ -1,129 +0,0 @@ -From d8ea4acd4f566899da1ba6def05c5dca4217fd52 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:47 +0100 -Subject: [PATCH 03/14] s390x/kvm: pass values instead of pointers to - kvm_s390_set_clock_*() - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-3-david@redhat.com> -Patchwork-id: 83759 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 02/12] s390x/kvm: pass values instead of pointers to kvm_s390_set_clock_*() -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -We are going to factor out the TOD into a separate device and use const -pointers for device class functions where possible. We are passing right -now ordinary pointers that should never be touched when setting the TOD. -Let's just pass the values directly. - -Note that s390_set_clock() will be removed in a follow-on patch and -therefore its calling convention is not changed. - -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-3-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 4ab6a1feac0a142045d3b7bdbb8182a99c0b8980) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu.c | 4 ++-- - target/s390x/kvm-stub.c | 4 ++-- - target/s390x/kvm.c | 12 ++++++------ - target/s390x/kvm_s390x.h | 4 ++-- - 4 files changed, 12 insertions(+), 12 deletions(-) - -diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c -index c2b775f..1f590d1 100644 ---- a/target/s390x/cpu.c -+++ b/target/s390x/cpu.c -@@ -414,9 +414,9 @@ int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) - int r = 0; - - if (kvm_enabled()) { -- r = kvm_s390_set_clock_ext(tod_high, tod_low); -+ r = kvm_s390_set_clock_ext(*tod_high, *tod_low); - if (r == -ENXIO) { -- return kvm_s390_set_clock(tod_high, tod_low); -+ return kvm_s390_set_clock(*tod_high, *tod_low); - } - } - /* Fixme TCG */ -diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c -index 29b1054..bf7795e 100644 ---- a/target/s390x/kvm-stub.c -+++ b/target/s390x/kvm-stub.c -@@ -60,12 +60,12 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) - return -ENOSYS; - } - --int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) -+int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low) - { - return -ENOSYS; - } - --int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low) -+int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low) - { - return -ENOSYS; - } -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index c27e628..009902e 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -696,13 +696,13 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) - return r; - } - --int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) -+int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low) - { - int r; - struct kvm_device_attr attr = { - .group = KVM_S390_VM_TOD, - .attr = KVM_S390_VM_TOD_LOW, -- .addr = (uint64_t)tod_low, -+ .addr = (uint64_t)&tod_low, - }; - - r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); -@@ -711,15 +711,15 @@ int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) - } - - attr.attr = KVM_S390_VM_TOD_HIGH; -- attr.addr = (uint64_t)tod_high; -+ attr.addr = (uint64_t)&tod_high; - return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); - } - --int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low) -+int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low) - { - struct kvm_s390_vm_tod_clock gtod = { -- .epoch_idx = *tod_high, -- .tod = *tod_low, -+ .epoch_idx = tod_high, -+ .tod = tod_low, - }; - struct kvm_device_attr attr = { - .group = KVM_S390_VM_TOD, -diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h -index c383bf4..36eb34b 100644 ---- a/target/s390x/kvm_s390x.h -+++ b/target/s390x/kvm_s390x.h -@@ -25,8 +25,8 @@ int kvm_s390_get_ri(void); - int kvm_s390_get_gs(void); - int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); - int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); --int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_clock); --int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); -+int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock); -+int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_clock); - void kvm_s390_enable_css_support(S390CPU *cpu); - int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, - int vq, bool assign); --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-refuse-to-start-guests-backed-by-hugetlbfs.patch b/SOURCES/kvm-s390x-refuse-to-start-guests-backed-by-hugetlbfs.patch deleted file mode 100644 index 8c73926..0000000 --- a/SOURCES/kvm-s390x-refuse-to-start-guests-backed-by-hugetlbfs.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 92fc5d11a4501a3734acc77b7d6a57190bd56154 Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Wed, 21 Nov 2018 10:17:06 +0100 -Subject: [PATCH 01/14] s390x: refuse to start guests backed by hugetlbfs - -RH-Author: Cornelia Huck -Message-id: <20181121101706.17562-1-cohuck@redhat.com> -Patchwork-id: 83089 -O-Subject: [PATCH RHEL-7.6.z qemu-kvm-ma BZ1650580] s390x: refuse to start guests backed by hugetlbfs -Bugzilla: 1672919 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Thomas Huth -RH-Acked-by: Dr. David Alan Gilbert - -In RHEL-ALT 7.x, running s390x guests with hugetlbfs backing -will not work due to missing support in the kernel. Unfortunately, -the guest will try to start and only then crash. This will lead -to problems when e.g. migrating a hugetlbfs backed guest from -RHEL 8 (where this is supported, but no new machine type has -been introduced.) - -Fix this by bailing out with an error message immediately. This -way, an incoming migration of a hugetlbfs backed guest will fail -immediately and properly fall back to the source. - -Signed-off-by: Cornelia Huck -Signed-off-by: Miroslav Rezanina ---- - target/s390x/kvm.c | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index ca8c32e..c27e628 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -34,6 +34,7 @@ - #include "qapi/error.h" - #include "qemu/error-report.h" - #include "qemu/timer.h" -+#include "qemu/mmap-alloc.h" - #include "sysemu/sysemu.h" - #include "sysemu/hw_accel.h" - #include "hw/hw.h" -@@ -282,10 +283,27 @@ void kvm_s390_crypto_reset(void) - } - } - -+static int kvm_s390_configure_mempath_backing(KVMState *s) -+{ -+ size_t path_psize = qemu_mempath_getpagesize(mem_path); -+ -+ if (path_psize == 4096) { -+ return 0; -+ } -+ -+ /* Disabled in Red Hat Enterprise Linux 7 (KVM support missing) */ -+ error_report("This QEMU does not support huge page mappings"); -+ return -EINVAL; -+} -+ - int kvm_arch_init(MachineState *ms, KVMState *s) - { - MachineClass *mc = MACHINE_GET_CLASS(ms); - -+ if (mem_path && kvm_s390_configure_mempath_backing(s)) { -+ return -EINVAL; -+ } -+ - mc->default_cpu_type = S390_CPU_TYPE_NAME("host"); - cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); - cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-SET-CLOCK-COMPARATOR-can-clear-CKC-interru.patch b/SOURCES/kvm-s390x-tcg-SET-CLOCK-COMPARATOR-can-clear-CKC-interru.patch deleted file mode 100644 index 6dbde57..0000000 --- a/SOURCES/kvm-s390x-tcg-SET-CLOCK-COMPARATOR-can-clear-CKC-interru.patch +++ /dev/null @@ -1,52 +0,0 @@ -From afe233642d38207ddb34da8bac4507d88c4c3422 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:51 +0100 -Subject: [PATCH 07/14] s390x/tcg: SET CLOCK COMPARATOR can clear CKC - interrupts - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-7-david@redhat.com> -Patchwork-id: 83769 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 06/12] s390x/tcg: SET CLOCK COMPARATOR can clear CKC interrupts -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -Let's stop the timer and delete any pending CKC IRQ before doing -anything else. - -While at it, add a comment why the check for ckc == -1ULL is needed. - -Reviewed-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-7-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 345f1ab96e8279a537f32ae7447296d23308c7d1) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/misc_helper.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index 4f675c7..cada7af 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -155,6 +155,13 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) - { - S390TODState *td = s390_get_todstate(); - -+ /* stop the timer and remove pending CKC IRQs */ -+ timer_del(env->tod_timer); -+ qemu_mutex_lock_iothread(); -+ env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR; -+ qemu_mutex_unlock_iothread(); -+ -+ /* the tod has to exceed the ckc, this can never happen if ckc is all 1's */ - if (time == -1ULL) { - return; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-avoid-overflows-in-time2tod-tod2time.patch b/SOURCES/kvm-s390x-tcg-avoid-overflows-in-time2tod-tod2time.patch deleted file mode 100644 index 386290d..0000000 --- a/SOURCES/kvm-s390x-tcg-avoid-overflows-in-time2tod-tod2time.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 6a97308e4496bf7d387198ae77cb501bc67145f8 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:46 +0100 -Subject: [PATCH 02/14] s390x/tcg: avoid overflows in time2tod/tod2time - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-2-david@redhat.com> -Patchwork-id: 83757 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 01/12] s390x/tcg: avoid overflows in time2tod/tod2time -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -Big values for the TOD/ns clock can result in some overflows that can be -avoided. Not all overflows can be handled however, as the conversion either -multiplies by 4.096 or divided by 4.096. - -Apply the trick used in the Linux kernel in arch/s390/include/asm/timex.h -for tod_to_ns() and use the same trick also for the conversion in the -other direction. - -Reviewed-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-2-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 14055ce53c2d901d826ffad7fb7d6bb8ab46bdfd) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/internal.h | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/target/s390x/internal.h b/target/s390x/internal.h -index d911e84..d1ed06f 100644 ---- a/target/s390x/internal.h -+++ b/target/s390x/internal.h -@@ -243,13 +243,14 @@ enum cc_op { - /* Converts ns to s390's clock format */ - static inline uint64_t time2tod(uint64_t ns) - { -- return (ns << 9) / 125; -+ return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9); -+ - } - - /* Converts s390's clock format to ns */ - static inline uint64_t tod2time(uint64_t t) - { -- return (t * 125) >> 9; -+ return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9); - } - - static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-drop-tod_basetime.patch b/SOURCES/kvm-s390x-tcg-drop-tod_basetime.patch deleted file mode 100644 index 7477ac1..0000000 --- a/SOURCES/kvm-s390x-tcg-drop-tod_basetime.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 7e7cd720a64754c0ebe4b38b310ceef2fc839c64 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:49 +0100 -Subject: [PATCH 05/14] s390x/tcg: drop tod_basetime - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-5-david@redhat.com> -Patchwork-id: 83768 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 04/12] s390x/tcg: drop tod_basetime -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -Never set to anything but 0. - -Reviewed-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-5-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit f777b20544fe5db3de179a83374cbf9f1e454427) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu.c | 1 - - target/s390x/cpu.h | 1 - - target/s390x/misc_helper.c | 4 ++-- - 3 files changed, 2 insertions(+), 4 deletions(-) - -diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c -index 167d089..5570741 100644 ---- a/target/s390x/cpu.c -+++ b/target/s390x/cpu.c -@@ -290,7 +290,6 @@ static void s390_cpu_initfn(Object *obj) - qemu_get_timedate(&tm, 0); - env->tod_offset = TOD_UNIX_EPOCH + - (time2tod(mktimegm(&tm)) * 1000000000ULL); -- env->tod_basetime = 0; - env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); - env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); - s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); -diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h -index 67118c8..04f9adf 100644 ---- a/target/s390x/cpu.h -+++ b/target/s390x/cpu.h -@@ -134,7 +134,6 @@ struct CPUS390XState { - #endif - - uint64_t tod_offset; -- uint64_t tod_basetime; - QEMUTimer *tod_timer; - - QEMUTimer *cpu_timer; -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index e0b23c1..8b3b040 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -142,7 +142,7 @@ uint64_t HELPER(stck)(CPUS390XState *env) - uint64_t time; - - time = env->tod_offset + -- time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); -+ time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); - - return time; - } -@@ -162,7 +162,7 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) - /* nanoseconds */ - time = tod2time(time); - -- timer_mod(env->tod_timer, env->tod_basetime + time); -+ timer_mod(env->tod_timer, time); - } - - /* Set Tod Programmable Field */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-fix-locking-problem-with-tcg_s390_tod_upda.patch b/SOURCES/kvm-s390x-tcg-fix-locking-problem-with-tcg_s390_tod_upda.patch deleted file mode 100644 index a7fefaf..0000000 --- a/SOURCES/kvm-s390x-tcg-fix-locking-problem-with-tcg_s390_tod_upda.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 76a996b5b9cc079655bde96db67b785db2094b98 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:54 +0100 -Subject: [PATCH 10/14] s390x/tcg: fix locking problem with - tcg_s390_tod_updated - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-10-david@redhat.com> -Patchwork-id: 83763 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 09/12] s390x/tcg: fix locking problem with tcg_s390_tod_updated -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -tcg_s390_tod_updated() is always called with the iothread being locked -(e.g. from S390TODClass->set() e.g. via HELPER(sck) or on incoming -migration). The helper we call takes the lock itself - bad. - -Let's change that by factoring out updating the ckc timer. This now looks -much nicer than having to call a helper from another function. - -While touching it we also make sure that env->ckc is updated even if the -new value is -1ULL, for now it would not have been modified in that case. - -Reported-by: Christian Borntraeger -Signed-off-by: David Hildenbrand -Message-Id: <20180629170520.13671-1-david@redhat.com> -Reviewed-by: Richard Henderson -Signed-off-by: Cornelia Huck -(cherry picked from commit 30c8db0e219a3c1d8b39c19e8b858830cb141738) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/misc_helper.c | 26 ++++++++++++++++---------- - 1 file changed, 16 insertions(+), 10 deletions(-) - -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index d629b2f..ffb9f6c 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -150,26 +150,23 @@ uint64_t HELPER(stck)(CPUS390XState *env) - return tod.low; - } - --/* Set Clock Comparator */ --void HELPER(sckc)(CPUS390XState *env, uint64_t time) -+static void update_ckc_timer(CPUS390XState *env) - { - S390TODState *td = s390_get_todstate(); -+ uint64_t time; - - /* stop the timer and remove pending CKC IRQs */ - timer_del(env->tod_timer); -- qemu_mutex_lock_iothread(); -+ g_assert(qemu_mutex_iothread_locked()); - env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR; -- qemu_mutex_unlock_iothread(); - - /* the tod has to exceed the ckc, this can never happen if ckc is all 1's */ -- if (time == -1ULL) { -+ if (env->ckc == -1ULL) { - return; - } - -- env->ckc = time; -- - /* difference between origins */ -- time -= td->base.low; -+ time = env->ckc - td->base.low; - - /* nanoseconds */ - time = tod2time(time); -@@ -177,12 +174,21 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) - timer_mod(env->tod_timer, time); - } - -+/* Set Clock Comparator */ -+void HELPER(sckc)(CPUS390XState *env, uint64_t ckc) -+{ -+ env->ckc = ckc; -+ -+ qemu_mutex_lock_iothread(); -+ update_ckc_timer(env); -+ qemu_mutex_unlock_iothread(); -+} -+ - void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque) - { - S390CPU *cpu = S390_CPU(cs); -- CPUS390XState *env = &cpu->env; - -- helper_sckc(env, env->ckc); -+ update_ckc_timer(&cpu->env); - } - - /* Set Clock */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-implement-SET-CLOCK.patch b/SOURCES/kvm-s390x-tcg-implement-SET-CLOCK.patch deleted file mode 100644 index 2352da0..0000000 --- a/SOURCES/kvm-s390x-tcg-implement-SET-CLOCK.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 79880b67f42bad47d885722d58abcedc53986759 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:52 +0100 -Subject: [PATCH 08/14] s390x/tcg: implement SET CLOCK - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-8-david@redhat.com> -Patchwork-id: 83762 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 07/12] s390x/tcg: implement SET CLOCK -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina - -Conflicts: - target/s390x/translate.c: ExitStatus vs. DisasJumpType - -This allows a guest to change its TOD. We already take care of updating -all CKC timers from within S390TODClass. - -Use MO_ALIGN to load the operand manually - this will properly trigger a -SPECIFICATION exception. - -Acked-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-8-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 9dc6753718d4c0fe327729fea94e4d9f3f5a3d17) -Signed-off-by: David Hildenbrand ---- - target/s390x/helper.h | 1 + - target/s390x/insn-data.def | 3 +-- - target/s390x/misc_helper.c | 16 ++++++++++++++++ - target/s390x/translate.c | 9 +++++++++ - 4 files changed, 27 insertions(+), 2 deletions(-) - -diff --git a/target/s390x/helper.h b/target/s390x/helper.h -index 59cba86..97c60ca 100644 ---- a/target/s390x/helper.h -+++ b/target/s390x/helper.h -@@ -127,6 +127,7 @@ DEF_HELPER_4(diag, void, env, i32, i32, i32) - DEF_HELPER_3(load_psw, noreturn, env, i64, i64) - DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) - DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) -+DEF_HELPER_FLAGS_2(sck, TCG_CALL_NO_RWG, i32, env, i64) - DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) - DEF_HELPER_FLAGS_2(sckpf, TCG_CALL_NO_RWG, void, env, i64) - DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) -diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def -index 1576194..5c6f33e 100644 ---- a/target/s390x/insn-data.def -+++ b/target/s390x/insn-data.def -@@ -997,8 +997,7 @@ - /* SET ADDRESS SPACE CONTROL FAST */ - C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) - /* SET CLOCK */ -- /* ??? Not implemented - is it necessary? */ -- C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) -+ C(0xb204, SCK, S, Z, la2, 0, 0, 0, sck, 0) - /* SET CLOCK COMPARATOR */ - C(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0) - /* SET CLOCK PROGRAMMABLE FIELD */ -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index cada7af..d629b2f 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -185,6 +185,22 @@ void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque) - helper_sckc(env, env->ckc); - } - -+/* Set Clock */ -+uint32_t HELPER(sck)(CPUS390XState *env, uint64_t tod_low) -+{ -+ S390TODState *td = s390_get_todstate(); -+ S390TODClass *tdc = S390_TOD_GET_CLASS(td); -+ S390TOD tod = { -+ .high = 0, -+ .low = tod_low, -+ }; -+ -+ qemu_mutex_lock_iothread(); -+ tdc->set(td, &tod, &error_abort); -+ qemu_mutex_unlock_iothread(); -+ return 0; -+} -+ - /* Set Tod Programmable Field */ - void HELPER(sckpf)(CPUS390XState *env, uint64_t r0) - { -diff --git a/target/s390x/translate.c b/target/s390x/translate.c -index 7d39ab3..ed9aff4 100644 ---- a/target/s390x/translate.c -+++ b/target/s390x/translate.c -@@ -4015,6 +4015,15 @@ static ExitStatus op_stcke(DisasContext *s, DisasOps *o) - return NO_EXIT; - } - -+static ExitStatus op_sck(DisasContext *s, DisasOps *o) -+{ -+ check_privileged(s); -+ tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN); -+ gen_helper_sck(cc_op, cpu_env, o->in1); -+ set_cc_static(s); -+ return NO_EXIT; -+} -+ - static ExitStatus op_sckc(DisasContext *s, DisasOps *o) - { - check_privileged(s); --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-properly-implement-the-TOD.patch b/SOURCES/kvm-s390x-tcg-properly-implement-the-TOD.patch deleted file mode 100644 index 1d5c4e3..0000000 --- a/SOURCES/kvm-s390x-tcg-properly-implement-the-TOD.patch +++ /dev/null @@ -1,350 +0,0 @@ -From f87cbf4e70d1df758df90f56934a39a0a018e2cc Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:50 +0100 -Subject: [PATCH 06/14] s390x/tcg: properly implement the TOD - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-6-david@redhat.com> -Patchwork-id: 83760 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 05/12] s390x/tcg: properly implement the TOD -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -Right now, each CPU has its own TOD. Especially, the TOD will differ -based on creation time of a CPU - e.g. when hotplugging a CPU the times -will differ quite a lot, resulting in stall warnings in the guest. - -Let's use a single TOD by implementing our new TOD device. Prepare it -for TOD-clock epoch extension. - -Most importantly, whenever we set the TOD, we have to update the CKC -timer. - -Introduce "tcg_s390x.h" just like "kvm_s390x.h" for tcg specific -function declarations that should not go into cpu.h. - -Reviewed-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-6-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 7de3b1cdc67dcb572c1761c2051252e91a438b22) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/tod-qemu.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- - hw/s390x/tod.c | 11 +++++++++++ - include/hw/s390x/tod.h | 19 +++++++++++++++++++ - target/s390x/cpu.c | 7 ------- - target/s390x/cpu.h | 1 - - target/s390x/internal.h | 16 ---------------- - target/s390x/misc_helper.c | 25 +++++++++++++++++++------ - target/s390x/tcg_s390x.h | 18 ++++++++++++++++++ - 8 files changed, 109 insertions(+), 34 deletions(-) - create mode 100644 target/s390x/tcg_s390x.h - -diff --git a/hw/s390x/tod-qemu.c b/hw/s390x/tod-qemu.c -index 03ea1ce..59c015c 100644 ---- a/hw/s390x/tod-qemu.c -+++ b/hw/s390x/tod-qemu.c -@@ -11,19 +11,43 @@ - #include "qemu/osdep.h" - #include "qapi/error.h" - #include "hw/s390x/tod.h" -+#include "qemu/timer.h" -+#include "qemu/cutils.h" -+#include "cpu.h" -+#include "tcg_s390x.h" - - static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod, - Error **errp) - { -- /* FIXME */ -- tod->high = 0; -- tod->low = 0; -+ *tod = td->base; -+ -+ tod->low += time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -+ if (tod->low < td->base.low) { -+ tod->high++; -+ } - } - - static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod, - Error **errp) - { -- /* FIXME */ -+ CPUState *cpu; -+ -+ td->base = *tod; -+ -+ td->base.low -= time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -+ if (td->base.low > tod->low) { -+ td->base.high--; -+ } -+ -+ /* -+ * The TOD has been changed and we have to recalculate the CKC values -+ * for all CPUs. We do this asynchronously, as "SET CLOCK should be -+ * issued only while all other activity on all CPUs .. has been -+ * suspended". -+ */ -+ CPU_FOREACH(cpu) { -+ async_run_on_cpu(cpu, tcg_s390_tod_updated, RUN_ON_CPU_NULL); -+ } - } - - static void qemu_s390_tod_class_init(ObjectClass *oc, void *data) -@@ -34,10 +58,24 @@ static void qemu_s390_tod_class_init(ObjectClass *oc, void *data) - tdc->set = qemu_s390_tod_set; - } - -+static void qemu_s390_tod_init(Object *obj) -+{ -+ S390TODState *td = S390_TOD(obj); -+ struct tm tm; -+ -+ qemu_get_timedate(&tm, 0); -+ td->base.high = 0; -+ td->base.low = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL); -+ if (td->base.low < TOD_UNIX_EPOCH) { -+ td->base.high += 1; -+ } -+} -+ - static TypeInfo qemu_s390_tod_info = { - .name = TYPE_QEMU_S390_TOD, - .parent = TYPE_S390_TOD, - .instance_size = sizeof(S390TODState), -+ .instance_init = qemu_s390_tod_init, - .class_init = qemu_s390_tod_class_init, - .class_size = sizeof(S390TODClass), - }; -diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c -index 0501aff..1c63f41 100644 ---- a/hw/s390x/tod.c -+++ b/hw/s390x/tod.c -@@ -30,6 +30,17 @@ void s390_init_tod(void) - qdev_init_nofail(DEVICE(obj)); - } - -+S390TODState *s390_get_todstate(void) -+{ -+ static S390TODState *ts; -+ -+ if (!ts) { -+ ts = S390_TOD(object_resolve_path_type("", TYPE_S390_TOD, NULL)); -+ } -+ -+ return ts; -+} -+ - #define S390_TOD_CLOCK_VALUE_MISSING 0x00 - #define S390_TOD_CLOCK_VALUE_PRESENT 0x01 - -diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h -index 7096b57..413c0d7 100644 ---- a/include/hw/s390x/tod.h -+++ b/include/hw/s390x/tod.h -@@ -30,6 +30,9 @@ typedef struct S390TOD { - typedef struct S390TODState { - /* private */ - DeviceState parent_obj; -+ -+ /* unused by KVM implementation */ -+ S390TOD base; - } S390TODState; - - typedef struct S390TODClass { -@@ -41,6 +44,22 @@ typedef struct S390TODClass { - void (*set)(S390TODState *td, const S390TOD *tod, Error **errp); - } S390TODClass; - -+/* The value of the TOD clock for 1.1.1970. */ -+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL -+ -+/* Converts ns to s390's clock format */ -+static inline uint64_t time2tod(uint64_t ns) -+{ -+ return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9); -+} -+ -+/* Converts s390's clock format to ns */ -+static inline uint64_t tod2time(uint64_t t) -+{ -+ return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9); -+} -+ - void s390_init_tod(void); -+S390TODState *s390_get_todstate(void); - - #endif -diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c -index 5570741..f74d2a3 100644 ---- a/target/s390x/cpu.c -+++ b/target/s390x/cpu.c -@@ -30,7 +30,6 @@ - #include "kvm_s390x.h" - #include "sysemu/kvm.h" - #include "qemu-common.h" --#include "qemu/cutils.h" - #include "qemu/timer.h" - #include "qemu/error-report.h" - #include "trace.h" -@@ -276,9 +275,6 @@ static void s390_cpu_initfn(Object *obj) - CPUState *cs = CPU(obj); - S390CPU *cpu = S390_CPU(obj); - CPUS390XState *env = &cpu->env; --#if !defined(CONFIG_USER_ONLY) -- struct tm tm; --#endif - - cs->env_ptr = env; - cs->halted = 1; -@@ -287,9 +283,6 @@ static void s390_cpu_initfn(Object *obj) - s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); - s390_cpu_model_register_props(obj); - #if !defined(CONFIG_USER_ONLY) -- qemu_get_timedate(&tm, 0); -- env->tod_offset = TOD_UNIX_EPOCH + -- (time2tod(mktimegm(&tm)) * 1000000000ULL); - env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); - env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); - s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); -diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h -index 04f9adf..6500f42 100644 ---- a/target/s390x/cpu.h -+++ b/target/s390x/cpu.h -@@ -133,7 +133,6 @@ struct CPUS390XState { - uint64_t cpuid; - #endif - -- uint64_t tod_offset; - QEMUTimer *tod_timer; - - QEMUTimer *cpu_timer; -diff --git a/target/s390x/internal.h b/target/s390x/internal.h -index d1ed06f..61a509d 100644 ---- a/target/s390x/internal.h -+++ b/target/s390x/internal.h -@@ -237,22 +237,6 @@ enum cc_op { - CC_OP_MAX - }; - --/* The value of the TOD clock for 1.1.1970. */ --#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL -- --/* Converts ns to s390's clock format */ --static inline uint64_t time2tod(uint64_t ns) --{ -- return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9); -- --} -- --/* Converts s390's clock format to ns */ --static inline uint64_t tod2time(uint64_t t) --{ -- return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9); --} -- - static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, - uint8_t *ar) - { -diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c -index 8b3b040..4f675c7 100644 ---- a/target/s390x/misc_helper.c -+++ b/target/s390x/misc_helper.c -@@ -29,6 +29,8 @@ - #include "exec/address-spaces.h" - #include "exec/exec-all.h" - #include "exec/cpu_ldst.h" -+#include "qapi/error.h" -+#include "tcg_s390x.h" - - #if !defined(CONFIG_USER_ONLY) - #include "sysemu/cpus.h" -@@ -40,6 +42,7 @@ - #include "hw/s390x/ioinst.h" - #include "hw/s390x/s390-pci-inst.h" - #include "hw/boards.h" -+#include "hw/s390x/tod.h" - #endif - - /* #define DEBUG_HELPER */ -@@ -139,17 +142,19 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) - /* Store Clock */ - uint64_t HELPER(stck)(CPUS390XState *env) - { -- uint64_t time; -+ S390TODState *td = s390_get_todstate(); -+ S390TODClass *tdc = S390_TOD_GET_CLASS(td); -+ S390TOD tod; - -- time = env->tod_offset + -- time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -- -- return time; -+ tdc->get(td, &tod, &error_abort); -+ return tod.low; - } - - /* Set Clock Comparator */ - void HELPER(sckc)(CPUS390XState *env, uint64_t time) - { -+ S390TODState *td = s390_get_todstate(); -+ - if (time == -1ULL) { - return; - } -@@ -157,7 +162,7 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) - env->ckc = time; - - /* difference between origins */ -- time -= env->tod_offset; -+ time -= td->base.low; - - /* nanoseconds */ - time = tod2time(time); -@@ -165,6 +170,14 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) - timer_mod(env->tod_timer, time); - } - -+void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque) -+{ -+ S390CPU *cpu = S390_CPU(cs); -+ CPUS390XState *env = &cpu->env; -+ -+ helper_sckc(env, env->ckc); -+} -+ - /* Set Tod Programmable Field */ - void HELPER(sckpf)(CPUS390XState *env, uint64_t r0) - { -diff --git a/target/s390x/tcg_s390x.h b/target/s390x/tcg_s390x.h -new file mode 100644 -index 0000000..4e308aa ---- /dev/null -+++ b/target/s390x/tcg_s390x.h -@@ -0,0 +1,18 @@ -+/* -+ * QEMU TCG support -- s390x specific functions. -+ * -+ * Copyright 2018 Red Hat, Inc. -+ * -+ * Authors: -+ * David Hildenbrand -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef TCG_S390X_H -+#define TCG_S390X_H -+ -+void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque); -+ -+#endif /* TCG_S390X_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tcg-rearm-the-CKC-timer-during-migration.patch b/SOURCES/kvm-s390x-tcg-rearm-the-CKC-timer-during-migration.patch deleted file mode 100644 index 245eacc..0000000 --- a/SOURCES/kvm-s390x-tcg-rearm-the-CKC-timer-during-migration.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0ae076c231b0b8096acf0103b559bc5d58c4fdcf Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:53 +0100 -Subject: [PATCH 09/14] s390x/tcg: rearm the CKC timer during migration - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-9-david@redhat.com> -Patchwork-id: 83767 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 08/12] s390x/tcg: rearm the CKC timer during migration -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -If the CPU data is migrated after the TOD clock, the CKC timer of a CPU -is not rearmed. Let's rearm it when loading the CPU state. - -Introduce tcg-stub.c just like kvm-stub.c for tcg specific stubs. - -Reviewed-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-9-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 7c12f710bad60dc7e509da4e80c77e952ef0490c) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/Makefile.objs | 1 + - target/s390x/machine.c | 6 ++++++ - target/s390x/tcg-stub.c | 20 ++++++++++++++++++++ - 3 files changed, 27 insertions(+) - create mode 100644 target/s390x/tcg-stub.c - -diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs -index 31932de..22a9a99 100644 ---- a/target/s390x/Makefile.objs -+++ b/target/s390x/Makefile.objs -@@ -5,6 +5,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o diag.o - obj-$(CONFIG_SOFTMMU) += sigp.o - obj-$(CONFIG_KVM) += kvm.o - obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o -+obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o - - # build and run feature list generator - feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/ -diff --git a/target/s390x/machine.c b/target/s390x/machine.c -index 8421deb..cb792aa 100644 ---- a/target/s390x/machine.c -+++ b/target/s390x/machine.c -@@ -19,6 +19,7 @@ - #include "cpu.h" - #include "internal.h" - #include "kvm_s390x.h" -+#include "tcg_s390x.h" - #include "sysemu/kvm.h" - - static int cpu_post_load(void *opaque, int version_id) -@@ -34,6 +35,11 @@ static int cpu_post_load(void *opaque, int version_id) - return kvm_s390_vcpu_interrupt_post_load(cpu); - } - -+ if (tcg_enabled()) { -+ /* Rearm the CKC timer if necessary */ -+ tcg_s390_tod_updated(CPU(cpu), RUN_ON_CPU_NULL); -+ } -+ - return 0; - } - -diff --git a/target/s390x/tcg-stub.c b/target/s390x/tcg-stub.c -new file mode 100644 -index 0000000..c93501d ---- /dev/null -+++ b/target/s390x/tcg-stub.c -@@ -0,0 +1,20 @@ -+/* -+ * QEMU TCG support -- s390x specific function stubs. -+ * -+ * Copyright (C) 2018 Red Hat Inc -+ * -+ * Authors: -+ * David Hildenbrand -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qemu-common.h" -+#include "cpu.h" -+#include "tcg_s390x.h" -+ -+void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque) -+{ -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tod-Properly-stop-the-KVM-TOD-while-the-guest-.patch b/SOURCES/kvm-s390x-tod-Properly-stop-the-KVM-TOD-while-the-guest-.patch deleted file mode 100644 index 64c88f5..0000000 --- a/SOURCES/kvm-s390x-tod-Properly-stop-the-KVM-TOD-while-the-guest-.patch +++ /dev/null @@ -1,250 +0,0 @@ -From f9494422b9c4abe8f7cfea0ecee729bbc618de02 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:56 +0100 -Subject: [PATCH 12/14] s390x/tod: Properly stop the KVM TOD while the guest is - not running - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-12-david@redhat.com> -Patchwork-id: 83765 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 11/12] s390x/tod: Properly stop the KVM TOD while the guest is not running -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -Just like on other architectures, we should stop the clock while the guest -is not running. This is already properly done for TCG. Right now, doing an -offline migration (stop, migrate, cont) can easily trigger stalls in the -guest. - -Even doing a - (hmp) stop - ... wait 2 minutes ... - (hmp) cont -will already trigger stalls. - -So whenever the guest stops, backup the KVM TOD. When continuing to run -the guest, restore the KVM TOD. - -One special case is starting a simple VM: Reading the TOD from KVM to -stop it right away until the guest is actually started means that the -time of any simple VM will already differ to the host time. We can -simply leave the TOD running and the guest won't be able to recognize -it. - -For migration, we actually want to keep the TOD stopped until really -starting the guest. To be able to catch most errors, we should however -try to set the TOD in addition to simply storing it. So we can still -catch basic migration problems. - -If anything goes wrong while backing up/restoring the TOD, we have to -ignore it (but print a warning). This is then basically a fallback to -old behavior (TOD remains running). - -I tested this very basically with an initrd: - 1. Start a simple VM. Observed that the TOD is kept running. Old - behavior. - 2. Ordinary live migration. Observed that the TOD is temporarily - stopped on the destination when setting the new value and - correctly started when finally starting the guest. - 3. Offline live migration. (stop, migrate, cont). Observed that the - TOD will be stopped on the source with the "stop" command. On the - destination, the TOD is temporarily stopped when setting the new - value and correctly started when finally starting the guest via - "cont". - 4. Simple stop/cont correctly stops/starts the TOD. (multiple stops - or conts in a row have no effect, so works as expected) - -In the future, we might want to send the guest a special kind of time sync -interrupt under some conditions, so it can synchronize its tod to the -host tod. This is interesting for migration scenarios but also when we -get time sync interrupts ourselves. This however will most probably have -to be handled in KVM (e.g. when the tods differ too much) and is not -desired e.g. when debugging the guest (single stepping should not -result in permanent time syncs). I consider something like that an add-on -on top of this basic "don't break the guest" handling. - -Signed-off-by: David Hildenbrand -Message-Id: <20181130094957.4121-1-david@redhat.com> -Acked-by: Christian Borntraeger -Reviewed-by: Thomas Huth -Signed-off-by: Cornelia Huck -(cherry picked from commit 9bc9d3d1ae3bcd1caaad1946494726b52f58b291) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/tod-kvm.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++- - include/hw/s390x/tod.h | 8 +++- - 2 files changed, 107 insertions(+), 3 deletions(-) - -diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c -index df564ab..2456bf7 100644 ---- a/hw/s390x/tod-kvm.c -+++ b/hw/s390x/tod-kvm.c -@@ -10,10 +10,11 @@ - - #include "qemu/osdep.h" - #include "qapi/error.h" -+#include "sysemu/sysemu.h" - #include "hw/s390x/tod.h" - #include "kvm_s390x.h" - --static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp) -+static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp) - { - int r; - -@@ -27,7 +28,17 @@ static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp) - } - } - --static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp) -+static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp) -+{ -+ if (td->stopped) { -+ *tod = td->base; -+ return; -+ } -+ -+ kvm_s390_get_tod_raw(tod, errp); -+} -+ -+static void kvm_s390_set_tod_raw(const S390TOD *tod, Error **errp) - { - int r; - -@@ -41,18 +52,105 @@ static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp) - } - } - -+static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp) -+{ -+ Error *local_err = NULL; -+ -+ /* -+ * Somebody (e.g. migration) set the TOD. We'll store it into KVM to -+ * properly detect errors now but take a look at the runstate to decide -+ * whether really to keep the tod running. E.g. during migration, this -+ * is the point where we want to stop the initially running TOD to fire -+ * it back up when actually starting the migrated guest. -+ */ -+ kvm_s390_set_tod_raw(tod, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ if (runstate_is_running()) { -+ td->stopped = false; -+ } else { -+ td->stopped = true; -+ td->base = *tod; -+ } -+} -+ -+static void kvm_s390_tod_vm_state_change(void *opaque, int running, -+ RunState state) -+{ -+ S390TODState *td = opaque; -+ Error *local_err = NULL; -+ -+ if (running && td->stopped) { -+ /* Set the old TOD when running the VM - start the TOD clock. */ -+ kvm_s390_set_tod_raw(&td->base, &local_err); -+ if (local_err) { -+ warn_report_err(local_err); -+ } -+ /* Treat errors like the TOD was running all the time. */ -+ td->stopped = false; -+ } else if (!running && !td->stopped) { -+ /* Store the TOD when stopping the VM - stop the TOD clock. */ -+ kvm_s390_get_tod_raw(&td->base, &local_err); -+ if (local_err) { -+ /* Keep the TOD running in case we could not back it up. */ -+ warn_report_err(local_err); -+ } else { -+ td->stopped = true; -+ } -+ } -+} -+ -+static void kvm_s390_tod_realize(DeviceState *dev, Error **errp) -+{ -+ S390TODState *td = S390_TOD(dev); -+ S390TODClass *tdc = S390_TOD_GET_CLASS(td); -+ Error *local_err = NULL; -+ -+ tdc->parent_realize(dev, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ /* -+ * We need to know when the VM gets started/stopped to start/stop the TOD. -+ * As we can never have more than one TOD instance (and that will never be -+ * removed), registering here and never unregistering is good enough. -+ */ -+ qemu_add_vm_change_state_handler(kvm_s390_tod_vm_state_change, td); -+} -+ - static void kvm_s390_tod_class_init(ObjectClass *oc, void *data) - { - S390TODClass *tdc = S390_TOD_CLASS(oc); - -+ device_class_set_parent_realize(DEVICE_CLASS(oc), kvm_s390_tod_realize, -+ &tdc->parent_realize); - tdc->get = kvm_s390_tod_get; - tdc->set = kvm_s390_tod_set; - } - -+static void kvm_s390_tod_init(Object *obj) -+{ -+ S390TODState *td = S390_TOD(obj); -+ -+ /* -+ * The TOD is initially running (value stored in KVM). Avoid needless -+ * loading/storing of the TOD when starting a simple VM, so let it -+ * run although the (never started) VM is stopped. For migration, we -+ * will properly set the TOD later. -+ */ -+ td->stopped = false; -+} -+ - static TypeInfo kvm_s390_tod_info = { - .name = TYPE_KVM_S390_TOD, - .parent = TYPE_S390_TOD, - .instance_size = sizeof(S390TODState), -+ .instance_init = kvm_s390_tod_init, - .class_init = kvm_s390_tod_class_init, - .class_size = sizeof(S390TODClass), - }; -diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h -index 413c0d7..cbd7552 100644 ---- a/include/hw/s390x/tod.h -+++ b/include/hw/s390x/tod.h -@@ -31,13 +31,19 @@ typedef struct S390TODState { - /* private */ - DeviceState parent_obj; - -- /* unused by KVM implementation */ -+ /* -+ * Used by TCG to remember the time base. Used by KVM to backup the TOD -+ * while the TOD is stopped. -+ */ - S390TOD base; -+ /* Used by KVM to remember if the TOD is stopped and base is valid. */ -+ bool stopped; - } S390TODState; - - typedef struct S390TODClass { - /* private */ - DeviceClass parent_class; -+ void (*parent_realize)(DeviceState *dev, Error **errp); - - /* public */ - void (*get)(const S390TODState *td, S390TOD *tod, Error **errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-tod-factor-out-TOD-into-separate-device.patch b/SOURCES/kvm-s390x-tod-factor-out-TOD-into-separate-device.patch deleted file mode 100644 index c294173..0000000 --- a/SOURCES/kvm-s390x-tod-factor-out-TOD-into-separate-device.patch +++ /dev/null @@ -1,516 +0,0 @@ -From eb4b0282363c6149a05d6b00b0b7d40535715598 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 21 Dec 2018 15:39:48 +0100 -Subject: [PATCH 04/14] s390x/tod: factor out TOD into separate device - -RH-Author: David Hildenbrand -Message-id: <20181221153957.28183-4-david@redhat.com> -Patchwork-id: 83761 -O-Subject: [RHEL-7.6.z qemu-kvm-ma PATCH 03/12] s390x/tod: factor out TOD into separate device -Bugzilla: 1672920 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/s390x/s390-virtio-ccw.c: contextual conflict (console init - rework) - -Let's treat this like a separate device. TCG will have to store the -actual state/time later on. - -Include cpu-qom.h in kvm_s390x.h (due to S390CPU) to compile tod-kvm.c. - -Reviewed-by: Thomas Huth -Signed-off-by: David Hildenbrand -Message-Id: <20180627134410.4901-4-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 8046f374a64b81fdf4f71f7a433bf4035d501521) -Signed-off-by: David Hildenbrand ---- - hw/s390x/Makefile.objs | 3 ++ - hw/s390x/s390-virtio-ccw.c | 57 ++-------------------- - hw/s390x/tod-kvm.c | 64 ++++++++++++++++++++++++ - hw/s390x/tod-qemu.c | 49 +++++++++++++++++++ - hw/s390x/tod.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ - include/hw/s390x/tod.h | 46 ++++++++++++++++++ - target/s390x/cpu.c | 32 ------------ - target/s390x/cpu.h | 2 - - target/s390x/kvm_s390x.h | 2 + - 9 files changed, 286 insertions(+), 88 deletions(-) - create mode 100644 hw/s390x/tod-kvm.c - create mode 100644 hw/s390x/tod-qemu.c - create mode 100644 hw/s390x/tod.c - create mode 100644 include/hw/s390x/tod.h - -diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs -index dc704b5..93282f7 100644 ---- a/hw/s390x/Makefile.objs -+++ b/hw/s390x/Makefile.objs -@@ -14,6 +14,9 @@ obj-$(CONFIG_PCI) += s390-pci-bus.o s390-pci-inst.o - obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o - obj-y += s390-skeys.o - obj-y += s390-stattrib.o -+obj-y += tod.o -+obj-$(CONFIG_KVM) += tod-kvm.o -+obj-$(CONFIG_TCG) += tod-qemu.o - obj-$(CONFIG_KVM) += s390-skeys-kvm.o - obj-$(CONFIG_KVM) += s390-stattrib-kvm.o - obj-y += s390-ccw.o -diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c -index bf039a1..3429e55 100644 ---- a/hw/s390x/s390-virtio-ccw.c -+++ b/hw/s390x/s390-virtio-ccw.c -@@ -35,6 +35,7 @@ - #include "migration/register.h" - #include "cpu_models.h" - #include "hw/nmi.h" -+#include "hw/s390x/tod.h" - - S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) - { -@@ -187,58 +188,6 @@ static void s390_memory_init(ram_addr_t mem_size) - s390_stattrib_init(); - } - --#define S390_TOD_CLOCK_VALUE_MISSING 0x00 --#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 -- --static void gtod_save(QEMUFile *f, void *opaque) --{ -- uint64_t tod_low; -- uint8_t tod_high; -- int r; -- -- r = s390_get_clock(&tod_high, &tod_low); -- if (r) { -- warn_report("Unable to get guest clock for migration: %s", -- strerror(-r)); -- error_printf("Guest clock will not be migrated " -- "which could cause the guest to hang."); -- qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); -- return; -- } -- -- qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); -- qemu_put_byte(f, tod_high); -- qemu_put_be64(f, tod_low); --} -- --static int gtod_load(QEMUFile *f, void *opaque, int version_id) --{ -- uint64_t tod_low; -- uint8_t tod_high; -- int r; -- -- if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { -- warn_report("Guest clock was not migrated. This could " -- "cause the guest to hang."); -- return 0; -- } -- -- tod_high = qemu_get_byte(f); -- tod_low = qemu_get_be64(f); -- -- r = s390_set_clock(&tod_high, &tod_low); -- if (r) { -- error_report("Unable to set KVM guest TOD clock: %s", strerror(-r)); -- } -- -- return r; --} -- --static SaveVMHandlers savevm_gtod = { -- .save_state = gtod_save, -- .load_state = gtod_load, --}; -- - static void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *firmware, -@@ -346,8 +295,8 @@ static void ccw_init(MachineState *machine) - /* Create VirtIO network adapters */ - s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); - -- /* Register savevm handler for guest TOD clock */ -- register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL); -+ /* init the TOD clock */ -+ s390_init_tod(); - } - - static void s390_cpu_plug(HotplugHandler *hotplug_dev, -diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c -new file mode 100644 -index 0000000..df564ab ---- /dev/null -+++ b/hw/s390x/tod-kvm.c -@@ -0,0 +1,64 @@ -+/* -+ * TOD (Time Of Day) clock - KVM implementation -+ * -+ * Copyright 2018 Red Hat, Inc. -+ * Author(s): David Hildenbrand -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "hw/s390x/tod.h" -+#include "kvm_s390x.h" -+ -+static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp) -+{ -+ int r; -+ -+ r = kvm_s390_get_clock_ext(&tod->high, &tod->low); -+ if (r == -ENXIO) { -+ r = kvm_s390_get_clock(&tod->high, &tod->low); -+ } -+ if (r) { -+ error_setg(errp, "Unable to get KVM guest TOD clock: %s", -+ strerror(-r)); -+ } -+} -+ -+static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp) -+{ -+ int r; -+ -+ r = kvm_s390_set_clock_ext(tod->high, tod->low); -+ if (r == -ENXIO) { -+ r = kvm_s390_set_clock(tod->high, tod->low); -+ } -+ if (r) { -+ error_setg(errp, "Unable to set KVM guest TOD clock: %s", -+ strerror(-r)); -+ } -+} -+ -+static void kvm_s390_tod_class_init(ObjectClass *oc, void *data) -+{ -+ S390TODClass *tdc = S390_TOD_CLASS(oc); -+ -+ tdc->get = kvm_s390_tod_get; -+ tdc->set = kvm_s390_tod_set; -+} -+ -+static TypeInfo kvm_s390_tod_info = { -+ .name = TYPE_KVM_S390_TOD, -+ .parent = TYPE_S390_TOD, -+ .instance_size = sizeof(S390TODState), -+ .class_init = kvm_s390_tod_class_init, -+ .class_size = sizeof(S390TODClass), -+}; -+ -+static void register_types(void) -+{ -+ type_register_static(&kvm_s390_tod_info); -+} -+type_init(register_types); -diff --git a/hw/s390x/tod-qemu.c b/hw/s390x/tod-qemu.c -new file mode 100644 -index 0000000..03ea1ce ---- /dev/null -+++ b/hw/s390x/tod-qemu.c -@@ -0,0 +1,49 @@ -+/* -+ * TOD (Time Of Day) clock - QEMU implementation -+ * -+ * Copyright 2018 Red Hat, Inc. -+ * Author(s): David Hildenbrand -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "hw/s390x/tod.h" -+ -+static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod, -+ Error **errp) -+{ -+ /* FIXME */ -+ tod->high = 0; -+ tod->low = 0; -+} -+ -+static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod, -+ Error **errp) -+{ -+ /* FIXME */ -+} -+ -+static void qemu_s390_tod_class_init(ObjectClass *oc, void *data) -+{ -+ S390TODClass *tdc = S390_TOD_CLASS(oc); -+ -+ tdc->get = qemu_s390_tod_get; -+ tdc->set = qemu_s390_tod_set; -+} -+ -+static TypeInfo qemu_s390_tod_info = { -+ .name = TYPE_QEMU_S390_TOD, -+ .parent = TYPE_S390_TOD, -+ .instance_size = sizeof(S390TODState), -+ .class_init = qemu_s390_tod_class_init, -+ .class_size = sizeof(S390TODClass), -+}; -+ -+static void register_types(void) -+{ -+ type_register_static(&qemu_s390_tod_info); -+} -+type_init(register_types); -diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c -new file mode 100644 -index 0000000..0501aff ---- /dev/null -+++ b/hw/s390x/tod.c -@@ -0,0 +1,119 @@ -+/* -+ * TOD (Time Of Day) clock -+ * -+ * Copyright 2018 Red Hat, Inc. -+ * Author(s): David Hildenbrand -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#include "qemu/osdep.h" -+#include "hw/s390x/tod.h" -+#include "qapi/error.h" -+#include "qemu/error-report.h" -+#include "sysemu/kvm.h" -+#include "migration/register.h" -+ -+void s390_init_tod(void) -+{ -+ Object *obj; -+ -+ if (kvm_enabled()) { -+ obj = object_new(TYPE_KVM_S390_TOD); -+ } else { -+ obj = object_new(TYPE_QEMU_S390_TOD); -+ } -+ object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj, NULL); -+ object_unref(obj); -+ -+ qdev_init_nofail(DEVICE(obj)); -+} -+ -+#define S390_TOD_CLOCK_VALUE_MISSING 0x00 -+#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 -+ -+static void s390_tod_save(QEMUFile *f, void *opaque) -+{ -+ S390TODState *td = opaque; -+ S390TODClass *tdc = S390_TOD_GET_CLASS(td); -+ Error *err = NULL; -+ S390TOD tod; -+ -+ tdc->get(td, &tod, &err); -+ if (err) { -+ warn_report_err(err); -+ error_printf("Guest clock will not be migrated " -+ "which could cause the guest to hang."); -+ qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); -+ return; -+ } -+ -+ qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); -+ qemu_put_byte(f, tod.high); -+ qemu_put_be64(f, tod.low); -+} -+ -+static int s390_tod_load(QEMUFile *f, void *opaque, int version_id) -+{ -+ S390TODState *td = opaque; -+ S390TODClass *tdc = S390_TOD_GET_CLASS(td); -+ Error *err = NULL; -+ S390TOD tod; -+ -+ if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { -+ warn_report("Guest clock was not migrated. This could " -+ "cause the guest to hang."); -+ return 0; -+ } -+ -+ tod.high = qemu_get_byte(f); -+ tod.low = qemu_get_be64(f); -+ -+ tdc->set(td, &tod, &err); -+ if (err) { -+ error_report_err(err); -+ return -1; -+ } -+ return 0; -+} -+ -+static SaveVMHandlers savevm_tod = { -+ .save_state = s390_tod_save, -+ .load_state = s390_tod_load, -+}; -+ -+static void s390_tod_realize(DeviceState *dev, Error **errp) -+{ -+ S390TODState *td = S390_TOD(dev); -+ -+ /* Legacy migration interface */ -+ register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td); -+} -+ -+static void s390_tod_class_init(ObjectClass *oc, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(oc); -+ -+ dc->desc = "TOD (Time Of Day) Clock"; -+ dc->realize = s390_tod_realize; -+ set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ -+ /* We only have one TOD clock in the system attached to the machine */ -+ dc->user_creatable = false; -+} -+ -+static TypeInfo s390_tod_info = { -+ .name = TYPE_S390_TOD, -+ .parent = TYPE_DEVICE, -+ .instance_size = sizeof(S390TODState), -+ .class_init = s390_tod_class_init, -+ .class_size = sizeof(S390TODClass), -+ .abstract = true, -+}; -+ -+static void register_types(void) -+{ -+ type_register_static(&s390_tod_info); -+} -+type_init(register_types); -diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h -new file mode 100644 -index 0000000..7096b57 ---- /dev/null -+++ b/include/hw/s390x/tod.h -@@ -0,0 +1,46 @@ -+/* -+ * TOD (Time Of Day) clock -+ * -+ * Copyright 2018 Red Hat, Inc. -+ * Author(s): David Hildenbrand -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ */ -+ -+#ifndef HW_S390_TOD_H -+#define HW_S390_TOD_H -+ -+#include "hw/qdev.h" -+ -+typedef struct S390TOD { -+ uint8_t high; -+ uint64_t low; -+} S390TOD; -+ -+#define TYPE_S390_TOD "s390-tod" -+#define S390_TOD(obj) OBJECT_CHECK(S390TODState, (obj), TYPE_S390_TOD) -+#define S390_TOD_CLASS(oc) OBJECT_CLASS_CHECK(S390TODClass, (oc), \ -+ TYPE_S390_TOD) -+#define S390_TOD_GET_CLASS(obj) OBJECT_GET_CLASS(S390TODClass, (obj), \ -+ TYPE_S390_TOD) -+#define TYPE_KVM_S390_TOD TYPE_S390_TOD "-kvm" -+#define TYPE_QEMU_S390_TOD TYPE_S390_TOD "-qemu" -+ -+typedef struct S390TODState { -+ /* private */ -+ DeviceState parent_obj; -+} S390TODState; -+ -+typedef struct S390TODClass { -+ /* private */ -+ DeviceClass parent_class; -+ -+ /* public */ -+ void (*get)(const S390TODState *td, S390TOD *tod, Error **errp); -+ void (*set)(S390TODState *td, const S390TOD *tod, Error **errp); -+} S390TODClass; -+ -+void s390_init_tod(void); -+ -+#endif -diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c -index 1f590d1..167d089 100644 ---- a/target/s390x/cpu.c -+++ b/target/s390x/cpu.c -@@ -391,38 +391,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) - return s390_count_running_cpus(); - } - --int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) --{ -- int r = 0; -- -- if (kvm_enabled()) { -- r = kvm_s390_get_clock_ext(tod_high, tod_low); -- if (r == -ENXIO) { -- return kvm_s390_get_clock(tod_high, tod_low); -- } -- } else { -- /* Fixme TCG */ -- *tod_high = 0; -- *tod_low = 0; -- } -- -- return r; --} -- --int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) --{ -- int r = 0; -- -- if (kvm_enabled()) { -- r = kvm_s390_set_clock_ext(*tod_high, *tod_low); -- if (r == -ENXIO) { -- return kvm_s390_set_clock(*tod_high, *tod_low); -- } -- } -- /* Fixme TCG */ -- return r; --} -- - int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) - { - if (kvm_enabled()) { -diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h -index 86d08fa..67118c8 100644 ---- a/target/s390x/cpu.h -+++ b/target/s390x/cpu.h -@@ -691,8 +691,6 @@ static inline uint64_t s390_build_validity_mcic(void) - - - /* cpu.c */ --int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low); --int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low); - void s390_crypto_reset(void); - bool s390_get_squash_mcss(void); - int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit); -diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h -index 36eb34b..6e52287 100644 ---- a/target/s390x/kvm_s390x.h -+++ b/target/s390x/kvm_s390x.h -@@ -10,6 +10,8 @@ - #ifndef KVM_S390X_H - #define KVM_S390X_H - -+#include "cpu-qom.h" -+ - struct kvm_s390_irq; - - void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq); --- -1.8.3.1 - diff --git a/SOURCES/kvm-sam460ex-Don-t-size-flash-memory-to-match-backing-im.patch b/SOURCES/kvm-sam460ex-Don-t-size-flash-memory-to-match-backing-im.patch new file mode 100644 index 0000000..1651288 --- /dev/null +++ b/SOURCES/kvm-sam460ex-Don-t-size-flash-memory-to-match-backing-im.patch @@ -0,0 +1,118 @@ +From 862385809b305a6b02bc9cf39c8fb055bf764838 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:50:57 +0200 +Subject: [PATCH 30/53] sam460ex: Don't size flash memory to match backing + image +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-9-armbru@redhat.com> +Patchwork-id: 87998 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 08/31] sam460ex: Don't size flash memory to match backing image +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +Machine "sam460ex" maps its flash memory at address 0xFFF00000. When +no image is supplied, its size is 1MiB (0x100000), and 512KiB of ROM +get mapped on top of its second half. Else, it's the size of the +image rounded up to the next multiple of 64KiB. + +The rounding is actually useless: pflash_cfi01_realize() fails with +"failed to read the initial flash content" unless it's a no-op. + +I have no idea what happens when the pflash's size exceeds 1MiB. +Useful outcomes seem unlikely. + +I guess memory at the end of the address space remains unmapped when +it's smaller than 1MiB. Again, useful outcomes seem unlikely. + +The physical hardware appears to have 512KiB of flash memory: +https://eu.mouser.com/datasheet/2/268/atmel_AT49BV040B-1180330.pdf + +For now, just set the flash memory size to 1MiB regardless of image +size, and document the mess. + +Cc: BALATON Zoltan +Signed-off-by: Markus Armbruster +Reviewed-by: BALATON Zoltan +Reviewed-by: Alex Bennée +Message-Id: <20190308094610.21210-7-armbru@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit f30bc99559306eee9ef363bc11bf63a021aee707) +[Trivial conflict in hw/ppc/sam460ex.c due to lack of commit ab3dd749241] + +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/sam460ex.c | 41 ++++++++++++++++++++++++++--------------- + 1 file changed, 26 insertions(+), 15 deletions(-) + +diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c +index dfff262..83c6e90 100644 +--- a/hw/ppc/sam460ex.c ++++ b/hw/ppc/sam460ex.c +@@ -212,32 +212,43 @@ static void generate_eeprom_serial(uint8_t *eeprom) + + static int sam460ex_load_uboot(void) + { ++ /* ++ * This first creates 1MiB of flash memory mapped at the end of ++ * the 32-bit address space (0xFFF00000..0xFFFFFFFF). ++ * ++ * If_PFLASH unit 0 is defined, the flash memory is initialized ++ * from that block backend. ++ * ++ * Else, it's initialized to zero. And then 512KiB of ROM get ++ * mapped on top of its second half (0xFFF80000..0xFFFFFFFF), ++ * initialized from u-boot-sam460-20100605.bin. ++ * ++ * This doesn't smell right. ++ * ++ * The physical hardware appears to have 512KiB flash memory. ++ * ++ * TODO Figure out what we really need here, and clean this up. ++ */ ++ + DriveInfo *dinfo; +- BlockBackend *blk = NULL; +- hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32); +- long bios_size = FLASH_SIZE; +- int fl_sectors; + + dinfo = drive_get(IF_PFLASH, 0, 0); +- if (dinfo) { +- blk = blk_by_legacy_dinfo(dinfo); +- bios_size = blk_getlength(blk); +- } +- fl_sectors = (bios_size + 65535) >> 16; +- +- if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size, +- blk, (64 * 1024), fl_sectors, ++ if (!pflash_cfi01_register(FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32), ++ NULL, "sam460ex.flash", FLASH_SIZE, ++ dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, ++ 64 * KiB, FLASH_SIZE / (64 * KiB), + 1, 0x89, 0x18, 0x0000, 0x0, 1)) { + error_report("qemu: Error registering flash memory."); + /* XXX: return an error instead? */ + exit(1); + } + +- if (!blk) { ++ if (!dinfo) { + /*error_report("No flash image given with the 'pflash' parameter," + " using default u-boot image");*/ +- base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32); +- rom_add_file_fixed(UBOOT_FILENAME, base, -1); ++ rom_add_file_fixed(UBOOT_FILENAME, ++ UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32), ++ -1); + } + + return 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-disk-Acquire-the-AioContext-in-scsi_-_realize.patch b/SOURCES/kvm-scsi-disk-Acquire-the-AioContext-in-scsi_-_realize.patch new file mode 100644 index 0000000..0f577ed --- /dev/null +++ b/SOURCES/kvm-scsi-disk-Acquire-the-AioContext-in-scsi_-_realize.patch @@ -0,0 +1,191 @@ +From e47b913ba52ead235fd3a03916d62ce49254c575 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 10 May 2019 13:28:24 +0200 +Subject: [PATCH 21/53] scsi-disk: Acquire the AioContext in scsi_*_realize() + +RH-Author: Markus Armbruster +Message-id: <20190510132825.29833-3-armbru@redhat.com> +Patchwork-id: 87265 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/3] scsi-disk: Acquire the AioContext in scsi_*_realize() +Bugzilla: 1673397 1673402 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +From: Alberto Garcia + +This fixes a crash when attaching two disks with the same blockdev to +a SCSI device that is using iothreads. Test case included. + +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit 3ff35ba391134e4e43ab96152deb38a62e62f858) +[Trivial conflict in hw/scsi/scsi-disk.c due to lack of commit +51f43d5792e resolved] +Signed-off-by: Markus Armbruster + +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 23 ++++++++++++++++++++--- + tests/qemu-iotests/240 | 18 ++++++++++++++++++ + tests/qemu-iotests/240.out | 16 ++++++++++++++++ + 3 files changed, 54 insertions(+), 3 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index 8033d7e..6cc5ccc 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -2386,10 +2386,13 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) + static void scsi_hd_realize(SCSIDevice *dev, Error **errp) + { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); ++ AioContext *ctx = NULL; + /* can happen for devices without drive. The error message for missing + * backend will be issued in scsi_realize + */ + if (s->qdev.conf.blk) { ++ ctx = blk_get_aio_context(s->qdev.conf.blk); ++ aio_context_acquire(ctx); + blkconf_blocksizes(&s->qdev.conf); + } + s->qdev.blocksize = s->qdev.conf.logical_block_size; +@@ -2398,11 +2401,15 @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp) + s->product = g_strdup("QEMU HARDDISK"); + } + scsi_realize(&s->qdev, errp); ++ if (ctx) { ++ aio_context_release(ctx); ++ } + } + + static void scsi_cd_realize(SCSIDevice *dev, Error **errp) + { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); ++ AioContext *ctx; + int ret; + + if (!dev->conf.blk) { +@@ -2413,6 +2420,8 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) + assert(ret == 0); + } + ++ ctx = blk_get_aio_context(dev->conf.blk); ++ aio_context_acquire(ctx); + s->qdev.blocksize = 2048; + s->qdev.type = TYPE_ROM; + s->features |= 1 << SCSI_DISK_F_REMOVABLE; +@@ -2420,6 +2429,7 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) + s->product = g_strdup("QEMU CD-ROM"); + } + scsi_realize(&s->qdev, errp); ++ aio_context_release(ctx); + } + + static void scsi_disk_realize(SCSIDevice *dev, Error **errp) +@@ -2558,6 +2568,7 @@ static int get_device_type(SCSIDiskState *s) + static void scsi_block_realize(SCSIDevice *dev, Error **errp) + { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); ++ AioContext *ctx; + int sg_version; + int rc; + +@@ -2566,6 +2577,9 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) + return; + } + ++ ctx = blk_get_aio_context(s->qdev.conf.blk); ++ aio_context_acquire(ctx); ++ + /* check we are using a driver managing SG_IO (version 3 and after) */ + rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); + if (rc < 0) { +@@ -2573,18 +2587,18 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) + if (rc != -EPERM) { + error_append_hint(errp, "Is this a SCSI device?\n"); + } +- return; ++ goto out; + } + if (sg_version < 30000) { + error_setg(errp, "scsi generic interface too old"); +- return; ++ goto out; + } + + /* get device type from INQUIRY data */ + rc = get_device_type(s); + if (rc < 0) { + error_setg(errp, "INQUIRY failed"); +- return; ++ goto out; + } + + /* Make a guess for the block size, we'll fix it when the guest sends. +@@ -2604,6 +2618,9 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) + + scsi_realize(&s->qdev, errp); + scsi_generic_read_device_inquiry(&s->qdev); ++ ++out: ++ aio_context_release(ctx); + } + + typedef struct SCSIBlockReq { +diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 +index ead7ee0..5d499c9 100755 +--- a/tests/qemu-iotests/240 ++++ b/tests/qemu-iotests/240 +@@ -83,6 +83,24 @@ run_qemu < +Date: Wed, 6 Feb 2019 15:58:29 +0100 +Subject: [PATCH 09/33] scsi-disk: Add device_id property + +RH-Author: Kevin Wolf +Message-id: <20190206155829.14641-3-kwolf@redhat.com> +Patchwork-id: 84254 +O-Subject: [RHEL-7.7/8.0-AV qemu-kvm-rhev PATCH 2/2] scsi-disk: Add device_id property +Bugzilla: 1673080 +RH-Acked-by: Max Reitz +RH-Acked-by: Thomas Huth +RH-Acked-by: Paolo Bonzini + +The new device_id property specifies which value to use for the vendor +specific designator in the Device Identification VPD page. + +In particular, this is necessary for libvirt to maintain guest ABI +compatibility when no serial number is given and a VM is switched from +-drive (where the BlockBackend name is used) to -blockdev (where the +vendor specific designator is left out by default). + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 7471a649fc3a391dd497297013fb2525ca9821ba) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index de6c7bc..8033d7e 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -103,6 +103,7 @@ typedef struct SCSIDiskState + char *serial; + char *vendor; + char *product; ++ char *device_id; + bool tray_open; + bool tray_locked; + /* +@@ -638,13 +639,8 @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + + case 0x83: /* Device identification page, mandatory */ + { +- const char *str = s->serial ?: blk_name(s->qdev.conf.blk); +- int max_len = s->serial ? 20 : 255 - 8; +- int id_len = strlen(str); ++ int id_len = s->device_id ? MIN(strlen(s->device_id), 255 - 8) : 0; + +- if (id_len > max_len) { +- id_len = max_len; +- } + DPRINTF("Inquiry EVPD[Device identification] " + "buffer size %zd\n", req->cmd.xfer); + +@@ -653,7 +649,7 @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + outbuf[buflen++] = 0; /* not officially assigned */ + outbuf[buflen++] = 0; /* reserved */ + outbuf[buflen++] = id_len; /* length of data following */ +- memcpy(outbuf + buflen, str, id_len); ++ memcpy(outbuf + buflen, s->device_id, id_len); + buflen += id_len; + } + +@@ -2360,6 +2356,16 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) + if (!s->vendor) { + s->vendor = g_strdup("QEMU"); + } ++ if (!s->device_id) { ++ if (s->serial) { ++ s->device_id = g_strdup_printf("%.20s", s->serial); ++ } else { ++ const char *str = blk_name(s->qdev.conf.blk); ++ if (str && *str) { ++ s->device_id = g_strdup(str); ++ } ++ } ++ } + + if (blk_is_sg(s->qdev.conf.blk)) { + error_setg(errp, "unwanted /dev/sg*"); +@@ -2895,7 +2901,9 @@ static const TypeInfo scsi_disk_base_info = { + DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ + DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \ + DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \ +- DEFINE_PROP_STRING("product", SCSIDiskState, product) ++ DEFINE_PROP_STRING("product", SCSIDiskState, product), \ ++ DEFINE_PROP_STRING("device_id", SCSIDiskState, device_id) ++ + + static Property scsi_hd_properties[] = { + DEFINE_SCSI_DISK_PROPERTIES(), +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-disk-Block-Device-Characteristics-emulation-fix.patch b/SOURCES/kvm-scsi-disk-Block-Device-Characteristics-emulation-fix.patch new file mode 100644 index 0000000..ccc47da --- /dev/null +++ b/SOURCES/kvm-scsi-disk-Block-Device-Characteristics-emulation-fix.patch @@ -0,0 +1,83 @@ +From 691b2859207e4cee5e86f0cb86a7a81b9efa2bda Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:03 +0100 +Subject: [PATCH 29/34] scsi-disk: Block Device Characteristics emulation fix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-6-pbonzini@redhat.com> +Patchwork-id: 82945 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 5/9] scsi-disk: Block Device Characteristics emulation fix +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +From: Daniel Henrique Barboza + +The current BDC VPD page (page 0xb1) is too short. This can be +seen running sg_utils: + +$ sg_vpd --page=bdc /dev/sda +Block device characteristics VPD page (SBC): +Block device characteristics VPD page length too short=8 + +By the SCSI spec, the expected size of the SBC page is 0x40. +There is no telling how the guest will behave with a shorter +message - it can ignore it, or worse, make (wrong) +assumptions. + +This patch fixes the emulation by setting the size to 0x40. +This is the output of the previous sg_vpd command after +applying it: + +$ sg_vpd --page=bdc /dev/sda -v + inquiry cdb: 12 01 b1 00 fc 00 +Block device characteristics VPD page (SBC): + [PQual=0 Peripheral device type: disk] + Medium rotation rate is not reported + Product type: Not specified + WABEREQ=0 + WACEREQ=0 + Nominal form factor not reported + FUAB=0 + VBULS=0 + +To improve readability, this patch also adds the VBULS value +explictly and add comments on the existing fields we're +setting. + +Signed-off-by: Daniel Henrique Barboza +Acked-by: Paolo Bonzini +Signed-off-by: Kevin Wolf +(cherry picked from commit 740842c9656cd5dbc9ccf2ea0c3a74f0ba35144a) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index b3d53ec..b8a27d6 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -774,11 +774,12 @@ int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + } + case 0xb1: /* block device characteristics */ + { +- buflen = 8; ++ buflen = 0x40; + outbuf[4] = (s->rotation_rate >> 8) & 0xff; + outbuf[5] = s->rotation_rate & 0xff; +- outbuf[6] = 0; +- outbuf[7] = 0; ++ outbuf[6] = 0; /* PRODUCT TYPE */ ++ outbuf[7] = 0; /* WABEREQ | WACEREQ | NOMINAL FORM FACTOR */ ++ outbuf[8] = 0; /* VBULS */ + break; + } + case 0xb2: /* thin provisioning */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-disk-Don-t-use-empty-string-as-device-id.patch b/SOURCES/kvm-scsi-disk-Don-t-use-empty-string-as-device-id.patch new file mode 100644 index 0000000..b734253 --- /dev/null +++ b/SOURCES/kvm-scsi-disk-Don-t-use-empty-string-as-device-id.patch @@ -0,0 +1,71 @@ +From 66d5fd223afbf662589611f3d6a22ff7bcc38bb0 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 6 Feb 2019 15:58:28 +0100 +Subject: [PATCH 08/33] scsi-disk: Don't use empty string as device id +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Kevin Wolf +Message-id: <20190206155829.14641-2-kwolf@redhat.com> +Patchwork-id: 84253 +O-Subject: [RHEL-7.7/8.0-AV qemu-kvm-rhev PATCH 1/2] scsi-disk: Don't use empty string as device id +Bugzilla: 1673080 +RH-Acked-by: Max Reitz +RH-Acked-by: Thomas Huth +RH-Acked-by: Paolo Bonzini + +scsi-disk includes in the Device Identification VPD page, depending on +configuration amongst others, a vendor specific designator that consists +either of the serial number if given or the BlockBackend name (which is +a host detail that better shouldn't have been leaked to the guest, but +now we have to maintain it for compatibility). + +With anonymous BlockBackends, i.e. scsi-disk devices constructed with +drive=, and no serial number explicitly specified, this ends +up as an empty string. If this happens to more than one disk, we have +accidentally signalled to the OS that this is a multipath setup, which +is obviously not what was intended. + +Instead of using an empty string for the vendor specific designator, +simply leave out that designator, which makes Linux detect such setups +as separate disks again. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit a8f58afcdb86e266e06c9dc41a71605e570244c3) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index a20ef91..de6c7bc 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -648,12 +648,14 @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + DPRINTF("Inquiry EVPD[Device identification] " + "buffer size %zd\n", req->cmd.xfer); + +- outbuf[buflen++] = 0x2; /* ASCII */ +- outbuf[buflen++] = 0; /* not officially assigned */ +- outbuf[buflen++] = 0; /* reserved */ +- outbuf[buflen++] = id_len; /* length of data following */ +- memcpy(outbuf + buflen, str, id_len); +- buflen += id_len; ++ if (id_len) { ++ outbuf[buflen++] = 0x2; /* ASCII */ ++ outbuf[buflen++] = 0; /* not officially assigned */ ++ outbuf[buflen++] = 0; /* reserved */ ++ outbuf[buflen++] = id_len; /* length of data following */ ++ memcpy(outbuf + buflen, str, id_len); ++ buflen += id_len; ++ } + + if (s->qdev.wwn) { + outbuf[buflen++] = 0x1; /* Binary */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-avoid-invalid-access-to-struct-when-emu.patch b/SOURCES/kvm-scsi-generic-avoid-invalid-access-to-struct-when-emu.patch new file mode 100644 index 0000000..1210410 --- /dev/null +++ b/SOURCES/kvm-scsi-generic-avoid-invalid-access-to-struct-when-emu.patch @@ -0,0 +1,335 @@ +From fd72da696d48452bf9ffc4816e049f4ed18f6117 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:06 +0100 +Subject: [PATCH 32/34] scsi-generic: avoid invalid access to struct when + emulating block limits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-9-pbonzini@redhat.com> +Patchwork-id: 82946 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 8/9] scsi-generic: avoid invalid access to struct when emulating block limits +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +Emulation of the block limits VPD page called back into scsi-disk.c, +which however expected the request to be for a SCSIDiskState and +accessed a scsi-generic device outside the bounds of its struct +(namely to retrieve s->max_unmap_size and s->max_io_size). + +To avoid this, move the emulation code to a separate function that +takes a new SCSIBlockLimits struct and marshals it into the VPD +response format. + +Reported-by: Max Reitz +Reviewed-by: Max Reitz +Signed-off-by: Paolo Bonzini +(cherry picked from commit 3d4a8bf0eed68a781e06118e4d1df6e2f106a1f2) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/Makefile.objs | 2 +- + hw/scsi/emulation.c | 42 +++++++++++++++++++++ + hw/scsi/scsi-disk.c | 92 ++++++++++----------------------------------- + hw/scsi/scsi-generic.c | 35 ++++++++++++----- + include/hw/scsi/emulation.h | 16 ++++++++ + include/hw/scsi/scsi.h | 1 - + 6 files changed, 104 insertions(+), 84 deletions(-) + create mode 100644 hw/scsi/emulation.c + create mode 100644 include/hw/scsi/emulation.h + +diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs +index b188f72..c4f249a 100644 +--- a/hw/scsi/Makefile.objs ++++ b/hw/scsi/Makefile.objs +@@ -1,4 +1,4 @@ +-common-obj-y += scsi-disk.o ++common-obj-y += scsi-disk.o emulation.o + common-obj-y += scsi-generic.o scsi-bus.o + common-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o + common-obj-$(CONFIG_MPTSAS_SCSI_PCI) += mptsas.o mptconfig.o mptendian.o +diff --git a/hw/scsi/emulation.c b/hw/scsi/emulation.c +new file mode 100644 +index 0000000..06d62f3 +--- /dev/null ++++ b/hw/scsi/emulation.c +@@ -0,0 +1,42 @@ ++#include "qemu/osdep.h" ++#include "qemu/units.h" ++#include "qemu/bswap.h" ++#include "hw/scsi/emulation.h" ++ ++int scsi_emulate_block_limits(uint8_t *outbuf, const SCSIBlockLimits *bl) ++{ ++ /* required VPD size with unmap support */ ++ memset(outbuf, 0, 0x3c); ++ ++ outbuf[0] = bl->wsnz; /* wsnz */ ++ ++ if (bl->max_io_sectors) { ++ /* optimal transfer length granularity. This field and the optimal ++ * transfer length can't be greater than maximum transfer length. ++ */ ++ stw_be_p(outbuf + 2, MIN(bl->min_io_size, bl->max_io_sectors)); ++ ++ /* maximum transfer length */ ++ stl_be_p(outbuf + 4, bl->max_io_sectors); ++ ++ /* optimal transfer length */ ++ stl_be_p(outbuf + 8, MIN(bl->opt_io_size, bl->max_io_sectors)); ++ } else { ++ stw_be_p(outbuf + 2, bl->min_io_size); ++ stl_be_p(outbuf + 8, bl->opt_io_size); ++ } ++ ++ /* max unmap LBA count */ ++ stl_be_p(outbuf + 16, bl->max_unmap_sectors); ++ ++ /* max unmap descriptors */ ++ stl_be_p(outbuf + 20, bl->max_unmap_descr); ++ ++ /* optimal unmap granularity; alignment is zero */ ++ stl_be_p(outbuf + 24, bl->unmap_sectors); ++ ++ /* max write same size, make it the same as maximum transfer length */ ++ stl_be_p(outbuf + 36, bl->max_io_sectors); ++ ++ return 0x3c; ++} +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index b8a27d6..a20ef91 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -32,6 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "hw/scsi/scsi.h" ++#include "hw/scsi/emulation.h" + #include "scsi/constants.h" + #include "sysemu/sysemu.h" + #include "sysemu/block-backend.h" +@@ -585,7 +586,7 @@ static uint8_t *scsi_get_buf(SCSIRequest *req) + return (uint8_t *)r->iov.iov_base; + } + +-int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) ++static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + uint8_t page_code = req->cmd.buf[2]; +@@ -687,89 +688,36 @@ int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) + } + case 0xb0: /* block limits */ + { +- unsigned int unmap_sectors = +- s->qdev.conf.discard_granularity / s->qdev.blocksize; +- unsigned int min_io_size = +- s->qdev.conf.min_io_size / s->qdev.blocksize; +- unsigned int opt_io_size = +- s->qdev.conf.opt_io_size / s->qdev.blocksize; +- unsigned int max_unmap_sectors = +- s->max_unmap_size / s->qdev.blocksize; +- unsigned int max_io_sectors = +- s->max_io_size / s->qdev.blocksize; ++ SCSIBlockLimits bl = {}; + + if (s->qdev.type == TYPE_ROM) { + DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n", + page_code); + return -1; + } ++ bl.wsnz = 1; ++ bl.unmap_sectors = ++ s->qdev.conf.discard_granularity / s->qdev.blocksize; ++ bl.min_io_size = ++ s->qdev.conf.min_io_size / s->qdev.blocksize; ++ bl.opt_io_size = ++ s->qdev.conf.opt_io_size / s->qdev.blocksize; ++ bl.max_unmap_sectors = ++ s->max_unmap_size / s->qdev.blocksize; ++ bl.max_io_sectors = ++ s->max_io_size / s->qdev.blocksize; ++ /* 255 descriptors fit in 4 KiB with an 8-byte header */ ++ bl.max_unmap_descr = 255; ++ + if (s->qdev.type == TYPE_DISK) { + int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk); + int max_io_sectors_blk = + max_transfer_blk / s->qdev.blocksize; + +- max_io_sectors = +- MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors); +- +- /* min_io_size and opt_io_size can't be greater than +- * max_io_sectors */ +- if (min_io_size) { +- min_io_size = MIN(min_io_size, max_io_sectors); +- } +- if (opt_io_size) { +- opt_io_size = MIN(opt_io_size, max_io_sectors); +- } ++ bl.max_io_sectors = ++ MIN_NON_ZERO(max_io_sectors_blk, bl.max_io_sectors); + } +- /* required VPD size with unmap support */ +- buflen = 0x40; +- memset(outbuf + 4, 0, buflen - 4); +- +- outbuf[4] = 0x1; /* wsnz */ +- +- /* optimal transfer length granularity */ +- outbuf[6] = (min_io_size >> 8) & 0xff; +- outbuf[7] = min_io_size & 0xff; +- +- /* maximum transfer length */ +- outbuf[8] = (max_io_sectors >> 24) & 0xff; +- outbuf[9] = (max_io_sectors >> 16) & 0xff; +- outbuf[10] = (max_io_sectors >> 8) & 0xff; +- outbuf[11] = max_io_sectors & 0xff; +- +- /* optimal transfer length */ +- outbuf[12] = (opt_io_size >> 24) & 0xff; +- outbuf[13] = (opt_io_size >> 16) & 0xff; +- outbuf[14] = (opt_io_size >> 8) & 0xff; +- outbuf[15] = opt_io_size & 0xff; +- +- /* max unmap LBA count, default is 1GB */ +- outbuf[20] = (max_unmap_sectors >> 24) & 0xff; +- outbuf[21] = (max_unmap_sectors >> 16) & 0xff; +- outbuf[22] = (max_unmap_sectors >> 8) & 0xff; +- outbuf[23] = max_unmap_sectors & 0xff; +- +- /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header */ +- outbuf[24] = 0; +- outbuf[25] = 0; +- outbuf[26] = 0; +- outbuf[27] = 255; +- +- /* optimal unmap granularity */ +- outbuf[28] = (unmap_sectors >> 24) & 0xff; +- outbuf[29] = (unmap_sectors >> 16) & 0xff; +- outbuf[30] = (unmap_sectors >> 8) & 0xff; +- outbuf[31] = unmap_sectors & 0xff; +- +- /* max write same size */ +- outbuf[36] = 0; +- outbuf[37] = 0; +- outbuf[38] = 0; +- outbuf[39] = 0; +- +- outbuf[40] = (max_io_sectors >> 24) & 0xff; +- outbuf[41] = (max_io_sectors >> 16) & 0xff; +- outbuf[42] = (max_io_sectors >> 8) & 0xff; +- outbuf[43] = max_io_sectors & 0xff; ++ buflen += scsi_emulate_block_limits(outbuf + buflen, &bl); + break; + } + case 0xb1: /* block device characteristics */ +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 6d6db69..f218cef 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -16,6 +16,7 @@ + #include "qemu-common.h" + #include "qemu/error-report.h" + #include "hw/scsi/scsi.h" ++#include "hw/scsi/emulation.h" + #include "sysemu/block-backend.h" + #include "sysemu/blockdev.h" + +@@ -182,7 +183,7 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + /* Also take care of the opt xfer len. */ + stl_be_p(&r->buf[12], + MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); +- } else if (page == 0x00 && s->needs_vpd_bl_emulation) { ++ } else if (s->needs_vpd_bl_emulation && page == 0x00) { + /* + * Now we're capable of supplying the VPD Block Limits + * response if the hardware can't. Add it in the INQUIRY +@@ -210,9 +211,24 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + } + } + +-static int scsi_emulate_block_limits(SCSIGenericReq *r) ++static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) + { +- r->buflen = scsi_disk_emulate_vpd_page(&r->req, r->buf); ++ int len; ++ uint8_t buf[64]; ++ ++ SCSIBlockLimits bl = { ++ .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize ++ }; ++ ++ memset(r->buf, 0, r->buflen); ++ stb_p(buf, s->type); ++ stb_p(buf + 1, 0xb0); ++ len = scsi_emulate_block_limits(buf + 4, &bl); ++ assert(len <= sizeof(buf) - 4); ++ stw_be_p(buf + 2, len); ++ ++ memcpy(r->buf, buf, MIN(r->buflen, len + 4)); ++ + r->io_header.sb_len_wr = 0; + + /* +@@ -254,13 +270,12 @@ static void scsi_read_complete(void * opaque, int ret) + * resulted in sense error but would need emulation. + * In this case, emulate a valid VPD response. + */ +- if (s->needs_vpd_bl_emulation) { +- int is_vpd_bl = r->req.cmd.buf[0] == INQUIRY && +- r->req.cmd.buf[1] & 0x01 && +- r->req.cmd.buf[2] == 0xb0; +- +- if (is_vpd_bl && sg_io_sense_from_errno(-ret, &r->io_header, &sense)) { +- len = scsi_emulate_block_limits(r); ++ if (s->needs_vpd_bl_emulation && ++ r->req.cmd.buf[0] == INQUIRY && ++ (r->req.cmd.buf[1] & 0x01) && ++ r->req.cmd.buf[2] == 0xb0) { ++ if (sg_io_sense_from_errno(-ret, &r->io_header, &sense)) { ++ len = scsi_generic_emulate_block_limits(r, s); + /* + * No need to let scsi_read_complete go on and handle an + * INQUIRY VPD BL request we created manually. +diff --git a/include/hw/scsi/emulation.h b/include/hw/scsi/emulation.h +new file mode 100644 +index 0000000..09fba1f +--- /dev/null ++++ b/include/hw/scsi/emulation.h +@@ -0,0 +1,16 @@ ++#ifndef HW_SCSI_EMULATION_H ++#define HW_SCSI_EMULATION_H 1 ++ ++typedef struct SCSIBlockLimits { ++ bool wsnz; ++ uint16_t min_io_size; ++ uint32_t max_unmap_descr; ++ uint32_t opt_io_size; ++ uint32_t max_unmap_sectors; ++ uint32_t unmap_sectors; ++ uint32_t max_io_sectors; ++} SCSIBlockLimits; ++ ++int scsi_emulate_block_limits(uint8_t *outbuf, const SCSIBlockLimits *bl); ++ ++#endif +diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h +index ee3a411..acef25f 100644 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -189,7 +189,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense); + void scsi_device_unit_attention_reported(SCSIDevice *dev); + void scsi_generic_read_device_inquiry(SCSIDevice *dev); + int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); +-int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf); + int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, + uint8_t *buf, uint8_t buf_size); + SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-avoid-out-of-bounds-access-to-VPD-page-.patch b/SOURCES/kvm-scsi-generic-avoid-out-of-bounds-access-to-VPD-page-.patch new file mode 100644 index 0000000..120b8a0 --- /dev/null +++ b/SOURCES/kvm-scsi-generic-avoid-out-of-bounds-access-to-VPD-page-.patch @@ -0,0 +1,49 @@ +From 7cf8326f7f34372f1646475f20a2617726aff797 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:05 +0100 +Subject: [PATCH 31/34] scsi-generic: avoid out-of-bounds access to VPD page + list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-8-pbonzini@redhat.com> +Patchwork-id: 82939 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 7/9] scsi-generic: avoid out-of-bounds access to VPD page list +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +A device can report an excessive number of VPD pages when asked for a +list; this can cause an out-of-bounds access to buf in +scsi_generic_set_vpd_bl_emulation. It should not happen, but +it is technically not incorrect so handle it: do not check any byte +past the allocation length that was sent to the INQUIRY command. + +Reported-by: Max Reitz +Reviewed-by: Max Reitz +Signed-off-by: Paolo Bonzini +(cherry picked from commit 57dbb58d800f62b9e56d946660dba4e8dbd20204) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 98c6a34..6d6db69 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -539,7 +539,7 @@ static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s) + } + + page_len = buf[3]; +- for (i = 4; i < page_len + 4; i++) { ++ for (i = 4; i < MIN(sizeof(buf), page_len + 4); i++) { + if (buf[i] == 0xb0) { + s->needs_vpd_bl_emulation = false; + return; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-avoid-possible-out-of-bounds-access-to-.patch b/SOURCES/kvm-scsi-generic-avoid-possible-out-of-bounds-access-to-.patch new file mode 100644 index 0000000..f48d5dd --- /dev/null +++ b/SOURCES/kvm-scsi-generic-avoid-possible-out-of-bounds-access-to-.patch @@ -0,0 +1,88 @@ +From afb03b05279fbb6e405ca1815e419f8ec3650a2c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 18:42:16 +0100 +Subject: [PATCH 10/33] scsi-generic: avoid possible out-of-bounds access to + r->buf + +RH-Author: John Snow +Message-id: <20190206184216.15861-2-jsnow@redhat.com> +Patchwork-id: 84258 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] scsi-generic: avoid possible out-of-bounds access to r->buf +Bugzilla: 1668999 +CVE: CVE-2019-6501/20190111 +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf +RH-Acked-by: Paolo Bonzini + +From: Paolo Bonzini + +Whenever the allocation length of a SCSI request is shorter than the size of the +VPD page list, page_idx is used blindly to index into r->buf. Even though +the stores in the insertion sort are protected against overflows, the same is not +true of the reads and the final store of 0xb0. + +This basically does the same thing as commit 57dbb58d80 ("scsi-generic: avoid +out-of-bounds access to VPD page list", 2018-11-06), except that here the +allocation length can be chosen by the guest. Note that according to the SCSI +standard, the contents of the PAGE LENGTH field are not altered based +on the allocation length. + +The code was introduced by commit 6c219fc8a1 ("scsi-generic: keep VPD +page list sorted", 2018-11-06) but the overflow was already possible before. + +Reported-by: Kevin Wolf +Reviewed-by: Kevin Wolf +Signed-off-by: Paolo Bonzini +Message-id: 20190111164506.15971-1-pbonzini@redhat.com +Fixes: a71c775b24ebc664129eb1d9b4c360590353efd5 +Signed-off-by: Paolo Bonzini +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-generic.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 4ac53e4..e21adf9 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -183,7 +183,7 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + /* Also take care of the opt xfer len. */ + stl_be_p(&r->buf[12], + MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); +- } else if (s->needs_vpd_bl_emulation && page == 0x00) { ++ } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) { + /* + * Now we're capable of supplying the VPD Block Limits + * response if the hardware can't. Add it in the INQUIRY +@@ -194,18 +194,20 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + * and will use it to proper setup the SCSI device. + * + * VPD page numbers must be sorted, so insert 0xb0 at the +- * right place with an in-place insert. After the initialization +- * part of the for loop is executed, the device response is +- * at r[0] to r[page_idx - 1]. ++ * right place with an in-place insert. When the while loop ++ * begins the device response is at r[0] to r[page_idx - 1]. + */ +- for (page_idx = lduw_be_p(r->buf + 2) + 4; +- page_idx > 4 && r->buf[page_idx - 1] >= 0xb0; +- page_idx--) { ++ page_idx = lduw_be_p(r->buf + 2) + 4; ++ page_idx = MIN(page_idx, r->buflen); ++ while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) { + if (page_idx < r->buflen) { + r->buf[page_idx] = r->buf[page_idx - 1]; + } ++ page_idx--; ++ } ++ if (page_idx < r->buflen) { ++ r->buf[page_idx] = 0xb0; + } +- r->buf[page_idx] = 0xb0; + stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-do-not-do-VPD-emulation-for-sense-other.patch b/SOURCES/kvm-scsi-generic-do-not-do-VPD-emulation-for-sense-other.patch new file mode 100644 index 0000000..8125b9e --- /dev/null +++ b/SOURCES/kvm-scsi-generic-do-not-do-VPD-emulation-for-sense-other.patch @@ -0,0 +1,61 @@ +From b6e4458e8c01c680b607495f1408b53c38138db0 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:07 +0100 +Subject: [PATCH 33/34] scsi-generic: do not do VPD emulation for sense other + than ILLEGAL_REQUEST +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-10-pbonzini@redhat.com> +Patchwork-id: 82942 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 9/9] scsi-generic: do not do VPD emulation for sense other than ILLEGAL_REQUEST +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +Pass other sense, such as UNIT_ATTENTION or BUSY, directly to the +guest. + +Reported-by: Max Reitz +Signed-off-by: Paolo Bonzini +(cherry picked from commit 763c56872b08b98fde062a1feca003f200e7bd5c) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-generic.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index f218cef..4ac53e4 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -247,7 +247,6 @@ static void scsi_read_complete(void * opaque, int ret) + { + SCSIGenericReq *r = (SCSIGenericReq *)opaque; + SCSIDevice *s = r->req.dev; +- SCSISense sense; + int len; + + assert(r->req.aiocb != NULL); +@@ -270,11 +269,14 @@ static void scsi_read_complete(void * opaque, int ret) + * resulted in sense error but would need emulation. + * In this case, emulate a valid VPD response. + */ +- if (s->needs_vpd_bl_emulation && ++ if (s->needs_vpd_bl_emulation && ret == 0 && ++ (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) && + r->req.cmd.buf[0] == INQUIRY && + (r->req.cmd.buf[1] & 0x01) && + r->req.cmd.buf[2] == 0xb0) { +- if (sg_io_sense_from_errno(-ret, &r->io_header, &sense)) { ++ SCSISense sense = ++ scsi_parse_sense_buf(r->req.sense, r->io_header.sb_len_wr); ++ if (sense.key == ILLEGAL_REQUEST) { + len = scsi_generic_emulate_block_limits(r, s); + /* + * No need to let scsi_read_complete go on and handle an +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-keep-VPD-page-list-sorted.patch b/SOURCES/kvm-scsi-generic-keep-VPD-page-list-sorted.patch new file mode 100644 index 0000000..7448ced --- /dev/null +++ b/SOURCES/kvm-scsi-generic-keep-VPD-page-list-sorted.patch @@ -0,0 +1,73 @@ +From 4967a91c66070002024af212794ddff2acaa0ad1 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 7 Nov 2018 18:00:04 +0100 +Subject: [PATCH 30/34] scsi-generic: keep VPD page list sorted +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20181107180007.22954-7-pbonzini@redhat.com> +Patchwork-id: 82944 +O-Subject: [RHEL7.6.z qemu-kvm-rhev PATCH 6/9] scsi-generic: keep VPD page list sorted +Bugzilla: 1566195 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé + +Block limits emulation is just placing 0xb0 as the final byte of the +VPD pages list. However, VPD page numbers must be sorted, so change +that to an in-place insert. Since I couldn't find any disk that triggered +the loop more than once, this was tested by adding manually 0xb1 +at the end of the list and checking that 0xb0 was added before. + +Reported-by: Max Reitz +Reviewed-by: Max Reitz +Signed-off-by: Paolo Bonzini +(cherry picked from commit 6c219fc8a112fc69b29f59ea2c7865717ff6e3e0) +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-generic.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 4266003..98c6a34 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -145,7 +145,7 @@ static int execute_command(BlockBackend *blk, + + static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + { +- uint8_t page, page_len; ++ uint8_t page, page_idx; + + /* + * EVPD set to zero returns the standard INQUIRY data. +@@ -191,10 +191,21 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + * + * This way, the guest kernel will be aware of the support + * and will use it to proper setup the SCSI device. ++ * ++ * VPD page numbers must be sorted, so insert 0xb0 at the ++ * right place with an in-place insert. After the initialization ++ * part of the for loop is executed, the device response is ++ * at r[0] to r[page_idx - 1]. + */ +- page_len = r->buf[3]; +- r->buf[page_len + 4] = 0xb0; +- r->buf[3] = ++page_len; ++ for (page_idx = lduw_be_p(r->buf + 2) + 4; ++ page_idx > 4 && r->buf[page_idx - 1] >= 0xb0; ++ page_idx--) { ++ if (page_idx < r->buflen) { ++ r->buf[page_idx] = r->buf[page_idx - 1]; ++ } ++ } ++ r->buf[page_idx] = 0xb0; ++ stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1); + } + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-prevent-guest-from-exceeding-SG_IO-limi.patch b/SOURCES/kvm-scsi-generic-prevent-guest-from-exceeding-SG_IO-limi.patch new file mode 100644 index 0000000..e9dccc9 --- /dev/null +++ b/SOURCES/kvm-scsi-generic-prevent-guest-from-exceeding-SG_IO-limi.patch @@ -0,0 +1,91 @@ +From ee5342df3b512da1ac1e85a7a65a50942d220019 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 24 Apr 2019 09:29:42 +0200 +Subject: [PATCH 02/12] scsi-generic: prevent guest from exceeding SG_IO limits + +RH-Author: Stefan Hajnoczi +Message-id: <20190424092942.29071-2-stefanha@redhat.com> +Patchwork-id: 85876 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] scsi-generic: prevent guest from exceeding SG_IO limits +Bugzilla: 1693879 +RH-Acked-by: Sergio Lopez Pascual +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Stefano Garzarella + +From: Paolo Bonzini + +Bugzilla: 1693879 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=21260328 +Upstream status: downstream only, see below + +Until Linux 4.5, the kernel placed a limit of UIO_MAXIOV pages on +SG_IO ioctls (and if the limit is exceeded, a confusing ENOMEM error is +returned[1]). The patches that removed the limitation are not easy to +backport to RHEL7, so instead we work around it in QEMU: just prevent +the guest from exceeding these limits by capping the maximum transfer +length to that value in the block limits VPD page. + +The customer has already tested the workaround of changing +max_sectors_kb in the guest. This fix has the same effect on the guest +but does not require manually setting max_sectors_kb inside the guest. + +RHEL8 does not have the problem; because this is for SCSI passthrough, +live migration is not an issue. + +[1] Oh well, at least it was easier to follow the kernel source knowing + it had to end as ENOMEM... + +Signed-off-by: Paolo Bonzini +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-generic.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index e21adf9..b815b91 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -144,6 +144,17 @@ static int execute_command(BlockBackend *blk, + return 0; + } + ++/* ++ * RHEL: Linux placed a hard limit on SG_IO transfers equal to UIO_MAXIOV ++ * pages until 4.5, which we need to factor in the block limits we return. ++ */ ++static uint32_t rhel_sg_max_transfer(SCSIDevice *s) ++{ ++ uint32_t max_transfer = blk_get_max_transfer(s->conf.blk); ++ max_transfer = MIN_NON_ZERO(max_transfer, UIO_MAXIOV * qemu_real_host_page_size); ++ return max_transfer; ++} ++ + static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + { + uint8_t page, page_idx; +@@ -175,10 +186,8 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) + if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) { + page = r->req.cmd.buf[2]; + if (page == 0xb0) { +- uint32_t max_transfer = +- blk_get_max_transfer(s->conf.blk) / s->blocksize; ++ uint32_t max_transfer = rhel_sg_max_transfer(s) / s->blocksize; + +- assert(max_transfer); + stl_be_p(&r->buf[8], max_transfer); + /* Also take care of the opt xfer len. */ + stl_be_p(&r->buf[12], +@@ -219,7 +228,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) + uint8_t buf[64]; + + SCSIBlockLimits bl = { +- .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize ++ .max_io_sectors = rhel_sg_max_transfer(s) / s->blocksize + }; + + memset(r->buf, 0, r->buflen); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-check-sscanf-result-when-emulating-ident.patch b/SOURCES/kvm-slirp-check-sscanf-result-when-emulating-ident.patch new file mode 100644 index 0000000..f7c737b --- /dev/null +++ b/SOURCES/kvm-slirp-check-sscanf-result-when-emulating-ident.patch @@ -0,0 +1,62 @@ +From cbf833ce3cbbd9162c22573278497e5b8bd1ccb4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 2 Apr 2019 14:03:50 +0200 +Subject: [PATCH 131/163] slirp: check sscanf result when emulating ident +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20190402140350.5604-1-marcandre.lureau@redhat.com> +Patchwork-id: 85306 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH] slirp: check sscanf result when emulating ident +Bugzilla: 1689793 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Dr. David Alan Gilbert + +From: William Bowling + +When emulating ident in tcp_emu, if the strchr checks passed but the +sscanf check failed, two uninitialized variables would be copied and +sent in the reply, so move this code inside the if(sscanf()) clause. + +Signed-off-by: William Bowling +Cc: qemu-stable@nongnu.org +Cc: secalert@redhat.com +Message-Id: <1551476756-25749-1-git-send-email-will@wbowling.info> +Signed-off-by: Samuel Thibault +Reviewed-by: Philippe Mathieu-Daudé + +(cherry picked from commit d3222975c7d6cda9e25809dea05241188457b113) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + slirp/tcp_subr.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c +index da0d537..98ceb4f 100644 +--- a/slirp/tcp_subr.c ++++ b/slirp/tcp_subr.c +@@ -660,12 +660,12 @@ tcp_emu(struct socket *so, struct mbuf *m) + break; + } + } ++ so_rcv->sb_cc = snprintf(so_rcv->sb_data, ++ so_rcv->sb_datalen, ++ "%d,%d\r\n", n1, n2); ++ so_rcv->sb_rptr = so_rcv->sb_data; ++ so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } +- so_rcv->sb_cc = snprintf(so_rcv->sb_data, +- so_rcv->sb_datalen, +- "%d,%d\r\n", n1, n2); +- so_rcv->sb_rptr = so_rcv->sb_data; +- so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } + m_free(m); + return 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-don-t-manipulate-so_rcv-in-tcp_emu.patch b/SOURCES/kvm-slirp-don-t-manipulate-so_rcv-in-tcp_emu.patch new file mode 100644 index 0000000..35ad2bb --- /dev/null +++ b/SOURCES/kvm-slirp-don-t-manipulate-so_rcv-in-tcp_emu.patch @@ -0,0 +1,127 @@ +From d92a9042320bd959eac36dc76de9dc293d8da2ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 20 May 2019 17:57:04 +0200 +Subject: [PATCH 3/3] slirp: don't manipulate so_rcv in tcp_emu() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20190520175704.6250-4-marcandre.lureau@redhat.com> +Patchwork-id: 88108 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/3] slirp: don't manipulate so_rcv in tcp_emu() +Bugzilla: 1669071 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Stefano Garzarella + +For some reason, EMU_IDENT is not like other "emulated" protocols and +tries to reconstitute the original buffer, if it came in multiple +packets. Unfortunately, it does so wrongly, as it doesn't respect the +sbuf circular buffer appending rules, nor does it maintain some of the +invariants (rptr is incremented without bounds, etc): this leads to +further memory corruption revealed by ASAN or various malloc +errors. Furthermore, the so_rcv buffer is regularly flushed, so there +is no guarantee that buffer reconstruction will do what is expected. + +Instead, do what the function comment says: "XXX Assumes the whole +command came in one packet", and don't touch so_rcv. + +Related to: https://bugzilla.redhat.com/show_bug.cgi?id=1664205 + +Cc: Prasad J Pandit +Signed-off-by: Marc-André Lureau + +(cherry picked from libslirp commit +9da0da837780f825b5db31db6620492f8b7cd5d6) + +[ MA - backported with style conflicts, and without qemu commit +a7104eda7dab99d0cdbd3595c211864cba415905 which is unnecessary with +this patch ] + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + slirp/tcp_subr.c | 63 +++++++++++++++++++++++++++----------------------------- + 1 file changed, 30 insertions(+), 33 deletions(-) + +diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c +index a801a14..0152f72 100644 +--- a/slirp/tcp_subr.c ++++ b/slirp/tcp_subr.c +@@ -636,42 +636,39 @@ tcp_emu(struct socket *so, struct mbuf *m) + struct socket *tmpso; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); +- struct sbuf *so_rcv = &so->so_rcv; +- +- memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); +- so_rcv->sb_wptr += m->m_len; +- so_rcv->sb_rptr += m->m_len; +- m_inc(m, m->m_len + 1); +- m->m_data[m->m_len] = 0; /* NULL terminate */ +- if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { +- if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) { +- HTONS(n1); +- HTONS(n2); +- /* n2 is the one on our host */ +- for (tmpso = slirp->tcb.so_next; +- tmpso != &slirp->tcb; +- tmpso = tmpso->so_next) { +- if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && +- tmpso->so_lport == n2 && +- tmpso->so_faddr.s_addr == so->so_faddr.s_addr && +- tmpso->so_fport == n1) { +- if (getsockname(tmpso->s, +- (struct sockaddr *)&addr, &addrlen) == 0) +- n2 = addr.sin_port; +- break; +- } ++ char *eol = g_strstr_len(m->m_data, m->m_len, "\r\n"); ++ ++ if (!eol) { ++ return 1; ++ } ++ ++ *eol = '\0'; ++ if (sscanf(m->m_data, "%u%*[ ,]%u", &n1, &n2) == 2) { ++ HTONS(n1); ++ HTONS(n2); ++ /* n2 is the one on our host */ ++ for (tmpso = slirp->tcb.so_next; tmpso != &slirp->tcb; ++ tmpso = tmpso->so_next) { ++ if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && ++ tmpso->so_lport == n2 && ++ tmpso->so_faddr.s_addr == so->so_faddr.s_addr && ++ tmpso->so_fport == n1) { ++ if (getsockname(tmpso->s, (struct sockaddr *)&addr, ++ &addrlen) == 0) ++ n2 = addr.sin_port; ++ break; + } +- NTOHS(n1); +- NTOHS(n2); +- so_rcv->sb_cc = snprintf(so_rcv->sb_data, +- so_rcv->sb_datalen, +- "%d,%d\r\n", n1, n2); +- so_rcv->sb_rptr = so_rcv->sb_data; +- so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } ++ NTOHS(n1); ++ NTOHS(n2); ++ m_inc(m, snprintf(NULL, 0, "%d,%d\r\n", n1, n2) + 1); ++ m->m_len = snprintf(m->m_data, M_ROOM(m), "%d,%d\r\n", n1, n2); ++ assert(m->m_len < M_ROOM(m)); ++ } else { ++ *eol = '\r'; + } +- m_free(m); +- return 0; ++ ++ return 1; + } + + case EMU_FTP: /* ftp */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-ensure-there-is-enough-space-in-mbuf-to-null-t.patch b/SOURCES/kvm-slirp-ensure-there-is-enough-space-in-mbuf-to-null-t.patch new file mode 100644 index 0000000..aec1fa7 --- /dev/null +++ b/SOURCES/kvm-slirp-ensure-there-is-enough-space-in-mbuf-to-null-t.patch @@ -0,0 +1,66 @@ +From dec442886deeedfbcb0c9958403627bc11a8d9e9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 20 May 2019 17:57:03 +0200 +Subject: [PATCH 2/3] slirp: ensure there is enough space in mbuf to + null-terminate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20190520175704.6250-3-marcandre.lureau@redhat.com> +Patchwork-id: 88109 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/3] slirp: ensure there is enough space in mbuf to null-terminate +Bugzilla: 1669071 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Stefano Garzarella + +Prevents from buffer overflows. +Related to: https://bugzilla.redhat.com/show_bug.cgi?id=1664205 + +Cc: Prasad J Pandit +Signed-off-by: Marc-André Lureau + +(cherry picked from libslirp commit +306fef58b54d793ba4b259728c21322765bda917) + +[ MA - backported with style conflicts fixes ] +Signed-off-by: Marc-André Lureau + +Signed-off-by: Miroslav Rezanina +--- + slirp/tcp_subr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c +index a61632d..a801a14 100644 +--- a/slirp/tcp_subr.c ++++ b/slirp/tcp_subr.c +@@ -641,6 +641,7 @@ tcp_emu(struct socket *so, struct mbuf *m) + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; ++ m_inc(m, m->m_len + 1); + m->m_data[m->m_len] = 0; /* NULL terminate */ + if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { + if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) { +@@ -674,6 +675,7 @@ tcp_emu(struct socket *so, struct mbuf *m) + } + + case EMU_FTP: /* ftp */ ++ m_inc(m, m->m_len + 1); + *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */ + if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { + /* +@@ -771,6 +773,7 @@ tcp_emu(struct socket *so, struct mbuf *m) + /* + * Need to emulate DCC CHAT, DCC SEND and DCC MOVE + */ ++ m_inc(m, m->m_len + 1); + *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ + if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) + return 1; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-fix-big-little-endian-conversion-in-ident-prot.patch b/SOURCES/kvm-slirp-fix-big-little-endian-conversion-in-ident-prot.patch new file mode 100644 index 0000000..71f89b9 --- /dev/null +++ b/SOURCES/kvm-slirp-fix-big-little-endian-conversion-in-ident-prot.patch @@ -0,0 +1,54 @@ +From ea9ac12820138a0a9714178bee36e625ed103026 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 20 May 2019 17:57:02 +0200 +Subject: [PATCH 1/3] slirp: fix big/little endian conversion in ident protocol +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20190520175704.6250-2-marcandre.lureau@redhat.com> +Patchwork-id: 88107 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/3] slirp: fix big/little endian conversion in ident protocol +Bugzilla: 1669071 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Stefano Garzarella + +From: Samuel Thibault + +Signed-off-by: Samuel Thibault +Reviewed-by: Philippe Mathieu-Daudé + +[ MA - backported to ease backport of + https://bugzilla.redhat.com/show_bug.cgi?id=1669068 ] + +(cherry picked from 1fd71067dae501f1c78618e9583c6cc72db0cfa6) +Signed-off-by: Marc-André Lureau + +Signed-off-by: Miroslav Rezanina +--- + slirp/tcp_subr.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c +index 98ceb4f..a61632d 100644 +--- a/slirp/tcp_subr.c ++++ b/slirp/tcp_subr.c +@@ -656,10 +656,12 @@ tcp_emu(struct socket *so, struct mbuf *m) + tmpso->so_fport == n1) { + if (getsockname(tmpso->s, + (struct sockaddr *)&addr, &addrlen) == 0) +- n2 = ntohs(addr.sin_port); ++ n2 = addr.sin_port; + break; + } + } ++ NTOHS(n1); ++ NTOHS(n2); + so_rcv->sb_cc = snprintf(so_rcv->sb_data, + so_rcv->sb_datalen, + "%d,%d\r\n", n1, n2); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-spapr-Add-H-Call-H_HOME_NODE_ASSOCIATIVITY.patch b/SOURCES/kvm-spapr-Add-H-Call-H_HOME_NODE_ASSOCIATIVITY.patch new file mode 100644 index 0000000..22af4ef --- /dev/null +++ b/SOURCES/kvm-spapr-Add-H-Call-H_HOME_NODE_ASSOCIATIVITY.patch @@ -0,0 +1,123 @@ +From 3e4f22bfb8e4a6a4da948983c96fe60c12c957a3 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Wed, 2 Jan 2019 11:29:48 +0100 +Subject: [PATCH 2/8] spapr: Add H-Call H_HOME_NODE_ASSOCIATIVITY + +RH-Author: Laurent Vivier +Message-id: <20190102112948.18536-3-lvivier@redhat.com> +Patchwork-id: 83821 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] spapr: Add H-Call H_HOME_NODE_ASSOCIATIVITY +Bugzilla: 1626347 +RH-Acked-by: Thomas Huth +RH-Acked-by: Serhii Popovych +RH-Acked-by: David Gibson + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1626347 + +H_HOME_NODE_ASSOCIATIVITY H-Call returns the associativity domain +designation associated with the identifier input parameter + +This fixes a crash when we try to hotplug a CPU in memory-less and +CPU-less numa node. In this case, the kernel tries to online the +node, but without the information provided by this h-call, the node id, +it cannot and the CPU is started while the node is not onlined. + +It also removes the warning message from the kernel: + VPHN is not supported. Disabling polling.. + +Signed-off-by: Laurent Vivier +Reviewed-by: Greg Kurz +Signed-off-by: David Gibson +(cherry picked from commit c24ba3d0a34f68ad2c6bf1a15bc43770005f6cc0) +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 1 + + hw/ppc/spapr_hcall.c | 40 ++++++++++++++++++++++++++++++++++++++++ + include/hw/ppc/spapr.h | 1 + + 3 files changed, 42 insertions(+) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index b49f377..76676aa 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -933,6 +933,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) + add_str(hypertas, "hcall-sprg0"); + add_str(hypertas, "hcall-copy"); + add_str(hypertas, "hcall-debug"); ++ add_str(hypertas, "hcall-vphn"); + add_str(qemu_hypertas, "hcall-memop1"); + + if (!kvm_enabled() || kvmppc_spapr_use_multitce()) { +diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c +index 16bccdd..9dd5cfd 100644 +--- a/hw/ppc/spapr_hcall.c ++++ b/hw/ppc/spapr_hcall.c +@@ -1664,6 +1664,42 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, + return H_SUCCESS; + } + ++static target_ulong h_home_node_associativity(PowerPCCPU *cpu, ++ sPAPRMachineState *spapr, ++ target_ulong opcode, ++ target_ulong *args) ++{ ++ target_ulong flags = args[0]; ++ target_ulong procno = args[1]; ++ PowerPCCPU *tcpu; ++ int idx; ++ ++ /* only support procno from H_REGISTER_VPA */ ++ if (flags != 0x1) { ++ return H_FUNCTION; ++ } ++ ++ tcpu = spapr_find_cpu(procno); ++ if (tcpu == NULL) { ++ return H_P2; ++ } ++ ++ /* sequence is the same as in the "ibm,associativity" property */ ++ ++ idx = 0; ++#define ASSOCIATIVITY(a, b) (((uint64_t)(a) << 32) | \ ++ ((uint64_t)(b) & 0xffffffff)) ++ args[idx++] = ASSOCIATIVITY(0, 0); ++ args[idx++] = ASSOCIATIVITY(0, tcpu->node_id); ++ args[idx++] = ASSOCIATIVITY(procno, -1); ++ for ( ; idx < 6; idx++) { ++ args[idx] = -1; ++ } ++#undef ASSOCIATIVITY ++ ++ return H_SUCCESS; ++} ++ + static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, +@@ -1823,6 +1859,10 @@ static void hypercall_register_types(void) + + /* ibm,client-architecture-support support */ + spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support); ++ ++ /* Virtual Processor Home Node */ ++ spapr_register_hypercall(H_HOME_NODE_ASSOCIATIVITY, ++ h_home_node_associativity); + } + + type_init(hypercall_register_types) +diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h +index 5118af6..5f1add0 100644 +--- a/include/hw/ppc/spapr.h ++++ b/include/hw/ppc/spapr.h +@@ -432,6 +432,7 @@ struct sPAPRMachineState { + #define H_GET_EM_PARMS 0x2B8 + #define H_SET_MPP 0x2D0 + #define H_GET_MPP 0x2D4 ++#define H_HOME_NODE_ASSOCIATIVITY 0x2EC + #define H_XIRR_X 0x2FC + #define H_RANDOM 0x300 + #define H_SET_MODE 0x31C +-- +1.8.3.1 + diff --git a/SOURCES/kvm-spapr-Fix-ibm-max-associativity-domains-property-num.patch b/SOURCES/kvm-spapr-Fix-ibm-max-associativity-domains-property-num.patch new file mode 100644 index 0000000..f28c87e --- /dev/null +++ b/SOURCES/kvm-spapr-Fix-ibm-max-associativity-domains-property-num.patch @@ -0,0 +1,136 @@ +From e145e366df21d291ba3cbcf2b4982598637bcc01 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Wed, 2 Jan 2019 11:29:47 +0100 +Subject: [PATCH 1/8] spapr: Fix ibm, max-associativity-domains property number + of nodes + +RH-Author: Laurent Vivier +Message-id: <20190102112948.18536-2-lvivier@redhat.com> +Patchwork-id: 83820 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] spapr: Fix ibm, max-associativity-domains property number of nodes +Bugzilla: 1626347 +RH-Acked-by: Thomas Huth +RH-Acked-by: Serhii Popovych +RH-Acked-by: David Gibson + +From: Serhii Popovych + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1626347 + +Laurent Vivier reported off by one with maximum number of NUMA nodes +provided by qemu-kvm being less by one than required according to +description of "ibm,max-associativity-domains" property in LoPAPR. + +It appears that I incorrectly treated LoPAPR description of this +property assuming it provides last valid domain (NUMA node here) +instead of maximum number of domains. + + ### Before hot-add + + (qemu) info numa + 3 nodes + node 0 cpus: 0 + node 0 size: 0 MB + node 0 plugged: 0 MB + node 1 cpus: + node 1 size: 1024 MB + node 1 plugged: 0 MB + node 2 cpus: + node 2 size: 0 MB + node 2 plugged: 0 MB + + $ numactl -H + available: 2 nodes (0-1) + node 0 cpus: 0 + node 0 size: 0 MB + node 0 free: 0 MB + node 1 cpus: + node 1 size: 999 MB + node 1 free: 658 MB + node distances: + node 0 1 + 0: 10 40 + 1: 40 10 + + ### Hot-add + + (qemu) object_add memory-backend-ram,id=mem0,size=1G + (qemu) device_add pc-dimm,id=dimm1,memdev=mem0,node=2 + (qemu) [ 87.704898] pseries-hotplug-mem: Attempting to hot-add 4 ... + + [ 87.705128] lpar: Attempting to resize HPT to shift 21 + ... + + ### After hot-add + + (qemu) info numa + 3 nodes + node 0 cpus: 0 + node 0 size: 0 MB + node 0 plugged: 0 MB + node 1 cpus: + node 1 size: 1024 MB + node 1 plugged: 0 MB + node 2 cpus: + node 2 size: 1024 MB + node 2 plugged: 1024 MB + + $ numactl -H + available: 2 nodes (0-1) + ^^^^^^^^^^^^^^^^^^^^^^^^ + Still only two nodes (and memory hot-added to node 0 below) + node 0 cpus: 0 + node 0 size: 1024 MB + node 0 free: 1021 MB + node 1 cpus: + node 1 size: 999 MB + node 1 free: 658 MB + node distances: + node 0 1 + 0: 10 40 + 1: 40 10 + +After fix applied numactl(8) reports 3 nodes available and memory +plugged into node 2 as expected. + +>From David Gibson: +------------------ + Qemu makes a distinction between "non NUMA" (nb_numa_nodes == 0) and + "NUMA with one node" (nb_numa_nodes == 1). But from a PAPR guests's + point of view these are equivalent. I don't want to present two + different cases to the guest when we don't need to, so even though the + guest can handle it, I'd prefer we put a '1' here for both the + nb_numa_nodes == 0 and nb_numa_nodes == 1 case. + +This consolidates everything discussed previously on mailing list. + +Fixes: da9f80fbad21 ("spapr: Add ibm,max-associativity-domains property") +Reported-by: Laurent Vivier +Signed-off-by: Serhii Popovych + +Signed-off-by: David Gibson +Reviewed-by: Greg Kurz +Reviewed-by: Laurent Vivier +(cherry picked from commit 3908a24fcb83913079d315de0ca6d598e8616dbb) +Signed-off-by: Laurent Vivier +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 5f26aea..b49f377 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -915,7 +915,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) + cpu_to_be32(0), + cpu_to_be32(0), + cpu_to_be32(0), +- cpu_to_be32(nb_numa_nodes ? nb_numa_nodes - 1 : 0), ++ cpu_to_be32(nb_numa_nodes ? nb_numa_nodes : 1), + }; + + _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas")); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-sysbus-Fix-latent-bug-with-onboard-devices.patch b/SOURCES/kvm-sysbus-Fix-latent-bug-with-onboard-devices.patch new file mode 100644 index 0000000..48e2f37 --- /dev/null +++ b/SOURCES/kvm-sysbus-Fix-latent-bug-with-onboard-devices.patch @@ -0,0 +1,77 @@ +From 18b6e8931b3aebefbbccf545165ccc6fcdd09a1e Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:10 +0200 +Subject: [PATCH 43/53] sysbus: Fix latent bug with onboard devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-22-armbru@redhat.com> +Patchwork-id: 87995 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 21/31] sysbus: Fix latent bug with onboard devices +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +The first call of sysbus_get_default() creates the main system bus and +stores it in QOM as "/machine/unattached/sysbus". This must not +happen before main() creates "/machine", or else container_get() would +"helpfully" create it as "container" object, and the real creation of +"/machine" would later abort with "attempt to add duplicate property +'machine' to object (type 'container')". Has been that way ever since +we wired up busses in QOM (commit f968fc6892d, v1.2.0). + +I believe the bug is latent. I got it to bite by trying to +qdev_create() a sysbus device from a machine's .instance_init() +method. + +The fix is obvious: store the main system bus in QOM right after +creating "/machine". + +Signed-off-by: Markus Armbruster +Reviewed-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Thomas Huth +Message-Id: <20190308131445.17502-5-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit e2fb3fbbf9ce6b8eed00b53a91d3a316362f1b0d) +Signed-off-by: Miroslav Rezanina +--- + hw/core/sysbus.c | 3 --- + vl.c | 4 ++++ + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c +index 5d0887f..db95cb0 100644 +--- a/hw/core/sysbus.c ++++ b/hw/core/sysbus.c +@@ -359,9 +359,6 @@ static void main_system_bus_create(void) + qbus_create_inplace(main_system_bus, system_bus_info.instance_size, + TYPE_SYSTEM_BUS, NULL, "main-system-bus"); + OBJECT(main_system_bus)->free = g_free; +- object_property_add_child(container_get(qdev_get_machine(), +- "/unattached"), +- "sysbus", OBJECT(main_system_bus), NULL); + } + + BusState *sysbus_get_default(void) +diff --git a/vl.c b/vl.c +index d46dff6..d89ac3a 100644 +--- a/vl.c ++++ b/vl.c +@@ -4162,6 +4162,10 @@ int main(int argc, char **argv, char **envp) + } + object_property_add_child(object_get_root(), "machine", + OBJECT(current_machine), &error_abort); ++ object_property_add_child(container_get(OBJECT(current_machine), ++ "/unattached"), ++ "sysbus", OBJECT(sysbus_get_default()), ++ NULL); + + if (machine_class->minimum_page_bits) { + if (!set_preferred_target_page_bits(machine_class->minimum_page_bits)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-cpu-Add-downstream-only-STIBP-CPUID-flag.patch b/SOURCES/kvm-target-i386-cpu-Add-downstream-only-STIBP-CPUID-flag.patch new file mode 100644 index 0000000..32f93e7 --- /dev/null +++ b/SOURCES/kvm-target-i386-cpu-Add-downstream-only-STIBP-CPUID-flag.patch @@ -0,0 +1,50 @@ +From 6e9de3f3fa020b351960f4f528f175aa802eb536 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Wed, 26 Sep 2018 18:50:59 +0200 +Subject: [PATCH] target-i386: cpu: Add downstream-only STIBP CPUID flag + +RH-Author: Eduardo Habkost +Message-id: <20180926185059.20691-1-ehabkost@redhat.com> +Patchwork-id: 82301 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] target-i386: cpu: Add downstream-only STIBP CPUID flag +Bugzilla: 1638077 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Kashyap Chamarthy +RH-Acked-by: Igor Mammedov + +From: Paolo Bonzini + +We accidentally dropped the downstream-only STIBP CPUID flag +during the 2.12.0 rebase. + +STIBP is a CPUID flag that was considered for the Spectre +(CVE-2017-5715) mitigations, but in the end it was not necessary: +spec-ctrl/IBRS was deemed enough. The kernel KVM STIBP CPUID +code was never merged upstream, but it's present on RHEL-7. + +This means we may have existing VMs created on RHEL-7.5 hosts +with the STIBP flag enabled, and we need to support +live-migration of those VMs to RHEL-7.6. + +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 6b5acdf..91f5a97 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1007,7 +1007,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, "spec-ctrl", NULL, ++ NULL, NULL, "spec-ctrl", "stibp", + NULL, NULL, NULL, "ssbd", + }, + .cpuid_eax = 7, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-AioContext-switch-in-drained-section.patch b/SOURCES/kvm-test-bdrv-drain-AioContext-switch-in-drained-section.patch new file mode 100644 index 0000000..3674a59 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-AioContext-switch-in-drained-section.patch @@ -0,0 +1,76 @@ +From ed61540140ae22f897f15846a359dc11a0a0b027 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Mar 2019 14:27:46 +0100 +Subject: [PATCH 4/9] test-bdrv-drain: AioContext switch in drained section + +RH-Author: Kevin Wolf +Message-id: <20190301142747.12251-5-kwolf@redhat.com> +Patchwork-id: 84766 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/5] test-bdrv-drain: AioContext switch in drained section +Bugzilla: 1671173 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 247d2737715833525725d27e5cecf5840c62f900) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 8641b54..05c6f12 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -1521,6 +1521,36 @@ static void test_append_to_drained(void) + blk_unref(blk); + } + ++static void test_set_aio_context(void) ++{ ++ BlockDriverState *bs; ++ IOThread *a = iothread_new(); ++ IOThread *b = iothread_new(); ++ AioContext *ctx_a = iothread_get_aio_context(a); ++ AioContext *ctx_b = iothread_get_aio_context(b); ++ ++ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, ++ &error_abort); ++ ++ bdrv_drained_begin(bs); ++ bdrv_set_aio_context(bs, ctx_a); ++ ++ aio_context_acquire(ctx_a); ++ bdrv_drained_end(bs); ++ ++ bdrv_drained_begin(bs); ++ bdrv_set_aio_context(bs, ctx_b); ++ aio_context_release(ctx_a); ++ aio_context_acquire(ctx_b); ++ bdrv_set_aio_context(bs, qemu_get_aio_context()); ++ aio_context_release(ctx_b); ++ bdrv_drained_end(bs); ++ ++ bdrv_unref(bs); ++ iothread_join(a); ++ iothread_join(b); ++} ++ + int main(int argc, char **argv) + { + int ret; +@@ -1602,6 +1632,8 @@ int main(int argc, char **argv) + + g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained); + ++ g_test_add_func("/bdrv-drain/set_aio_context", test_set_aio_context); ++ + ret = g_test_run(); + qemu_event_destroy(&done_event); + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-hbitmap-Add-non-advancing-iter_next-tests.patch b/SOURCES/kvm-test-hbitmap-Add-non-advancing-iter_next-tests.patch new file mode 100644 index 0000000..4f47bb3 --- /dev/null +++ b/SOURCES/kvm-test-hbitmap-Add-non-advancing-iter_next-tests.patch @@ -0,0 +1,126 @@ +From c19a999e13b0584ba947801c8795e34e5928412c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 6 Feb 2019 22:12:24 +0100 +Subject: [PATCH 14/33] test-hbitmap: Add non-advancing iter_next tests + +RH-Author: John Snow +Message-id: <20190206221243.7407-5-jsnow@redhat.com> +Patchwork-id: 84269 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 04/23] test-hbitmap: Add non-advancing iter_next tests +Bugzilla: 1658343 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi + +From: Max Reitz + +Add a function that wraps hbitmap_iter_next() and always calls it in +non-advancing mode first, and in advancing mode next. The result should +always be the same. + +By using this function everywhere we called hbitmap_iter_next() before, +we should get good test coverage for non-advancing hbitmap_iter_next(). + +Signed-off-by: Max Reitz +Reviewed-by: Fam Zheng +Reviewed-by: John Snow +Message-id: 20180613181823.13618-9-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 269576848ec3d57d2d958cf5ac69b08c44adf816) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-hbitmap.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index f2158f7..5e67ac1 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -30,6 +30,18 @@ typedef struct TestHBitmapData { + } TestHBitmapData; + + ++static int64_t check_hbitmap_iter_next(HBitmapIter *hbi) ++{ ++ int next0, next1; ++ ++ next0 = hbitmap_iter_next(hbi, false); ++ next1 = hbitmap_iter_next(hbi, true); ++ ++ g_assert_cmpint(next0, ==, next1); ++ ++ return next0; ++} ++ + /* Check that the HBitmap and the shadow bitmap contain the same data, + * ignoring the same "first" bits. + */ +@@ -46,7 +58,7 @@ static void hbitmap_test_check(TestHBitmapData *data, + + i = first; + for (;;) { +- next = hbitmap_iter_next(&hbi, true); ++ next = check_hbitmap_iter_next(&hbi); + if (next < 0) { + next = data->size; + } +@@ -435,25 +447,25 @@ static void test_hbitmap_iter_granularity(TestHBitmapData *data, + /* Note that hbitmap_test_check has to be invoked manually in this test. */ + hbitmap_test_init(data, 131072 << 7, 7); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); + + hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); + + hbitmap_test_set(data, (131072 << 7) - 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, (L2 + L1 + 1) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, 131071 << 7); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), ==, 131071 << 7); +- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, 131071 << 7); ++ g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0); + } + + static void hbitmap_test_set_boundary_bits(TestHBitmapData *data, ssize_t diff) +@@ -893,7 +905,7 @@ static void test_hbitmap_serialize_zeroes(TestHBitmapData *data, + for (i = 0; i < num_positions; i++) { + hbitmap_deserialize_zeroes(data->hb, positions[i], min_l1, true); + hbitmap_iter_init(&iter, data->hb, 0); +- next = hbitmap_iter_next(&iter, true); ++ next = check_hbitmap_iter_next(&iter); + if (i == num_positions - 1) { + g_assert_cmpint(next, ==, -1); + } else { +@@ -919,10 +931,10 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + + hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); + +- hbitmap_iter_next(&hbi, true); ++ check_hbitmap_iter_next(&hbi); + + hbitmap_reset_all(data->hb); +- hbitmap_iter_next(&hbi, true); ++ check_hbitmap_iter_next(&hbi); + } + + static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-Add-unit-tests-for-image-locking.patch b/SOURCES/kvm-tests-Add-unit-tests-for-image-locking.patch new file mode 100644 index 0000000..3ece257 --- /dev/null +++ b/SOURCES/kvm-tests-Add-unit-tests-for-image-locking.patch @@ -0,0 +1,213 @@ +From dd4c2ba6b27a2af57c355fce5a868eb83c48625d Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 4 Feb 2019 20:42:05 +0100 +Subject: [PATCH 05/33] tests: Add unit tests for image locking + +RH-Author: Max Reitz +Message-id: <20190204204207.18079-6-mreitz@redhat.com> +Patchwork-id: 84224 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 5/7] tests: Add unit tests for image locking +Bugzilla: 1551486 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +From: Fam Zheng + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit aef96d7d4f0b6746e329bfa7a1ea38e1611237e3) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/Makefile.include | 2 + + tests/test-image-locking.c | 157 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 159 insertions(+) + create mode 100644 tests/test-image-locking.c + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index 9dd63e5..c0376fb 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -95,6 +95,7 @@ check-unit-y += tests/test-bdrv-drain$(EXESUF) + check-unit-y += tests/test-blockjob$(EXESUF) + check-unit-y += tests/test-blockjob-txn$(EXESUF) + check-unit-y += tests/test-block-backend$(EXESUF) ++check-unit-y += tests/test-image-locking$(EXESUF) + check-unit-y += tests/test-x86-cpuid$(EXESUF) + # all code tested by test-x86-cpuid is inside topology.h + gcov-files-test-x86-cpuid-y = +@@ -610,6 +611,7 @@ tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(te + tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) + tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) + tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y) ++tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y) + tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) + tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) + tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y) +diff --git a/tests/test-image-locking.c b/tests/test-image-locking.c +new file mode 100644 +index 0000000..7614cbf +--- /dev/null ++++ b/tests/test-image-locking.c +@@ -0,0 +1,157 @@ ++/* ++ * Image locking tests ++ * ++ * Copyright (c) 2018 Red Hat Inc. ++ * ++ * Author: Fam Zheng ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "qemu/osdep.h" ++#include "block/block.h" ++#include "sysemu/block-backend.h" ++#include "qapi/error.h" ++#include "qapi/qmp/qdict.h" ++ ++static BlockBackend *open_image(const char *path, ++ uint64_t perm, uint64_t shared_perm, ++ Error **errp) ++{ ++ Error *local_err = NULL; ++ BlockBackend *blk; ++ QDict *options = qdict_new(); ++ ++ qdict_put_str(options, "driver", "raw"); ++ blk = blk_new_open(path, NULL, options, BDRV_O_RDWR, &local_err); ++ if (blk) { ++ g_assert_null(local_err); ++ if (blk_set_perm(blk, perm, shared_perm, errp)) { ++ blk_unref(blk); ++ blk = NULL; ++ } ++ } else { ++ error_propagate(errp, local_err); ++ } ++ return blk; ++} ++ ++static void check_locked_bytes(int fd, uint64_t perm_locks, ++ uint64_t shared_perm_locks) ++{ ++ int i; ++ ++ if (!perm_locks && !shared_perm_locks) { ++ g_assert(!qemu_lock_fd_test(fd, 0, 0, true)); ++ return; ++ } ++ for (i = 0; (1ULL << i) <= BLK_PERM_ALL; i++) { ++ uint64_t bit = (1ULL << i); ++ bool perm_expected = !!(bit & perm_locks); ++ bool shared_perm_expected = !!(bit & shared_perm_locks); ++ g_assert_cmpint(perm_expected, ==, ++ !!qemu_lock_fd_test(fd, 100 + i, 1, true)); ++ g_assert_cmpint(shared_perm_expected, ==, ++ !!qemu_lock_fd_test(fd, 200 + i, 1, true)); ++ } ++} ++ ++static void test_image_locking_basic(void) ++{ ++ BlockBackend *blk1, *blk2, *blk3; ++ char img_path[] = "/tmp/qtest.XXXXXX"; ++ uint64_t perm, shared_perm; ++ ++ int fd = mkstemp(img_path); ++ assert(fd >= 0); ++ ++ perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; ++ shared_perm = BLK_PERM_ALL; ++ blk1 = open_image(img_path, perm, shared_perm, &error_abort); ++ g_assert(blk1); ++ ++ check_locked_bytes(fd, perm, ~shared_perm); ++ ++ /* compatible perm between blk1 and blk2 */ ++ blk2 = open_image(img_path, perm | BLK_PERM_RESIZE, shared_perm, NULL); ++ g_assert(blk2); ++ check_locked_bytes(fd, perm | BLK_PERM_RESIZE, ~shared_perm); ++ ++ /* incompatible perm with already open blk1 and blk2 */ ++ blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, NULL); ++ g_assert_null(blk3); ++ ++ blk_unref(blk2); ++ ++ /* Check that extra bytes in blk2 are correctly unlocked */ ++ check_locked_bytes(fd, perm, ~shared_perm); ++ ++ blk_unref(blk1); ++ ++ /* Image is unused, no lock there */ ++ check_locked_bytes(fd, 0, 0); ++ blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, &error_abort); ++ g_assert(blk3); ++ blk_unref(blk3); ++ close(fd); ++ unlink(img_path); ++} ++ ++static void test_set_perm_abort(void) ++{ ++ BlockBackend *blk1, *blk2; ++ char img_path[] = "/tmp/qtest.XXXXXX"; ++ uint64_t perm, shared_perm; ++ int r; ++ int fd = mkstemp(img_path); ++ assert(fd >= 0); ++ ++ perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; ++ shared_perm = BLK_PERM_ALL; ++ blk1 = open_image(img_path, perm, shared_perm, &error_abort); ++ g_assert(blk1); ++ ++ blk2 = open_image(img_path, perm, shared_perm, &error_abort); ++ g_assert(blk2); ++ ++ check_locked_bytes(fd, perm, ~shared_perm); ++ ++ /* A failed blk_set_perm mustn't change perm status (locked bytes) */ ++ r = blk_set_perm(blk2, perm | BLK_PERM_RESIZE, BLK_PERM_WRITE_UNCHANGED, ++ NULL); ++ g_assert_cmpint(r, !=, 0); ++ check_locked_bytes(fd, perm, ~shared_perm); ++ blk_unref(blk1); ++ blk_unref(blk2); ++} ++ ++int main(int argc, char **argv) ++{ ++ bdrv_init(); ++ qemu_init_main_loop(&error_abort); ++ ++ g_test_init(&argc, &argv, NULL); ++ ++ if (qemu_has_ofd_lock()) { ++ g_test_add_func("/image-locking/basic", test_image_locking_basic); ++ g_test_add_func("/image-locking/set-perm-abort", test_set_perm_abort); ++ } ++ ++ return g_test_run(); ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-Simplify-.gitignore.patch b/SOURCES/kvm-tests-Simplify-.gitignore.patch new file mode 100644 index 0000000..2591bd0 --- /dev/null +++ b/SOURCES/kvm-tests-Simplify-.gitignore.patch @@ -0,0 +1,153 @@ +From 9cc9f8d61a69620645360e2ff399042ea992067b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:17 +0100 +Subject: [PATCH 050/163] tests: Simplify .gitignore +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-5-jsnow@redhat.com> +Patchwork-id: 85088 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/28] tests: Simplify .gitignore +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Eric Blake + +Commit 0bcc8e5b was yet another instance of 'git status' reporting +dirty files after an in-tree build, thanks to the new binary +tests/check-block-qdict. + +Instead of piecemeal exemptions of each new binary as they are +added, let's use git's negative globbing feature to exempt ALL +files that have a 'test-' or 'check-' prefix, except for the ones +ending in '.c' or '.sh'. We still have a couple of generated +files that then need (re-)exclusion, but the overall list is a +LOT shorter, and less prone to needing future edits. + +Signed-off-by: Eric Blake +Message-Id: <20180619203918.65450-1-eblake@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit ac5de4984df282d64feb4af33b92e0a75652e2b6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/.gitignore | 92 +++----------------------------------------------------- + 1 file changed, 5 insertions(+), 87 deletions(-) + +diff --git a/tests/.gitignore b/tests/.gitignore +index fb62d22..08e2df1 100644 +--- a/tests/.gitignore ++++ b/tests/.gitignore +@@ -2,100 +2,18 @@ atomic_add-bench + benchmark-crypto-cipher + benchmark-crypto-hash + benchmark-crypto-hmac +-check-qdict +-check-qnum +-check-qjson +-check-qlist +-check-qlit +-check-qnull +-check-qobject +-check-qstring +-check-qom-interface +-check-qom-proplist ++check-* ++!check-*.c ++!check-*.sh + qht-bench + rcutorture +-test-aio +-test-aio-multithread +-test-arm-mptimer +-test-base64 +-test-bdrv-drain +-test-bitops +-test-bitcnt +-test-blockjob +-test-blockjob-txn +-test-bufferiszero +-test-char +-test-clone-visitor +-test-coroutine +-test-crypto-afsplit +-test-crypto-block +-test-crypto-cipher +-test-crypto-hash +-test-crypto-hmac +-test-crypto-ivgen +-test-crypto-pbkdf +-test-crypto-secret +-test-crypto-tlscredsx509 +-test-crypto-tlscredsx509-work/ +-test-crypto-tlscredsx509-certs/ +-test-crypto-tlssession +-test-crypto-tlssession-work/ +-test-crypto-tlssession-client/ +-test-crypto-tlssession-server/ +-test-crypto-xts +-test-cutils +-test-hbitmap +-test-hmp +-test-int128 +-test-iov +-test-io-channel-buffer +-test-io-channel-command +-test-io-channel-command.fifo +-test-io-channel-file +-test-io-channel-file.txt +-test-io-channel-socket +-test-io-channel-tls +-test-io-task +-test-keyval +-test-logging +-test-mul64 +-test-opts-visitor ++test-* ++!test-*.c + test-qapi-commands.[ch] + test-qapi-events.[ch] + test-qapi-types.[ch] +-test-qapi-util + test-qapi-visit.[ch] +-test-qdev-global-props +-test-qemu-opts +-test-qdist +-test-qga +-test-qht +-test-qht-par +-test-qmp-cmds +-test-qmp-event +-test-qobject-input-strict +-test-qobject-input-visitor + test-qapi-introspect.[ch] +-test-qobject-output-visitor +-test-rcu-list +-test-replication +-test-shift128 +-test-string-input-visitor +-test-string-output-visitor +-test-thread-pool +-test-throttle +-test-timed-average +-test-uuid +-test-util-sockets +-test-visitor-serialization +-test-vmstate +-test-write-threshold +-test-x86-cpuid +-test-x86-cpuid-compat +-test-xbzrle +-test-netfilter +-test-filter-mirror +-test-filter-redirector + *-test + qapi-schema/*.test.* + vm/*.img +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-add-iotests-helpers-for-dealing-with-TLS-certi.patch b/SOURCES/kvm-tests-add-iotests-helpers-for-dealing-with-TLS-certi.patch new file mode 100644 index 0000000..fc16215 --- /dev/null +++ b/SOURCES/kvm-tests-add-iotests-helpers-for-dealing-with-TLS-certi.patch @@ -0,0 +1,183 @@ +From bb9e921fa704fb0ccb9e79bb07ff9d229559e9ed Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:34 +0100 +Subject: [PATCH 067/163] tests: add iotests helpers for dealing with TLS + certificates +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-22-jsnow@redhat.com> +Patchwork-id: 85111 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 21/28] tests: add iotests helpers for dealing with TLS certificates +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +Add helpers to common.tls for creating TLS certificates for a CA, +server and client. + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20181116155325.22428-6-berrange@redhat.com> +Reviewed-by: Eric Blake +[eblake: spelling and quoting touchups] +Signed-off-by: Eric Blake +(cherry picked from commit a46b68410669fa14c4a85d9284953fc0d42392d0) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.tls | 137 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 137 insertions(+) + create mode 100644 tests/qemu-iotests/common.tls + +diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls +new file mode 100644 +index 0000000..cecab26 +--- /dev/null ++++ b/tests/qemu-iotests/common.tls +@@ -0,0 +1,137 @@ ++#!/bin/bash ++# ++# Helpers for TLS related config ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# 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 . ++# ++ ++tls_dir="${TEST_DIR}/tls" ++ ++function tls_x509_cleanup() ++{ ++ rm -f "${tls_dir}"/*.pem ++ rm -f "${tls_dir}"/*/*.pem ++ rmdir "${tls_dir}"/* ++ rmdir "${tls_dir}" ++} ++ ++ ++function tls_x509_init() ++{ ++ mkdir -p "${tls_dir}" ++ ++ # use a fixed key so we don't waste system entropy on ++ # each test run ++ cat > "${tls_dir}/key.pem" < "${tls_dir}/ca.info" <&1 | head -1 ++ ++ rm -f "${tls_dir}/ca.info" ++} ++ ++ ++function tls_x509_create_server() ++{ ++ caname=$1 ++ name=$2 ++ ++ mkdir -p "${tls_dir}/$name" ++ cat > "${tls_dir}/cert.info" <&1 | head -1 ++ ln -s "${tls_dir}/$caname-cert.pem" "${tls_dir}/$name/ca-cert.pem" ++ ln -s "${tls_dir}/key.pem" "${tls_dir}/$name/server-key.pem" ++ ++ rm -f "${tls_dir}/cert.info" ++} ++ ++ ++function tls_x509_create_client() ++{ ++ caname=$1 ++ name=$2 ++ ++ mkdir -p "${tls_dir}/$name" ++ cat > "${tls_dir}/cert.info" <&1 | head -1 ++ ln -s "${tls_dir}/$caname-cert.pem" "${tls_dir}/$name/ca-cert.pem" ++ ln -s "${tls_dir}/key.pem" "${tls_dir}/$name/client-key.pem" ++ ++ rm -f "${tls_dir}/cert.info" ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-add-tests-for-hbitmap_next_dirty_area.patch b/SOURCES/kvm-tests-add-tests-for-hbitmap_next_dirty_area.patch new file mode 100644 index 0000000..bb5b8b9 --- /dev/null +++ b/SOURCES/kvm-tests-add-tests-for-hbitmap_next_dirty_area.patch @@ -0,0 +1,152 @@ +From b60d35c274a27a49097d99c626a70d18d313bff2 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:32 +0100 +Subject: [PATCH 039/163] tests: add tests for hbitmap_next_dirty_area + +RH-Author: John Snow +Message-id: <20190320214838.22027-5-jsnow@redhat.com> +Patchwork-id: 84996 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 04/10] tests: add tests for hbitmap_next_dirty_area +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit bb6a0ec10ee3f791835f1479a8a3226f64cb6d75) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-hbitmap.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 107 insertions(+) + +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index c0da31a..4f312e9 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -1016,6 +1016,106 @@ static void test_hbitmap_next_zero_4(TestHBitmapData *data, const void *unused) + test_hbitmap_next_zero_do(data, 4); + } + ++static void test_hbitmap_next_dirty_area_check(TestHBitmapData *data, ++ uint64_t offset, ++ uint64_t count) ++{ ++ uint64_t off1, off2; ++ uint64_t len1 = 0, len2; ++ bool ret1, ret2; ++ int64_t end; ++ ++ off1 = offset; ++ len1 = count; ++ ret1 = hbitmap_next_dirty_area(data->hb, &off1, &len1); ++ ++ end = offset > data->size || data->size - offset < count ? data->size : ++ offset + count; ++ ++ for (off2 = offset; off2 < end && !hbitmap_get(data->hb, off2); off2++) { ++ ; ++ } ++ ++ for (len2 = 1; off2 + len2 < end && hbitmap_get(data->hb, off2 + len2); ++ len2++) { ++ ; ++ } ++ ++ ret2 = off2 < end; ++ if (!ret2) { ++ /* leave unchanged */ ++ off2 = offset; ++ len2 = count; ++ } ++ ++ g_assert_cmpint(ret1, ==, ret2); ++ g_assert_cmpint(off1, ==, off2); ++ g_assert_cmpint(len1, ==, len2); ++} ++ ++static void test_hbitmap_next_dirty_area_do(TestHBitmapData *data, ++ int granularity) ++{ ++ hbitmap_test_init(data, L3, granularity); ++ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, 0, 1); ++ test_hbitmap_next_dirty_area_check(data, L3 - 1, 1); ++ ++ hbitmap_set(data->hb, L2, 1); ++ test_hbitmap_next_dirty_area_check(data, 0, 1); ++ test_hbitmap_next_dirty_area_check(data, 0, L2); ++ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2 - 1, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2 - 1, 1); ++ test_hbitmap_next_dirty_area_check(data, L2 - 1, 2); ++ test_hbitmap_next_dirty_area_check(data, L2 - 1, 3); ++ test_hbitmap_next_dirty_area_check(data, L2, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2, 1); ++ test_hbitmap_next_dirty_area_check(data, L2 + 1, 1); ++ ++ hbitmap_set(data->hb, L2 + 5, L1); ++ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2 - 2, 8); ++ test_hbitmap_next_dirty_area_check(data, L2 + 1, 5); ++ test_hbitmap_next_dirty_area_check(data, L2 + 1, 3); ++ test_hbitmap_next_dirty_area_check(data, L2 + 4, L1); ++ test_hbitmap_next_dirty_area_check(data, L2 + 5, L1); ++ test_hbitmap_next_dirty_area_check(data, L2 + 7, L1); ++ test_hbitmap_next_dirty_area_check(data, L2 + L1, L1); ++ test_hbitmap_next_dirty_area_check(data, L2, 0); ++ test_hbitmap_next_dirty_area_check(data, L2 + 1, 0); ++ ++ hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2); ++ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2 + 1, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2 + 5 + L1 - 1, UINT64_MAX); ++ test_hbitmap_next_dirty_area_check(data, L2 + 5 + L1, 5); ++ test_hbitmap_next_dirty_area_check(data, L2 * 2 - L1, L1 + 1); ++ test_hbitmap_next_dirty_area_check(data, L2 * 2, L2); ++ ++ hbitmap_set(data->hb, 0, L3); ++ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX); ++} ++ ++static void test_hbitmap_next_dirty_area_0(TestHBitmapData *data, ++ const void *unused) ++{ ++ test_hbitmap_next_dirty_area_do(data, 0); ++} ++ ++static void test_hbitmap_next_dirty_area_1(TestHBitmapData *data, ++ const void *unused) ++{ ++ test_hbitmap_next_dirty_area_do(data, 1); ++} ++ ++static void test_hbitmap_next_dirty_area_4(TestHBitmapData *data, ++ const void *unused) ++{ ++ test_hbitmap_next_dirty_area_do(data, 4); ++} ++ + int main(int argc, char **argv) + { + g_test_init(&argc, &argv, NULL); +@@ -1082,6 +1182,13 @@ int main(int argc, char **argv) + hbitmap_test_add("/hbitmap/next_zero/next_zero_4", + test_hbitmap_next_zero_4); + ++ hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_0", ++ test_hbitmap_next_dirty_area_0); ++ hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_1", ++ test_hbitmap_next_dirty_area_1); ++ hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_4", ++ test_hbitmap_next_dirty_area_4); ++ + g_test_run(); + + return 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-add-tests-for-hbitmap_next_zero-with-specified.patch b/SOURCES/kvm-tests-add-tests-for-hbitmap_next_zero-with-specified.patch new file mode 100644 index 0000000..57221f4 --- /dev/null +++ b/SOURCES/kvm-tests-add-tests-for-hbitmap_next_zero-with-specified.patch @@ -0,0 +1,106 @@ +From 3f336fb2dbf569591917be5a01fa8f760fa8ee77 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 20 Mar 2019 21:48:30 +0100 +Subject: [PATCH 037/163] tests: add tests for hbitmap_next_zero with specified + end parameter + +RH-Author: John Snow +Message-id: <20190320214838.22027-3-jsnow@redhat.com> +Patchwork-id: 84994 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 02/10] tests: add tests for hbitmap_next_zero with specified end parameter +Bugzilla: 1691048 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit fa9c2da29404be9baeb7b8f88fed3cb232688cd9) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-hbitmap.c | 32 ++++++++++++++++++++++++++++---- + 1 file changed, 28 insertions(+), 4 deletions(-) + +diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c +index b04a45a..c0da31a 100644 +--- a/tests/test-hbitmap.c ++++ b/tests/test-hbitmap.c +@@ -937,31 +937,49 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + check_hbitmap_iter_next(&hbi); + } + +-static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start) ++static void test_hbitmap_next_zero_check_range(TestHBitmapData *data, ++ uint64_t start, ++ uint64_t count) + { +- int64_t ret1 = hbitmap_next_zero(data->hb, start, UINT64_MAX); ++ int64_t ret1 = hbitmap_next_zero(data->hb, start, count); + int64_t ret2 = start; +- for ( ; ret2 < data->size && hbitmap_get(data->hb, ret2); ret2++) { ++ int64_t end = start >= data->size || data->size - start < count ? ++ data->size : start + count; ++ ++ for ( ; ret2 < end && hbitmap_get(data->hb, ret2); ret2++) { + ; + } +- if (ret2 == data->size) { ++ if (ret2 == end) { + ret2 = -1; + } + + g_assert_cmpint(ret1, ==, ret2); + } + ++static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start) ++{ ++ test_hbitmap_next_zero_check_range(data, start, UINT64_MAX); ++} ++ + static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity) + { + hbitmap_test_init(data, L3, granularity); + test_hbitmap_next_zero_check(data, 0); + test_hbitmap_next_zero_check(data, L3 - 1); ++ test_hbitmap_next_zero_check_range(data, 0, 1); ++ test_hbitmap_next_zero_check_range(data, L3 - 1, 1); + + hbitmap_set(data->hb, L2, 1); + test_hbitmap_next_zero_check(data, 0); + test_hbitmap_next_zero_check(data, L2 - 1); + test_hbitmap_next_zero_check(data, L2); + test_hbitmap_next_zero_check(data, L2 + 1); ++ test_hbitmap_next_zero_check_range(data, 0, 1); ++ test_hbitmap_next_zero_check_range(data, 0, L2); ++ test_hbitmap_next_zero_check_range(data, L2 - 1, 1); ++ test_hbitmap_next_zero_check_range(data, L2 - 1, 2); ++ test_hbitmap_next_zero_check_range(data, L2, 1); ++ test_hbitmap_next_zero_check_range(data, L2 + 1, 1); + + hbitmap_set(data->hb, L2 + 5, L1); + test_hbitmap_next_zero_check(data, 0); +@@ -970,6 +988,10 @@ static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity) + test_hbitmap_next_zero_check(data, L2 + 5); + test_hbitmap_next_zero_check(data, L2 + L1 - 1); + test_hbitmap_next_zero_check(data, L2 + L1); ++ test_hbitmap_next_zero_check_range(data, L2, 6); ++ test_hbitmap_next_zero_check_range(data, L2 + 1, 3); ++ test_hbitmap_next_zero_check_range(data, L2 + 4, L1); ++ test_hbitmap_next_zero_check_range(data, L2 + 5, L1); + + hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2); + test_hbitmap_next_zero_check(data, L2 * 2 - L1); +@@ -977,6 +999,8 @@ static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity) + test_hbitmap_next_zero_check(data, L2 * 2 - 1); + test_hbitmap_next_zero_check(data, L2 * 2); + test_hbitmap_next_zero_check(data, L3 - 1); ++ test_hbitmap_next_zero_check_range(data, L2 * 2 - L1, L1 + 1); ++ test_hbitmap_next_zero_check_range(data, L2 * 2, L2); + + hbitmap_set(data->hb, 0, L3); + test_hbitmap_next_zero_check(data, 0); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-check-if-qemu-nbd-is-still-alive-before-waitin.patch b/SOURCES/kvm-tests-check-if-qemu-nbd-is-still-alive-before-waitin.patch new file mode 100644 index 0000000..81991da --- /dev/null +++ b/SOURCES/kvm-tests-check-if-qemu-nbd-is-still-alive-before-waitin.patch @@ -0,0 +1,70 @@ +From 44ff04f6ce608282484fa9894d7fc91e8722015d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:33 +0100 +Subject: [PATCH 066/163] tests: check if qemu-nbd is still alive before + waiting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-21-jsnow@redhat.com> +Patchwork-id: 85102 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 20/28] tests: check if qemu-nbd is still alive before waiting +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +If the qemu-nbd UNIX socket has not shown up, the tests will sleep a bit +and then check again repeatedly for up to 30 seconds. This is pointless +if the qemu-nbd process has quit due to an error, so check whether the +pid is still alive before waiting and retrying. + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20181116155325.22428-5-berrange@redhat.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +(cherry picked from commit b39b58d5d0da3e7057d7d636641018b0fc25139b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.nbd | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd +index 27357f3..9f841ab 100644 +--- a/tests/qemu-iotests/common.nbd ++++ b/tests/qemu-iotests/common.nbd +@@ -37,11 +37,19 @@ function nbd_server_stop() + + function nbd_server_wait_for_unix_socket() + { ++ pid=$1 ++ + for ((i = 0; i < 300; i++)) + do + if [ -r "$nbd_unix_socket" ]; then + return + fi ++ kill -s 0 $pid 2>/dev/null ++ if test $? != 0 ++ then ++ echo "qemu-nbd unexpectedly quit" ++ exit 1 ++ fi + sleep 0.1 + done + echo "Failed in check of unix socket created by qemu-nbd" +@@ -52,5 +60,5 @@ function nbd_server_start_unix_socket() + { + nbd_server_stop + $QEMU_NBD -v -t -k "$nbd_unix_socket" "$@" & +- nbd_server_wait_for_unix_socket ++ nbd_server_wait_for_unix_socket $! + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-crypto-Use-the-IEC-binary-prefix-definitions.patch b/SOURCES/kvm-tests-crypto-Use-the-IEC-binary-prefix-definitions.patch new file mode 100644 index 0000000..c518c6d --- /dev/null +++ b/SOURCES/kvm-tests-crypto-Use-the-IEC-binary-prefix-definitions.patch @@ -0,0 +1,134 @@ +From 6da2990d427f11549d7d5ee6f230af95e6b69219 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Wed, 24 Apr 2019 10:30:22 +0200 +Subject: [PATCH 03/12] tests/crypto: Use the IEC binary prefix definitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Daniel P. Berrange +Message-id: <20190424103030.2925-2-berrange@redhat.com> +Patchwork-id: 85892 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/9] tests/crypto: Use the IEC binary prefix definitions +Bugzilla: 1666336 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +From: Philippe Mathieu-Daudé + +It eases code review, unit is explicit. + +Patch generated using: + + $ git grep -n '[<>][<>]= ?[1-5]0' + +and modified manually. + +Suggested-by: Eric Blake +Signed-off-by: Philippe Mathieu-Daudé +Message-Id: <20180625124238.25339-45-f4bug@amsat.org> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 68dbb6d05db59fe39af0c192005490576d9f5b7c) +Signed-off-by: Miroslav Rezanina +--- + tests/benchmark-crypto-cipher.c | 6 +++--- + tests/benchmark-crypto-hash.c | 5 +++-- + tests/benchmark-crypto-hmac.c | 6 +++--- + 3 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/tests/benchmark-crypto-cipher.c b/tests/benchmark-crypto-cipher.c +index cf98443..f5a0d0b 100644 +--- a/tests/benchmark-crypto-cipher.c ++++ b/tests/benchmark-crypto-cipher.c +@@ -11,6 +11,7 @@ + * top-level directory. + */ + #include "qemu/osdep.h" ++#include "qemu/units.h" + #include "crypto/init.h" + #include "crypto/cipher.h" + +@@ -56,8 +57,7 @@ static void test_cipher_speed(const void *opaque) + total += chunk_size; + } while (g_test_timer_elapsed() < 5.0); + +- total /= 1024 * 1024; /* to MB */ +- ++ total /= MiB; + g_print("cbc(aes128): "); + g_print("Testing chunk_size %zu bytes ", chunk_size); + g_print("done: %.2f MB in %.2f secs: ", total, g_test_timer_last()); +@@ -78,7 +78,7 @@ int main(int argc, char **argv) + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + +- for (i = 512; i <= (64 * 1204); i *= 2) { ++ for (i = 512; i <= 64 * KiB; i *= 2) { + memset(name, 0 , sizeof(name)); + snprintf(name, sizeof(name), "/crypto/cipher/speed-%zu", i); + g_test_add_data_func(name, (void *)i, test_cipher_speed); +diff --git a/tests/benchmark-crypto-hash.c b/tests/benchmark-crypto-hash.c +index 122bfb6..9b6f7a9 100644 +--- a/tests/benchmark-crypto-hash.c ++++ b/tests/benchmark-crypto-hash.c +@@ -11,6 +11,7 @@ + * top-level directory. + */ + #include "qemu/osdep.h" ++#include "qemu/units.h" + #include "crypto/init.h" + #include "crypto/hash.h" + +@@ -39,7 +40,7 @@ static void test_hash_speed(const void *opaque) + total += chunk_size; + } while (g_test_timer_elapsed() < 5.0); + +- total /= 1024 * 1024; /* to MB */ ++ total /= MiB; + g_print("sha256: "); + g_print("Testing chunk_size %zu bytes ", chunk_size); + g_print("done: %.2f MB in %.2f secs: ", total, g_test_timer_last()); +@@ -57,7 +58,7 @@ int main(int argc, char **argv) + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + +- for (i = 512; i <= (64 * 1204); i *= 2) { ++ for (i = 512; i <= 64 * KiB; i *= 2) { + memset(name, 0 , sizeof(name)); + snprintf(name, sizeof(name), "/crypto/hash/speed-%zu", i); + g_test_add_data_func(name, (void *)i, test_hash_speed); +diff --git a/tests/benchmark-crypto-hmac.c b/tests/benchmark-crypto-hmac.c +index c30250d..f1dfa24 100644 +--- a/tests/benchmark-crypto-hmac.c ++++ b/tests/benchmark-crypto-hmac.c +@@ -11,6 +11,7 @@ + * top-level directory. + */ + #include "qemu/osdep.h" ++#include "qemu/units.h" + #include "crypto/init.h" + #include "crypto/hmac.h" + +@@ -53,8 +54,7 @@ static void test_hmac_speed(const void *opaque) + total += chunk_size; + } while (g_test_timer_elapsed() < 5.0); + +- total /= 1024 * 1024; /* to MB */ +- ++ total /= MiB; + g_print("hmac(sha256): "); + g_print("Testing chunk_size %zu bytes ", chunk_size); + g_print("done: %.2f MB in %.2f secs: ", total, g_test_timer_last()); +@@ -72,7 +72,7 @@ int main(int argc, char **argv) + g_test_init(&argc, &argv, NULL); + g_assert(qcrypto_init(NULL) == 0); + +- for (i = 512; i <= (64 * 1204); i *= 2) { ++ for (i = 512; i <= 64 * KiB; i *= 2) { + memset(name, 0 , sizeof(name)); + snprintf(name, sizeof(name), "/crypto/hmac/speed-%zu", i); + g_test_add_data_func(name, (void *)i, test_hmac_speed); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-exercise-NBD-server-in-TLS-mode.patch b/SOURCES/kvm-tests-exercise-NBD-server-in-TLS-mode.patch new file mode 100644 index 0000000..80448e1 --- /dev/null +++ b/SOURCES/kvm-tests-exercise-NBD-server-in-TLS-mode.patch @@ -0,0 +1,262 @@ +From 74a1f98290aa6ec986bea9bcd87c4fb8b93afd4d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:35 +0100 +Subject: [PATCH 068/163] tests: exercise NBD server in TLS mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-23-jsnow@redhat.com> +Patchwork-id: 85104 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 22/28] tests: exercise NBD server in TLS mode +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +Add tests that validate it is possible to connect to an NBD server +running TLS mode. Also test mis-matched TLS vs non-TLS connections +correctly fail. + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20181116155325.22428-7-berrange@redhat.com> +Reviewed-by: Eric Blake +Tested-by: Eric Blake +[eblake: rebase to iotests shell cleanups, use ss instead of socat for +port probing, sanitize port number in expected output] +Signed-off-by: Eric Blake +(cherry picked from commit afcd1c2f2d438930a17eb87293c0ac2c377158fa) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/233 | 102 ++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/233.out | 30 +++++++++++++ + tests/qemu-iotests/common.nbd | 45 +++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 4 files changed, 178 insertions(+) + create mode 100755 tests/qemu-iotests/233 + create mode 100644 tests/qemu-iotests/233.out + +diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 +new file mode 100755 +index 0000000..46013ce +--- /dev/null ++++ b/tests/qemu-iotests/233 +@@ -0,0 +1,102 @@ ++#!/bin/bash ++# ++# Test NBD TLS certificate / authorization integration ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# 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 . ++# ++ ++# creator ++owner=berrange@redhat.com ++ ++seq=$(basename $0) ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ nbd_server_stop ++ _cleanup_test_img ++ tls_x509_cleanup ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++. ./common.pattern ++. ./common.tls ++. ./common.nbd ++ ++_supported_fmt raw qcow2 ++_supported_proto file ++# If porting to non-Linux, consider using socat instead of ss in common.nbd ++_supported_os Linux ++_require_command QEMU_NBD ++ ++nbd_server_set_tcp_port ++tls_x509_init ++ ++echo ++echo "== preparing TLS creds ==" ++ ++tls_x509_create_root_ca "ca1" ++tls_x509_create_root_ca "ca2" ++tls_x509_create_server "ca1" "server1" ++tls_x509_create_client "ca1" "client1" ++tls_x509_create_client "ca2" "client2" ++ ++echo ++echo "== preparing image ==" ++_make_test_img 64M ++ ++ ++echo ++echo "== check TLS client to plain server fails ==" ++nbd_server_start_tcp_socket "$TEST_IMG" ++ ++$QEMU_IMG info --image-opts \ ++ --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ ++ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ ++ 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++ ++nbd_server_stop ++ ++echo ++echo "== check plain client to TLS server fails ==" ++ ++nbd_server_start_tcp_socket --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes --tls-creds tls0 "$TEST_IMG" ++ ++$QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++ ++echo ++echo "== check TLS works ==" ++$QEMU_IMG info --image-opts \ ++ --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ ++ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ ++ 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++ ++echo ++echo "== check TLS with different CA fails ==" ++$QEMU_IMG info --image-opts \ ++ --object tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 \ ++ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ ++ 2>&1 | sed "s/$nbd_tcp_port/PORT/g" ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out +new file mode 100644 +index 0000000..616e923 +--- /dev/null ++++ b/tests/qemu-iotests/233.out +@@ -0,0 +1,30 @@ ++QA output created by 233 ++ ++== preparing TLS creds == ++Generating a self signed certificate... ++Generating a self signed certificate... ++Generating a signed certificate... ++Generating a signed certificate... ++Generating a signed certificate... ++ ++== preparing image == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++ ++== check TLS client to plain server fails == ++qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls) ++server reported: TLS not configured ++ ++== check plain client to TLS server fails == ++qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply) ++server reported: Option 0x8 not permitted before TLS ++ ++== check TLS works == ++image: nbd://127.0.0.1:PORT ++file format: nbd ++virtual size: 64M (67108864 bytes) ++disk size: unavailable ++ ++== check TLS with different CA fails == ++option negotiation failed: Verify failed: No certificate was found. ++qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer ++*** done +diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd +index 9f841ab..0f4497a 100644 +--- a/tests/qemu-iotests/common.nbd ++++ b/tests/qemu-iotests/common.nbd +@@ -20,6 +20,7 @@ + # + + nbd_unix_socket="${TEST_DIR}/qemu-nbd.sock" ++nbd_tcp_addr="127.0.0.1" + nbd_pid_file="${TEST_DIR}/qemu-nbd.pid" + + function nbd_server_stop() +@@ -62,3 +63,47 @@ function nbd_server_start_unix_socket() + $QEMU_NBD -v -t -k "$nbd_unix_socket" "$@" & + nbd_server_wait_for_unix_socket $! + } ++ ++function nbd_server_set_tcp_port() ++{ ++ (ss --help) >/dev/null 2>&1 || _notrun "ss utility not found, skipping test" ++ ++ for ((port = 10809; port <= 10909; port++)) ++ do ++ if ! ss -tln | grep -sqE ":$port\b"; then ++ nbd_tcp_port=$port ++ return ++ fi ++ done ++ ++ echo "Cannot find free TCP port for nbd in range 10809-10909" ++ exit 1 ++} ++ ++function nbd_server_wait_for_tcp_socket() ++{ ++ pid=$1 ++ ++ for ((i = 0; i < 300; i++)) ++ do ++ if ss -tln | grep -sqE ":$nbd_tcp_port\b"; then ++ return ++ fi ++ kill -s 0 $pid 2>/dev/null ++ if test $? != 0 ++ then ++ echo "qemu-nbd unexpectedly quit" ++ exit 1 ++ fi ++ sleep 0.1 ++ done ++ echo "Failed in check of TCP socket created by qemu-nbd" ++ exit 1 ++} ++ ++function nbd_server_start_tcp_socket() ++{ ++ nbd_server_stop ++ $QEMU_NBD -v -t -b $nbd_tcp_addr -p $nbd_tcp_port "$@" & ++ nbd_server_wait_for_tcp_socket $! ++} +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index bee2855..b3aeb6b 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -226,6 +226,7 @@ + 229 auto quick + 231 auto quick + 232 auto quick ++233 auto quick + 234 auto quick migration + 236 auto quick + 242 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-pull-qemu-nbd-iotest-helpers-into-common.nbd-f.patch b/SOURCES/kvm-tests-pull-qemu-nbd-iotest-helpers-into-common.nbd-f.patch new file mode 100644 index 0000000..400f0e9 --- /dev/null +++ b/SOURCES/kvm-tests-pull-qemu-nbd-iotest-helpers-into-common.nbd-f.patch @@ -0,0 +1,185 @@ +From ef0a9b41515ff3392afdaeeb37bd32568ba8ffe4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 22 Mar 2019 03:22:32 +0100 +Subject: [PATCH 065/163] tests: pull qemu-nbd iotest helpers into common.nbd + file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190322032241.8111-20-jsnow@redhat.com> +Patchwork-id: 85108 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 19/28] tests: pull qemu-nbd iotest helpers into common.nbd file +Bugzilla: 1691563 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +The helpers for starting/stopping qemu-nbd in 058 will be useful in +other test cases, so move them into a common.nbd file. + +Signed-off-by: Daniel P. Berrangé +Message-Id: <20181116155325.22428-4-berrange@redhat.com> +Reviewed-by: Eric Blake +[eblake: fix shell quoting] +Signed-off-by: Eric Blake +(cherry picked from commit e6d5d6fdd43484f60f678e66c21f0d1286749977) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/058 | 47 +++++++----------------------------- + tests/qemu-iotests/common.nbd | 56 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 64 insertions(+), 39 deletions(-) + create mode 100644 tests/qemu-iotests/common.nbd + +diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 +index 0d741a7..d6d4f94 100755 +--- a/tests/qemu-iotests/058 ++++ b/tests/qemu-iotests/058 +@@ -28,55 +28,19 @@ echo "QA output created by $seq" + + status=1 # failure is the default! + +-nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket +-nbd_snapshot_img="nbd:unix:$nbd_unix_socket" +-rm -f "${TEST_DIR}/qemu-nbd.pid" +- +-_cleanup_nbd() +-{ +- local NBD_SNAPSHOT_PID +- if [ -f "${TEST_DIR}/qemu-nbd.pid" ]; then +- read NBD_SNAPSHOT_PID < "${TEST_DIR}/qemu-nbd.pid" +- rm -f "${TEST_DIR}/qemu-nbd.pid" +- if [ -n "$NBD_SNAPSHOT_PID" ]; then +- kill "$NBD_SNAPSHOT_PID" +- fi +- fi +- rm -f "$nbd_unix_socket" +-} +- +-_wait_for_nbd() +-{ +- for ((i = 0; i < 300; i++)) +- do +- if [ -r "$nbd_unix_socket" ]; then +- return +- fi +- sleep 0.1 +- done +- echo "Failed in check of unix socket created by qemu-nbd" +- exit 1 +-} +- +-converted_image=$TEST_IMG.converted +- + _export_nbd_snapshot() + { +- _cleanup_nbd +- $QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l $1 & +- _wait_for_nbd ++ nbd_server_start_unix_socket "$TEST_IMG" -l $1 + } + + _export_nbd_snapshot1() + { +- _cleanup_nbd +- $QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l snapshot.name=$1 & +- _wait_for_nbd ++ nbd_server_start_unix_socket "$TEST_IMG" -l snapshot.name=$1 + } + + _cleanup() + { +- _cleanup_nbd ++ nbd_server_stop + _cleanup_test_img + rm -f "$converted_image" + } +@@ -86,6 +50,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 + . ./common.rc + . ./common.filter + . ./common.pattern ++. ./common.nbd + + _supported_fmt qcow2 + _supported_proto file +@@ -94,6 +59,10 @@ _require_command QEMU_NBD + # Internal snapshots are (currently) impossible with refcount_bits=1 + _unsupported_imgopts 'refcount_bits=1[^0-9]' + ++nbd_snapshot_img="nbd:unix:$nbd_unix_socket" ++ ++converted_image=$TEST_IMG.converted ++ + # Use -f raw instead of -f $IMGFMT for the NBD connection + QEMU_IO_NBD="$QEMU_IO -f raw --cache=$CACHEMODE" + +diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd +new file mode 100644 +index 0000000..27357f3 +--- /dev/null ++++ b/tests/qemu-iotests/common.nbd +@@ -0,0 +1,56 @@ ++#!/bin/bash ++# -*- shell-script-mode -*- ++# ++# Helpers for NBD server related config ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# 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 . ++# ++ ++nbd_unix_socket="${TEST_DIR}/qemu-nbd.sock" ++nbd_pid_file="${TEST_DIR}/qemu-nbd.pid" ++ ++function nbd_server_stop() ++{ ++ local NBD_PID ++ if [ -f "$nbd_pid_file" ]; then ++ read NBD_PID < "$nbd_pid_file" ++ rm -f "$nbd_pid_file" ++ if [ -n "$NBD_PID" ]; then ++ kill "$NBD_PID" ++ fi ++ fi ++ rm -f "$nbd_unix_socket" ++} ++ ++function nbd_server_wait_for_unix_socket() ++{ ++ for ((i = 0; i < 300; i++)) ++ do ++ if [ -r "$nbd_unix_socket" ]; then ++ return ++ fi ++ sleep 0.1 ++ done ++ echo "Failed in check of unix socket created by qemu-nbd" ++ exit 1 ++} ++ ++function nbd_server_start_unix_socket() ++{ ++ nbd_server_stop ++ $QEMU_NBD -v -t -k "$nbd_unix_socket" "$@" & ++ nbd_server_wait_for_unix_socket ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-qemu-iotests-add-bitmap-resize-test-246.patch b/SOURCES/kvm-tests-qemu-iotests-add-bitmap-resize-test-246.patch new file mode 100644 index 0000000..fbbef11 --- /dev/null +++ b/SOURCES/kvm-tests-qemu-iotests-add-bitmap-resize-test-246.patch @@ -0,0 +1,471 @@ +From 47d5d00fbef6568ecbf0cc6367c8629d75c275af Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 3 Apr 2019 22:42:52 +0200 +Subject: [PATCH 157/163] tests/qemu-iotests: add bitmap resize test 246 + +RH-Author: John Snow +Message-id: <20190403224253.5251-5-jsnow@redhat.com> +Patchwork-id: 85436 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/5] tests/qemu-iotests: add bitmap resize test 246 +Bugzilla: 1666884 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Sergio Lopez Pascual + +Test that we can actually resize qcow2 images with persistent bitmaps +correctly. Throw some other goofy stuff at the test while we're at it, +like adding bitmaps of different granularities and at different times. + +Signed-off-by: John Snow +Signed-off-by: Vladimir Sementsov-Ogievskiy +Tested-by: Eric Blake +Message-id: 20190311185147.52309-5-vsementsov@virtuozzo.com + [vsmentsov: drop \n from the end of test output, + test output changed a bit: some bitmaps goes in other order + int the output] +Signed-off-by: John Snow +(cherry picked from commit e2ec4119dc57e9d65e419b2e9071d35300aa1d92) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/246 | 114 ++++++++++++++++++ + tests/qemu-iotests/246.out | 295 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 410 insertions(+) + create mode 100755 tests/qemu-iotests/246 + create mode 100644 tests/qemu-iotests/246.out + +diff --git a/tests/qemu-iotests/246 b/tests/qemu-iotests/246 +new file mode 100755 +index 0000000..b0997a3 +--- /dev/null ++++ b/tests/qemu-iotests/246 +@@ -0,0 +1,114 @@ ++#!/usr/bin/env python ++# ++# Test persistent bitmap resizing. ++# ++# Copyright (c) 2019 John Snow for Red Hat, Inc. ++# ++# 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 . ++# ++# owner=jsnow@redhat.com ++ ++import iotests ++from iotests import log ++ ++iotests.verify_image_format(supported_fmts=['qcow2']) ++size = 64 * 1024 * 1024 * 1024 ++gran_small = 32 * 1024 ++gran_large = 128 * 1024 ++ ++def query_bitmaps(vm): ++ res = vm.qmp("query-block") ++ return { "bitmaps": { device['device']: device.get('dirty-bitmaps', []) for ++ device in res['return'] } } ++ ++with iotests.FilePath('img') as img_path, \ ++ iotests.VM() as vm: ++ ++ log('--- Preparing image & VM ---\n') ++ iotests.qemu_img_create('-f', iotests.imgfmt, img_path, str(size)) ++ vm.add_drive(img_path) ++ ++ ++ log('--- 1st Boot (Establish Baseline Image) ---\n') ++ vm.launch() ++ ++ log('\n--- Adding bitmaps Small, Medium, Large, and Transient ---\n') ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="Small", granularity=gran_small, persistent=True) ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="Medium", persistent=True) ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="Large", granularity=gran_large, persistent=True) ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="Transient", persistent=False) ++ ++ log('--- Forcing flush of bitmaps to disk ---\n') ++ log(query_bitmaps(vm), indent=2) ++ vm.shutdown() ++ ++ ++ log('--- 2nd Boot (Grow Image) ---\n') ++ vm.launch() ++ log(query_bitmaps(vm), indent=2) ++ ++ log('--- Adding new bitmap, growing image, and adding 2nd new bitmap ---') ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="New", persistent=True) ++ vm.qmp_log("human-monitor-command", ++ command_line="block_resize drive0 70G") ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="Newtwo", persistent=True) ++ log(query_bitmaps(vm), indent=2) ++ ++ log('--- Forcing flush of bitmaps to disk ---\n') ++ vm.shutdown() ++ ++ ++ log('--- 3rd Boot (Shrink Image) ---\n') ++ vm.launch() ++ log(query_bitmaps(vm), indent=2) ++ ++ log('--- Adding "NewB" bitmap, removing "New" bitmap ---') ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="NewB", persistent=True) ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", ++ name="New") ++ ++ log('--- Truncating image ---\n') ++ vm.qmp_log("human-monitor-command", ++ command_line="block_resize drive0 50G") ++ ++ log('--- Adding "NewC" bitmap, removing "NewTwo" bitmap ---') ++ vm.qmp_log("block-dirty-bitmap-add", node="drive0", ++ name="NewC", persistent=True) ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Newtwo") ++ ++ log('--- Forcing flush of bitmaps to disk ---\n') ++ vm.shutdown() ++ ++ ++ log('--- 4th Boot (Verification and Cleanup) ---\n') ++ vm.launch() ++ log(query_bitmaps(vm), indent=2) ++ ++ log('--- Removing all Bitmaps ---\n') ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Small") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Medium") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="Large") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="NewB") ++ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="NewC") ++ log(query_bitmaps(vm), indent=2) ++ ++ log('\n--- Done ---') ++ vm.shutdown() +diff --git a/tests/qemu-iotests/246.out b/tests/qemu-iotests/246.out +new file mode 100644 +index 0000000..b991945 +--- /dev/null ++++ b/tests/qemu-iotests/246.out +@@ -0,0 +1,295 @@ ++--- Preparing image & VM --- ++ ++--- 1st Boot (Establish Baseline Image) --- ++ ++ ++--- Adding bitmaps Small, Medium, Large, and Transient --- ++ ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 32768, "name": "Small", "node": "drive0", "persistent": true}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-add", "arguments": {"name": "Medium", "node": "drive0", "persistent": true}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 131072, "name": "Large", "node": "drive0", "persistent": true}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-add", "arguments": {"name": "Transient", "node": "drive0", "persistent": false}} ++{"return": {}} ++--- Forcing flush of bitmaps to disk --- ++ ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Transient", ++ "persistent": false, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 131072, ++ "name": "Large", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Medium", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 32768, ++ "name": "Small", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++--- 2nd Boot (Grow Image) --- ++ ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 32768, ++ "name": "Small", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Medium", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 131072, ++ "name": "Large", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++--- Adding new bitmap, growing image, and adding 2nd new bitmap --- ++{"execute": "block-dirty-bitmap-add", "arguments": {"name": "New", "node": "drive0", "persistent": true}} ++{"return": {}} ++{"execute": "human-monitor-command", "arguments": {"command_line": "block_resize drive0 70G"}} ++{"return": ""} ++{"execute": "block-dirty-bitmap-add", "arguments": {"name": "Newtwo", "node": "drive0", "persistent": true}} ++{"return": {}} ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Newtwo", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "New", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 32768, ++ "name": "Small", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Medium", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 131072, ++ "name": "Large", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++--- Forcing flush of bitmaps to disk --- ++ ++--- 3rd Boot (Shrink Image) --- ++ ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "New", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Newtwo", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 32768, ++ "name": "Small", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Medium", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 131072, ++ "name": "Large", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++--- Adding "NewB" bitmap, removing "New" bitmap --- ++{"execute": "block-dirty-bitmap-add", "arguments": {"name": "NewB", "node": "drive0", "persistent": true}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "New", "node": "drive0"}} ++{"return": {}} ++--- Truncating image --- ++ ++{"execute": "human-monitor-command", "arguments": {"command_line": "block_resize drive0 50G"}} ++{"return": ""} ++--- Adding "NewC" bitmap, removing "NewTwo" bitmap --- ++{"execute": "block-dirty-bitmap-add", "arguments": {"name": "NewC", "node": "drive0", "persistent": true}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Newtwo", "node": "drive0"}} ++{"return": {}} ++--- Forcing flush of bitmaps to disk --- ++ ++--- 4th Boot (Verification and Cleanup) --- ++ ++{ ++ "bitmaps": { ++ "drive0": [ ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "NewB", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "NewC", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 32768, ++ "name": "Small", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 65536, ++ "name": "Medium", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ }, ++ { ++ "busy": false, ++ "count": 0, ++ "granularity": 131072, ++ "name": "Large", ++ "persistent": true, ++ "recording": true, ++ "status": "active" ++ } ++ ] ++ } ++} ++--- Removing all Bitmaps --- ++ ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Small", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Medium", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "Large", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "NewB", "node": "drive0"}} ++{"return": {}} ++{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "NewC", "node": "drive0"}} ++{"return": {}} ++{ ++ "bitmaps": { ++ "drive0": [] ++ } ++} ++ ++--- Done --- +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index b3aeb6b..7da1334 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -230,3 +230,4 @@ + 234 auto quick migration + 236 auto quick + 242 rw auto quick ++246 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-virtio-blk-test-Disable-auto-read-only.patch b/SOURCES/kvm-tests-virtio-blk-test-Disable-auto-read-only.patch new file mode 100644 index 0000000..8215269 --- /dev/null +++ b/SOURCES/kvm-tests-virtio-blk-test-Disable-auto-read-only.patch @@ -0,0 +1,43 @@ +From b8529f23bd95687344653d4ffd56080d35b4a94f Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 15 Mar 2019 18:09:57 +0100 +Subject: [PATCH 001/163] tests/virtio-blk-test: Disable auto-read-only + +RH-Author: Kevin Wolf +Message-id: <20190315181010.14964-2-kwolf@redhat.com> +Patchwork-id: 84878 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 01/14] tests/virtio-blk-test: Disable auto-read-only +Bugzilla: 1685989 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina + +tests/virtio-blk-test uses a temporary image file that it deletes while +QEMU is still running, so it can't be reopened when writers are +attached or detached. Disable auto-read-only to keep it always writable. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 70304118bb920f2aa961530b64efcce761e4cb5b) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/virtio-blk-test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c +index 9be9ffb..2ed4e74 100644 +--- a/tests/virtio-blk-test.c ++++ b/tests/virtio-blk-test.c +@@ -62,7 +62,7 @@ static QOSState *pci_test_start(void) + QOSState *qs; + const char *arch = qtest_get_arch(); + char *tmp_path; +- const char *cmd = "-drive if=none,id=drive0,file=%s,format=raw " ++ const char *cmd = "-drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off " + "-drive if=none,id=drive1,file=null-co://,format=raw " + "-device virtio-blk-pci,id=drv0,drive=drive0," + "addr=%x.%x"; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ui-Allow-specifying-rendernode-display-option-for-eg.patch b/SOURCES/kvm-ui-Allow-specifying-rendernode-display-option-for-eg.patch new file mode 100644 index 0000000..3f2b6eb --- /dev/null +++ b/SOURCES/kvm-ui-Allow-specifying-rendernode-display-option-for-eg.patch @@ -0,0 +1,53 @@ +From 5c8182b9ee049c2a66ae41aaf664a8f97c86cf16 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 5 Mar 2019 08:26:15 +0100 +Subject: [PATCH 7/9] ui: Allow specifying 'rendernode' display option for + egl-headless +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190305082617.14614-3-kraxel@redhat.com> +Patchwork-id: 84798 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/4] ui: Allow specifying 'rendernode' display option for egl-headless +Bugzilla: 1648236 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Marc-André Lureau +RH-Acked-by: John Snow +RH-Acked-by: Erik Skultety + +From: Erik Skultety + +As libvirt can't predict which rendernode QEMU would pick, it +won't adjust the permissions on the device, hence QEMU getting +"Permission denied" when opening the DRI device. Therefore, enable +'rendernode' option for egl-headless display type. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1648236 + +Signed-off-by: Erik Skultety +Message-id: 27f4617f19aa1072114f10f1aa9dd199735ef982.1542362949.git.eskultet@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 91e61947eb2be21b00091d34f5692f89cef41376) +Signed-off-by: Miroslav Rezanina +--- + ui/egl-headless.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ui/egl-headless.c b/ui/egl-headless.c +index 7c87712..03fec49 100644 +--- a/ui/egl-headless.c ++++ b/ui/egl-headless.c +@@ -175,7 +175,7 @@ static void egl_headless_init(DisplayState *ds, DisplayOptions *opts) + egl_dpy *edpy; + int idx; + +- if (egl_rendernode_init(NULL) < 0) { ++ if (egl_rendernode_init(opts->u.egl_headless.rendernode) < 0) { + error_report("egl: render node init failed"); + exit(1); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-usb-call-reset-handler-before-updating-state.patch b/SOURCES/kvm-usb-call-reset-handler-before-updating-state.patch new file mode 100644 index 0000000..82d983e --- /dev/null +++ b/SOURCES/kvm-usb-call-reset-handler-before-updating-state.patch @@ -0,0 +1,48 @@ +From ea3cee9424ef12e8f1d6dda411efef4488f98936 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 3 Jun 2019 13:45:48 +0200 +Subject: [PATCH 5/9] usb: call reset handler before updating state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190603134550.30153-3-kraxel@redhat.com> +Patchwork-id: 88447 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/4] usb: call reset handler before updating state +Bugzilla: 1710861 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +That way the device reset handler can see what +the before-reset state of the device is. + +Signed-off-by: Gerd Hoffmann +Message-id: 20190522094702.17619-2-kraxel@redhat.com +(cherry picked from commit 7ed4657396add28382081a15557c78cd480c1cf1) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index 241ae66..07b67fb 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -87,10 +87,10 @@ void usb_device_reset(USBDevice *dev) + if (dev == NULL || !dev->attached) { + return; + } ++ usb_device_handle_reset(dev); + dev->remote_wakeup = 0; + dev->addr = 0; + dev->state = USB_STATE_DEFAULT; +- usb_device_handle_reset(dev); + } + + void usb_wakeup(USBEndpoint *ep, unsigned int stream) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-usb-host-avoid-libusb_set_configuration-calls.patch b/SOURCES/kvm-usb-host-avoid-libusb_set_configuration-calls.patch new file mode 100644 index 0000000..0f8230f --- /dev/null +++ b/SOURCES/kvm-usb-host-avoid-libusb_set_configuration-calls.patch @@ -0,0 +1,69 @@ +From 1ae7aca2d3a283cf75f1cdf2df404ecb97423236 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 3 Jun 2019 13:45:50 +0200 +Subject: [PATCH 7/9] usb-host: avoid libusb_set_configuration calls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190603134550.30153-5-kraxel@redhat.com> +Patchwork-id: 88450 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/4] usb-host: avoid libusb_set_configuration calls +Bugzilla: 1710861 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +Seems some devices become confused when we call +libusb_set_configuration(). So before calling the function check +whenever the device has multiple configurations in the first place, and +in case it hasn't (which is the case for the majority of devices) simply +skip the call as it will have no effect anyway. + +Signed-off-by: Gerd Hoffmann +Message-id: 20190522094702.17619-4-kraxel@redhat.com +(cherry picked from commit bfe44898848614cfcb3a269bc965afbe1f0f331c) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/host-libusb.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c +index 1d7e386..878c515 100644 +--- a/hw/usb/host-libusb.c ++++ b/hw/usb/host-libusb.c +@@ -1216,19 +1216,21 @@ static void usb_host_set_address(USBHostDevice *s, int addr) + + static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p) + { +- int rc; ++ int rc = 0; + + trace_usb_host_set_config(s->bus_num, s->addr, config); + + usb_host_release_interfaces(s); +- rc = libusb_set_configuration(s->dh, config); +- if (rc != 0) { +- usb_host_libusb_error("libusb_set_configuration", rc); +- p->status = USB_RET_STALL; +- if (rc == LIBUSB_ERROR_NO_DEVICE) { +- usb_host_nodev(s); ++ if (s->ddesc.bNumConfigurations != 1) { ++ rc = libusb_set_configuration(s->dh, config); ++ if (rc != 0) { ++ usb_host_libusb_error("libusb_set_configuration", rc); ++ p->status = USB_RET_STALL; ++ if (rc == LIBUSB_ERROR_NO_DEVICE) { ++ usb_host_nodev(s); ++ } ++ return; + } +- return; + } + p->status = usb_host_claim_interfaces(s, config); + if (p->status != USB_RET_SUCCESS) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-usb-host-skip-reset-for-untouched-devices.patch b/SOURCES/kvm-usb-host-skip-reset-for-untouched-devices.patch new file mode 100644 index 0000000..a46e487 --- /dev/null +++ b/SOURCES/kvm-usb-host-skip-reset-for-untouched-devices.patch @@ -0,0 +1,47 @@ +From 2aed844c2485cfc07bee58f67be64749655f7f12 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 3 Jun 2019 13:45:49 +0200 +Subject: [PATCH 6/9] usb-host: skip reset for untouched devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20190603134550.30153-4-kraxel@redhat.com> +Patchwork-id: 88448 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/4] usb-host: skip reset for untouched devices +Bugzilla: 1710861 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Max Reitz +RH-Acked-by: Miroslav Rezanina + +If the guest didn't talk to the device yet, skip the reset. +Without this usb-host devices get resetted a number of times +at boot time for no good reason. + +Signed-off-by: Gerd Hoffmann +Message-id: 20190522094702.17619-3-kraxel@redhat.com +(cherry picked from commit 65f14ab98da1da920f98ee8734dc1588b01d6b2b) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/host-libusb.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c +index 0425f0e..1d7e386 100644 +--- a/hw/usb/host-libusb.c ++++ b/hw/usb/host-libusb.c +@@ -1450,6 +1450,9 @@ static void usb_host_handle_reset(USBDevice *udev) + if (!s->allow_guest_reset) { + return; + } ++ if (udev->addr == 0) { ++ return; ++ } + + trace_usb_host_reset(s->bus_num, s->addr); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Inhibit-ballooning-based-on-group-attachment-to.patch b/SOURCES/kvm-vfio-Inhibit-ballooning-based-on-group-attachment-to.patch new file mode 100644 index 0000000..913f09c --- /dev/null +++ b/SOURCES/kvm-vfio-Inhibit-ballooning-based-on-group-attachment-to.patch @@ -0,0 +1,129 @@ +From d171459ebce617bcd42e7c4a5932b3b0f3fa36d2 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:53:07 +0100 +Subject: [PATCH 20/34] vfio: Inhibit ballooning based on group attachment to a + container + +RH-Author: Alex Williamson +Message-id: <154387398693.26945.4148583224290166798.stgit@gimli.home> +Patchwork-id: 83229 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/7] vfio: Inhibit ballooning based on group attachment to a container +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +We use a VFIOContainer to associate an AddressSpace to one or more +VFIOGroups. The VFIOContainer represents the DMA context for that +AdressSpace for those VFIOGroups and is synchronized to changes in +that AddressSpace via a MemoryListener. For IOMMU backed devices, +maintaining the DMA context for a VFIOGroup generally involves +pinning a host virtual address in order to create a stable host +physical address and then mapping a translation from the associated +guest physical address to that host physical address into the IOMMU. + +While the above maintains the VFIOContainer synchronized to the QEMU +memory API of the VM, memory ballooning occurs outside of that API. +Inflating the memory balloon (ie. cooperatively capturing pages from +the guest for use by the host) simply uses MADV_DONTNEED to "zap" +pages from QEMU's host virtual address space. The page pinning and +IOMMU mapping above remains in place, negating the host's ability to +reuse the page, but the host virtual to host physical mapping of the +page is invalidated outside of QEMU's memory API. + +When the balloon is later deflated, attempting to cooperatively +return pages to the guest, the page is simply freed by the guest +balloon driver, allowing it to be used in the guest and incurring a +page fault when that occurs. The page fault maps a new host physical +page backing the existing host virtual address, meanwhile the +VFIOContainer still maintains the translation to the original host +physical address. At this point the guest vCPU and any assigned +devices will map different host physical addresses to the same guest +physical address. Badness. + +The IOMMU typically does not have page level granularity with which +it can track this mapping without also incurring inefficiencies in +using page size mappings throughout. MMU notifiers in the host +kernel also provide indicators for invalidating the mapping on +balloon inflation, not for updating the mapping when the balloon is +deflated. For these reasons we assume a default behavior that the +mapping of each VFIOGroup into the VFIOContainer is incompatible +with memory ballooning and increment the balloon inhibitor to match +the attached VFIOGroups. + +Reviewed-by: Peter Xu +Signed-off-by: Alex Williamson +(cherry picked from commit c65ee433153b5925e183a00ebf568e160077c694) +Signed-off-by: Miroslav Rezanina +--- + hw/vfio/common.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 07ffa0b..7e8f289 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -32,6 +32,7 @@ + #include "hw/hw.h" + #include "qemu/error-report.h" + #include "qemu/range.h" ++#include "sysemu/balloon.h" + #include "sysemu/kvm.h" + #include "trace.h" + #include "qapi/error.h" +@@ -1039,6 +1040,33 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + + space = vfio_get_address_space(as); + ++ /* ++ * VFIO is currently incompatible with memory ballooning insofar as the ++ * madvise to purge (zap) the page from QEMU's address space does not ++ * interact with the memory API and therefore leaves stale virtual to ++ * physical mappings in the IOMMU if the page was previously pinned. We ++ * therefore add a balloon inhibit for each group added to a container, ++ * whether the container is used individually or shared. This provides ++ * us with options to allow devices within a group to opt-in and allow ++ * ballooning, so long as it is done consistently for a group (for instance ++ * if the device is an mdev device where it is known that the host vendor ++ * driver will never pin pages outside of the working set of the guest ++ * driver, which would thus not be ballooning candidates). ++ * ++ * The first opportunity to induce pinning occurs here where we attempt to ++ * attach the group to existing containers within the AddressSpace. If any ++ * pages are already zapped from the virtual address space, such as from a ++ * previous ballooning opt-in, new pinning will cause valid mappings to be ++ * re-established. Likewise, when the overall MemoryListener for a new ++ * container is registered, a replay of mappings within the AddressSpace ++ * will occur, re-establishing any previously zapped pages as well. ++ * ++ * NB. Balloon inhibiting does not currently block operation of the ++ * balloon driver or revoke previously pinned pages, it only prevents ++ * calling madvise to modify the virtual mapping of ballooned pages. ++ */ ++ qemu_balloon_inhibit(true); ++ + QLIST_FOREACH(container, &space->containers, next) { + if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { + group->container = container; +@@ -1227,6 +1255,7 @@ close_fd_exit: + close(fd); + + put_space_exit: ++ qemu_balloon_inhibit(false); + vfio_put_address_space(space); + + return ret; +@@ -1347,6 +1376,7 @@ void vfio_put_group(VFIOGroup *group) + return; + } + ++ qemu_balloon_inhibit(false); + vfio_kvm_device_del_group(group); + vfio_disconnect_container(group); + QLIST_REMOVE(group, next); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-ccw-pci-Allow-devices-to-opt-in-for-ballooning.patch b/SOURCES/kvm-vfio-ccw-pci-Allow-devices-to-opt-in-for-ballooning.patch new file mode 100644 index 0000000..dfc5051 --- /dev/null +++ b/SOURCES/kvm-vfio-ccw-pci-Allow-devices-to-opt-in-for-ballooning.patch @@ -0,0 +1,204 @@ +From f353edbaafbd3b501495a240ae0d4d679c4ae929 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:53:21 +0100 +Subject: [PATCH 21/34] vfio/ccw/pci: Allow devices to opt-in for ballooning + +RH-Author: Alex Williamson +Message-id: <154387400169.26945.14372894868026827700.stgit@gimli.home> +Patchwork-id: 83230 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 4/7] vfio/ccw/pci: Allow devices to opt-in for ballooning +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +If a vfio assigned device makes use of a physical IOMMU, then memory +ballooning is necessarily inhibited due to the page pinning, lack of +page level granularity at the IOMMU, and sufficient notifiers to both +remove the page on balloon inflation and add it back on deflation. +However, not all devices are backed by a physical IOMMU. In the case +of mediated devices, if a vendor driver is well synchronized with the +guest driver, such that only pages actively used by the guest driver +are pinned by the host mdev vendor driver, then there should be no +overlap between pages available for the balloon driver and pages +actively in use by the device. Under these conditions, ballooning +should be safe. + +vfio-ccw devices are always mediated devices and always operate under +the constraints above. Therefore we can consider all vfio-ccw devices +as balloon compatible. + +The situation is far from straightforward with vfio-pci. These +devices can be physical devices with physical IOMMU backing or +mediated devices where it is unknown whether a physical IOMMU is in +use or whether the vendor driver is well synchronized to the working +set of the guest driver. The safest approach is therefore to assume +all vfio-pci devices are incompatible with ballooning, but allow user +opt-in should they have further insight into mediated devices. + +Signed-off-by: Alex Williamson +(cherry picked from commit 238e91728503d400e1c4e644e3a9b80f9e621682) +Signed-off-by: Miroslav Rezanina +--- + hw/vfio/ccw.c | 9 +++++++++ + hw/vfio/common.c | 23 ++++++++++++++++++++++- + hw/vfio/pci.c | 26 +++++++++++++++++++++++++- + hw/vfio/trace-events | 1 + + include/hw/vfio/vfio-common.h | 2 ++ + 5 files changed, 59 insertions(+), 2 deletions(-) + +diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c +index fe34b50..0c74dda 100644 +--- a/hw/vfio/ccw.c ++++ b/hw/vfio/ccw.c +@@ -362,6 +362,15 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) + } + } + ++ /* ++ * All vfio-ccw devices are believed to operate in a way compatible with ++ * memory ballooning, ie. pages pinned in the host are in the current ++ * working set of the guest driver and therefore never overlap with pages ++ * available to the guest balloon driver. This needs to be set before ++ * vfio_get_device() for vfio common to handle the balloon inhibitor. ++ */ ++ vcdev->vdev.balloon_allowed = true; ++ + if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, &err)) { + g_free(vcdev->vdev.name); + goto out_device_err; +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 7e8f289..cda2d1f 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1376,7 +1376,9 @@ void vfio_put_group(VFIOGroup *group) + return; + } + +- qemu_balloon_inhibit(false); ++ if (!group->balloon_allowed) { ++ qemu_balloon_inhibit(false); ++ } + vfio_kvm_device_del_group(group); + vfio_disconnect_container(group); + QLIST_REMOVE(group, next); +@@ -1412,6 +1414,25 @@ int vfio_get_device(VFIOGroup *group, const char *name, + return ret; + } + ++ /* ++ * Clear the balloon inhibitor for this group if the driver knows the ++ * device operates compatibly with ballooning. Setting must be consistent ++ * per group, but since compatibility is really only possible with mdev ++ * currently, we expect singleton groups. ++ */ ++ if (vbasedev->balloon_allowed != group->balloon_allowed) { ++ if (!QLIST_EMPTY(&group->device_list)) { ++ error_setg(errp, ++ "Inconsistent device balloon setting within group"); ++ return -1; ++ } ++ ++ if (!group->balloon_allowed) { ++ group->balloon_allowed = true; ++ qemu_balloon_inhibit(false); ++ } ++ } ++ + vbasedev->fd = fd; + vbasedev->group = group; + QLIST_INSERT_HEAD(&group->device_list, vbasedev, next); +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index c00b91c..3bc7636 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2802,12 +2802,13 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIODevice *vbasedev_iter; + VFIOGroup *group; +- char *tmp, group_path[PATH_MAX], *group_name; ++ char *tmp, *subsys, group_path[PATH_MAX], *group_name; + Error *err = NULL; + ssize_t len; + struct stat st; + int groupid; + int ret, i = 0; ++ bool is_mdev; + + QLIST_FOREACH(group, &vfio_group_list, next) { + QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { +@@ -2879,6 +2880,27 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + } + } + ++ /* ++ * Mediated devices *might* operate compatibly with memory ballooning, but ++ * we cannot know for certain, it depends on whether the mdev vendor driver ++ * stays in sync with the active working set of the guest driver. Prevent ++ * the x-balloon-allowed option unless this is minimally an mdev device. ++ */ ++ tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev); ++ subsys = realpath(tmp, NULL); ++ g_free(tmp); ++ is_mdev = (strcmp(subsys, "/sys/bus/mdev") == 0); ++ free(subsys); ++ ++ trace_vfio_mdev(vdev->vbasedev.name, is_mdev); ++ ++ if (vdev->vbasedev.balloon_allowed && !is_mdev) { ++ error_setg(errp, "x-balloon-allowed only potentially compatible " ++ "with mdev devices"); ++ vfio_put_group(group); ++ goto error; ++ } ++ + ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp); + if (ret) { + vfio_put_group(group); +@@ -3176,6 +3198,8 @@ static Property vfio_pci_dev_properties[] = { + DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features, + VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false), + DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false), ++ DEFINE_PROP_BOOL("x-balloon-allowed", VFIOPCIDevice, ++ vbasedev.balloon_allowed, false), + DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false), + DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false), + DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false), +diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events +index 20109cb..9487887 100644 +--- a/hw/vfio/trace-events ++++ b/hw/vfio/trace-events +@@ -39,6 +39,7 @@ vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: % + vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx" + vfio_populate_device_get_irq_info_failure(void) "VFIO_DEVICE_GET_IRQ_INFO failure: %m" + vfio_realize(const char *name, int group_id) " (%s) group %d" ++vfio_mdev(const char *name, bool is_mdev) " (%s) is_mdev %d" + vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s 0x%x@0x%x" + vfio_pci_reset(const char *name) " (%s)" + vfio_pci_reset_flr(const char *name) "%s FLR/VFIO_DEVICE_RESET" +diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h +index d936014..c5c4cac 100644 +--- a/include/hw/vfio/vfio-common.h ++++ b/include/hw/vfio/vfio-common.h +@@ -122,6 +122,7 @@ typedef struct VFIODevice { + bool reset_works; + bool needs_reset; + bool no_mmap; ++ bool balloon_allowed; + VFIODeviceOps *ops; + unsigned int num_irqs; + unsigned int num_regions; +@@ -141,6 +142,7 @@ typedef struct VFIOGroup { + QLIST_HEAD(, VFIODevice) device_list; + QLIST_ENTRY(VFIOGroup) next; + QLIST_ENTRY(VFIOGroup) container_next; ++ bool balloon_allowed; + } VFIOGroup; + + typedef struct VFIODMABuf { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pci-Fix-failure-to-close-file-descriptor-on-err.patch b/SOURCES/kvm-vfio-pci-Fix-failure-to-close-file-descriptor-on-err.patch new file mode 100644 index 0000000..5c9f55b --- /dev/null +++ b/SOURCES/kvm-vfio-pci-Fix-failure-to-close-file-descriptor-on-err.patch @@ -0,0 +1,44 @@ +From da8839a4373667b017e935d7c365af6cbfd97bb9 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:54:02 +0100 +Subject: [PATCH 23/34] vfio/pci: Fix failure to close file descriptor on error + +RH-Author: Alex Williamson +Message-id: <154387404228.26945.9774510369852793346.stgit@gimli.home> +Patchwork-id: 83232 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 6/7] vfio/pci: Fix failure to close file descriptor on error +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +A new error path fails to close the device file descriptor when +triggered by a ballooning incompatibility within the group. Fix it. + +Fixes: 238e91728503 ("vfio/ccw/pci: Allow devices to opt-in for ballooning") +Reviewed-by: Peter Xu +Signed-off-by: Alex Williamson +(cherry picked from commit 8709b3954d4161bad30ccc435408ec50e10f53cc) +Signed-off-by: Miroslav Rezanina +--- + hw/vfio/common.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index cda2d1f..3ab92bd 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -1424,6 +1424,7 @@ int vfio_get_device(VFIOGroup *group, const char *name, + if (!QLIST_EMPTY(&group->device_list)) { + error_setg(errp, + "Inconsistent device balloon setting within group"); ++ close(fd); + return -1; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pci-Handle-subsystem-realpath-returning-NULL.patch b/SOURCES/kvm-vfio-pci-Handle-subsystem-realpath-returning-NULL.patch new file mode 100644 index 0000000..e7809eb --- /dev/null +++ b/SOURCES/kvm-vfio-pci-Handle-subsystem-realpath-returning-NULL.patch @@ -0,0 +1,46 @@ +From 9cf75f15324ca15f013d3dc6a95bb5066a58d375 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 3 Dec 2018 21:53:40 +0100 +Subject: [PATCH 22/34] vfio/pci: Handle subsystem realpath() returning NULL + +RH-Author: Alex Williamson +Message-id: <154387402054.26945.6430332743475303163.stgit@gimli.home> +Patchwork-id: 83231 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 5/7] vfio/pci: Handle subsystem realpath() returning NULL +Bugzilla: 1619778 +RH-Acked-by: Peter Xu +RH-Acked-by: Cornelia Huck +RH-Acked-by: Auger Eric +RH-Acked-by: David Hildenbrand + +Bugzilla: 1619778 + +Fix error reported by Coverity where realpath can return NULL, +resulting in a segfault in strcmp(). This should never happen given +that we're working through regularly structured sysfs paths, but +trivial enough to easily avoid. + +Fixes: 238e91728503 ("vfio/ccw/pci: Allow devices to opt-in for ballooning") +Signed-off-by: Alex Williamson +(cherry picked from commit a1c0f886496cfb4c336f8eb4155ed424567d653e) +Signed-off-by: Miroslav Rezanina +--- + hw/vfio/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 3bc7636..ba3a393 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -2889,7 +2889,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) + tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev); + subsys = realpath(tmp, NULL); + g_free(tmp); +- is_mdev = (strcmp(subsys, "/sys/bus/mdev") == 0); ++ is_mdev = subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); + free(subsys); + + trace_vfio_mdev(vdev->vbasedev.name, is_mdev); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost_net-don-t-set-backend-for-the-uninitialized-vi.patch b/SOURCES/kvm-vhost_net-don-t-set-backend-for-the-uninitialized-vi.patch new file mode 100644 index 0000000..a941479 --- /dev/null +++ b/SOURCES/kvm-vhost_net-don-t-set-backend-for-the-uninitialized-vi.patch @@ -0,0 +1,91 @@ +From 55e77ff717339c63b0408e0b9a1bcd313d6c0c48 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Fri, 24 May 2019 12:56:42 +0200 +Subject: [PATCH] vhost_net: don't set backend for the uninitialized virtqueue + +RH-Author: Xiao Wang +Message-id: <1558702602-3677-1-git-send-email-jasowang@redhat.com> +Patchwork-id: 88204 +O-Subject: [RHEL-7.7 qemu-kvm PATCH] vhost_net: don't set backend for the uninitialized virtqueue +Bugzilla: 1608226 +RH-Acked-by: Thomas Huth +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Jens Freimann + +We used to set backend unconditionally, this won't work for some +guests (e.g windows driver) who may not initialize all virtqueues. For +kernel backend, this will fail since it may try to validate the rings +during setting backend. + +Fixing this by simply skipping the backend set when we find desc is +not ready. + +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +(cherry picked from commit 23bfaf77fa801ba30bb136de7cec47728eb02f4b) +Signed-off-by: Miroslav Rezanina +--- + hw/net/vhost_net.c | 10 ++++++++++ + hw/virtio/virtio.c | 5 +++++ + include/hw/virtio/virtio.h | 1 + + 3 files changed, 16 insertions(+) + +diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c +index e037db6..ec22727 100644 +--- a/hw/net/vhost_net.c ++++ b/hw/net/vhost_net.c +@@ -246,6 +246,11 @@ static int vhost_net_start_one(struct vhost_net *net, + qemu_set_fd_handler(net->backend, NULL, NULL, NULL); + file.fd = net->backend; + for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { ++ if (!virtio_queue_enabled(dev, net->dev.vq_index + ++ file.index)) { ++ /* Queue might not be ready for start */ ++ continue; ++ } + r = vhost_net_set_backend(&net->dev, &file); + if (r < 0) { + r = -errno; +@@ -258,6 +263,11 @@ fail: + file.fd = -1; + if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + while (file.index-- > 0) { ++ if (!virtio_queue_enabled(dev, net->dev.vq_index + ++ file.index)) { ++ /* Queue might not be ready for start */ ++ continue; ++ } + int r = vhost_net_set_backend(&net->dev, &file); + assert(r >= 0); + } +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 1c936ad..3492b20 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2317,6 +2317,11 @@ hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) + return vdev->vq[n].vring.desc; + } + ++bool virtio_queue_enabled(VirtIODevice *vdev, int n) ++{ ++ return virtio_queue_get_desc_addr(vdev, n) != 0; ++} ++ + hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n) + { + return vdev->vq[n].vring.avail; +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 96313e8..3029758 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -268,6 +268,7 @@ typedef struct VirtIORNGConf VirtIORNGConf; + VIRTIO_F_IOMMU_PLATFORM, false) + + hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); ++bool virtio_queue_enabled(VirtIODevice *vdev, int n); + hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); + hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n); + hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-Return-true-from-virtio_queue_empty-if-broken.patch b/SOURCES/kvm-virtio-Return-true-from-virtio_queue_empty-if-broken.patch new file mode 100644 index 0000000..b76f1aa --- /dev/null +++ b/SOURCES/kvm-virtio-Return-true-from-virtio_queue_empty-if-broken.patch @@ -0,0 +1,108 @@ +From 6b1bea7682e1f321225e29cc6ee934a32f7b09d5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 25 Jan 2019 22:50:07 +0100 +Subject: [PATCH 07/23] virtio: Return true from virtio_queue_empty if broken +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20190125225007.8197-8-jsnow@redhat.com> +Patchwork-id: 84122 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 7/7] virtio: Return true from virtio_queue_empty if broken +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Fam Zheng + +Both virtio-blk and virtio-scsi use virtio_queue_empty() as the +loop condition in VQ handlers (virtio_blk_handle_vq, +virtio_scsi_handle_cmd_vq). When a device is marked broken in +virtqueue_pop, for example if a vIOMMU address translation failed, we +want to break out of the loop. + +This fixes a hanging problem when booting a CentOS 3.10.0-862.el7.x86_64 +kernel with ATS enabled: + + $ qemu-system-x86_64 \ + ... \ + -device intel-iommu,intremap=on,caching-mode=on,eim=on,device-iotlb=on \ + -device virtio-scsi-pci,iommu_platform=on,ats=on,id=scsi0,bus=pci.4,addr=0x0 + +The dead loop happens immediately when the kernel boots and initializes +the device, where virtio_scsi_data_plane_handle_cmd will not return: + + > ... + > #13 0x00005586602b7793 in virtio_scsi_handle_cmd_vq + > #14 0x00005586602b8d66 in virtio_scsi_data_plane_handle_cmd + > #15 0x00005586602ddab7 in virtio_queue_notify_aio_vq + > #16 0x00005586602dfc9f in virtio_queue_host_notifier_aio_poll + > #17 0x00005586607885da in run_poll_handlers_once + > #18 0x000055866078880e in try_poll_mode + > #19 0x00005586607888eb in aio_poll + > #20 0x0000558660784561 in aio_wait_bh_oneshot + > #21 0x00005586602b9582 in virtio_scsi_dataplane_stop + > #22 0x00005586605a7110 in virtio_bus_stop_ioeventfd + > #23 0x00005586605a9426 in virtio_pci_stop_ioeventfd + > #24 0x00005586605ab808 in virtio_pci_common_write + > #25 0x0000558660242396 in memory_region_write_accessor + > #26 0x00005586602425ab in access_with_adjusted_size + > #27 0x0000558660245281 in memory_region_dispatch_write + > #28 0x00005586601e008e in flatview_write_continue + > #29 0x00005586601e01d8 in flatview_write + > #30 0x00005586601e04de in address_space_write + > #31 0x00005586601e052f in address_space_rw + > #32 0x00005586602607f2 in kvm_cpu_exec + > #33 0x0000558660227148 in qemu_kvm_cpu_thread_fn + > #34 0x000055866078bde7 in qemu_thread_start + > #35 0x00007f5784906594 in start_thread + > #36 0x00007f5784639e6f in clone + +With this patch, virtio_queue_empty will now return 1 as soon as the +vdev is marked as broken, after a "virtio: zero sized buffers are not +allowed" error. + +To be consistent, update virtio_queue_empty_rcu as well. + +Signed-off-by: Fam Zheng +Message-Id: <20180910145616.8598-2-famz@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 2d1df8591022737b8ef19d681ff74eda389f5198) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 77eadaa..1c936ad 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -345,6 +345,10 @@ int virtio_queue_ready(VirtQueue *vq) + * Called within rcu_read_lock(). */ + static int virtio_queue_empty_rcu(VirtQueue *vq) + { ++ if (unlikely(vq->vdev->broken)) { ++ return 1; ++ } ++ + if (unlikely(!vq->vring.avail)) { + return 1; + } +@@ -360,6 +364,10 @@ int virtio_queue_empty(VirtQueue *vq) + { + bool empty; + ++ if (unlikely(vq->vdev->broken)) { ++ return 1; ++ } ++ + if (unlikely(!vq->vring.avail)) { + return 1; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-blk-Increase-in_flight-for-request-restart-BH.patch b/SOURCES/kvm-virtio-blk-Increase-in_flight-for-request-restart-BH.patch new file mode 100644 index 0000000..c0bb952 --- /dev/null +++ b/SOURCES/kvm-virtio-blk-Increase-in_flight-for-request-restart-BH.patch @@ -0,0 +1,62 @@ +From 399ed639cc85835eb7a4a7241df6c1741c0578ba Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 1 Mar 2019 14:27:44 +0100 +Subject: [PATCH 2/9] virtio-blk: Increase in_flight for request restart BH + +RH-Author: Kevin Wolf +Message-id: <20190301142747.12251-3-kwolf@redhat.com> +Patchwork-id: 84762 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 2/5] virtio-blk: Increase in_flight for request restart BH +Bugzilla: 1671173 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow + +virtio_blk_dma_restart_bh() submits new requests, so in order to make +sure that these requests are not started inside a drained section of the +attached BlockBackend, we need to make sure that draining the +BlockBackend waits for the BH to be executed. + +This BH is still questionable because its scheduled in the main thread +instead of the configured iothread. Leave a FIXME comment for this. + +But with this fix, enabling the data plane at least waits for these +requests (in bdrv_set_aio_context()) instead of changing the AioContext +under their feet and making them run in the wrong thread, causing +crashes and failures (e.g. due to missing locking). + +Signed-off-by: Kevin Wolf +(cherry picked from commit 680f200217748e0920b79ec1d524717c2f50935b) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + hw/block/virtio-blk.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c +index b1532e4..691ade4 100644 +--- a/hw/block/virtio-blk.c ++++ b/hw/block/virtio-blk.c +@@ -678,6 +678,7 @@ static void virtio_blk_dma_restart_bh(void *opaque) + if (mrb.num_reqs) { + virtio_blk_submit_multireq(s->blk, &mrb); + } ++ blk_dec_in_flight(s->conf.conf.blk); + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); + } + +@@ -691,8 +692,11 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, + } + + if (!s->bh) { ++ /* FIXME The data plane is not started yet, so these requests are ++ * processed in the main thread. */ + s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk), + virtio_blk_dma_restart_bh, s); ++ blk_inc_in_flight(s->conf.conf.blk); + qemu_bh_schedule(s->bh); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-scsi-Forbid-devices-with-different-iothreads-.patch b/SOURCES/kvm-virtio-scsi-Forbid-devices-with-different-iothreads-.patch new file mode 100644 index 0000000..15d674a --- /dev/null +++ b/SOURCES/kvm-virtio-scsi-Forbid-devices-with-different-iothreads-.patch @@ -0,0 +1,117 @@ +From f482ed4845d33ce74a990ee935475dfbabf1df70 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 10 May 2019 13:28:25 +0200 +Subject: [PATCH 22/53] virtio-scsi: Forbid devices with different iothreads + sharing a blockdev + +RH-Author: Markus Armbruster +Message-id: <20190510132825.29833-4-armbru@redhat.com> +Patchwork-id: 87266 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/3] virtio-scsi: Forbid devices with different iothreads sharing a blockdev +Bugzilla: 1673397 1673402 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +From: Alberto Garcia + +This patch forbids attaching a disk to a SCSI device if its using a +different AioContext. Test case included. + +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit eb97813ff5fd5bdffc8ed9f5be5a3a50eae70a2c) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/virtio-scsi.c | 7 +++++++ + tests/qemu-iotests/240 | 22 ++++++++++++++++++++++ + tests/qemu-iotests/240.out | 20 ++++++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 85073f6..391500b 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -800,9 +800,16 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, + return; + } + if (s->ctx && !s->dataplane_fenced) { ++ AioContext *ctx; + if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { + return; + } ++ ctx = blk_get_aio_context(sd->conf.blk); ++ if (ctx != s->ctx && ctx != qemu_get_aio_context()) { ++ error_setg(errp, "Cannot attach a blockdev that is using " ++ "a different iothread"); ++ return; ++ } + virtio_scsi_acquire(s); + blk_set_aio_context(sd->conf.blk, s->ctx); + virtio_scsi_release(s); +diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 +index 5d499c9..65cc3b3 100755 +--- a/tests/qemu-iotests/240 ++++ b/tests/qemu-iotests/240 +@@ -101,6 +101,28 @@ run_qemu < +Date: Fri, 17 May 2019 14:51:31 +0200 +Subject: [PATCH 20/53] virtio-scsi: Move BlockBackend back to the main + AioContext on unplug + +RH-Author: Markus Armbruster +Message-id: <20190510132825.29833-2-armbru@redhat.com> +Patchwork-id: 87267 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/3] virtio-scsi: Move BlockBackend back to the main AioContext on unplug +Bugzilla: 1673397 1673402 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +From: Alberto Garcia + +This fixes a crash when attaching a disk to a SCSI device using +iothreads, then detaching it and reattaching it again. Test case +included. + +Signed-off-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit a6f230c8d13a7ff3a0c7f1097412f44bfd9eff0b) +[Trivial conflict in tests/qemu-iotests/group resolved] +Signed-off-by: Markus Armbruster +--- + hw/scsi/virtio-scsi.c | 6 ++++ + tests/qemu-iotests/240 | 89 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/240.out | 18 ++++++++++ + tests/qemu-iotests/group | 1 + + 4 files changed, 114 insertions(+) + create mode 100755 tests/qemu-iotests/240 + create mode 100644 tests/qemu-iotests/240.out + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 52a3c1d..85073f6 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -841,6 +841,12 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, + virtio_scsi_release(s); + } + ++ if (s->ctx) { ++ virtio_scsi_acquire(s); ++ blk_set_aio_context(sd->conf.blk, qemu_get_aio_context()); ++ virtio_scsi_release(s); ++ } ++ + qdev_simple_device_unplug_cb(hotplug_dev, dev, errp); + } + +diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 +new file mode 100755 +index 0000000..ead7ee0 +--- /dev/null ++++ b/tests/qemu-iotests/240 +@@ -0,0 +1,89 @@ ++#!/bin/bash ++# ++# Test hot plugging and unplugging with iothreads ++# ++# Copyright (C) 2019 Igalia, S.L. ++# Author: Alberto Garcia ++# ++# 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 . ++# ++ ++# creator ++owner=berto@igalia.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt generic ++_supported_proto generic ++_supported_os Linux ++ ++do_run_qemu() ++{ ++ echo Testing: "$@" ++ $QEMU -nographic -qmp stdio -serial none "$@" ++ echo ++} ++ ++# Remove QMP events from (pretty-printed) output. Doesn't handle ++# nested dicts correctly, but we don't get any of those in this test. ++_filter_qmp_events() ++{ ++ tr '\n' '\t' | sed -e \ ++ 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \ ++ | tr '\t' '\n' ++} ++ ++run_qemu() ++{ ++ do_run_qemu "$@" 2>&1 | _filter_qmp | _filter_qmp_events ++} ++ ++case "$QEMU_DEFAULT_MACHINE" in ++ s390-ccw-virtio) ++ virtio_scsi=virtio-scsi-ccw ++ ;; ++ *) ++ virtio_scsi=virtio-scsi-pci ++ ;; ++esac ++ ++echo ++echo === Unplug a SCSI disk and then plug it again === ++echo ++ ++run_qemu < +Date: Fri, 25 Jan 2019 22:50:05 +0100 +Subject: [PATCH 05/23] virtio: update MemoryRegionCaches when guest negotiates + features + +RH-Author: John Snow +Message-id: <20190125225007.8197-6-jsnow@redhat.com> +Patchwork-id: 84121 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 5/7] virtio: update MemoryRegionCaches when guest negotiates features +Bugzilla: 1597482 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Peter Xu +RH-Acked-by: Stefano Garzarella + +From: Paolo Bonzini + +Because the cache is sized to include the rings and the event indices, +negotiating the VIRTIO_RING_F_EVENT_IDX feature will result in the size +of the cache changing. And because MemoryRegionCache accesses are +range-checked, if we skip this we end up with an assertion failure. +This happens with OpenBSD 6.3. + +Reported-by: Fam Zheng +Fixes: 97cd965c070152bc626c7507df9fb356bbe1cd81 +Cc: qemu-stable@nongnu.org +Signed-off-by: Paolo Bonzini +Tested-by: Fam Zheng +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit db812c4073c77c8a64db8d6663b3416a587c7b4a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 5549bb4..77eadaa 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2021,14 +2021,25 @@ static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) + + int virtio_set_features(VirtIODevice *vdev, uint64_t val) + { +- /* ++ int ret; ++ /* + * The driver must not attempt to set features after feature negotiation + * has finished. + */ + if (vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) { + return -EINVAL; + } +- return virtio_set_features_nocheck(vdev, val); ++ ret = virtio_set_features_nocheck(vdev, val); ++ if (!ret && virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { ++ /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */ ++ int i; ++ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { ++ if (vdev->vq[i].vring.num != 0) { ++ virtio_init_region_cache(vdev, i); ++ } ++ } ++ } ++ return ret; + } + + int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Create-block-backends-before-setting-machine-prop.patch b/SOURCES/kvm-vl-Create-block-backends-before-setting-machine-prop.patch new file mode 100644 index 0000000..754a265 --- /dev/null +++ b/SOURCES/kvm-vl-Create-block-backends-before-setting-machine-prop.patch @@ -0,0 +1,71 @@ +From ae3fa9b069ad0e99fda95a34b18c68effe576f85 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:13 +0200 +Subject: [PATCH 46/53] vl: Create block backends before setting machine + properties +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-25-armbru@redhat.com> +Patchwork-id: 87985 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 24/31] vl: Create block backends before setting machine properties +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +qemu-system-FOO's main() acts on command line arguments in its own +idiosyncratic order. There's not much method to its madness. +Whenever we find a case where one kind of command line argument needs +to refer to something created for another kind later, we rejigger the +order. + +Block devices get created long after machine properties get processed. +Therefore, block device machine properties can be created, but not +set. No such properties exist. But the next commit will create some. +Time to rejigger again: create block devices earlier. + +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20190308131445.17502-8-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit cda4aa9a5a08777cf13e164c0543bd4888b8adce) +[Trivial conflict in vl.c due to lack of commit 2d5a3a8b02a] + +Signed-off-by: Miroslav Rezanina +--- + vl.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/vl.c b/vl.c +index e0e60fb..15e87a4 100644 +--- a/vl.c ++++ b/vl.c +@@ -4465,6 +4465,13 @@ int main(int argc, char **argv, char **envp) + exit(0); + } + ++ /* ++ * Note: we need to create block backends before ++ * machine_set_property(), so machine properties can refer to ++ * them. ++ */ ++ configure_blockdev(&bdo_queue, machine_class, snapshot); ++ + machine_opts = qemu_get_machine_opts(); + if (qemu_opt_foreach(machine_opts, machine_set_property, current_machine, + NULL)) { +@@ -4590,8 +4597,6 @@ int main(int argc, char **argv, char **envp) + ram_mig_init(); + dirty_bitmap_mig_init(); + +- configure_blockdev(&bdo_queue, machine_class, snapshot); +- + if (qemu_opts_foreach(qemu_find_opts("mon"), + mon_init_func, NULL, NULL)) { + exit(1); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Factor-configure_blockdev-out-of-main.patch b/SOURCES/kvm-vl-Factor-configure_blockdev-out-of-main.patch new file mode 100644 index 0000000..5afaa54 --- /dev/null +++ b/SOURCES/kvm-vl-Factor-configure_blockdev-out-of-main.patch @@ -0,0 +1,122 @@ +From 8278c1cf3ba3ad55f42ab690a83de66a76ec9316 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:12 +0200 +Subject: [PATCH 45/53] vl: Factor configure_blockdev() out of main() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-24-armbru@redhat.com> +Patchwork-id: 88008 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 23/31] vl: Factor configure_blockdev() out of main() +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Message-Id: <20190308131445.17502-7-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit d11bf9bf0fd66057aa5e8acb1bbc797419d5a4e6) +[Conflict in vl.c due to lack of commit c4f26c9f37c and 7c89fcbac86] + +Signed-off-by: Miroslav Rezanina +--- + vl.c | 72 +++++++++++++++++++++++++++++++++++++++----------------------------- + 1 file changed, 41 insertions(+), 31 deletions(-) + +diff --git a/vl.c b/vl.c +index a5c17a0..e0e60fb 100644 +--- a/vl.c ++++ b/vl.c +@@ -1279,6 +1279,46 @@ typedef struct BlockdevOptionsQueueEntry { + + typedef QSIMPLEQ_HEAD(, BlockdevOptionsQueueEntry) BlockdevOptionsQueue; + ++static void configure_blockdev(BlockdevOptionsQueue *bdo_queue, ++ MachineClass *machine_class, int snapshot) ++{ ++ /* ++ * If the currently selected machine wishes to override the ++ * units-per-bus property of its default HBA interface type, do so ++ * now. ++ */ ++ if (machine_class->units_per_default_bus) { ++ override_max_devs(machine_class->block_default_type, ++ machine_class->units_per_default_bus); ++ } ++ ++ /* open the virtual block devices */ ++ while (!QSIMPLEQ_EMPTY(bdo_queue)) { ++ BlockdevOptionsQueueEntry *bdo = QSIMPLEQ_FIRST(bdo_queue); ++ ++ QSIMPLEQ_REMOVE_HEAD(bdo_queue, entry); ++ loc_push_restore(&bdo->loc); ++ qmp_blockdev_add(bdo->bdo, &error_fatal); ++ loc_pop(&bdo->loc); ++ qapi_free_BlockdevOptions(bdo->bdo); ++ g_free(bdo); ++ } ++ if (snapshot || replay_mode != REPLAY_MODE_NONE) { ++ qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, ++ NULL, NULL); ++ } ++ if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, ++ &machine_class->block_default_type, NULL)) { ++ exit(1); ++ } ++ ++ default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2, ++ CDROM_OPTS); ++ default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); ++ default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); ++ ++} ++ + static QemuOptsList qemu_smp_opts = { + .name = "smp-opts", + .implied_opt_name = "cpus", +@@ -4550,37 +4590,7 @@ int main(int argc, char **argv, char **envp) + ram_mig_init(); + dirty_bitmap_mig_init(); + +- /* If the currently selected machine wishes to override the units-per-bus +- * property of its default HBA interface type, do so now. */ +- if (machine_class->units_per_default_bus) { +- override_max_devs(machine_class->block_default_type, +- machine_class->units_per_default_bus); +- } +- +- /* open the virtual block devices */ +- while (!QSIMPLEQ_EMPTY(&bdo_queue)) { +- BlockdevOptionsQueueEntry *bdo = QSIMPLEQ_FIRST(&bdo_queue); +- +- QSIMPLEQ_REMOVE_HEAD(&bdo_queue, entry); +- loc_push_restore(&bdo->loc); +- qmp_blockdev_add(bdo->bdo, &error_fatal); +- loc_pop(&bdo->loc); +- qapi_free_BlockdevOptions(bdo->bdo); +- g_free(bdo); +- } +- if (snapshot || replay_mode != REPLAY_MODE_NONE) { +- qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, +- NULL, NULL); +- } +- if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, +- &machine_class->block_default_type, NULL)) { +- exit(1); +- } +- +- default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2, +- CDROM_OPTS); +- default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); +- default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); ++ configure_blockdev(&bdo_queue, machine_class, snapshot); + + if (qemu_opts_foreach(qemu_find_opts("mon"), + mon_init_func, NULL, NULL)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Fix-drive-blockdev-persistent-reservation-managem.patch b/SOURCES/kvm-vl-Fix-drive-blockdev-persistent-reservation-managem.patch new file mode 100644 index 0000000..16be6d0 --- /dev/null +++ b/SOURCES/kvm-vl-Fix-drive-blockdev-persistent-reservation-managem.patch @@ -0,0 +1,68 @@ +From 4e62b63ba343036417b227a36a28f9cbf94bdf0c Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Thu, 6 Jun 2019 12:12:44 +0200 +Subject: [PATCH 9/9] vl: Fix -drive / -blockdev persistent reservation + management + +RH-Author: Markus Armbruster +Message-id: <20190606121244.23738-2-armbru@redhat.com> +Patchwork-id: 88604 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] vl: Fix -drive / -blockdev persistent reservation management +Bugzilla: 1714160 +RH-Acked-by: John Snow +RH-Acked-by: Stefano Garzarella +RH-Acked-by: Paolo Bonzini + +qemu-system-FOO's main() acts on command line arguments in its own +idiosyncratic order. There's not much method to its madness. +Whenever we find a case where one kind of command line argument needs +to refer to something created for another kind later, we rejigger the +order. + +Recent commit cda4aa9a5a "vl: Create block backends before setting +machine properties" was such a rejigger. Block backends are now +created before "delayed" objects. This broke persistent reservation +management. Reproducer: + + $ qemu-system-x86_64 -object pr-manager-helper,id=pr-helper0,path=/tmp/pr-helper0.sock-drive -drive file=/dev/mapper/crypt,file.pr-manager=pr-helper0,format=raw,if=none,id=drive-scsi0-0-0-2 + qemu-system-x86_64: -drive file=/dev/mapper/crypt,file.pr-manager=pr-helper0,format=raw,if=none,id=drive-scsi0-0-0-2: No persistent reservation manager with id 'pr-helper0' + +The delayed pr-manager-helper object is created too late for use by +-drive or -blockdev. Normal objects are still created in time. + +pr-manager-helper has always been a delayed object (commit 7c9e527659 +"scsi, file-posix: add support for persistent reservation +management"). Turns out there's no real reason for that. Make it a +normal object. + +Fixes: cda4aa9a5a08777cf13e164c0543bd4888b8adce +Signed-off-by: Markus Armbruster +Message-Id: <20190604151251.9903-2-armbru@redhat.com> +Reviewed-by: Michal Privoznik +Cc: qemu-stable@nongnu.org +Signed-off-by: Paolo Bonzini +(cherry picked from commit 9ea18ed25a36527167e9676f25d983df5e7f76e6) +[Straightforward conflict resolved] + +Signed-off-by: Miroslav Rezanina +--- + vl.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/vl.c b/vl.c +index 61247eb..5b337e1 100644 +--- a/vl.c ++++ b/vl.c +@@ -2926,8 +2926,7 @@ static int machine_set_property(void *opaque, + */ + static bool object_create_initial(const char *type) + { +- if (g_str_equal(type, "rng-egd") || +- g_str_has_prefix(type, "pr-manager-")) { ++ if (g_str_equal(type, "rng-egd")) { + return false; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Fix-latent-bug-with-global-and-onboard-devices.patch b/SOURCES/kvm-vl-Fix-latent-bug-with-global-and-onboard-devices.patch new file mode 100644 index 0000000..5389dc8 --- /dev/null +++ b/SOURCES/kvm-vl-Fix-latent-bug-with-global-and-onboard-devices.patch @@ -0,0 +1,85 @@ +From 55d59dd99ea53889b67956467fb8b25fb57df019 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:09 +0200 +Subject: [PATCH 42/53] vl: Fix latent bug with -global and onboard devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-21-armbru@redhat.com> +Patchwork-id: 87991 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 20/31] vl: Fix latent bug with -global and onboard devices +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +main() registers the user's -global only after we create the machine +object, i.e. too late for devices created in the machine's +.instance_init(). + +Fortunately, we know the bug is only latent: the commit before +previous fixed a bug that would've crashed any attempt to create a +device in an .instance_init(). + +Signed-off-by: Markus Armbruster +Reviewed-by: Marc-André Lureau +Message-Id: <20190308131445.17502-4-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +(cherry picked from commit fc4a473482d595da08ae20ce239f0b62fa55d0f2) +[The commit message's "we know the bug is only latent" part doesn't +apply downstream] + +Signed-off-by: Miroslav Rezanina +--- + vl.c | 19 ++----------------- + 1 file changed, 2 insertions(+), 17 deletions(-) + +diff --git a/vl.c b/vl.c +index 72c489f..d46dff6 100644 +--- a/vl.c ++++ b/vl.c +@@ -3052,17 +3052,6 @@ static void user_register_global_props(void) + global_init_func, NULL, NULL); + } + +-/* +- * Note: we should see that these properties are actually having a +- * priority: accel < machine < user. This means e.g. when user +- * specifies something in "-global", it'll always be used with highest +- * priority than either machine/accelerator compat properties. +- */ +-static void register_global_properties(MachineState *ms) +-{ +- user_register_global_props(); +-} +- + int main(int argc, char **argv, char **envp) + { + int i; +@@ -4119,6 +4108,8 @@ int main(int argc, char **argv, char **envp) + */ + loc_set_none(); + ++ user_register_global_props(); ++ + replay_configure(icount_opts); + + /* Maximum number of CPUs limited for Red Hat Enterprise Linux */ +@@ -4438,12 +4429,6 @@ int main(int argc, char **argv, char **envp) + configure_accelerator(current_machine); + + /* +- * Register all the global properties, including accel properties, +- * machine properties, and user-specified ones. +- */ +- register_global_properties(current_machine); +- +- /* + * Migration object can only be created after global properties + * are applied correctly. + */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Improve-legibility-of-BlockdevOptions-queue.patch b/SOURCES/kvm-vl-Improve-legibility-of-BlockdevOptions-queue.patch new file mode 100644 index 0000000..8fe0616 --- /dev/null +++ b/SOURCES/kvm-vl-Improve-legibility-of-BlockdevOptions-queue.patch @@ -0,0 +1,96 @@ +From edb07556033d42de5dc065d03aef2ea1ae663d8d Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:11 +0200 +Subject: [PATCH 44/53] vl: Improve legibility of BlockdevOptions queue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-23-armbru@redhat.com> +Patchwork-id: 87992 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 22/31] vl: Improve legibility of BlockdevOptions queue +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +Give the queue head type a name: BlockdevOptionsQueue. + +Rename the queue entry type from BlockdevOptions_queue to +BlockdevOptionsQueueEntry. + +Signed-off-by: Markus Armbruster +Message-Id: <20190308131445.17502-6-armbru@redhat.com> +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit 651af51c0882a4c60704716819878043c1b8a215) +Signed-off-by: Miroslav Rezanina +--- + vl.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/vl.c b/vl.c +index d89ac3a..a5c17a0 100644 +--- a/vl.c ++++ b/vl.c +@@ -1271,6 +1271,14 @@ static void default_drive(int enable, int snapshot, BlockInterfaceType type, + + } + ++typedef struct BlockdevOptionsQueueEntry { ++ BlockdevOptions *bdo; ++ Location loc; ++ QSIMPLEQ_ENTRY(BlockdevOptionsQueueEntry) entry; ++} BlockdevOptionsQueueEntry; ++ ++typedef QSIMPLEQ_HEAD(, BlockdevOptionsQueueEntry) BlockdevOptionsQueue; ++ + static QemuOptsList qemu_smp_opts = { + .name = "smp-opts", + .implied_opt_name = "cpus", +@@ -3087,13 +3095,7 @@ int main(int argc, char **argv, char **envp) + Error *err = NULL; + bool list_data_dirs = false; + char *dir, **dirs; +- typedef struct BlockdevOptions_queue { +- BlockdevOptions *bdo; +- Location loc; +- QSIMPLEQ_ENTRY(BlockdevOptions_queue) entry; +- } BlockdevOptions_queue; +- QSIMPLEQ_HEAD(, BlockdevOptions_queue) bdo_queue +- = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); ++ BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); + + module_call_init(MODULE_INIT_TRACE); + +@@ -3224,7 +3226,7 @@ int main(int argc, char **argv, char **envp) + case QEMU_OPTION_blockdev: + { + Visitor *v; +- BlockdevOptions_queue *bdo; ++ BlockdevOptionsQueueEntry *bdo; + + v = qobject_input_visitor_new_str(optarg, "driver", &err); + if (!v) { +@@ -3232,7 +3234,7 @@ int main(int argc, char **argv, char **envp) + exit(1); + } + +- bdo = g_new(BlockdevOptions_queue, 1); ++ bdo = g_new(BlockdevOptionsQueueEntry, 1); + visit_type_BlockdevOptions(v, NULL, &bdo->bdo, + &error_fatal); + visit_free(v); +@@ -4557,7 +4559,7 @@ int main(int argc, char **argv, char **envp) + + /* open the virtual block devices */ + while (!QSIMPLEQ_EMPTY(&bdo_queue)) { +- BlockdevOptions_queue *bdo = QSIMPLEQ_FIRST(&bdo_queue); ++ BlockdevOptionsQueueEntry *bdo = QSIMPLEQ_FIRST(&bdo_queue); + + QSIMPLEQ_REMOVE_HEAD(&bdo_queue, entry); + loc_push_restore(&bdo->loc); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Prepare-fix-of-latent-bug-with-global-and-onboard.patch b/SOURCES/kvm-vl-Prepare-fix-of-latent-bug-with-global-and-onboard.patch new file mode 100644 index 0000000..f7be97b --- /dev/null +++ b/SOURCES/kvm-vl-Prepare-fix-of-latent-bug-with-global-and-onboard.patch @@ -0,0 +1,113 @@ +From fee69ca995ff34fc343fa3e0f57aab5f0e5f7351 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 17 May 2019 06:51:08 +0200 +Subject: [PATCH 41/53] vl: Prepare fix of latent bug with -global and onboard + devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20190517065120.12028-20-armbru@redhat.com> +Patchwork-id: 87980 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v3 19/31] vl: Prepare fix of latent bug with -global and onboard devices +Bugzilla: 1624009 +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +main() registers the user's -global only after we create the machine +object, i.e. too late for devices created in the machine's +.instance_init(). The next commit is upstream's fix. To make it +apply, we need to move machine and accelerator compat property +creation out of register_global_properties(), so its MachineState +parameter becomes unused. + +Create machine compat props right after select_machine(). Create +accelerator compat props in accel_init_machine(). In both cases, this +creates them as early as possible, and exactly where upstream creates +them since commit 1a3ec8c1564. Note that their relative order remains +unchanged; machine compat props still override accelerator compat +props. + +Why not backport commit 1a3ec8c1564 instead? That commit fixes a +latent bug in upstream's reorganization of compat properties (merge +commit 31ed41889e6). It has a bug fixed up in commit 79b9d4bde7d. It +doesn't apply without the reorganization. This commit reimplements +enough of the two commits (without fixing any bugs) to make the +remainder of the upstream series apply cleanly. + +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + accel/accel.c | 2 ++ + hw/core/machine.c | 3 +-- + include/hw/boards.h | 2 +- + vl.c | 3 +-- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/accel/accel.c b/accel/accel.c +index 124f957..2e0bff5 100644 +--- a/accel/accel.c ++++ b/accel/accel.c +@@ -64,6 +64,8 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms) + ms->accelerator = NULL; + *(acc->allowed) = false; + object_unref(OBJECT(accel)); ++ } else { ++ accel_register_compat_props(ms->accelerator); + } + return ret; + } +diff --git a/hw/core/machine.c b/hw/core/machine.c +index b4804e9..e5b8881 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -839,9 +839,8 @@ static void machine_class_finalize(ObjectClass *klass, void *data) + g_free(mc->name); + } + +-void machine_register_compat_props(MachineState *machine) ++void machine_register_compat_props(MachineClass *mc) + { +- MachineClass *mc = MACHINE_GET_CLASS(machine); + int i; + GlobalProperty *p; + +diff --git a/include/hw/boards.h b/include/hw/boards.h +index a609239..cf24cbf 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -70,7 +70,7 @@ int machine_kvm_shadow_mem(MachineState *machine); + int machine_phandle_start(MachineState *machine); + bool machine_dump_guest_core(MachineState *machine); + bool machine_mem_merge(MachineState *machine); +-void machine_register_compat_props(MachineState *machine); ++void machine_register_compat_props(MachineClass *mc); + HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine); + void machine_set_cpu_numa_node(MachineState *machine, + const CpuInstanceProperties *props, +diff --git a/vl.c b/vl.c +index a22da93..72c489f 100644 +--- a/vl.c ++++ b/vl.c +@@ -3060,8 +3060,6 @@ static void user_register_global_props(void) + */ + static void register_global_properties(MachineState *ms) + { +- accel_register_compat_props(ms->accelerator); +- machine_register_compat_props(ms); + user_register_global_props(); + } + +@@ -4127,6 +4125,7 @@ int main(int argc, char **argv, char **envp) + limit_max_cpus_in_machines(); + + machine_class = select_machine(); ++ machine_register_compat_props(machine_class); + + set_memory_options(&ram_slots, &maxram_size, machine_class); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vnc-call-sasl_server_init-only-when-required.patch b/SOURCES/kvm-vnc-call-sasl_server_init-only-when-required.patch new file mode 100644 index 0000000..2f80000 --- /dev/null +++ b/SOURCES/kvm-vnc-call-sasl_server_init-only-when-required.patch @@ -0,0 +1,84 @@ +From cf93ce54ee801dca9d9da7dd10557b8772418520 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Thu, 22 Nov 2018 18:34:50 +0100 +Subject: [PATCH 01/34] vnc: call sasl_server_init() only when required +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20181122183450.719-2-marcandre.lureau@redhat.com> +Patchwork-id: 83099 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] vnc: call sasl_server_init() only when required +Bugzilla: 1614302 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Philippe Mathieu-Daudé +RH-Acked-by: Markus Armbruster + +VNC server is calling sasl_server_init() during startup of QEMU, even +if SASL auth has not been enabled. + +This may create undesirable warnings like "Could not find keytab file: +/etc/qemu/krb5.tab" when the user didn't configure SASL on host and +started VNC server. + +Instead, only initialize SASL when needed. Note that HMP/QMP "change +vnc" calls vnc_display_open() again, which will initialize SASL if +needed. + +Fix assignment in if condition, while touching this code. + +Related to: +https://bugzilla.redhat.com/show_bug.cgi?id=1609327 + +Signed-off-by: Marc-André Lureau +Reviewed-by: Daniel P. Berrangé +Message-id: 20180907063634.359-1-marcandre.lureau@redhat.com +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit b5dc0d7d565048fcf2767060261d8385805aced1) + +[ Fix minor confict due to "qemu" vs "qemu-kvm" string difference ] +Signed-off-by: Marc-André Lureau + +Signed-off-by: Miroslav Rezanina +--- + ui/vnc.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/ui/vnc.c b/ui/vnc.c +index 0c3011b..86c6762 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -3869,9 +3869,6 @@ void vnc_display_open(const char *id, Error **errp) + bool reverse = false; + const char *credid; + bool sasl = false; +-#ifdef CONFIG_VNC_SASL +- int saslErr; +-#endif + int acl = 0; + int lock_key_sync = 1; + int key_delay_ms; +@@ -4045,10 +4042,14 @@ void vnc_display_open(const char *id, Error **errp) + trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth); + + #ifdef CONFIG_VNC_SASL +- if ((saslErr = sasl_server_init(NULL, "qemu-kvm")) != SASL_OK) { +- error_setg(errp, "Failed to initialize SASL auth: %s", +- sasl_errstring(saslErr, NULL, NULL)); +- goto fail; ++ if (sasl) { ++ int saslErr = sasl_server_init(NULL, "qemu-kvm"); ++ ++ if (saslErr != SASL_OK) { ++ error_setg(errp, "Failed to initialize SASL auth: %s", ++ sasl_errstring(saslErr, NULL, NULL)); ++ goto fail; ++ } + } + #endif + vd->lock_key_sync = lock_key_sync; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-x86-cpu-Enable-CLDEMOTE-Demote-Cache-Line-cpu-featur.patch b/SOURCES/kvm-x86-cpu-Enable-CLDEMOTE-Demote-Cache-Line-cpu-featur.patch new file mode 100644 index 0000000..c5c8e52 --- /dev/null +++ b/SOURCES/kvm-x86-cpu-Enable-CLDEMOTE-Demote-Cache-Line-cpu-featur.patch @@ -0,0 +1,71 @@ +From 45be760eda02e18ac33b603224a47b3954bfb762 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Mon, 4 Feb 2019 17:31:05 +0100 +Subject: [PATCH 01/12] x86/cpu: Enable CLDEMOTE(Demote Cache Line) cpu feature + +RH-Author: plai@redhat.com +Message-id: <1549301465-19852-1-git-send-email-plai@redhat.com> +Patchwork-id: 84206 +O-Subject: [RHEL7.7 qemu-kvm-rhev PATCH BZ 1537776 RESEND] x86/cpu: Enable CLDEMOTE(Demote Cache Line) cpu feature +Bugzilla: 1537776 +RH-Acked-by: Bandan Das +RH-Acked-by: Eduardo Habkost +RH-Acked-by: John Snow + +The CLDEMOTE instruction hints to hardware that the cache line that +contains the linear address should be moved("demoted") from +the cache(s) closest to the processor core to a level more distant +from the processor core. This may accelerate subsequent accesses +to the line by other cores in the same coherence domain, +especially if the line was written by the core that demotes the line. + +Intel Snow Ridge has added new cpu feature, CLDEMOTE. +The new cpu feature needs to be exposed to guest VM. + +The bit definition: +CPUID.(EAX=7,ECX=0):ECX[bit 25] CLDEMOTE + +The release document ref below link: +https://software.intel.com/sites/default/files/managed/c5/15/\ +architecture-instruction-set-extensions-programming-reference.pdf + +Signed-off-by: Jingqi Liu +Message-Id: <1525406253-54846-1-git-send-email-jingqi.liu@intel.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit 0da0fb062841d0dcd8ba47e4a989d2e952cdf0ff) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index c5156c8..4558b1a 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -991,7 +991,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "avx512bitalg", NULL, "avx512-vpopcntdq", NULL, + "la57", NULL, NULL, NULL, + NULL, NULL, "rdpid", NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "cldemote", NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid_eax = 7, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 392065d..ea8c355 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -682,6 +682,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_ECX_AVX512_VPOPCNTDQ (1U << 14) /* POPCNT for vectors of DW/QW */ + #define CPUID_7_0_ECX_LA57 (1U << 16) + #define CPUID_7_0_ECX_RDPID (1U << 22) ++#define CPUID_7_0_ECX_CLDEMOTE (1U << 25) /* CLDEMOTE Instruction */ + + #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ + #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-x86-host-phys-bits-limit-option.patch b/SOURCES/kvm-x86-host-phys-bits-limit-option.patch new file mode 100644 index 0000000..7bf79d6 --- /dev/null +++ b/SOURCES/kvm-x86-host-phys-bits-limit-option.patch @@ -0,0 +1,96 @@ +From 714c0396845fe74f8ccb9a72a7f0ab6753248e6e Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 11 Apr 2019 21:48:45 +0200 +Subject: [PATCH 159/163] x86: host-phys-bits-limit option + +RH-Author: Eduardo Habkost +Message-id: <20190411214846.8816-2-ehabkost@redhat.com> +Patchwork-id: 85608 +O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/2] x86: host-phys-bits-limit option +Bugzilla: 1691519 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Dr. David Alan Gilbert + +Some downstream distributions of QEMU set host-phys-bits=on by +default. This worked very well for most use cases, because +phys-bits really didn't have huge consequences. The only +difference was on the CPUID data seen by guests, and on the +handling of reserved bits. + +This changed in KVM commit 855feb673640 ("KVM: MMU: Add 5 level +EPT & Shadow page table support"). Now choosing a large +phys-bits value for a VM has bigger impact: it will make KVM use +5-level EPT even when it's not really necessary. This means +using the host phys-bits value may not be the best choice. + +Management software could address this problem by manually +configuring phys-bits depending on the size of the VM and the +amount of MMIO address space required for hotplug. But this is +not trivial to implement. + +However, there's another workaround that would work for most +cases: keep using the host phys-bits value, but only if it's +smaller than 48. This patch makes this possible by introducing a +new "-cpu" option: "host-phys-bits-limit". Management software +or users can make sure they will always use 4-level EPT using: +"host-phys-bits=on,host-phys-bits-limit=48". + +This behavior is still not enabled by default because QEMU +doesn't enable host-phys-bits=on by default. But users, +management software, or downstream distributions may choose to +change their defaults using the new option. + +Signed-off-by: Eduardo Habkost +Message-Id: <20181211192527.13254-1-ehabkost@redhat.com> +[ehabkost: removed test code while some issues are addressed] +Signed-off-by: Eduardo Habkost +(cherry picked from commit 258fe08bd341d2e230676228307294e41f33002c) +Signed-off-by: Eduardo Habkost + +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 5 +++++ + target/i386/cpu.h | 3 +++ + 2 files changed, 8 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 2f6d5f4..c5156c8 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4826,6 +4826,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + if (cpu->host_phys_bits) { + /* The user asked for us to use the host physical bits */ + cpu->phys_bits = host_phys_bits; ++ if (cpu->host_phys_bits_limit && ++ cpu->phys_bits > cpu->host_phys_bits_limit) { ++ cpu->phys_bits = cpu->host_phys_bits_limit; ++ } + } + + /* Print a warning if the user set it to a value that's not the +@@ -5377,6 +5381,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), + DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0), + DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), ++ DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0), + DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), + DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX), + DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, UINT32_MAX), +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 75cf5ed..392065d 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1419,6 +1419,9 @@ struct X86CPU { + /* if true override the phys_bits value with a value read from the host */ + bool host_phys_bits; + ++ /* if set, limit maximum value for phys_bits when host_phys_bits is true */ ++ uint8_t host_phys_bits_limit; ++ + /* Stop SMI delivery for migration compatibility with old machines */ + bool kvm_no_smi_migration; + +-- +1.8.3.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 21ca722..e372a7f 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -108,7 +108,7 @@ Obsoletes: %1%{rhel_ma_suffix} < %{obsoletes_version2} \ Summary: QEMU is a machine emulator and virtualizer Name: %{pkgname}%{?pkgsuffix} Version: 2.12.0 -Release: 18%{?dist}.4 +Release: 33%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 License: GPLv2 and GPLv2+ and CC-BY @@ -1114,39 +1114,746 @@ Patch478: kvm-test-bdrv-drain-Fix-outdated-comments.patch Patch479: kvm-block-Use-a-single-global-AioWait.patch # For bz#1618584 - block commit aborts with "Co-routine was already scheduled" Patch480: kvm-test-bdrv-drain-Test-draining-job-source-child-and-p.patch -# For bz#1672919 - Trying to start a guest with hugetlbfs backing does not bail out so providing saying that hugetlbfs is not supported before actually trying to start the guest. [rhel-7.6.z] -Patch481: kvm-s390x-refuse-to-start-guests-backed-by-hugetlbfs.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch482: kvm-s390x-tcg-avoid-overflows-in-time2tod-tod2time.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch483: kvm-s390x-kvm-pass-values-instead-of-pointers-to-kvm_s39.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch484: kvm-s390x-tod-factor-out-TOD-into-separate-device.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch485: kvm-s390x-tcg-drop-tod_basetime.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch486: kvm-s390x-tcg-properly-implement-the-TOD.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch487: kvm-s390x-tcg-SET-CLOCK-COMPARATOR-can-clear-CKC-interru.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch488: kvm-s390x-tcg-implement-SET-CLOCK.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch489: kvm-s390x-tcg-rearm-the-CKC-timer-during-migration.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch490: kvm-s390x-tcg-fix-locking-problem-with-tcg_s390_tod_upda.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch491: kvm-hw-s390x-Include-the-tod-qemu-also-for-builds-with-d.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch492: kvm-s390x-tod-Properly-stop-the-KVM-TOD-while-the-guest-.patch -# For bz#1672920 - Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z] -Patch493: kvm-hw-s390x-Fix-bad-mask-in-time2tod.patch -# For bz#1667843 - RHEL-Alt-7.6 - Backport diag308 stable exception fix (qemu-kvm-ma) -# For bz#1668424 - RHEL-Alt-7.6 - Backport diag308 stable exception fix (qemu-kvm-ma) [rhel-7.6.z] -Patch494: kvm-s390x-Return-specification-exception-for-unimplement.patch -# For bz#1693112 - CVE-2018-20815 qemu-kvm-ma: QEMU: device_tree: heap buffer overflow while loading device tree blob [rhel-7.6.z] -Patch495: kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch -# For bz#1720262 - RHEL-Alt-7.6 - QEMU toleration patch to ensure cpu detection in a nested KVM [rhel-7.6.z] -Patch496: kvm-s390x-cpumodel-ignore-csske-for-expansion.patch +# For bz#1638077 - Cross migration from RHEL7.5 to RHEL7.6 fails with cpu flag stibp [rhel-7.6.z] +Patch481: kvm-target-i386-cpu-Add-downstream-only-STIBP-CPUID-flag.patch +# For bz#1638835 - High Host CPU load for Windows 10 Guests (Update 1803) when idle [rhel-7.6.z] +Patch482: kvm-Re-enable-disabled-Hyper-V-enlightenments.patch +# For bz#1636148 - qemu NBD_CMD_CACHE flaws impacting non-qemu NBD clients +Patch483: kvm-nbd-server-fix-NBD_CMD_CACHE.patch +# For bz#1636148 - qemu NBD_CMD_CACHE flaws impacting non-qemu NBD clients +Patch484: kvm-nbd-fix-NBD_FLAG_SEND_CACHE-value.patch +# For bz#1629720 - [Intel 7.6 BUG][Crystal Ridge] pc_dimm_get_free_addr: assertion failed: (QEMU_ALIGN_UP(address_space_start, align) == address_space_start) +Patch485: kvm-pc-dimm-turn-alignment-assert-into-check.patch +# For bz#1629717 - qemu_ram_mmap: Assertion `is_power_of_2(align)' failed +Patch486: kvm-exec-check-that-alignment-is-a-power-of-two.patch +# For bz#1620373 - Failed to do migration after hotplug and hotunplug the ivshmem device +Patch487: kvm-nvdimm-no-need-to-overwrite-get_vmstate_memory_regio.patch +# For bz#1620373 - Failed to do migration after hotplug and hotunplug the ivshmem device +Patch488: kvm-hostmem-drop-error-variable-from-host_memory_backend.patch +# For bz#1620373 - Failed to do migration after hotplug and hotunplug the ivshmem device +Patch489: kvm-ivshmem-Fix-unplug-of-device-ivshmem-plain.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch490: kvm-qemu-error-introduce-error-warn-_report_once.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch491: kvm-intel-iommu-start-to-use-error_report_once.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch492: kvm-intel-iommu-replace-more-vtd_err_-traces.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch493: kvm-intel_iommu-introduce-vtd_reset_caches.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch494: kvm-intel_iommu-better-handling-of-dmar-state-switch.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch495: kvm-intel_iommu-move-ce-fetching-out-when-sync-shadow.patch +# For bz#1627272 - boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest +Patch496: kvm-intel_iommu-handle-invalid-ce-for-shadow-sync.patch +# For bz#1607406 - [RHEL 7.7] RFE: Define firmware metadata format +Patch497: kvm-qapi-fill-in-CpuInfoFast.arch-in-query-cpus-fast.patch +# For bz#1607406 - [RHEL 7.7] RFE: Define firmware metadata format +Patch498: kvm-qapi-add-SysEmuTarget-to-common.json.patch +# For bz#1607406 - [RHEL 7.7] RFE: Define firmware metadata format +Patch499: kvm-qapi-change-the-type-of-TargetInfo.arch-from-string-.patch +# For bz#1607406 - [RHEL 7.7] RFE: Define firmware metadata format +Patch500: kvm-qapi-discriminate-CpuInfoFast-on-SysEmuTarget-not-Cp.patch +# For bz#1607406 - [RHEL 7.7] RFE: Define firmware metadata format +Patch501: kvm-qapi-deprecate-CpuInfoFast.arch.patch +# For bz#1607406 - [RHEL 7.7] RFE: Define firmware metadata format +Patch502: kvm-docs-interop-add-firmware.json.patch +# For bz#1608877 - After postcopy migration, do savevm and loadvm, guest hang and call trace +Patch503: kvm-migration-postcopy-Clear-have_listen_thread.patch +# For bz#1608877 - After postcopy migration, do savevm and loadvm, guest hang and call trace +Patch504: kvm-migration-cleanup-in-error-paths-in-loadvm.patch +# For bz#1614302 - qemu-kvm: Could not find keytab file: /etc/qemu/krb5.tab: No such file or directory +Patch505: kvm-vnc-call-sasl_server_init-only-when-required.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch506: kvm-block-Update-flags-in-bdrv_set_read_only.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch507: kvm-block-Add-auto-read-only-option.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch508: kvm-rbd-Close-image-in-qemu_rbd_open-error-path.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch509: kvm-block-Require-auto-read-only-for-existing-fallbacks.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch510: kvm-nbd-Support-auto-read-only-option.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch511: kvm-file-posix-Support-auto-read-only-option.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch512: kvm-curl-Support-auto-read-only-option.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch513: kvm-gluster-Support-auto-read-only-option.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch514: kvm-iscsi-Support-auto-read-only-option.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch515: kvm-block-Make-auto-read-only-on-default-for-drive.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch516: kvm-qemu-iotests-Test-auto-read-only-with-drive-and-bloc.patch +# For bz#1623986 - block-commit can't be used with -blockdev +Patch517: kvm-block-Fix-update-of-BDRV_O_AUTO_RDONLY-in-update_fla.patch +# For bz#1585155 - QEMU core dumped when hotplug memory exceeding host hugepages and with discard-data=yes +Patch518: kvm-memory-cleanup-side-effects-of-memory_region_init_fo.patch +# For bz#1633536 - Qemu core dump when do migration after hot plugging a backend image with 'blockdev-add'(without the frontend) +Patch519: kvm-block-Don-t-inactivate-children-before-parents.patch +# For bz#1633536 - Qemu core dump when do migration after hot plugging a backend image with 'blockdev-add'(without the frontend) +Patch520: kvm-iotests-Test-migration-with-blockdev.patch +# For bz#1607768 - qemu aborted when start guest with a big iothreads +Patch521: kvm-iothread-fix-crash-with-invalid-properties.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch522: kvm-balloon-Allow-multiple-inhibit-users.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch523: kvm-Use-inhibit-to-prevent-ballooning-without-synchr.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch524: kvm-vfio-Inhibit-ballooning-based-on-group-attachment-to.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch525: kvm-vfio-ccw-pci-Allow-devices-to-opt-in-for-ballooning.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch526: kvm-vfio-pci-Handle-subsystem-realpath-returning-NULL.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch527: kvm-vfio-pci-Fix-failure-to-close-file-descriptor-on-err.patch +# For bz#1619778 - Ballooning is incompatible with vfio assigned devices, but not prevented +Patch528: kvm-postcopy-Synchronize-usage-of-the-balloon-inhibitor.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch529: kvm-include-Add-IEC-binary-prefixes-in-qemu-units.h.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch530: kvm-hw-scsi-cleanups-before-VPD-BL-emulation.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch531: kvm-hw-scsi-centralize-SG_IO-calls-into-single-function.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch532: kvm-hw-scsi-add-VPD-Block-Limits-emulation.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch533: kvm-scsi-disk-Block-Device-Characteristics-emulation-fix.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch534: kvm-scsi-generic-keep-VPD-page-list-sorted.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch535: kvm-scsi-generic-avoid-out-of-bounds-access-to-VPD-page-.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch536: kvm-scsi-generic-avoid-invalid-access-to-struct-when-emu.patch +# For bz#1566195 - Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i) +Patch537: kvm-scsi-generic-do-not-do-VPD-emulation-for-sense-other.patch +# For bz#1626347 - RHEL7.6 - [Power8][Host: 3.10.0-933.el7.ppc64le][Guest: 3.10.0-933.el7.ppc64le] [qemu-kvm-ma-2.12.0-8.el7.ppc64le] Guest VM crashes during vcpu hotplug with specific numa configuration (kvm) +Patch538: kvm-spapr-Fix-ibm-max-associativity-domains-property-num.patch +# For bz#1626347 - RHEL7.6 - [Power8][Host: 3.10.0-933.el7.ppc64le][Guest: 3.10.0-933.el7.ppc64le] [qemu-kvm-ma-2.12.0-8.el7.ppc64le] Guest VM crashes during vcpu hotplug with specific numa configuration (kvm) +Patch539: kvm-spapr-Add-H-Call-H_HOME_NODE_ASSOCIATIVITY.patch +# For bz#1628098 - [Intel 7.7 BUG][KVM][Crystal Ridge]object_get_canonical_path_component: assertion failed: (obj->parent != NULL) +Patch540: kvm-hostmem-file-remove-object-id-from-pmem-error-messag.patch +# For bz#1614610 - Guest quit with error when hotunplug cpu +Patch541: kvm-cpus-ignore-ESRCH-in-qemu_cpu_kick_thread.patch +# For bz#1658426 - qemu core dumped when doing incremental live backup without "bitmap" parameter by mistake in a transaction mode((blockdev-backup/block-dirty-bitmap-add/x-block-dirty-bitmap-merge) +Patch542: kvm-blockdev-abort-transactions-in-reverse-order.patch +# For bz#1658426 - qemu core dumped when doing incremental live backup without "bitmap" parameter by mistake in a transaction mode((blockdev-backup/block-dirty-bitmap-add/x-block-dirty-bitmap-merge) +Patch543: kvm-block-dirty-bitmap-remove-assertion-from-restore.patch +# For bz#1531888 - Local VM and migrated VM on the same host can run with same RAW file as visual disk source while without shareable configured or lock manager enabled +Patch544: kvm-block-Fix-invalidate_cache-error-path-for-parent-act.patch +# For bz#1598119 - "share-rw=on" does not work for luks format image +Patch545: kvm-luks-Allow-share-rw-on.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch546: kvm-iotests-153-Fix-dead-code.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch547: kvm-file-posix-Include-filename-in-locking-error-message.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch548: kvm-file-posix-Skip-effectiveless-OFD-lock-operations.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch549: kvm-file-posix-Drop-s-lock_fd.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch550: kvm-tests-Add-unit-tests-for-image-locking.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch551: kvm-file-posix-Fix-shared-locks-on-reopen-commit.patch +# For bz#1551486 - QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd) +Patch552: kvm-iotests-Test-file-posix-locking-and-reopen.patch +# For bz#1673080 - "An unknown error has occurred" when using cdrom to install the system with two blockdev disks.(when choose installation destination) +Patch553: kvm-scsi-disk-Don-t-use-empty-string-as-device-id.patch +# For bz#1673080 - "An unknown error has occurred" when using cdrom to install the system with two blockdev disks.(when choose installation destination) +Patch554: kvm-scsi-disk-Add-device_id-property.patch +# For bz#1668999 - CVE-2019-6501 qemu-kvm-rhev: QEMU: scsi-generic: possible OOB access while handling inquiry request [rhel-7] +Patch555: kvm-scsi-generic-avoid-possible-out-of-bounds-access-to-.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch556: kvm-block-remove-bdrv_dirty_bitmap_make_anon.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch557: kvm-block-simplify-code-around-releasing-bitmaps.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch558: kvm-hbitmap-Add-advance-param-to-hbitmap_iter_next.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch559: kvm-test-hbitmap-Add-non-advancing-iter_next-tests.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch560: kvm-block-dirty-bitmap-Add-bdrv_dirty_iter_next_area.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch561: kvm-dirty-bitmap-switch-assert-fails-to-errors-in-bdrv_m.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch562: kvm-dirty-bitmap-rename-bdrv_undo_clear_dirty_bitmap.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch563: kvm-dirty-bitmap-make-it-possible-to-restore-bitmap-afte.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch564: kvm-blockdev-rename-block-dirty-bitmap-clear-transaction.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch565: kvm-qapi-add-transaction-support-for-x-block-dirty-bitma.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch566: kvm-block-dirty-bitmaps-add-user_locked-status-checker.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch567: kvm-block-dirty-bitmaps-fix-merge-permissions.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch568: kvm-block-dirty-bitmaps-allow-clear-on-disabled-bitmaps.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch569: kvm-block-dirty-bitmaps-prohibit-enable-disable-on-locke.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch570: kvm-block-backup-prohibit-backup-from-using-in-use-bitma.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch571: kvm-nbd-forbid-use-of-frozen-bitmaps.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch572: kvm-bitmap-Update-count-after-a-merge.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch573: kvm-iotests-169-drop-deprecated-autoload-parameter.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch574: kvm-block-qcow2-improve-error-message-in-qcow2_inactivat.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch575: kvm-bloc-qcow2-drop-dirty_bitmaps_loaded-state-variable.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch576: kvm-dirty-bitmaps-clean-up-bitmaps-loading-and-migration.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch577: kvm-iotests-improve-169.patch +# For bz#1658343 - QEMU incremental backup fixes and improvements (from upstream and in RHEL8) +Patch578: kvm-iotests-169-add-cases-for-source-vm-resuming.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch579: kvm-exec-move-memory-access-declarations-to-a-common-hea.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch580: kvm-exec-small-changes-to-flatview_do_translate.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch581: kvm-exec-extract-address_space_translate_iommu-fix-page_.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch582: kvm-exec-reintroduce-MemoryRegion-caching.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch583: kvm-virtio-update-MemoryRegionCaches-when-guest-negotiat.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch584: kvm-exec-Fix-MAP_RAM-for-cached-access.patch +# For bz#1597482 - qemu crashed when disk enable the IOMMU +Patch585: kvm-virtio-Return-true-from-virtio_queue_empty-if-broken.patch +# For bz#1631615 - Wrong werror default for -device drive= +Patch586: kvm-block-backend-Set-werror-rerror-defaults-in-blk_new.patch +# For bz#1667320 - -blockdev: auto-read-only is ineffective for drivers on read-only whitelist +Patch587: kvm-block-Apply-auto-read-only-for-ro-whitelist-drivers.patch +# For bz#1656913 - qcow2 cache is too small +Patch588: kvm-qcow2-Give-the-refcount-cache-the-minimum-possible-s.patch +# For bz#1656913 - qcow2 cache is too small +Patch589: kvm-docs-Document-the-new-default-sizes-of-the-qcow2-cac.patch +# For bz#1656913 - qcow2 cache is too small +Patch590: kvm-qcow2-Fix-Coverity-warning-when-calculating-the-refc.patch +# For bz#1656913 - qcow2 cache is too small +Patch591: kvm-qcow2-Options-documentation-fixes.patch +# For bz#1656913 - qcow2 cache is too small +Patch592: kvm-include-Add-a-lookup-table-of-sizes.patch +# For bz#1656913 - qcow2 cache is too small +Patch593: kvm-qcow2-Make-sizes-more-humanly-readable.patch +# For bz#1656913 - qcow2 cache is too small +Patch594: kvm-qcow2-Avoid-duplication-in-setting-the-refcount-cach.patch +# For bz#1656913 - qcow2 cache is too small +Patch595: kvm-qcow2-Assign-the-L2-cache-relatively-to-the-image-si.patch +# For bz#1656913 - qcow2 cache is too small +Patch596: kvm-qcow2-Increase-the-default-upper-limit-on-the-L2-cac.patch +# For bz#1656913 - qcow2 cache is too small +Patch597: kvm-qcow2-Resize-the-cache-upon-image-resizing.patch +# For bz#1656913 - qcow2 cache is too small +Patch598: kvm-qcow2-Set-the-default-cache-clean-interval-to-10-min.patch +# For bz#1656913 - qcow2 cache is too small +Patch599: kvm-qcow2-Explicit-number-replaced-by-a-constant.patch +# For bz#1656913 - qcow2 cache is too small +Patch600: kvm-qcow2-Fix-cache-clean-interval-documentation.patch +# For bz#1671173 - qemu with iothreads enabled crashes on resume after enospc pause for disk extension +Patch601: kvm-block-backend-Make-blk_inc-dec_in_flight-public.patch +# For bz#1671173 - qemu with iothreads enabled crashes on resume after enospc pause for disk extension +Patch602: kvm-virtio-blk-Increase-in_flight-for-request-restart-BH.patch +# For bz#1671173 - qemu with iothreads enabled crashes on resume after enospc pause for disk extension +Patch603: kvm-block-Fix-AioContext-switch-for-drained-node.patch +# For bz#1671173 - qemu with iothreads enabled crashes on resume after enospc pause for disk extension +Patch604: kvm-test-bdrv-drain-AioContext-switch-in-drained-section.patch +# For bz#1671173 - qemu with iothreads enabled crashes on resume after enospc pause for disk extension +Patch605: kvm-block-Use-normal-drain-for-bdrv_set_aio_context.patch +# For bz#1648236 - QEMU doesn't expose rendernode option for egl-headless display type +Patch606: kvm-qapi-Add-rendernode-display-option-for-egl-headless.patch +# For bz#1648236 - QEMU doesn't expose rendernode option for egl-headless display type +Patch607: kvm-ui-Allow-specifying-rendernode-display-option-for-eg.patch +# For bz#1648236 - QEMU doesn't expose rendernode option for egl-headless display type +Patch608: kvm-qapi-add-query-display-options-command.patch +# For bz#1648236 - QEMU doesn't expose rendernode option for egl-headless display type +Patch609: kvm-egl-headless-parse-rendernode.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch610: kvm-tests-virtio-blk-test-Disable-auto-read-only.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch611: kvm-block-Avoid-useless-local_err.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch612: kvm-block-Simplify-bdrv_reopen_abort.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch613: kvm-block-Always-abort-reopen-after-prepare-succeeded.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch614: kvm-block-Make-permission-changes-in-reopen-less-wrong.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch615: kvm-block-Fix-use-after-free-error-in-bdrv_open_inherit.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch616: kvm-qemu-iotests-Test-snapshot-on-with-nonexistent-TMPDI.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch617: kvm-file-posix-Fix-bdrv_open_flags-for-snapshot-on.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch618: kvm-file-posix-Use-error-API-properly.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch619: kvm-file-posix-Factor-out-raw_reconfigure_getfd.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch620: kvm-file-posix-Store-BDRVRawState.reopen_state-during-re.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch621: kvm-file-posix-Lock-new-fd-in-raw_reopen_prepare.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch622: kvm-file-posix-Prepare-permission-code-for-fd-switching.patch +# For bz#1685989 - Add facility to use block jobs with backing images without write permission +Patch623: kvm-file-posix-Make-auto-read-only-dynamic.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch624: kvm-qapi-bitmap-merge-document-name-change.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch625: kvm-iotests-Enhance-223-to-cover-multiple-bitmap-granula.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch626: kvm-iotests-Unify-log-outputs-between-Python-2-and-3.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch627: kvm-blockdev-n-ary-bitmap-merge.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch628: kvm-block-remove-x-prefix-from-experimental-bitmap-APIs.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch629: kvm-iotests.py-don-t-abort-if-IMGKEYSECRET-is-undefined.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch630: kvm-iotests-add-filter_generated_node_ids.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch631: kvm-iotests-add-qmp-recursive-sorting-function.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch632: kvm-iotests-remove-default-filters-from-qmp_log.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch633: kvm-iotests-change-qmp_log-filters-to-expect-QMP-objects.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch634: kvm-iotests-implement-pretty-print-for-log-and-qmp_log.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch635: kvm-iotests-add-iotest-236-for-testing-bitmap-merge.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch636: kvm-iotests-236-fix-transaction-kwarg-order.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch637: kvm-iotests-Re-add-filename-filters.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch638: kvm-iotests-Remove-superfluous-rm-from-232.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch639: kvm-iotests-Fix-232-for-LUKS.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch640: kvm-iotests-Fix-207-to-use-QMP-filters-for-qmp_log.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch641: kvm-iotests.py-Add-is_str.patch +# For bz#1668956 - incremental backup bitmap API needs a finalized interface +Patch642: kvm-iotests.py-Filter-filename-in-any-string-value.patch +# For bz#1691018 - Fix iotest 226 for local development builds +Patch643: kvm-iotest-Fix-filtering-order-in-226.patch +# For bz#1691018 - Fix iotest 226 for local development builds +Patch644: kvm-iotests-Don-t-lock-dev-null-in-226.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch645: kvm-dirty-bitmap-improve-bdrv_dirty_bitmap_next_zero.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch646: kvm-tests-add-tests-for-hbitmap_next_zero-with-specified.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch647: kvm-dirty-bitmap-add-bdrv_dirty_bitmap_next_dirty_area.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch648: kvm-tests-add-tests-for-hbitmap_next_dirty_area.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch649: kvm-Revert-block-dirty-bitmap-Add-bdrv_dirty_iter_next_a.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch650: kvm-Revert-test-hbitmap-Add-non-advancing-iter_next-test.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch651: kvm-Revert-hbitmap-Add-advance-param-to-hbitmap_iter_nex.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch652: kvm-bdrv_query_image_info-Error-parameter-added.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch653: kvm-qcow2-Add-list-of-bitmaps-to-ImageInfoSpecificQCow2.patch +# For bz#1691048 - Add qemu-img info support for querying bitmaps offline +Patch654: kvm-qcow2-list-of-bitmaps-new-test-242.patch +# For bz#1672010 - [RHEL7]Qemu coredump when remove a persistent bitmap after vm re-start(dataplane enabled) +Patch655: kvm-blockdev-acquire-aio_context-for-bitmap-add-remove.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch656: kvm-nbd-client-fix-nbd_negotiate_simple_meta_context.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch657: kvm-nbd-client-Fix-error-messages-during-NBD_INFO_BLOCK_.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch658: kvm-nbd-client-Relax-handling-of-large-NBD_CMD_BLOCK_STA.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch659: kvm-tests-Simplify-.gitignore.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch660: kvm-iotests-nbd-Stop-qemu-nbd-before-remaking-image.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch661: kvm-iotests-Disallow-compat-0.10-in-223.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch662: kvm-nbd-server-fix-bitmap-export.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch663: kvm-nbd-server-send-more-than-one-extent-of-base-allocat.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch664: kvm-nbd-Don-t-take-address-of-fields-in-packed-structs.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch665: kvm-qemu-nbd-Document-tls-creds.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch666: kvm-qemu-nbd-drop-old-style-negotiation.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch667: kvm-nbd-server-drop-old-style-negotiation.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch668: kvm-qemu-iotests-remove-unused-variable-here.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch669: kvm-qemu-iotests-convert-pwd-and-pwd-to-PWD.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch670: kvm-qemu-iotests-Modern-shell-scripting-use-instead-of.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch671: kvm-nbd-fix-whitespace-in-server-error-message.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch672: kvm-nbd-server-Ignore-write-errors-when-replying-to-NBD_.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch673: kvm-io-return-0-for-EOF-in-TLS-session-read-after-shutdo.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch674: kvm-tests-pull-qemu-nbd-iotest-helpers-into-common.nbd-f.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch675: kvm-tests-check-if-qemu-nbd-is-still-alive-before-waitin.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch676: kvm-tests-add-iotests-helpers-for-dealing-with-TLS-certi.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch677: kvm-tests-exercise-NBD-server-in-TLS-mode.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch678: kvm-iotests-Also-test-I-O-over-NBD-TLS.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch679: kvm-iotests-Drop-use-of-bash-keyword-function.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch680: kvm-nbd-server-Advertise-all-contexts-in-response-to-bar.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch681: kvm-nbd-client-Make-x-dirty-bitmap-more-reliable.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch682: kvm-nbd-client-Send-NBD_CMD_DISC-if-open-fails-after-con.patch +# For bz#1691563 - QEMU NBD Feature parity roundup (QEMU 3.1.0) +Patch683: kvm-iotests-fix-nbd-test-233-to-work-correctly-with-raw-.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch684: kvm-iotests-Skip-233-if-certtool-not-installed.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch685: kvm-iotests-Make-nbd-fault-injector-flush.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch686: kvm-iotests-make-083-specific-to-raw.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch687: kvm-nbd-publish-_lookup-functions.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch688: kvm-nbd-client-Trace-all-server-option-error-messages.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch689: kvm-block-nbd-client-use-traces-instead-of-noisy-error_r.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch690: kvm-qemu-nbd-Use-program-name-in-error-messages.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch691: kvm-nbd-Document-timeline-of-various-features.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch692: kvm-nbd-client-More-consistent-error-messages.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch693: kvm-qemu-nbd-Fail-earlier-for-c-d-on-non-linux.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch694: kvm-nbd-client-Drop-pointless-buf-variable.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch695: kvm-qemu-nbd-Rename-exp-variable-clashing-with-math-exp-.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch696: kvm-nbd-Add-some-error-case-testing-to-iotests-223.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch697: kvm-nbd-Forbid-nbd-server-stop-when-server-is-not-runnin.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch698: kvm-nbd-Only-require-disabled-bitmap-for-read-only-expor.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch699: kvm-nbd-Merge-nbd_export_set_name-into-nbd_export_new.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch700: kvm-nbd-Allow-bitmap-export-during-QMP-nbd-server-add.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch701: kvm-nbd-Remove-x-nbd-server-add-bitmap.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch702: kvm-nbd-Merge-nbd_export_bitmap-into-nbd_export_new.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch703: kvm-qemu-nbd-Add-bitmap-NAME-option.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch704: kvm-qom-Clean-up-error-reporting-in-user_creatable_add_o.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch705: kvm-qemu-img-fix-error-reporting-for-object.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch706: kvm-iotests-Make-233-output-more-reliable.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch707: kvm-maint-Allow-for-EXAMPLES-in-texi2pod.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch708: kvm-qemu-nbd-Enhance-man-page.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch709: kvm-qemu-nbd-Sanity-check-partition-bounds.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch710: kvm-nbd-server-Hoist-length-check-to-qmp_nbd_server_add.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch711: kvm-nbd-server-Favor-u-int64_t-over-off_t.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch712: kvm-qemu-nbd-Avoid-strtol-open-coding.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch713: kvm-nbd-client-Refactor-nbd_receive_list.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch714: kvm-nbd-client-Move-export-name-into-NBDExportInfo.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch715: kvm-nbd-client-Change-signature-of-nbd_negotiate_simple_.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch716: kvm-nbd-client-Split-out-nbd_send_meta_query.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch717: kvm-nbd-client-Split-out-nbd_receive_one_meta_context.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch718: kvm-nbd-client-Refactor-return-of-nbd_receive_negotiate.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch719: kvm-nbd-client-Split-handshake-into-two-functions.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch720: kvm-nbd-client-Pull-out-oldstyle-size-determination.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch721: kvm-nbd-client-Refactor-nbd_opt_go-to-support-NBD_OPT_IN.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch722: kvm-nbd-client-Add-nbd_receive_export_list.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch723: kvm-nbd-client-Add-meta-contexts-to-nbd_receive_export_l.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch724: kvm-qemu-nbd-Add-list-option.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch725: kvm-nbd-client-Work-around-3.0-bug-for-listing-meta-cont.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch726: kvm-iotests-Enhance-223-233-to-cover-qemu-nbd-list.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch727: kvm-qemu-nbd-Deprecate-qemu-nbd-partition.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch728: kvm-nbd-generalize-usage-of-nbd_read.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch729: kvm-block-nbd-client-split-channel-errors-from-export-er.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch730: kvm-block-nbd-move-connection-code-from-block-nbd-to-blo.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch731: kvm-block-nbd-client-split-connection-from-initializatio.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch732: kvm-block-nbd-client-fix-nbd_reply_chunk_iter_receive.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch733: kvm-block-nbd-client-don-t-check-ioc.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch734: kvm-block-nbd-client-rename-read_reply_co-to-connection_.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch735: kvm-nbd-server-Kill-pointless-shadowed-variable.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch736: kvm-iotests-ensure-we-print-nbd-server-log-on-error.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch737: kvm-iotests-avoid-broken-pipe-with-certtool.patch +# For bz#1691009 - NBD pull mode incremental backup API needs a finalized interface +Patch738: kvm-iotests-Wait-for-qemu-to-end-in-223.patch +# For bz#1689793 - CVE-2019-9824 qemu-kvm-rhev: QEMU: Slirp: information leakage in tcp_emu() due to uninitialized stack variables [rhel-7] +Patch740: kvm-slirp-check-sscanf-result-when-emulating-ident.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch741: kvm-dirty-bitmap-Expose-persistent-flag-to-query-block.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch742: kvm-block-dirty-bitmap-Documentation-and-Comment-fixups.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch743: kvm-block-dirty-bitmap-add-recording-and-busy-properties.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch744: kvm-block-dirty-bitmaps-rename-frozen-predicate-helper.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch745: kvm-block-dirty-bitmap-remove-set-reset-assertions-again.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch746: kvm-block-dirty-bitmap-change-semantics-of-enabled-predi.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch747: kvm-nbd-change-error-checking-order-for-bitmaps.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch748: kvm-block-dirty-bitmap-explicitly-lock-bitmaps-with-succ.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch749: kvm-block-dirty-bitmaps-unify-qmp_locked-and-user_locked.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch750: kvm-block-dirty-bitmaps-move-comment-block.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch751: kvm-blockdev-remove-unused-paio-parameter-documentation.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch752: kvm-iotests-add-busy-recording-bit-test-to-124.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch753: kvm-block-dirty-bitmaps-add-inconsistent-bit.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch754: kvm-block-dirty-bitmap-add-inconsistent-status.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch755: kvm-block-dirty-bitmaps-add-block_dirty_bitmap_check-fun.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch756: kvm-block-dirty-bitmaps-prohibit-readonly-bitmaps-for-ba.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch757: kvm-block-dirty-bitmaps-prohibit-removing-readonly-bitma.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch758: kvm-block-dirty-bitmaps-disallow-busy-bitmaps-as-merge-s.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch759: kvm-block-dirty-bitmaps-implement-inconsistent-bit.patch +# For bz#1677073 - Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7 +Patch760: kvm-bitmaps-Fix-typo-in-function-name.patch +# For bz#1603104 - Qemu Aborted (core dumped) for 'qemu-kvm: Failed to lock byte 100' when remote NFS or GlusterFS volume stopped during the block mirror(or block commit/stream) process +Patch762: kvm-block-file-posix-do-not-fail-on-unlock-bytes.patch +# For bz#1666884 - persistent bitmaps prevent qcow2 image resize +Patch763: kvm-docs-interop-qcow2-Improve-bitmap-flag-in_use-specif.patch +# For bz#1666884 - persistent bitmaps prevent qcow2 image resize +Patch764: kvm-block-qcow2-bitmap-Don-t-check-size-for-IN_USE-bitma.patch +# For bz#1666884 - persistent bitmaps prevent qcow2 image resize +Patch765: kvm-block-qcow2-bitmap-Allow-resizes-with-persistent-bit.patch +# For bz#1666884 - persistent bitmaps prevent qcow2 image resize +Patch766: kvm-tests-qemu-iotests-add-bitmap-resize-test-246.patch +# For bz#1691519 - physical bits should <= 48 when host with 5level paging &EPT5 and qemu command with "-cpu qemu64" parameters. +Patch768: kvm-x86-host-phys-bits-limit-option.patch +# For bz#1691519 - physical bits should <= 48 when host with 5level paging &EPT5 and qemu command with "-cpu qemu64" parameters. +Patch769: kvm-rhel-Set-host-phys-bits-limit-48-on-rhel-machine-typ.patch +# For bz#1693115 - CVE-2018-20815 qemu-kvm-rhev: QEMU: device_tree: heap buffer overflow while loading device tree blob [rhel-7.7] +Patch770: kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch +# For bz#1672819 - RHEL7.6/RHV4.2 - qemu doesn't free up hugepage memory when hotplug/hotunplug using memory-backend-file (qemu-kvm-rhev) +Patch771: kvm-mmap-alloc-unfold-qemu_ram_mmap.patch +# For bz#1672819 - RHEL7.6/RHV4.2 - qemu doesn't free up hugepage memory when hotplug/hotunplug using memory-backend-file (qemu-kvm-rhev) +Patch772: kvm-mmap-alloc-fix-hugetlbfs-misaligned-length-in-ppc64.patch +# For bz#1537776 - [Intel 7.7 Feat] KVM Enabling SnowRidge new NIs - qemu-kvm-rhev +Patch773: kvm-x86-cpu-Enable-CLDEMOTE-Demote-Cache-Line-cpu-featur.patch +# For bz#1693879 - RHV VM pauses when 'dd' issued inside guest to a direct lun configured as virtio-scsi with scsi-passthrough +Patch774: kvm-scsi-generic-prevent-guest-from-exceeding-SG_IO-limi.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch775: kvm-tests-crypto-Use-the-IEC-binary-prefix-definitions.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch776: kvm-crypto-expand-algorithm-coverage-for-cipher-benchmar.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch777: kvm-crypto-remove-code-duplication-in-tweak-encrypt-decr.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch778: kvm-crypto-introduce-a-xts_uint128-data-type.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch779: kvm-crypto-convert-xts_tweak_encdec-to-use-xts_uint128-t.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch780: kvm-crypto-convert-xts_mult_x-to-use-xts_uint128-type.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch781: kvm-crypto-annotate-xts_tweak_encdec-as-inlineable.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch782: kvm-crypto-refactor-XTS-cipher-mode-test-suite.patch +# For bz#1666336 - severe performance impact using encrypted Cinder volume (QEMU luks) +Patch783: kvm-crypto-add-testing-for-unaligned-buffers-with-XTS-ci.patch +# For bz#1631227 - Qemu Core dump when quit vm that's in status "paused(io-error)" with data plane enabled +Patch784: kvm-block-Fix-AioContext-switch-for-bs-drv-NULL.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch785: kvm-qemu-img-Report-bdrv_block_status-failures.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch786: kvm-nbd-Tolerate-some-server-non-compliance-in-NBD_CMD_B.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch787: kvm-nbd-Don-t-lose-server-s-error-to-NBD_CMD_BLOCK_STATU.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch788: kvm-nbd-Permit-simple-error-to-NBD_CMD_BLOCK_STATUS.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch789: kvm-qemu-img-Gracefully-shutdown-when-map-can-t-finish.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch790: kvm-nbd-client-Work-around-server-BLOCK_STATUS-misalignm.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch791: kvm-iotests-Add-241-to-test-NBD-on-unaligned-images.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch792: kvm-nbd-client-Lower-min_block-for-block-status-unaligne.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch793: kvm-nbd-client-Report-offsets-in-bdrv_block_status.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch794: kvm-nbd-client-Reject-inaccessible-tail-of-inconsistent-.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch795: kvm-nbd-client-Support-qemu-img-convert-from-unaligned-s.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch796: kvm-block-Add-bdrv_get_request_alignment.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch797: kvm-nbd-server-Advertise-actual-minimum-block-size.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch798: kvm-nbd-client-Trace-server-noncompliance-on-structured-.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch799: kvm-nbd-server-Fix-blockstatus-trace.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch800: kvm-nbd-server-Trace-client-noncompliance-on-unaligned-r.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch801: kvm-nbd-server-Don-t-fail-NBD_OPT_INFO-for-byte-aligned-.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch802: kvm-nbd-client-Fix-error-message-for-server-with-unusabl.patch +# For bz#1692018 - qemu-img: Protocol error: simple reply when structured reply chunk was expected +Patch803: kvm-iotest-Fix-241-to-run-in-generic-directory.patch +# For bz#1673397 - [RHEL.7] qemu-kvm core dumped after hotplug the deleted disk with iothread parameter +# For bz#1673402 - Qemu core dump when start guest with two disks using same drive +Patch804: kvm-virtio-scsi-Move-BlockBackend-back-to-the-main-AioCo.patch +# For bz#1673397 - [RHEL.7] qemu-kvm core dumped after hotplug the deleted disk with iothread parameter +# For bz#1673402 - Qemu core dump when start guest with two disks using same drive +Patch805: kvm-scsi-disk-Acquire-the-AioContext-in-scsi_-_realize.patch +# For bz#1673397 - [RHEL.7] qemu-kvm core dumped after hotplug the deleted disk with iothread parameter +# For bz#1673402 - Qemu core dump when start guest with two disks using same drive +Patch806: kvm-virtio-scsi-Forbid-devices-with-different-iothreads-.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch807: kvm-monitor-move-init-global-earlier.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch808: kvm-block-pflash_cfi02-Fix-memory-leak-and-potential-use.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch809: kvm-pflash-Rename-pflash_t-to-PFlashCFI01-PFlashCFI02.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch810: kvm-pflash_cfi01-Do-not-exit-on-guest-aborting-write-to-.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch811: kvm-pflash_cfi01-Log-use-of-flawed-write-to-buffer.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch812: kvm-pflash-Rename-CFI_PFLASH-to-PFLASH_CFI.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch813: kvm-hw-Use-PFLASH_CFI0-1-2-and-TYPE_PFLASH_CFI0-1-2.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch814: kvm-sam460ex-Don-t-size-flash-memory-to-match-backing-im.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch815: kvm-ppc405_boards-Delete-stale-disabled-DEBUG_BOARD_INIT.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch816: kvm-ppc405_boards-Don-t-size-flash-memory-to-match-backi.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch817: kvm-r2d-Fix-flash-memory-size-sector-size-width-device-I.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch818: kvm-mips_malta-Delete-disabled-broken-DEBUG_BOARD_INIT-c.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch819: kvm-hw-mips-malta-Remove-fl_sectors-variable.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch820: kvm-hw-mips-malta-Restrict-bios_size-variable-scope.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch821: kvm-mips_malta-Clean-up-definition-of-flash-memory-size-.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch822: kvm-pflash-Clean-up-after-commit-368a354f02b-part-1.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch823: kvm-pflash-Clean-up-after-commit-368a354f02b-part-2.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch824: kvm-qdev-Loosen-coupling-between-compat-and-other-global.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch825: kvm-vl-Prepare-fix-of-latent-bug-with-global-and-onboard.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch826: kvm-vl-Fix-latent-bug-with-global-and-onboard-devices.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch827: kvm-sysbus-Fix-latent-bug-with-onboard-devices.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch828: kvm-vl-Improve-legibility-of-BlockdevOptions-queue.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch829: kvm-vl-Factor-configure_blockdev-out-of-main.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch830: kvm-vl-Create-block-backends-before-setting-machine-prop.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch831: kvm-pflash_cfi01-Add-pflash_cfi01_get_blk-helper.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch832: kvm-pc_sysfw-Remove-unused-PcSysFwDevice.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch833: kvm-pc_sysfw-Pass-PCMachineState-to-pc_system_firmware_i.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch834: kvm-pc-Support-firmware-configuration-with-blockdev.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch835: kvm-docs-interop-firmware.json-Prefer-machine-to-if-pfla.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch836: kvm-Revert-migration-move-only_migratable-to-MigrationSt.patch +# For bz#1624009 - allow backing of pflash via -blockdev +Patch837: kvm-migration-Support-adding-migration-blockers-earlier.patch +# For bz#1669071 - CVE-2019-6778 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow in tcp_emu() [rhel-7.7] +Patch838: kvm-slirp-fix-big-little-endian-conversion-in-ident-prot.patch +# For bz#1669071 - CVE-2019-6778 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow in tcp_emu() [rhel-7.7] +Patch839: kvm-slirp-ensure-there-is-enough-space-in-mbuf-to-null-t.patch +# For bz#1669071 - CVE-2019-6778 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow in tcp_emu() [rhel-7.7] +Patch840: kvm-slirp-don-t-manipulate-so_rcv-in-tcp_emu.patch +# For bz#1636727 - CVE-2018-17958 qemu-kvm: Qemu: rtl8139: integer overflow leads to buffer overflow [rhel-7] +# For bz#1636780 - CVE-2018-17963 qemu-kvm-rhev: Qemu: net: ignore packets with large size [rhel-7] +Patch841: kvm-rtl8139-fix-possible-out-of-bound-access.patch +# For bz#1636779 - CVE-2018-17963 qemu-kvm: Qemu: net: ignore packets with large size [rhel-7] +# For bz#1636780 - CVE-2018-17963 qemu-kvm-rhev: Qemu: net: ignore packets with large size [rhel-7] +Patch842: kvm-net-ignore-packet-size-greater-than-INT_MAX.patch +# For bz#1636779 - CVE-2018-17963 qemu-kvm: Qemu: net: ignore packets with large size [rhel-7] +# For bz#1636780 - CVE-2018-17963 qemu-kvm-rhev: Qemu: net: ignore packets with large size [rhel-7] +Patch843: kvm-net-drop-too-large-packet-early.patch +# For bz#1710861 - Detached device when trying to upgrade USB device firmware when in doing USB Passthrough via QEMU +Patch844: kvm-Introduce-new-no_guest_reset-parameter-for-usb-host-.patch +# For bz#1710861 - Detached device when trying to upgrade USB device firmware when in doing USB Passthrough via QEMU +Patch845: kvm-usb-call-reset-handler-before-updating-state.patch +# For bz#1710861 - Detached device when trying to upgrade USB device firmware when in doing USB Passthrough via QEMU +Patch846: kvm-usb-host-skip-reset-for-untouched-devices.patch +# For bz#1710861 - Detached device when trying to upgrade USB device firmware when in doing USB Passthrough via QEMU +Patch847: kvm-usb-host-avoid-libusb_set_configuration-calls.patch +# For bz#1703916 - Qemu core dump when quit vm after forbidden to do backup with a read-only bitmap +Patch848: kvm-blockdev-fix-missed-target-unref-for-drive-backup.patch +# For bz#1714160 - Guest with 'reservations' for a disk start failed +Patch849: kvm-vl-Fix-drive-blockdev-persistent-reservation-managem.patch +# For bz#1608226 - [virtual-network][mq] prompt warning "qemu-kvm: unable to start vhost net: 14: falling back on userspace virtio" when boot with win8+ guests with multi-queue +Patch850: kvm-vhost_net-don-t-set-backend-for-the-uninitialized-vi.patch BuildRequires: zlib-devel BuildRequires: glib2-devel @@ -1258,6 +1965,9 @@ BuildRequires: pkgconfig(xkbcommon) BuildRequires: pkgconfig(epoxy) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(gbm) +Requires: mesa-libGL +Requires: mesa-libEGL +Requires: mesa-dri-drivers %endif Requires: qemu-img%{?pkgsuffix} = %{epoch}:%{version}-%{release} @@ -1308,6 +2018,9 @@ This package provides documentation and auxiliary programs used with qemu-kvm. Summary: KVM debugging and diagnostics tools Group: Development/Tools +# Needed due to coloring hack +Requires: libxkbcommon + %rhel_rhev_conflicts qemu-kvm-tools %description -n qemu-kvm-tools%{?pkgsuffix} @@ -1857,6 +2570,357 @@ ApplyOptionalPatch() %patch494 -p1 %patch495 -p1 %patch496 -p1 +%patch497 -p1 +%patch498 -p1 +%patch499 -p1 +%patch500 -p1 +%patch501 -p1 +%patch502 -p1 +%patch503 -p1 +%patch504 -p1 +%patch505 -p1 +%patch506 -p1 +%patch507 -p1 +%patch508 -p1 +%patch509 -p1 +%patch510 -p1 +%patch511 -p1 +%patch512 -p1 +%patch513 -p1 +%patch514 -p1 +%patch515 -p1 +%patch516 -p1 +%patch517 -p1 +%patch518 -p1 +%patch519 -p1 +%patch520 -p1 +%patch521 -p1 +%patch522 -p1 +%patch523 -p1 +%patch524 -p1 +%patch525 -p1 +%patch526 -p1 +%patch527 -p1 +%patch528 -p1 +%patch529 -p1 +%patch530 -p1 +%patch531 -p1 +%patch532 -p1 +%patch533 -p1 +%patch534 -p1 +%patch535 -p1 +%patch536 -p1 +%patch537 -p1 +%patch538 -p1 +%patch539 -p1 +%patch540 -p1 +%patch541 -p1 +%patch542 -p1 +%patch543 -p1 +%patch544 -p1 +%patch545 -p1 +%patch546 -p1 +%patch547 -p1 +%patch548 -p1 +%patch549 -p1 +%patch550 -p1 +%patch551 -p1 +%patch552 -p1 +%patch553 -p1 +%patch554 -p1 +%patch555 -p1 +%patch556 -p1 +%patch557 -p1 +%patch558 -p1 +%patch559 -p1 +%patch560 -p1 +%patch561 -p1 +%patch562 -p1 +%patch563 -p1 +%patch564 -p1 +%patch565 -p1 +%patch566 -p1 +%patch567 -p1 +%patch568 -p1 +%patch569 -p1 +%patch570 -p1 +%patch571 -p1 +%patch572 -p1 +%patch573 -p1 +%patch574 -p1 +%patch575 -p1 +%patch576 -p1 +%patch577 -p1 +%patch578 -p1 +%patch579 -p1 +%patch580 -p1 +%patch581 -p1 +%patch582 -p1 +%patch583 -p1 +%patch584 -p1 +%patch585 -p1 +%patch586 -p1 +%patch587 -p1 +%patch588 -p1 +%patch589 -p1 +%patch590 -p1 +%patch591 -p1 +%patch592 -p1 +%patch593 -p1 +%patch594 -p1 +%patch595 -p1 +%patch596 -p1 +%patch597 -p1 +%patch598 -p1 +%patch599 -p1 +%patch600 -p1 +%patch601 -p1 +%patch602 -p1 +%patch603 -p1 +%patch604 -p1 +%patch605 -p1 +%patch606 -p1 +%patch607 -p1 +%patch608 -p1 +%patch609 -p1 +%patch610 -p1 +%patch611 -p1 +%patch612 -p1 +%patch613 -p1 +%patch614 -p1 +%patch615 -p1 +%patch616 -p1 +%patch617 -p1 +%patch618 -p1 +%patch619 -p1 +%patch620 -p1 +%patch621 -p1 +%patch622 -p1 +%patch623 -p1 +%patch624 -p1 +%patch625 -p1 +%patch626 -p1 +%patch627 -p1 +%patch628 -p1 +%patch629 -p1 +%patch630 -p1 +%patch631 -p1 +%patch632 -p1 +%patch633 -p1 +%patch634 -p1 +%patch635 -p1 +%patch636 -p1 +%patch637 -p1 +%patch638 -p1 +%patch639 -p1 +%patch640 -p1 +%patch641 -p1 +%patch642 -p1 +%patch643 -p1 +%patch644 -p1 +%patch645 -p1 +%patch646 -p1 +%patch647 -p1 +%patch648 -p1 +%patch649 -p1 +%patch650 -p1 +%patch651 -p1 +%patch652 -p1 +%patch653 -p1 +%patch654 -p1 +%patch655 -p1 +%patch656 -p1 +%patch657 -p1 +%patch658 -p1 +%patch659 -p1 +%patch660 -p1 +%patch661 -p1 +%patch662 -p1 +%patch663 -p1 +%patch664 -p1 +%patch665 -p1 +%patch666 -p1 +%patch667 -p1 +%patch668 -p1 +%patch669 -p1 +%patch670 -p1 +%patch671 -p1 +%patch672 -p1 +%patch673 -p1 +%patch674 -p1 +%patch675 -p1 +%patch676 -p1 +%patch677 -p1 +%patch678 -p1 +%patch679 -p1 +%patch680 -p1 +%patch681 -p1 +%patch682 -p1 +%patch683 -p1 +%patch684 -p1 +%patch685 -p1 +%patch686 -p1 +%patch687 -p1 +%patch688 -p1 +%patch689 -p1 +%patch690 -p1 +%patch691 -p1 +%patch692 -p1 +%patch693 -p1 +%patch694 -p1 +%patch695 -p1 +%patch696 -p1 +%patch697 -p1 +%patch698 -p1 +%patch699 -p1 +%patch700 -p1 +%patch701 -p1 +%patch702 -p1 +%patch703 -p1 +%patch704 -p1 +%patch705 -p1 +%patch706 -p1 +%patch707 -p1 +%patch708 -p1 +%patch709 -p1 +%patch710 -p1 +%patch711 -p1 +%patch712 -p1 +%patch713 -p1 +%patch714 -p1 +%patch715 -p1 +%patch716 -p1 +%patch717 -p1 +%patch718 -p1 +%patch719 -p1 +%patch720 -p1 +%patch721 -p1 +%patch722 -p1 +%patch723 -p1 +%patch724 -p1 +%patch725 -p1 +%patch726 -p1 +%patch727 -p1 +%patch728 -p1 +%patch729 -p1 +%patch730 -p1 +%patch731 -p1 +%patch732 -p1 +%patch733 -p1 +%patch734 -p1 +%patch735 -p1 +%patch736 -p1 +%patch737 -p1 +%patch738 -p1 +%patch740 -p1 +%patch741 -p1 +%patch742 -p1 +%patch743 -p1 +%patch744 -p1 +%patch745 -p1 +%patch746 -p1 +%patch747 -p1 +%patch748 -p1 +%patch749 -p1 +%patch750 -p1 +%patch751 -p1 +%patch752 -p1 +%patch753 -p1 +%patch754 -p1 +%patch755 -p1 +%patch756 -p1 +%patch757 -p1 +%patch758 -p1 +%patch759 -p1 +%patch760 -p1 +%patch762 -p1 +%patch763 -p1 +%patch764 -p1 +%patch765 -p1 +%patch766 -p1 +%patch768 -p1 +%patch769 -p1 +%patch770 -p1 +%patch771 -p1 +%patch772 -p1 +%patch773 -p1 +%patch774 -p1 +%patch775 -p1 +%patch776 -p1 +%patch777 -p1 +%patch778 -p1 +%patch779 -p1 +%patch780 -p1 +%patch781 -p1 +%patch782 -p1 +%patch783 -p1 +%patch784 -p1 +%patch785 -p1 +%patch786 -p1 +%patch787 -p1 +%patch788 -p1 +%patch789 -p1 +%patch790 -p1 +%patch791 -p1 +%patch792 -p1 +%patch793 -p1 +%patch794 -p1 +%patch795 -p1 +%patch796 -p1 +%patch797 -p1 +%patch798 -p1 +%patch799 -p1 +%patch800 -p1 +%patch801 -p1 +%patch802 -p1 +%patch803 -p1 +%patch804 -p1 +%patch805 -p1 +%patch806 -p1 +%patch807 -p1 +%patch808 -p1 +%patch809 -p1 +%patch810 -p1 +%patch811 -p1 +%patch812 -p1 +%patch813 -p1 +%patch814 -p1 +%patch815 -p1 +%patch816 -p1 +%patch817 -p1 +%patch818 -p1 +%patch819 -p1 +%patch820 -p1 +%patch821 -p1 +%patch822 -p1 +%patch823 -p1 +%patch824 -p1 +%patch825 -p1 +%patch826 -p1 +%patch827 -p1 +%patch828 -p1 +%patch829 -p1 +%patch830 -p1 +%patch831 -p1 +%patch832 -p1 +%patch833 -p1 +%patch834 -p1 +%patch835 -p1 +%patch836 -p1 +%patch837 -p1 +%patch838 -p1 +%patch839 -p1 +%patch840 -p1 +%patch841 -p1 +%patch842 -p1 +%patch843 -p1 +%patch844 -p1 +%patch845 -p1 +%patch846 -p1 +%patch847 -p1 +%patch848 -p1 +%patch849 -p1 +%patch850 -p1 # Fix executable permission for iotests chmod 755 $(ls tests/qemu-iotests/???) @@ -2204,6 +3268,20 @@ chmod 0644 $RPM_BUILD_ROOT%{_bindir}/qemu-keymap %check export DIFF=diff; make check V=1 +pushd tests/qemu-iotests +%if %{rhev} +./check -v -raw 001 002 003 004 008 009 010 011 012 021 025 032 033 045 048 052 063 077 101 104 106 113 120 132 140 143 145 147 152 157 159 160 162 170 184 194 205 208 218 222 226 227 232 233 236 +./check -v -qcow2 001 002 003 004 005 007 008 009 010 011 012 017 018 019 020 021 022 024 025 027 029 031 032 033 034 035 036 037 038 039 042 043 046 047 048 049 050 052 053 054 056 062 063 065 066 068 069 072 073 074 080 082 085 086 087 089 090 091 095 096 097 098 102 103 104 105 107 108 110 111 114 117 120 126 127 130 132 133 134 137 140 141 142 143 144 145 147 150 152 156 157 158 159 162 165 170 174 177 179 184 187 188 189 190 191 194 195 196 198 202 203 204 205 206 208 209 214 216 217 218 222 223 226 227 232 233 236 242 246 +./check -v -luks 001 002 003 004 009 010 011 012 021 032 033 052 140 143 145 157 162 174 184 208 218 227 236 +./check -v -nbd 001 002 003 004 008 009 011 021 032 045 077 119 123 132 143 145 147 152 162 184 194 205 208 218 222 236 +# qemu-kvm-ma +%else +./check -v -raw 001 002 003 004 008 009 010 011 012 021 025 032 033 045 048 052 077 101 104 106 113 120 140 143 145 147 157 159 160 162 170 184 205 226 227 232 233 236 +./check -v -qcow2 001 002 003 004 005 007 008 009 010 011 012 017 018 019 020 021 022 024 025 027 029 031 032 033 034 035 036 037 038 039 042 043 046 047 048 049 050 051 051 053 054 057 058 061 062 063 065 066 068 069 072 073 074 082 086 087 089 090 091 097 098 102 103 104 105 107 108 110 111 114 117 120 126 130 133 134 137 140 143 145 147 150 157 158 162 165 170 174 177 179 184 187 188 189 190 195 196 198 202 203 204 205 206 209 214 216 217 223 226 227 232 233 236 242 246 +./check -v -luks 001 002 003 004 008 009 010 011 012 021 032 033 052 140 143 145 157 162 174 184 210 227 236 +./check -v -nbd 001 003 004 008 009 010 021 032 033 045 077 104 119 123 143 145 147 162 184 205 236 +%endif +popd %post # load kvm modules now, so we can make sure no reboot is needed. @@ -2377,36 +3455,535 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog -* Sat Jun 22 2019 Miroslav Rezanina - 2.12.0-18.el7_6.4 -- kvm-s390x-cpumodel-ignore-csske-for-expansion.patch [bz#1720262] -- Resolves: bz#1720262 - -* Fri May 17 2019 Miroslav Rezanina - 2.12.0-18.el7_6.3 -- kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch [bz#1693112] -- Resolves: bz#1693112 - (CVE-2018-20815 qemu-kvm-ma: QEMU: device_tree: heap buffer overflow while loading device tree blob [rhel-7.6.z]) - -* Wed Feb 06 2019 Miroslav Rezanina - ma-2.12.0-18.el7_6.2 -- kvm-s390x-refuse-to-start-guests-backed-by-hugetlbfs.patch [bz#1672919] -- kvm-s390x-tcg-avoid-overflows-in-time2tod-tod2time.patch [bz#1672920] -- kvm-s390x-kvm-pass-values-instead-of-pointers-to-kvm_s39.patch [bz#1672920] -- kvm-s390x-tod-factor-out-TOD-into-separate-device.patch [bz#1672920] -- kvm-s390x-tcg-drop-tod_basetime.patch [bz#1672920] -- kvm-s390x-tcg-properly-implement-the-TOD.patch [bz#1672920] -- kvm-s390x-tcg-SET-CLOCK-COMPARATOR-can-clear-CKC-interru.patch [bz#1672920] -- kvm-s390x-tcg-implement-SET-CLOCK.patch [bz#1672920] -- kvm-s390x-tcg-rearm-the-CKC-timer-during-migration.patch [bz#1672920] -- kvm-s390x-tcg-fix-locking-problem-with-tcg_s390_tod_upda.patch [bz#1672920] -- kvm-hw-s390x-Include-the-tod-qemu-also-for-builds-with-d.patch [bz#1672920] -- kvm-s390x-tod-Properly-stop-the-KVM-TOD-while-the-guest-.patch [bz#1672920] -- kvm-hw-s390x-Fix-bad-mask-in-time2tod.patch [bz#1672920] -- kvm-s390x-Return-specification-exception-for-unimplement.patch [bz#1668424] -- Resolves: bz#1668424 - (RHEL-Alt-7.6 - Backport diag308 stable exception fix (qemu-kvm-ma) [rhel-7.6.z]) -- Resolves: bz#1672919 - (Trying to start a guest with hugetlbfs backing does not bail out so providing saying that hugetlbfs is not supported before actually trying to start the guest. [rhel-7.6.z]) -- Resolves: bz#1672920 - (Stress guest and stop it, then do live migration, guest hit call trace on destination end [rhel-7.6.z]) +* Thu Jun 20 2019 Miroslav Rezanina - 2.12.0-33.el7 +- kvm-vhost_net-don-t-set-backend-for-the-uninitialized-vi.patch [bz#1608226] +- Resolves: bz#1608226 + ([virtual-network][mq] prompt warning "qemu-kvm: unable to start vhost net: 14: falling back on userspace virtio" when boot with win8+ guests with multi-queue) + +* Tue Jun 11 2019 Miroslav Rezanina - 2.12.0-32.el7 +- kvm-rtl8139-fix-possible-out-of-bound-access.patch [bz#1636727 bz#1636780] +- kvm-net-ignore-packet-size-greater-than-INT_MAX.patch [bz#1636779 bz#1636780] +- kvm-net-drop-too-large-packet-early.patch [bz#1636779 bz#1636780] +- kvm-Introduce-new-no_guest_reset-parameter-for-usb-host-.patch [bz#1710861] +- kvm-usb-call-reset-handler-before-updating-state.patch [bz#1710861] +- kvm-usb-host-skip-reset-for-untouched-devices.patch [bz#1710861] +- kvm-usb-host-avoid-libusb_set_configuration-calls.patch [bz#1710861] +- kvm-blockdev-fix-missed-target-unref-for-drive-backup.patch [bz#1703916] +- kvm-vl-Fix-drive-blockdev-persistent-reservation-managem.patch [bz#1714160] +- Resolves: bz#1636727 + (CVE-2018-17958 qemu-kvm: Qemu: rtl8139: integer overflow leads to buffer overflow [rhel-7]) +- Resolves: bz#1636779 + (CVE-2018-17963 qemu-kvm: Qemu: net: ignore packets with large size [rhel-7]) +- Resolves: bz#1636780 + (CVE-2018-17963 qemu-kvm-rhev: Qemu: net: ignore packets with large size [rhel-7]) +- Resolves: bz#1703916 + (Qemu core dump when quit vm after forbidden to do backup with a read-only bitmap) +- Resolves: bz#1710861 + (Detached device when trying to upgrade USB device firmware when in doing USB Passthrough via QEMU) +- Resolves: bz#1714160 + (Guest with 'reservations' for a disk start failed) + +* Tue Jun 04 2019 Miroslav Rezanina - 2.12.0-31.el7 +- kvm-seccomp-set-the-seccomp-filter-to-all-threads.patch [bz#1618504] +- Resolves: bz#1618504 + (qemu-kvm-rhev: Qemu: seccomp: blacklist is not applied to all threads [rhel-7]) + +* Tue May 28 2019 Miroslav Rezanina - 2.12.0-30.el7 +- kvm-slirp-fix-big-little-endian-conversion-in-ident-prot.patch [bz#1669071] +- kvm-slirp-ensure-there-is-enough-space-in-mbuf-to-null-t.patch [bz#1669071] +- kvm-slirp-don-t-manipulate-so_rcv-in-tcp_emu.patch [bz#1669071] +- Resolves: bz#1669071 + (CVE-2019-6778 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow in tcp_emu() [rhel-7.7]) + +* Fri May 17 2019 Miroslav Rezanina - 2.12.0-29.el7 +- kvm-qemu-img-Report-bdrv_block_status-failures.patch [bz#1692018] +- kvm-nbd-Tolerate-some-server-non-compliance-in-NBD_CMD_B.patch [bz#1692018] +- kvm-nbd-Don-t-lose-server-s-error-to-NBD_CMD_BLOCK_STATU.patch [bz#1692018] +- kvm-nbd-Permit-simple-error-to-NBD_CMD_BLOCK_STATUS.patch [bz#1692018] +- kvm-qemu-img-Gracefully-shutdown-when-map-can-t-finish.patch [bz#1692018] +- kvm-nbd-client-Work-around-server-BLOCK_STATUS-misalignm.patch [bz#1692018] +- kvm-iotests-Add-241-to-test-NBD-on-unaligned-images.patch [bz#1692018] +- kvm-nbd-client-Lower-min_block-for-block-status-unaligne.patch [bz#1692018] +- kvm-nbd-client-Report-offsets-in-bdrv_block_status.patch [bz#1692018] +- kvm-nbd-client-Reject-inaccessible-tail-of-inconsistent-.patch [bz#1692018] +- kvm-nbd-client-Support-qemu-img-convert-from-unaligned-s.patch [bz#1692018] +- kvm-block-Add-bdrv_get_request_alignment.patch [bz#1692018] +- kvm-nbd-server-Advertise-actual-minimum-block-size.patch [bz#1692018] +- kvm-nbd-client-Trace-server-noncompliance-on-structured-.patch [bz#1692018] +- kvm-nbd-server-Fix-blockstatus-trace.patch [bz#1692018] +- kvm-nbd-server-Trace-client-noncompliance-on-unaligned-r.patch [bz#1692018] +- kvm-nbd-server-Don-t-fail-NBD_OPT_INFO-for-byte-aligned-.patch [bz#1692018] +- kvm-nbd-client-Fix-error-message-for-server-with-unusabl.patch [bz#1692018] +- kvm-iotest-Fix-241-to-run-in-generic-directory.patch [bz#1692018] +- kvm-virtio-scsi-Move-BlockBackend-back-to-the-main-AioCo.patch [bz#1673397 bz#1673402] +- kvm-scsi-disk-Acquire-the-AioContext-in-scsi_-_realize.patch [bz#1673397 bz#1673402] +- kvm-virtio-scsi-Forbid-devices-with-different-iothreads-.patch [bz#1673397 bz#1673402] +- kvm-monitor-move-init-global-earlier.patch [bz#1624009] +- kvm-block-pflash_cfi02-Fix-memory-leak-and-potential-use.patch [bz#1624009] +- kvm-pflash-Rename-pflash_t-to-PFlashCFI01-PFlashCFI02.patch [bz#1624009] +- kvm-pflash_cfi01-Do-not-exit-on-guest-aborting-write-to-.patch [bz#1624009] +- kvm-pflash_cfi01-Log-use-of-flawed-write-to-buffer.patch [bz#1624009] +- kvm-pflash-Rename-CFI_PFLASH-to-PFLASH_CFI.patch [bz#1624009] +- kvm-hw-Use-PFLASH_CFI0-1-2-and-TYPE_PFLASH_CFI0-1-2.patch [bz#1624009] +- kvm-sam460ex-Don-t-size-flash-memory-to-match-backing-im.patch [bz#1624009] +- kvm-ppc405_boards-Delete-stale-disabled-DEBUG_BOARD_INIT.patch [bz#1624009] +- kvm-ppc405_boards-Don-t-size-flash-memory-to-match-backi.patch [bz#1624009] +- kvm-r2d-Fix-flash-memory-size-sector-size-width-device-I.patch [bz#1624009] +- kvm-mips_malta-Delete-disabled-broken-DEBUG_BOARD_INIT-c.patch [bz#1624009] +- kvm-hw-mips-malta-Remove-fl_sectors-variable.patch [bz#1624009] +- kvm-hw-mips-malta-Restrict-bios_size-variable-scope.patch [bz#1624009] +- kvm-mips_malta-Clean-up-definition-of-flash-memory-size-.patch [bz#1624009] +- kvm-pflash-Clean-up-after-commit-368a354f02b-part-1.patch [bz#1624009] +- kvm-pflash-Clean-up-after-commit-368a354f02b-part-2.patch [bz#1624009] +- kvm-qdev-Loosen-coupling-between-compat-and-other-global.patch [bz#1624009] +- kvm-vl-Prepare-fix-of-latent-bug-with-global-and-onboard.patch [bz#1624009] +- kvm-vl-Fix-latent-bug-with-global-and-onboard-devices.patch [bz#1624009] +- kvm-sysbus-Fix-latent-bug-with-onboard-devices.patch [bz#1624009] +- kvm-vl-Improve-legibility-of-BlockdevOptions-queue.patch [bz#1624009] +- kvm-vl-Factor-configure_blockdev-out-of-main.patch [bz#1624009] +- kvm-vl-Create-block-backends-before-setting-machine-prop.patch [bz#1624009] +- kvm-pflash_cfi01-Add-pflash_cfi01_get_blk-helper.patch [bz#1624009] +- kvm-pc_sysfw-Remove-unused-PcSysFwDevice.patch [bz#1624009] +- kvm-pc_sysfw-Pass-PCMachineState-to-pc_system_firmware_i.patch [bz#1624009] +- kvm-pc-Support-firmware-configuration-with-blockdev.patch [bz#1624009] +- kvm-docs-interop-firmware.json-Prefer-machine-to-if-pfla.patch [bz#1624009] +- kvm-Revert-migration-move-only_migratable-to-MigrationSt.patch [bz#1624009] +- kvm-migration-Support-adding-migration-blockers-earlier.patch [bz#1624009] +- Resolves: bz#1624009 + (allow backing of pflash via -blockdev) +- Resolves: bz#1673397 + ([RHEL.7] qemu-kvm core dumped after hotplug the deleted disk with iothread parameter) +- Resolves: bz#1673402 + (Qemu core dump when start guest with two disks using same drive) +- Resolves: bz#1692018 + (qemu-img: Protocol error: simple reply when structured reply chunk was expected) + +* Mon May 13 2019 Miroslav Rezanina - 2.12.0-28.el7 +- kvm-x86-cpu-Enable-CLDEMOTE-Demote-Cache-Line-cpu-featur.patch [bz#1537776] +- kvm-scsi-generic-prevent-guest-from-exceeding-SG_IO-limi.patch [bz#1693879] +- kvm-tests-crypto-Use-the-IEC-binary-prefix-definitions.patch [bz#1666336] +- kvm-crypto-expand-algorithm-coverage-for-cipher-benchmar.patch [bz#1666336] +- kvm-crypto-remove-code-duplication-in-tweak-encrypt-decr.patch [bz#1666336] +- kvm-crypto-introduce-a-xts_uint128-data-type.patch [bz#1666336] +- kvm-crypto-convert-xts_tweak_encdec-to-use-xts_uint128-t.patch [bz#1666336] +- kvm-crypto-convert-xts_mult_x-to-use-xts_uint128-type.patch [bz#1666336] +- kvm-crypto-annotate-xts_tweak_encdec-as-inlineable.patch [bz#1666336] +- kvm-crypto-refactor-XTS-cipher-mode-test-suite.patch [bz#1666336] +- kvm-crypto-add-testing-for-unaligned-buffers-with-XTS-ci.patch [bz#1666336] +- kvm-block-Fix-AioContext-switch-for-bs-drv-NULL.patch [bz#1631227] +- Resolves: bz#1537776 + ([Intel 7.7 Feat] KVM Enabling SnowRidge new NIs - qemu-kvm-rhev) +- Resolves: bz#1631227 + (Qemu Core dump when quit vm that's in status "paused(io-error)" with data plane enabled) +- Resolves: bz#1666336 + (severe performance impact using encrypted Cinder volume (QEMU luks)) +- Resolves: bz#1693879 + (RHV VM pauses when 'dd' issued inside guest to a direct lun configured as virtio-scsi with scsi-passthrough) + +* Wed Apr 24 2019 Miroslav Rezanina - 2.12.0-27.el7 +- kvm-tests-virtio-blk-test-Disable-auto-read-only.patch [bz#1685989] +- kvm-block-Avoid-useless-local_err.patch [bz#1685989] +- kvm-block-Simplify-bdrv_reopen_abort.patch [bz#1685989] +- kvm-block-Always-abort-reopen-after-prepare-succeeded.patch [bz#1685989] +- kvm-block-Make-permission-changes-in-reopen-less-wrong.patch [bz#1685989] +- kvm-block-Fix-use-after-free-error-in-bdrv_open_inherit.patch [bz#1685989] +- kvm-qemu-iotests-Test-snapshot-on-with-nonexistent-TMPDI.patch [bz#1685989] +- kvm-file-posix-Fix-bdrv_open_flags-for-snapshot-on.patch [bz#1685989] +- kvm-file-posix-Use-error-API-properly.patch [bz#1685989] +- kvm-file-posix-Factor-out-raw_reconfigure_getfd.patch [bz#1685989] +- kvm-file-posix-Store-BDRVRawState.reopen_state-during-re.patch [bz#1685989] +- kvm-file-posix-Lock-new-fd-in-raw_reopen_prepare.patch [bz#1685989] +- kvm-file-posix-Prepare-permission-code-for-fd-switching.patch [bz#1685989] +- kvm-file-posix-Make-auto-read-only-dynamic.patch [bz#1685989] +- kvm-qapi-bitmap-merge-document-name-change.patch [bz#1668956] +- kvm-iotests-Enhance-223-to-cover-multiple-bitmap-granula.patch [bz#1668956] +- kvm-iotests-Unify-log-outputs-between-Python-2-and-3.patch [bz#1668956] +- kvm-blockdev-n-ary-bitmap-merge.patch [bz#1668956] +- kvm-block-remove-x-prefix-from-experimental-bitmap-APIs.patch [bz#1668956] +- kvm-iotests.py-don-t-abort-if-IMGKEYSECRET-is-undefined.patch [bz#1668956] +- kvm-iotests-add-filter_generated_node_ids.patch [bz#1668956] +- kvm-iotests-add-qmp-recursive-sorting-function.patch [bz#1668956] +- kvm-iotests-remove-default-filters-from-qmp_log.patch [bz#1668956] +- kvm-iotests-change-qmp_log-filters-to-expect-QMP-objects.patch [bz#1668956] +- kvm-iotests-implement-pretty-print-for-log-and-qmp_log.patch [bz#1668956] +- kvm-iotests-add-iotest-236-for-testing-bitmap-merge.patch [bz#1668956] +- kvm-iotests-236-fix-transaction-kwarg-order.patch [bz#1668956] +- kvm-iotests-Re-add-filename-filters.patch [bz#1668956] +- kvm-iotests-Remove-superfluous-rm-from-232.patch [bz#1668956] +- kvm-iotests-Fix-232-for-LUKS.patch [bz#1668956] +- kvm-iotests-Fix-207-to-use-QMP-filters-for-qmp_log.patch [bz#1668956] +- kvm-iotests.py-Add-is_str.patch [bz#1668956] +- kvm-iotests.py-Filter-filename-in-any-string-value.patch [bz#1668956] +- kvm-iotest-Fix-filtering-order-in-226.patch [bz#1691018] +- kvm-iotests-Don-t-lock-dev-null-in-226.patch [bz#1691018] +- kvm-dirty-bitmap-improve-bdrv_dirty_bitmap_next_zero.patch [bz#1691048] +- kvm-tests-add-tests-for-hbitmap_next_zero-with-specified.patch [bz#1691048] +- kvm-dirty-bitmap-add-bdrv_dirty_bitmap_next_dirty_area.patch [bz#1691048] +- kvm-tests-add-tests-for-hbitmap_next_dirty_area.patch [bz#1691048] +- kvm-Revert-block-dirty-bitmap-Add-bdrv_dirty_iter_next_a.patch [bz#1691048] +- kvm-Revert-test-hbitmap-Add-non-advancing-iter_next-test.patch [bz#1691048] +- kvm-Revert-hbitmap-Add-advance-param-to-hbitmap_iter_nex.patch [bz#1691048] +- kvm-bdrv_query_image_info-Error-parameter-added.patch [bz#1691048] +- kvm-qcow2-Add-list-of-bitmaps-to-ImageInfoSpecificQCow2.patch [bz#1691048] +- kvm-qcow2-list-of-bitmaps-new-test-242.patch [bz#1691048] +- kvm-blockdev-acquire-aio_context-for-bitmap-add-remove.patch [bz#1672010] +- kvm-nbd-client-fix-nbd_negotiate_simple_meta_context.patch [bz#1691563] +- kvm-nbd-client-Fix-error-messages-during-NBD_INFO_BLOCK_.patch [bz#1691563] +- kvm-nbd-client-Relax-handling-of-large-NBD_CMD_BLOCK_STA.patch [bz#1691563] +- kvm-tests-Simplify-.gitignore.patch [bz#1691563] +- kvm-iotests-nbd-Stop-qemu-nbd-before-remaking-image.patch [bz#1691563] +- kvm-iotests-Disallow-compat-0.10-in-223.patch [bz#1691563] +- kvm-nbd-server-fix-bitmap-export.patch [bz#1691563] +- kvm-nbd-server-send-more-than-one-extent-of-base-allocat.patch [bz#1691563] +- kvm-nbd-Don-t-take-address-of-fields-in-packed-structs.patch [bz#1691563] +- kvm-qemu-nbd-Document-tls-creds.patch [bz#1691563] +- kvm-qemu-nbd-drop-old-style-negotiation.patch [bz#1691563] +- kvm-nbd-server-drop-old-style-negotiation.patch [bz#1691563] +- kvm-qemu-iotests-remove-unused-variable-here.patch [bz#1691563] +- kvm-qemu-iotests-convert-pwd-and-pwd-to-PWD.patch [bz#1691563] +- kvm-qemu-iotests-Modern-shell-scripting-use-instead-of.patch [bz#1691563] +- kvm-nbd-fix-whitespace-in-server-error-message.patch [bz#1691563] +- kvm-nbd-server-Ignore-write-errors-when-replying-to-NBD_.patch [bz#1691563] +- kvm-io-return-0-for-EOF-in-TLS-session-read-after-shutdo.patch [bz#1691563] +- kvm-tests-pull-qemu-nbd-iotest-helpers-into-common.nbd-f.patch [bz#1691563] +- kvm-tests-check-if-qemu-nbd-is-still-alive-before-waitin.patch [bz#1691563] +- kvm-tests-add-iotests-helpers-for-dealing-with-TLS-certi.patch [bz#1691563] +- kvm-tests-exercise-NBD-server-in-TLS-mode.patch [bz#1691563] +- kvm-iotests-Also-test-I-O-over-NBD-TLS.patch [bz#1691563] +- kvm-iotests-Drop-use-of-bash-keyword-function.patch [bz#1691563] +- kvm-nbd-server-Advertise-all-contexts-in-response-to-bar.patch [bz#1691563] +- kvm-nbd-client-Make-x-dirty-bitmap-more-reliable.patch [bz#1691563] +- kvm-nbd-client-Send-NBD_CMD_DISC-if-open-fails-after-con.patch [bz#1691563] +- kvm-iotests-fix-nbd-test-233-to-work-correctly-with-raw-.patch [bz#1691563] +- kvm-iotests-Skip-233-if-certtool-not-installed.patch [bz#1691009] +- kvm-iotests-Make-nbd-fault-injector-flush.patch [bz#1691009] +- kvm-iotests-make-083-specific-to-raw.patch [bz#1691009] +- kvm-nbd-publish-_lookup-functions.patch [bz#1691009] +- kvm-nbd-client-Trace-all-server-option-error-messages.patch [bz#1691009] +- kvm-block-nbd-client-use-traces-instead-of-noisy-error_r.patch [bz#1691009] +- kvm-qemu-nbd-Use-program-name-in-error-messages.patch [bz#1691009] +- kvm-nbd-Document-timeline-of-various-features.patch [bz#1691009] +- kvm-nbd-client-More-consistent-error-messages.patch [bz#1691009] +- kvm-qemu-nbd-Fail-earlier-for-c-d-on-non-linux.patch [bz#1691009] +- kvm-nbd-client-Drop-pointless-buf-variable.patch [bz#1691009] +- kvm-qemu-nbd-Rename-exp-variable-clashing-with-math-exp-.patch [bz#1691009] +- kvm-nbd-Add-some-error-case-testing-to-iotests-223.patch [bz#1691009] +- kvm-nbd-Forbid-nbd-server-stop-when-server-is-not-runnin.patch [bz#1691009] +- kvm-nbd-Only-require-disabled-bitmap-for-read-only-expor.patch [bz#1691009] +- kvm-nbd-Merge-nbd_export_set_name-into-nbd_export_new.patch [bz#1691009] +- kvm-nbd-Allow-bitmap-export-during-QMP-nbd-server-add.patch [bz#1691009] +- kvm-nbd-Remove-x-nbd-server-add-bitmap.patch [bz#1691009] +- kvm-nbd-Merge-nbd_export_bitmap-into-nbd_export_new.patch [bz#1691009] +- kvm-qemu-nbd-Add-bitmap-NAME-option.patch [bz#1691009] +- kvm-qom-Clean-up-error-reporting-in-user_creatable_add_o.patch [bz#1691009] +- kvm-qemu-img-fix-error-reporting-for-object.patch [bz#1691009] +- kvm-iotests-Make-233-output-more-reliable.patch [bz#1691009] +- kvm-maint-Allow-for-EXAMPLES-in-texi2pod.patch [bz#1691009] +- kvm-qemu-nbd-Enhance-man-page.patch [bz#1691009] +- kvm-qemu-nbd-Sanity-check-partition-bounds.patch [bz#1691009] +- kvm-nbd-server-Hoist-length-check-to-qmp_nbd_server_add.patch [bz#1691009] +- kvm-nbd-server-Favor-u-int64_t-over-off_t.patch [bz#1691009] +- kvm-qemu-nbd-Avoid-strtol-open-coding.patch [bz#1691009] +- kvm-nbd-client-Refactor-nbd_receive_list.patch [bz#1691009] +- kvm-nbd-client-Move-export-name-into-NBDExportInfo.patch [bz#1691009] +- kvm-nbd-client-Change-signature-of-nbd_negotiate_simple_.patch [bz#1691009] +- kvm-nbd-client-Split-out-nbd_send_meta_query.patch [bz#1691009] +- kvm-nbd-client-Split-out-nbd_receive_one_meta_context.patch [bz#1691009] +- kvm-nbd-client-Refactor-return-of-nbd_receive_negotiate.patch [bz#1691009] +- kvm-nbd-client-Split-handshake-into-two-functions.patch [bz#1691009] +- kvm-nbd-client-Pull-out-oldstyle-size-determination.patch [bz#1691009] +- kvm-nbd-client-Refactor-nbd_opt_go-to-support-NBD_OPT_IN.patch [bz#1691009] +- kvm-nbd-client-Add-nbd_receive_export_list.patch [bz#1691009] +- kvm-nbd-client-Add-meta-contexts-to-nbd_receive_export_l.patch [bz#1691009] +- kvm-qemu-nbd-Add-list-option.patch [bz#1691009] +- kvm-nbd-client-Work-around-3.0-bug-for-listing-meta-cont.patch [bz#1691009] +- kvm-iotests-Enhance-223-233-to-cover-qemu-nbd-list.patch [bz#1691009] +- kvm-qemu-nbd-Deprecate-qemu-nbd-partition.patch [bz#1691009] +- kvm-nbd-generalize-usage-of-nbd_read.patch [bz#1691009] +- kvm-block-nbd-client-split-channel-errors-from-export-er.patch [bz#1691009] +- kvm-block-nbd-move-connection-code-from-block-nbd-to-blo.patch [bz#1691009] +- kvm-block-nbd-client-split-connection-from-initializatio.patch [bz#1691009] +- kvm-block-nbd-client-fix-nbd_reply_chunk_iter_receive.patch [bz#1691009] +- kvm-block-nbd-client-don-t-check-ioc.patch [bz#1691009] +- kvm-block-nbd-client-rename-read_reply_co-to-connection_.patch [bz#1691009] +- kvm-nbd-server-Kill-pointless-shadowed-variable.patch [bz#1691009] +- kvm-iotests-ensure-we-print-nbd-server-log-on-error.patch [bz#1691009] +- kvm-iotests-avoid-broken-pipe-with-certtool.patch [bz#1691009] +- kvm-iotests-Wait-for-qemu-to-end-in-223.patch [bz#1691009] +- kvm-qemu-kvm-rhev.spec-add-iotest-233.patch [bz#1691009] +- kvm-slirp-check-sscanf-result-when-emulating-ident.patch [bz#1689793] +- kvm-dirty-bitmap-Expose-persistent-flag-to-query-block.patch [bz#1677073] +- kvm-block-dirty-bitmap-Documentation-and-Comment-fixups.patch [bz#1677073] +- kvm-block-dirty-bitmap-add-recording-and-busy-properties.patch [bz#1677073] +- kvm-block-dirty-bitmaps-rename-frozen-predicate-helper.patch [bz#1677073] +- kvm-block-dirty-bitmap-remove-set-reset-assertions-again.patch [bz#1677073] +- kvm-block-dirty-bitmap-change-semantics-of-enabled-predi.patch [bz#1677073] +- kvm-nbd-change-error-checking-order-for-bitmaps.patch [bz#1677073] +- kvm-block-dirty-bitmap-explicitly-lock-bitmaps-with-succ.patch [bz#1677073] +- kvm-block-dirty-bitmaps-unify-qmp_locked-and-user_locked.patch [bz#1677073] +- kvm-block-dirty-bitmaps-move-comment-block.patch [bz#1677073] +- kvm-blockdev-remove-unused-paio-parameter-documentation.patch [bz#1677073] +- kvm-iotests-add-busy-recording-bit-test-to-124.patch [bz#1677073] +- kvm-block-dirty-bitmaps-add-inconsistent-bit.patch [bz#1677073] +- kvm-block-dirty-bitmap-add-inconsistent-status.patch [bz#1677073] +- kvm-block-dirty-bitmaps-add-block_dirty_bitmap_check-fun.patch [bz#1677073] +- kvm-block-dirty-bitmaps-prohibit-readonly-bitmaps-for-ba.patch [bz#1677073] +- kvm-block-dirty-bitmaps-prohibit-removing-readonly-bitma.patch [bz#1677073] +- kvm-block-dirty-bitmaps-disallow-busy-bitmaps-as-merge-s.patch [bz#1677073] +- kvm-block-dirty-bitmaps-implement-inconsistent-bit.patch [bz#1677073] +- kvm-bitmaps-Fix-typo-in-function-name.patch [bz#1677073] +- kvm-qemu-kvm-rhev.spec-add-bitmap-related-tests.patch [bz#1677073] +- kvm-block-file-posix-do-not-fail-on-unlock-bytes.patch [bz#1603104] +- kvm-docs-interop-qcow2-Improve-bitmap-flag-in_use-specif.patch [bz#1666884] +- kvm-block-qcow2-bitmap-Don-t-check-size-for-IN_USE-bitma.patch [bz#1666884] +- kvm-block-qcow2-bitmap-Allow-resizes-with-persistent-bit.patch [bz#1666884] +- kvm-tests-qemu-iotests-add-bitmap-resize-test-246.patch [bz#1666884] +- kvm-qemu-kvm-rhev.spec-add-iotest-246.patch [bz#1666884] +- kvm-x86-host-phys-bits-limit-option.patch [bz#1691519] +- kvm-rhel-Set-host-phys-bits-limit-48-on-rhel-machine-typ.patch [bz#1691519] +- kvm-device_tree-Fix-integer-overflowing-in-load_device_t.patch [bz#1693115] +- kvm-mmap-alloc-unfold-qemu_ram_mmap.patch [bz#1672819] +- kvm-mmap-alloc-fix-hugetlbfs-misaligned-length-in-ppc64.patch [bz#1672819] +- Resolves: bz#1603104 + (Qemu Aborted (core dumped) for 'qemu-kvm: Failed to lock byte 100' when remote NFS or GlusterFS volume stopped during the block mirror(or block commit/stream) process) +- Resolves: bz#1666884 + (persistent bitmaps prevent qcow2 image resize) +- Resolves: bz#1668956 + (incremental backup bitmap API needs a finalized interface) +- Resolves: bz#1672010 + ([RHEL7]Qemu coredump when remove a persistent bitmap after vm re-start(dataplane enabled)) +- Resolves: bz#1672819 + (RHEL7.6/RHV4.2 - qemu doesn't free up hugepage memory when hotplug/hotunplug using memory-backend-file (qemu-kvm-rhev)) +- Resolves: bz#1677073 + (Backport additional QEMU 4.0 Bitmap API changes to RHEL 7.7) +- Resolves: bz#1685989 + (Add facility to use block jobs with backing images without write permission) +- Resolves: bz#1689793 + (CVE-2019-9824 qemu-kvm-rhev: QEMU: Slirp: information leakage in tcp_emu() due to uninitialized stack variables [rhel-7]) +- Resolves: bz#1691009 + (NBD pull mode incremental backup API needs a finalized interface) +- Resolves: bz#1691018 + (Fix iotest 226 for local development builds) +- Resolves: bz#1691048 + (Add qemu-img info support for querying bitmaps offline) +- Resolves: bz#1691519 + (physical bits should <= 48 when host with 5level paging &EPT5 and qemu command with "-cpu qemu64" parameters.) +- Resolves: bz#1691563 + (QEMU NBD Feature parity roundup (QEMU 3.1.0)) +- Resolves: bz#1693115 + (CVE-2018-20815 qemu-kvm-rhev: QEMU: device_tree: heap buffer overflow while loading device tree blob [rhel-7.7]) + +* Tue Mar 19 2019 Miroslav Rezanina - 2.12.0-25.el7 +- kvm-block-backend-Make-blk_inc-dec_in_flight-public.patch [bz#1671173] +- kvm-virtio-blk-Increase-in_flight-for-request-restart-BH.patch [bz#1671173] +- kvm-block-Fix-AioContext-switch-for-drained-node.patch [bz#1671173] +- kvm-test-bdrv-drain-AioContext-switch-in-drained-section.patch [bz#1671173] +- kvm-block-Use-normal-drain-for-bdrv_set_aio_context.patch [bz#1671173] +- kvm-qapi-Add-rendernode-display-option-for-egl-headless.patch [bz#1648236] +- kvm-ui-Allow-specifying-rendernode-display-option-for-eg.patch [bz#1648236] +- kvm-qapi-add-query-display-options-command.patch [bz#1648236] +- kvm-egl-headless-parse-rendernode.patch [bz#1648236] +- Resolves: bz#1648236 + (QEMU doesn't expose rendernode option for egl-headless display type) +- Resolves: bz#1671173 + (qemu with iothreads enabled crashes on resume after enospc pause for disk extension) + +* Tue Feb 26 2019 Miroslav Rezanina - 2.12.0-24.el7 +- kvm-exec-move-memory-access-declarations-to-a-common-hea.patch [bz#1597482] +- kvm-exec-small-changes-to-flatview_do_translate.patch [bz#1597482] +- kvm-exec-extract-address_space_translate_iommu-fix-page_.patch [bz#1597482] +- kvm-exec-reintroduce-MemoryRegion-caching.patch [bz#1597482] +- kvm-virtio-update-MemoryRegionCaches-when-guest-negotiat.patch [bz#1597482] +- kvm-exec-Fix-MAP_RAM-for-cached-access.patch [bz#1597482] +- kvm-virtio-Return-true-from-virtio_queue_empty-if-broken.patch [bz#1597482] +- kvm-block-backend-Set-werror-rerror-defaults-in-blk_new.patch [bz#1631615] +- kvm-block-Apply-auto-read-only-for-ro-whitelist-drivers.patch [bz#1667320] +- kvm-qcow2-Give-the-refcount-cache-the-minimum-possible-s.patch [bz#1656913] +- kvm-docs-Document-the-new-default-sizes-of-the-qcow2-cac.patch [bz#1656913] +- kvm-qcow2-Fix-Coverity-warning-when-calculating-the-refc.patch [bz#1656913] +- kvm-qcow2-Options-documentation-fixes.patch [bz#1656913] +- kvm-include-Add-a-lookup-table-of-sizes.patch [bz#1656913] +- kvm-qcow2-Make-sizes-more-humanly-readable.patch [bz#1656913] +- kvm-qcow2-Avoid-duplication-in-setting-the-refcount-cach.patch [bz#1656913] +- kvm-qcow2-Assign-the-L2-cache-relatively-to-the-image-si.patch [bz#1656913] +- kvm-qcow2-Increase-the-default-upper-limit-on-the-L2-cac.patch [bz#1656913] +- kvm-qcow2-Resize-the-cache-upon-image-resizing.patch [bz#1656913] +- kvm-qcow2-Set-the-default-cache-clean-interval-to-10-min.patch [bz#1656913] +- kvm-qcow2-Explicit-number-replaced-by-a-constant.patch [bz#1656913] +- kvm-qcow2-Fix-cache-clean-interval-documentation.patch [bz#1656913] +- kvm-Add-raw-qcow2-nbd-and-luks-iotests-to-run-during-the.patch [bz#1676728 bz#1678898] +- Resolves: bz#1597482 + (qemu crashed when disk enable the IOMMU) +- Resolves: bz#1631615 + (Wrong werror default for -device drive=) +- Resolves: bz#1656913 + (qcow2 cache is too small) +- Resolves: bz#1667320 + (-blockdev: auto-read-only is ineffective for drivers on read-only whitelist) +- Resolves: bz#1676728 + (RHEL77: Run iotests as part of build process) +- Resolves: bz#1678898 + (Run iotests in rhel77 qemu-kvm-ma build %check phase) + +* Tue Feb 12 2019 Miroslav Rezanina - 2.12.0-23.el7 +- kvm-iotests-153-Fix-dead-code.patch [bz#1551486] +- kvm-file-posix-Include-filename-in-locking-error-message.patch [bz#1551486] +- kvm-file-posix-Skip-effectiveless-OFD-lock-operations.patch [bz#1551486] +- kvm-file-posix-Drop-s-lock_fd.patch [bz#1551486] +- kvm-tests-Add-unit-tests-for-image-locking.patch [bz#1551486] +- kvm-file-posix-Fix-shared-locks-on-reopen-commit.patch [bz#1551486] +- kvm-iotests-Test-file-posix-locking-and-reopen.patch [bz#1551486] +- kvm-scsi-disk-Don-t-use-empty-string-as-device-id.patch [bz#1673080] +- kvm-scsi-disk-Add-device_id-property.patch [bz#1673080] +- kvm-scsi-generic-avoid-possible-out-of-bounds-access-to-.patch [bz#1668999] +- kvm-block-remove-bdrv_dirty_bitmap_make_anon.patch [bz#1658343] +- kvm-block-simplify-code-around-releasing-bitmaps.patch [bz#1658343] +- kvm-hbitmap-Add-advance-param-to-hbitmap_iter_next.patch [bz#1658343] +- kvm-test-hbitmap-Add-non-advancing-iter_next-tests.patch [bz#1658343] +- kvm-block-dirty-bitmap-Add-bdrv_dirty_iter_next_area.patch [bz#1658343] +- kvm-dirty-bitmap-switch-assert-fails-to-errors-in-bdrv_m.patch [bz#1658343] +- kvm-dirty-bitmap-rename-bdrv_undo_clear_dirty_bitmap.patch [bz#1658343] +- kvm-dirty-bitmap-make-it-possible-to-restore-bitmap-afte.patch [bz#1658343] +- kvm-blockdev-rename-block-dirty-bitmap-clear-transaction.patch [bz#1658343] +- kvm-qapi-add-transaction-support-for-x-block-dirty-bitma.patch [bz#1658343] +- kvm-block-dirty-bitmaps-add-user_locked-status-checker.patch [bz#1658343] +- kvm-block-dirty-bitmaps-fix-merge-permissions.patch [bz#1658343] +- kvm-block-dirty-bitmaps-allow-clear-on-disabled-bitmaps.patch [bz#1658343] +- kvm-block-dirty-bitmaps-prohibit-enable-disable-on-locke.patch [bz#1658343] +- kvm-block-backup-prohibit-backup-from-using-in-use-bitma.patch [bz#1658343] +- kvm-nbd-forbid-use-of-frozen-bitmaps.patch [bz#1658343] +- kvm-bitmap-Update-count-after-a-merge.patch [bz#1658343] +- kvm-iotests-169-drop-deprecated-autoload-parameter.patch [bz#1658343] +- kvm-block-qcow2-improve-error-message-in-qcow2_inactivat.patch [bz#1658343] +- kvm-bloc-qcow2-drop-dirty_bitmaps_loaded-state-variable.patch [bz#1658343] +- kvm-dirty-bitmaps-clean-up-bitmaps-loading-and-migration.patch [bz#1658343] +- kvm-iotests-improve-169.patch [bz#1658343] +- kvm-iotests-169-add-cases-for-source-vm-resuming.patch [bz#1658343] +- Resolves: bz#1551486 + (QEMU image locking needn't double open fd number (i.e. drop file-posix.c:s->lock_fd)) +- Resolves: bz#1658343 + (QEMU incremental backup fixes and improvements (from upstream and in RHEL8)) +- Resolves: bz#1668999 + (CVE-2019-6501 qemu-kvm-rhev: QEMU: scsi-generic: possible OOB access while handling inquiry request [rhel-7]) +- Resolves: bz#1673080 + ("An unknown error has occurred" when using cdrom to install the system with two blockdev disks.(when choose installation destination)) + +* Tue Feb 05 2019 Miroslav Rezanina - 2.12.0-22.el7 +- kvm-spapr-Fix-ibm-max-associativity-domains-property-num.patch [bz#1626347] +- kvm-spapr-Add-H-Call-H_HOME_NODE_ASSOCIATIVITY.patch [bz#1626347] +- kvm-hostmem-file-remove-object-id-from-pmem-error-messag.patch [bz#1628098] +- kvm-cpus-ignore-ESRCH-in-qemu_cpu_kick_thread.patch [bz#1614610] +- kvm-blockdev-abort-transactions-in-reverse-order.patch [bz#1658426] +- kvm-block-dirty-bitmap-remove-assertion-from-restore.patch [bz#1658426] +- kvm-block-Fix-invalidate_cache-error-path-for-parent-act.patch [bz#1531888] +- kvm-luks-Allow-share-rw-on.patch [bz#1598119] +- Resolves: bz#1531888 + (Local VM and migrated VM on the same host can run with same RAW file as visual disk source while without shareable configured or lock manager enabled) +- Resolves: bz#1598119 + ("share-rw=on" does not work for luks format image) +- Resolves: bz#1614610 + (Guest quit with error when hotunplug cpu) +- Resolves: bz#1626347 + (RHEL7.6 - [Power8][Host: 3.10.0-933.el7.ppc64le][Guest: 3.10.0-933.el7.ppc64le] [qemu-kvm-ma-2.12.0-8.el7.ppc64le] Guest VM crashes during vcpu hotplug with specific numa configuration (kvm)) +- Resolves: bz#1628098 + ([Intel 7.7 BUG][KVM][Crystal Ridge]object_get_canonical_path_component: assertion failed: (obj->parent != NULL)) +- Resolves: bz#1658426 + (qemu core dumped when doing incremental live backup without "bitmap" parameter by mistake in a transaction mode((blockdev-backup/block-dirty-bitmap-add/x-block-dirty-bitmap-merge)) + +* Wed Jan 02 2019 Miroslav Rezanina - 2.12.0-21.el7 +- kvm-Add-dependency-to-libxkbcommon.patch [bz#1642551] +- Resolves: bz#1642551 + (qemu-kvm-tools-rhev depends on libxkbcommon, but the RPM-level dependency is missing) + +* Thu Dec 06 2018 Miroslav Rezanina - 2.12.0-20.el7 +- kvm-vnc-call-sasl_server_init-only-when-required.patch [bz#1614302] +- kvm-block-Update-flags-in-bdrv_set_read_only.patch [bz#1623986] +- kvm-block-Add-auto-read-only-option.patch [bz#1623986] +- kvm-rbd-Close-image-in-qemu_rbd_open-error-path.patch [bz#1623986] +- kvm-block-Require-auto-read-only-for-existing-fallbacks.patch [bz#1623986] +- kvm-nbd-Support-auto-read-only-option.patch [bz#1623986] +- kvm-file-posix-Support-auto-read-only-option.patch [bz#1623986] +- kvm-curl-Support-auto-read-only-option.patch [bz#1623986] +- kvm-gluster-Support-auto-read-only-option.patch [bz#1623986] +- kvm-iscsi-Support-auto-read-only-option.patch [bz#1623986] +- kvm-block-Make-auto-read-only-on-default-for-drive.patch [bz#1623986] +- kvm-qemu-iotests-Test-auto-read-only-with-drive-and-bloc.patch [bz#1623986] +- kvm-block-Fix-update-of-BDRV_O_AUTO_RDONLY-in-update_fla.patch [bz#1623986] +- kvm-memory-cleanup-side-effects-of-memory_region_init_fo.patch [bz#1585155] +- kvm-block-Don-t-inactivate-children-before-parents.patch [bz#1633536] +- kvm-iotests-Test-migration-with-blockdev.patch [bz#1633536] +- kvm-iothread-fix-crash-with-invalid-properties.patch [bz#1607768] +- kvm-balloon-Allow-multiple-inhibit-users.patch [bz#1619778] +- kvm-Use-inhibit-to-prevent-ballooning-without-synchr.patch [bz#1619778] +- kvm-vfio-Inhibit-ballooning-based-on-group-attachment-to.patch [bz#1619778] +- kvm-vfio-ccw-pci-Allow-devices-to-opt-in-for-ballooning.patch [bz#1619778] +- kvm-vfio-pci-Handle-subsystem-realpath-returning-NULL.patch [bz#1619778] +- kvm-vfio-pci-Fix-failure-to-close-file-descriptor-on-err.patch [bz#1619778] +- kvm-postcopy-Synchronize-usage-of-the-balloon-inhibitor.patch [bz#1619778] +- kvm-include-Add-IEC-binary-prefixes-in-qemu-units.h.patch [bz#1566195] +- kvm-hw-scsi-cleanups-before-VPD-BL-emulation.patch [bz#1566195] +- kvm-hw-scsi-centralize-SG_IO-calls-into-single-function.patch [bz#1566195] +- kvm-hw-scsi-add-VPD-Block-Limits-emulation.patch [bz#1566195] +- kvm-scsi-disk-Block-Device-Characteristics-emulation-fix.patch [bz#1566195] +- kvm-scsi-generic-keep-VPD-page-list-sorted.patch [bz#1566195] +- kvm-scsi-generic-avoid-out-of-bounds-access-to-VPD-page-.patch [bz#1566195] +- kvm-scsi-generic-avoid-invalid-access-to-struct-when-emu.patch [bz#1566195] +- kvm-scsi-generic-do-not-do-VPD-emulation-for-sense-other.patch [bz#1566195] +- kvm-redhat-add-opengl-runtime-dependencies.patch [bz#1628455] +- Resolves: bz#1566195 + (Guests don't always see correct transfer limits for passed through scsi devices (e.g. raid0 controlled by sas 9361-8i)) +- Resolves: bz#1585155 + (QEMU core dumped when hotplug memory exceeding host hugepages and with discard-data=yes) +- Resolves: bz#1607768 + (qemu aborted when start guest with a big iothreads) +- Resolves: bz#1614302 + (qemu-kvm: Could not find keytab file: /etc/qemu/krb5.tab: No such file or directory) +- Resolves: bz#1619778 + (Ballooning is incompatible with vfio assigned devices, but not prevented) +- Resolves: bz#1623986 + (block-commit can't be used with -blockdev) +- Resolves: bz#1628455 + (qemu-kvm-rhev should add opengl packages as dependencies) +- Resolves: bz#1633536 + (Qemu core dump when do migration after hot plugging a backend image with 'blockdev-add'(without the frontend)) + +* Wed Nov 21 2018 Miroslav Rezanina - 2.12.0-19.el7 +- kvm-nbd-server-fix-NBD_CMD_CACHE.patch [bz#1636148] +- kvm-nbd-fix-NBD_FLAG_SEND_CACHE-value.patch [bz#1636148] +- kvm-pc-dimm-turn-alignment-assert-into-check.patch [bz#1629720] +- kvm-exec-check-that-alignment-is-a-power-of-two.patch [bz#1629717] +- kvm-nvdimm-no-need-to-overwrite-get_vmstate_memory_regio.patch [bz#1620373] +- kvm-hostmem-drop-error-variable-from-host_memory_backend.patch [bz#1620373] +- kvm-ivshmem-Fix-unplug-of-device-ivshmem-plain.patch [bz#1620373] +- kvm-qemu-error-introduce-error-warn-_report_once.patch [bz#1627272] +- kvm-intel-iommu-start-to-use-error_report_once.patch [bz#1627272] +- kvm-intel-iommu-replace-more-vtd_err_-traces.patch [bz#1627272] +- kvm-intel_iommu-introduce-vtd_reset_caches.patch [bz#1627272] +- kvm-intel_iommu-better-handling-of-dmar-state-switch.patch [bz#1627272] +- kvm-intel_iommu-move-ce-fetching-out-when-sync-shadow.patch [bz#1627272] +- kvm-intel_iommu-handle-invalid-ce-for-shadow-sync.patch [bz#1627272] +- kvm-qapi-fill-in-CpuInfoFast.arch-in-query-cpus-fast.patch [bz#1607406] +- kvm-qapi-add-SysEmuTarget-to-common.json.patch [bz#1607406] +- kvm-qapi-change-the-type-of-TargetInfo.arch-from-string-.patch [bz#1607406] +- kvm-qapi-discriminate-CpuInfoFast-on-SysEmuTarget-not-Cp.patch [bz#1607406] +- kvm-qapi-deprecate-CpuInfoFast.arch.patch [bz#1607406] +- kvm-docs-interop-add-firmware.json.patch [bz#1607406] +- kvm-migration-postcopy-Clear-have_listen_thread.patch [bz#1608877] +- kvm-migration-cleanup-in-error-paths-in-loadvm.patch [bz#1608877] +- Resolves: bz#1607406 + ([RHEL 7.7] RFE: Define firmware metadata format) +- Resolves: bz#1608877 + (After postcopy migration, do savevm and loadvm, guest hang and call trace) +- Resolves: bz#1620373 + (Failed to do migration after hotplug and hotunplug the ivshmem device) +- Resolves: bz#1627272 + (boot guest with q35+vIOMMU+ device assignment, qemu crash when return assigned network devices from vfio driver to ixgbe in guest) +- Resolves: bz#1629717 + (qemu_ram_mmap: Assertion `is_power_of_2(align)' failed) +- Resolves: bz#1629720 + ([Intel 7.6 BUG][Crystal Ridge] pc_dimm_get_free_addr: assertion failed: (QEMU_ALIGN_UP(address_space_start, align) == address_space_start)) +- Resolves: bz#1636148 + (qemu NBD_CMD_CACHE flaws impacting non-qemu NBD clients) * Fri Sep 21 2018 Miroslav Rezanina - 2.12.0-18.el7 - kvm-test-bdrv-drain-Fix-outdated-comments.patch [bz#1618584]