update submodule and patches to QEMU 8.0.0
Many changes were necessary this time around:
* QAPI was changed to avoid redundant has_* variables, see commit
44ea9d9be3 ("qapi: Start to elide redundant has_FOO in generated C")
for details. This affected many QMP commands added by Proxmox too.
* Pending querying for migration got split into two functions, one to
estimate, one for exact value, see commit c8df4a7aef ("migration:
Split save_live_pending() into state_pending_*") for details. Relevant
for savevm-async and PBS dirty bitmap.
* Some block (driver) functions got converted to coroutines, so the
Proxmox block drivers needed to be adapted.
* Alloc track auto-detaching during PBS live restore got broken by
AioContext-related changes resulting in a deadlock. The current, hacky
method was replaced by a simpler one. Stefan apparently ran into a
problem with that when he wrote the driver, but there were
improvements in the stream job code since then and I didn't manage to
reproduce the issue. It's a separate patch "alloc-track: fix deadlock
during drop" for now, you can find the details there.
* Async snapshot-related changes:
  - The pending querying got adapted to the above-mentioned split and
  a patch is added to optimize it/make it more similar to what
  upstream code does.
  - Added initialization of the compression counters (for
    future-proofing).
  - It's necessary the hold the BQL (big QEMU lock = iothread mutex)
  during the setup phase, because block layer functions are used there
  and not doing so leads to racy, hard-to-debug crashes or hangs. It's
  necessary to change some upstream code too for this, a version of
  the patch "migration: for snapshots, hold the BQL during setup
  callbacks" is intended to be upstreamed.
  - Need to take the bdrv graph read lock before flushing.
* hmp_info_balloon was moved to a different file.
* Needed to include a new headers from time to time to still get the
correct functions.
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
			
			
This commit is contained in:
		
							parent
							
								
									fb818ea5b9
								
							
						
					
					
						commit
						bf251437e9
					
				| @ -27,16 +27,18 @@ Signed-off-by: Ma Haocong <mahaocong@didichuxing.com> | ||||
| Signed-off-by: John Snow <jsnow@redhat.com> | ||||
| Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: rebased for 8.0] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/mirror.c                         | 98 +++++++++++++++++++++----- | ||||
|  blockdev.c                             | 39 +++++++++- | ||||
|  blockdev.c                             | 38 +++++++++- | ||||
|  include/block/block_int-global-state.h |  4 +- | ||||
|  qapi/block-core.json                   | 29 ++++++-- | ||||
|  tests/unit/test-block-iothread.c       |  4 +- | ||||
|  5 files changed, 145 insertions(+), 29 deletions(-) | ||||
|  5 files changed, 144 insertions(+), 29 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/mirror.c b/block/mirror.c
 | ||||
| index 251adc5ae0..8ead5f77a0 100644
 | ||||
| index 663e2b7002..9099c75992 100644
 | ||||
| --- a/block/mirror.c
 | ||||
| +++ b/block/mirror.c
 | ||||
| @@ -51,7 +51,7 @@ typedef struct MirrorBlockJob {
 | ||||
| @ -57,7 +59,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|      BdrvDirtyBitmap *dirty_bitmap; | ||||
|      BdrvDirtyBitmapIter *dbi; | ||||
|      uint8_t *buf; | ||||
| @@ -699,7 +701,8 @@ static int mirror_exit_common(Job *job)
 | ||||
| @@ -703,7 +705,8 @@ static int mirror_exit_common(Job *job)
 | ||||
|      bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, | ||||
|                               &error_abort); | ||||
|      if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { | ||||
| @ -67,7 +69,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|          BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs); | ||||
|   | ||||
|          if (bdrv_cow_bs(unfiltered_target) != backing) { | ||||
| @@ -797,6 +800,16 @@ static void mirror_abort(Job *job)
 | ||||
| @@ -801,6 +804,16 @@ static void mirror_abort(Job *job)
 | ||||
|      assert(ret == 0); | ||||
|  } | ||||
|   | ||||
| @ -84,7 +86,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|  static void coroutine_fn mirror_throttle(MirrorBlockJob *s) | ||||
|  { | ||||
|      int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); | ||||
| @@ -977,7 +990,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
 | ||||
| @@ -987,7 +1000,8 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
 | ||||
|      mirror_free_init(s); | ||||
|   | ||||
|      s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); | ||||
| @ -94,7 +96,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|          ret = mirror_dirty_init(s); | ||||
|          if (ret < 0 || job_is_cancelled(&s->common.job)) { | ||||
|              goto immediate_exit; | ||||
| @@ -1224,6 +1238,7 @@ static const BlockJobDriver mirror_job_driver = {
 | ||||
| @@ -1240,6 +1254,7 @@ static const BlockJobDriver mirror_job_driver = {
 | ||||
|          .run                    = mirror_run, | ||||
|          .prepare                = mirror_prepare, | ||||
|          .abort                  = mirror_abort, | ||||
| @ -102,7 +104,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|          .pause                  = mirror_pause, | ||||
|          .complete               = mirror_complete, | ||||
|          .cancel                 = mirror_cancel, | ||||
| @@ -1240,6 +1255,7 @@ static const BlockJobDriver commit_active_job_driver = {
 | ||||
| @@ -1256,6 +1271,7 @@ static const BlockJobDriver commit_active_job_driver = {
 | ||||
|          .run                    = mirror_run, | ||||
|          .prepare                = mirror_prepare, | ||||
|          .abort                  = mirror_abort, | ||||
| @ -110,7 +112,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|          .pause                  = mirror_pause, | ||||
|          .complete               = mirror_complete, | ||||
|          .cancel                 = commit_active_cancel, | ||||
| @@ -1627,7 +1643,10 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1647,7 +1663,10 @@ static BlockJob *mirror_start_job(
 | ||||
|                               BlockCompletionFunc *cb, | ||||
|                               void *opaque, | ||||
|                               const BlockJobDriver *driver, | ||||
| @ -122,7 +124,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|                               bool auto_complete, const char *filter_node_name, | ||||
|                               bool is_mirror, MirrorCopyMode copy_mode, | ||||
|                               Error **errp) | ||||
| @@ -1639,10 +1658,39 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1659,10 +1678,39 @@ static BlockJob *mirror_start_job(
 | ||||
|      uint64_t target_perms, target_shared_perms; | ||||
|      int ret; | ||||
|   | ||||
| @ -164,7 +166,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|      assert(is_power_of_2(granularity)); | ||||
|   | ||||
|      if (buf_size < 0) { | ||||
| @@ -1774,7 +1822,9 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1793,7 +1841,9 @@ static BlockJob *mirror_start_job(
 | ||||
|      s->replaces = g_strdup(replaces); | ||||
|      s->on_source_error = on_source_error; | ||||
|      s->on_target_error = on_target_error; | ||||
| @ -175,7 +177,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|      s->backing_mode = backing_mode; | ||||
|      s->zero_target = zero_target; | ||||
|      s->copy_mode = copy_mode; | ||||
| @@ -1795,6 +1845,18 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1814,6 +1864,18 @@ static BlockJob *mirror_start_job(
 | ||||
|          bdrv_disable_dirty_bitmap(s->dirty_bitmap); | ||||
|      } | ||||
|   | ||||
| @ -194,7 +196,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|      ret = block_job_add_bdrv(&s->common, "source", bs, 0, | ||||
|                               BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | | ||||
|                               BLK_PERM_CONSISTENT_READ, | ||||
| @@ -1872,6 +1934,9 @@ fail:
 | ||||
| @@ -1891,6 +1953,9 @@ fail:
 | ||||
|          if (s->dirty_bitmap) { | ||||
|              bdrv_release_dirty_bitmap(s->dirty_bitmap); | ||||
|          } | ||||
| @ -204,7 +206,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|          job_early_fail(&s->common.job); | ||||
|      } | ||||
|   | ||||
| @@ -1889,31 +1954,25 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -1908,31 +1973,25 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
 | ||||
|                    BlockDriverState *target, const char *replaces, | ||||
|                    int creation_flags, int64_t speed, | ||||
|                    uint32_t granularity, int64_t buf_size, | ||||
| @ -241,7 +243,7 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|  } | ||||
|   | ||||
|  BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, | ||||
| @@ -1940,7 +1999,8 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -1959,7 +2018,8 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
 | ||||
|                       job_id, bs, creation_flags, base, NULL, speed, 0, 0, | ||||
|                       MIRROR_LEAVE_BACKING_CHAIN, false, | ||||
|                       on_error, on_error, true, cb, opaque, | ||||
| @ -252,21 +254,20 @@ index 251adc5ae0..8ead5f77a0 100644 | ||||
|                       errp); | ||||
|      if (!job) { | ||||
| diff --git a/blockdev.c b/blockdev.c
 | ||||
| index 3f1dec6242..2ee30323cb 100644
 | ||||
| index d7b5c18f0a..6c34d9bb3a 100644
 | ||||
| --- a/blockdev.c
 | ||||
| +++ b/blockdev.c
 | ||||
| @@ -2946,6 +2946,10 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -2932,6 +2932,9 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
|                                     BlockDriverState *target, | ||||
|                                     bool has_replaces, const char *replaces, | ||||
|                                     const char *replaces, | ||||
|                                     enum MirrorSyncMode sync, | ||||
| +                                   bool has_bitmap,
 | ||||
| +                                   const char *bitmap_name,
 | ||||
| +                                   bool has_bitmap_mode,
 | ||||
| +                                   BitmapSyncMode bitmap_mode,
 | ||||
|                                     BlockMirrorBackingMode backing_mode, | ||||
|                                     bool zero_target, | ||||
|                                     bool has_speed, int64_t speed, | ||||
| @@ -2965,6 +2969,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -2950,6 +2953,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
|  { | ||||
|      BlockDriverState *unfiltered_bs; | ||||
|      int job_flags = JOB_DEFAULT; | ||||
| @ -274,11 +275,11 @@ index 3f1dec6242..2ee30323cb 100644 | ||||
|   | ||||
|      if (!has_speed) { | ||||
|          speed = 0; | ||||
| @@ -3019,6 +3024,29 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -3001,6 +3005,29 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
|          sync = MIRROR_SYNC_MODE_FULL; | ||||
|      } | ||||
|   | ||||
| +    if (has_bitmap) {
 | ||||
| +    if (bitmap) {
 | ||||
| +        if (granularity) {
 | ||||
| +            error_setg(errp, "Granularity and bitmap cannot both be set");
 | ||||
| +            return;
 | ||||
| @ -301,53 +302,53 @@ index 3f1dec6242..2ee30323cb 100644 | ||||
| +        }
 | ||||
| +    }
 | ||||
| +
 | ||||
|      if (!has_replaces) { | ||||
|      if (!replaces) { | ||||
|          /* We want to mirror from @bs, but keep implicit filters on top */ | ||||
|          unfiltered_bs = bdrv_skip_implicit_filters(bs); | ||||
| @@ -3065,8 +3093,8 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -3046,8 +3073,8 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
|       * and will allow to check whether the node still exist at mirror completion | ||||
|       */ | ||||
|      mirror_start(job_id, bs, target, | ||||
| -                 has_replaces ? replaces : NULL, job_flags,
 | ||||
| -                 replaces, job_flags,
 | ||||
| -                 speed, granularity, buf_size, sync, backing_mode, zero_target,
 | ||||
| +                 has_replaces ? replaces : NULL, job_flags, speed, granularity,
 | ||||
| +                 buf_size, sync, bitmap, bitmap_mode, backing_mode, zero_target,
 | ||||
| +                 replaces, job_flags, speed, granularity, buf_size, sync,
 | ||||
| +                 bitmap, bitmap_mode, backing_mode, zero_target,
 | ||||
|                   on_source_error, on_target_error, unmap, filter_node_name, | ||||
|                   copy_mode, errp); | ||||
|  } | ||||
| @@ -3211,6 +3239,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 | ||||
| @@ -3192,6 +3219,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 | ||||
|   | ||||
|      blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, | ||||
|                             arg->has_replaces, arg->replaces, arg->sync, | ||||
| +                           arg->has_bitmap, arg->bitmap,
 | ||||
|      blockdev_mirror_common(arg->job_id, bs, target_bs, | ||||
|                             arg->replaces, arg->sync, | ||||
| +                           arg->bitmap,
 | ||||
| +                           arg->has_bitmap_mode, arg->bitmap_mode,
 | ||||
|                             backing_mode, zero_target, | ||||
|                             arg->has_speed, arg->speed, | ||||
|                             arg->has_granularity, arg->granularity, | ||||
| @@ -3232,6 +3262,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
 | ||||
| @@ -3213,6 +3242,8 @@ void qmp_blockdev_mirror(const char *job_id,
 | ||||
|                           const char *device, const char *target, | ||||
|                           bool has_replaces, const char *replaces, | ||||
|                           const char *replaces, | ||||
|                           MirrorSyncMode sync, | ||||
| +                         bool has_bitmap, const char *bitmap,
 | ||||
| +                         const char *bitmap,
 | ||||
| +                         bool has_bitmap_mode, BitmapSyncMode bitmap_mode,
 | ||||
|                           bool has_speed, int64_t speed, | ||||
|                           bool has_granularity, uint32_t granularity, | ||||
|                           bool has_buf_size, int64_t buf_size, | ||||
| @@ -3281,7 +3313,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
 | ||||
| @@ -3261,7 +3292,8 @@ void qmp_blockdev_mirror(const char *job_id,
 | ||||
|      } | ||||
|   | ||||
|      blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs, | ||||
| -                           has_replaces, replaces, sync, backing_mode,
 | ||||
| +                           has_replaces, replaces, sync, has_bitmap,
 | ||||
|      blockdev_mirror_common(job_id, bs, target_bs, | ||||
| -                           replaces, sync, backing_mode,
 | ||||
| +                           replaces, sync,
 | ||||
| +                           bitmap, has_bitmap_mode, bitmap_mode, backing_mode,
 | ||||
|                             zero_target, has_speed, speed, | ||||
|                             has_granularity, granularity, | ||||
|                             has_buf_size, buf_size, | ||||
| diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h
 | ||||
| index b49f4eb35b..9d744db618 100644
 | ||||
| index 902406eb99..d559be928c 100644
 | ||||
| --- a/include/block/block_int-global-state.h
 | ||||
| +++ b/include/block/block_int-global-state.h
 | ||||
| @@ -149,7 +149,9 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -152,7 +152,9 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
 | ||||
|                    BlockDriverState *target, const char *replaces, | ||||
|                    int creation_flags, int64_t speed, | ||||
|                    uint32_t granularity, int64_t buf_size, | ||||
| @ -359,10 +360,10 @@ index b49f4eb35b..9d744db618 100644 | ||||
|                    BlockdevOnError on_source_error, | ||||
|                    BlockdevOnError on_target_error, | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 95ac4fa634..7daaf545be 100644
 | ||||
| index c05ad0c07e..3c945c1f93 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -2000,10 +2000,19 @@
 | ||||
| @@ -2095,10 +2095,19 @@
 | ||||
|  #        (all the disk, only the sectors allocated in the topmost image, or | ||||
|  #        only new I/O). | ||||
|  # | ||||
| @ -383,7 +384,7 @@ index 95ac4fa634..7daaf545be 100644 | ||||
|  # | ||||
|  # @buf-size: maximum amount of data in flight from source to | ||||
|  #            target (since 1.4). | ||||
| @@ -2043,7 +2052,9 @@
 | ||||
| @@ -2138,7 +2147,9 @@
 | ||||
|  { 'struct': 'DriveMirror', | ||||
|    'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', | ||||
|              '*format': 'str', '*node-name': 'str', '*replaces': 'str', | ||||
| @ -394,7 +395,7 @@ index 95ac4fa634..7daaf545be 100644 | ||||
|              '*speed': 'int', '*granularity': 'uint32', | ||||
|              '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', | ||||
|              '*on-target-error': 'BlockdevOnError', | ||||
| @@ -2322,10 +2333,19 @@
 | ||||
| @@ -2417,10 +2428,19 @@
 | ||||
|  #        (all the disk, only the sectors allocated in the topmost image, or | ||||
|  #        only new I/O). | ||||
|  # | ||||
| @ -415,7 +416,7 @@ index 95ac4fa634..7daaf545be 100644 | ||||
|  # | ||||
|  # @buf-size: maximum amount of data in flight from source to | ||||
|  #            target | ||||
| @@ -2375,7 +2395,8 @@
 | ||||
| @@ -2470,7 +2490,8 @@
 | ||||
|  { 'command': 'blockdev-mirror', | ||||
|    'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', | ||||
|              '*replaces': 'str', | ||||
| @ -426,10 +427,10 @@ index 95ac4fa634..7daaf545be 100644 | ||||
|              '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', | ||||
|              '*on-target-error': 'BlockdevOnError', | ||||
| diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
 | ||||
| index 8ca5adec5e..dae80e5a5f 100644
 | ||||
| index 3a5e1eb2c4..c1ecc49073 100644
 | ||||
| --- a/tests/unit/test-block-iothread.c
 | ||||
| +++ b/tests/unit/test-block-iothread.c
 | ||||
| @@ -755,8 +755,8 @@ static void test_propagate_mirror(void)
 | ||||
| @@ -757,8 +757,8 @@ static void test_propagate_mirror(void)
 | ||||
|   | ||||
|      /* Start a mirror job */ | ||||
|      mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, | ||||
|  | ||||
| @ -24,10 +24,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 18 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/mirror.c b/block/mirror.c
 | ||||
| index 8ead5f77a0..35c1b8f25d 100644
 | ||||
| index 9099c75992..e2ff42067b 100644
 | ||||
| --- a/block/mirror.c
 | ||||
| +++ b/block/mirror.c
 | ||||
| @@ -676,8 +676,6 @@ static int mirror_exit_common(Job *job)
 | ||||
| @@ -680,8 +680,6 @@ static int mirror_exit_common(Job *job)
 | ||||
|          bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs); | ||||
|      } | ||||
|   | ||||
| @ -36,7 +36,7 @@ index 8ead5f77a0..35c1b8f25d 100644 | ||||
|      /* Make sure that the source BDS doesn't go away during bdrv_replace_node, | ||||
|       * before we can call bdrv_drained_end */ | ||||
|      bdrv_ref(src); | ||||
| @@ -778,6 +776,18 @@ static int mirror_exit_common(Job *job)
 | ||||
| @@ -782,6 +780,18 @@ static int mirror_exit_common(Job *job)
 | ||||
|      block_job_remove_all_bdrv(bjob); | ||||
|      bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort); | ||||
|   | ||||
| @ -55,7 +55,7 @@ index 8ead5f77a0..35c1b8f25d 100644 | ||||
|      bs_opaque->job = NULL; | ||||
|   | ||||
|      bdrv_drained_end(src); | ||||
| @@ -1668,10 +1678,6 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1688,10 +1698,6 @@ static BlockJob *mirror_start_job(
 | ||||
|                         " sync mode", | ||||
|                         MirrorSyncMode_str(sync_mode)); | ||||
|              return NULL; | ||||
| @ -66,7 +66,7 @@ index 8ead5f77a0..35c1b8f25d 100644 | ||||
|          } | ||||
|      } else if (bitmap) { | ||||
|          error_setg(errp, | ||||
| @@ -1688,6 +1694,12 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1708,6 +1714,12 @@ static BlockJob *mirror_start_job(
 | ||||
|              return NULL; | ||||
|          } | ||||
|          granularity = bdrv_dirty_bitmap_granularity(bitmap); | ||||
|  | ||||
| @ -16,10 +16,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| diff --git a/blockdev.c b/blockdev.c
 | ||||
| index 2ee30323cb..dd1c2cdef7 100644
 | ||||
| index 6c34d9bb3a..24a76b451d 100644
 | ||||
| --- a/blockdev.c
 | ||||
| +++ b/blockdev.c
 | ||||
| @@ -3045,6 +3045,9 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -3026,6 +3026,9 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
|          if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { | ||||
|              return; | ||||
|          } | ||||
| @ -28,4 +28,4 @@ index 2ee30323cb..dd1c2cdef7 100644 | ||||
| +        return;
 | ||||
|      } | ||||
|   | ||||
|      if (!has_replaces) { | ||||
|      if (!replaces) { | ||||
|  | ||||
| @ -16,10 +16,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 4 insertions(+), 7 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/mirror.c b/block/mirror.c
 | ||||
| index 35c1b8f25d..4969c6833c 100644
 | ||||
| index e2ff42067b..f42953837b 100644
 | ||||
| --- a/block/mirror.c
 | ||||
| +++ b/block/mirror.c
 | ||||
| @@ -782,8 +782,8 @@ static int mirror_exit_common(Job *job)
 | ||||
| @@ -786,8 +786,8 @@ static int mirror_exit_common(Job *job)
 | ||||
|               job->ret == 0 && ret == 0)) { | ||||
|              /* Success; synchronize copy back to sync. */ | ||||
|              bdrv_clear_dirty_bitmap(s->sync_bitmap, NULL); | ||||
| @ -30,7 +30,7 @@ index 35c1b8f25d..4969c6833c 100644 | ||||
|          } | ||||
|      } | ||||
|      bdrv_release_dirty_bitmap(s->dirty_bitmap); | ||||
| @@ -1862,11 +1862,8 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1881,11 +1881,8 @@ static BlockJob *mirror_start_job(
 | ||||
|      } | ||||
|   | ||||
|      if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) { | ||||
|  | ||||
| @ -12,6 +12,8 @@ uniform w.r.t. backup block jobs. | ||||
| 
 | ||||
| Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: rebase for 8.0] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/mirror.c             | 28 +++------------ | ||||
|  blockdev.c                 | 29 +++++++++++++++ | ||||
| @ -19,10 +21,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  3 files changed, 70 insertions(+), 59 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/mirror.c b/block/mirror.c
 | ||||
| index 4969c6833c..cf85ae1074 100644
 | ||||
| index f42953837b..8f79efaa87 100644
 | ||||
| --- a/block/mirror.c
 | ||||
| +++ b/block/mirror.c
 | ||||
| @@ -1668,31 +1668,13 @@ static BlockJob *mirror_start_job(
 | ||||
| @@ -1688,31 +1688,13 @@ static BlockJob *mirror_start_job(
 | ||||
|      uint64_t target_perms, target_shared_perms; | ||||
|      int ret; | ||||
|   | ||||
| @ -60,17 +62,17 @@ index 4969c6833c..cf85ae1074 100644 | ||||
|   | ||||
|          if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { | ||||
| diff --git a/blockdev.c b/blockdev.c
 | ||||
| index dd1c2cdef7..756e980889 100644
 | ||||
| index 24a76b451d..3917af7d02 100644
 | ||||
| --- a/blockdev.c
 | ||||
| +++ b/blockdev.c
 | ||||
| @@ -3024,7 +3024,36 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -3005,7 +3005,36 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
 | ||||
|          sync = MIRROR_SYNC_MODE_FULL; | ||||
|      } | ||||
|   | ||||
| +    if ((sync == MIRROR_SYNC_MODE_BITMAP) ||
 | ||||
| +        (sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
 | ||||
| +        /* done before desugaring 'incremental' to print the right message */
 | ||||
| +        if (!has_bitmap) {
 | ||||
| +        if (!bitmap) {
 | ||||
| +            error_setg(errp, "Must provide a valid bitmap name for "
 | ||||
| +                       "'%s' sync mode", MirrorSyncMode_str(sync));
 | ||||
| +            return;
 | ||||
| @ -91,7 +93,7 @@ index dd1c2cdef7..756e980889 100644 | ||||
| +        bitmap_mode = BITMAP_SYNC_MODE_ON_SUCCESS;
 | ||||
| +    }
 | ||||
| +
 | ||||
|      if (has_bitmap) { | ||||
|      if (bitmap) { | ||||
| +        if (sync != MIRROR_SYNC_MODE_BITMAP) {
 | ||||
| +            error_setg(errp, "Sync mode '%s' not supported with bitmap.",
 | ||||
| +                       MirrorSyncMode_str(sync));
 | ||||
|  | ||||
| @ -48,7 +48,7 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  6 files changed, 59 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
 | ||||
| index 737e750670..38804b8595 100644
 | ||||
| index 033390f699..ad35d4fea8 100644
 | ||||
| --- a/include/monitor/monitor.h
 | ||||
| +++ b/include/monitor/monitor.h
 | ||||
| @@ -16,6 +16,7 @@ extern QemuOptsList qemu_mon_opts;
 | ||||
| @ -60,7 +60,7 @@ index 737e750670..38804b8595 100644 | ||||
|  void monitor_init_globals(void); | ||||
|  void monitor_init_globals_core(void); | ||||
| diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
 | ||||
| index a2cdbbf646..b531bd50e7 100644
 | ||||
| index 53e3808054..a19f8cbc2b 100644
 | ||||
| --- a/monitor/monitor-internal.h
 | ||||
| +++ b/monitor/monitor-internal.h
 | ||||
| @@ -152,6 +152,13 @@ typedef struct {
 | ||||
| @ -78,7 +78,7 @@ index a2cdbbf646..b531bd50e7 100644 | ||||
|   | ||||
|  /** | ||||
| diff --git a/monitor/monitor.c b/monitor/monitor.c
 | ||||
| index 86949024f6..c306cadcf4 100644
 | ||||
| index 8dc96f6af9..f3c38cb714 100644
 | ||||
| --- a/monitor/monitor.c
 | ||||
| +++ b/monitor/monitor.c
 | ||||
| @@ -135,6 +135,21 @@ bool monitor_cur_is_qmp(void)
 | ||||
|  | ||||
| @ -1,42 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Fiona Ebner <f.ebner@proxmox.com> | ||||
| Date: Fri, 28 Oct 2022 10:09:46 +0200 | ||||
| Subject: [PATCH] init: daemonize: defuse PID file resolve error | ||||
| 
 | ||||
| When proxmox-file-restore invokes QEMU, the PID file is a (temporary) | ||||
| file that's already unlinked, so resolving the absolute path here | ||||
| failed. | ||||
| 
 | ||||
| It should not be a critical error when the PID file unlink handler | ||||
| can't be registered, because the path can't be resolved for whatever | ||||
| reason. If the file is already gone from QEMU's perspective (i.e. | ||||
| errno is ENOENT), silently ignore the error. Otherwise, print a | ||||
| warning. | ||||
| 
 | ||||
| Reported-by: Dominik Csapak <d.csapak@proxmox.com> | ||||
| Suggested-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  softmmu/vl.c | 9 +++++---- | ||||
|  1 file changed, 5 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/softmmu/vl.c b/softmmu/vl.c
 | ||||
| index 5115221efe..5f7f6ca981 100644
 | ||||
| --- a/softmmu/vl.c
 | ||||
| +++ b/softmmu/vl.c
 | ||||
| @@ -2460,10 +2460,11 @@ static void qemu_maybe_daemonize(const char *pid_file)
 | ||||
|   | ||||
|          pid_file_realpath = g_malloc0(PATH_MAX); | ||||
|          if (!realpath(pid_file, pid_file_realpath)) { | ||||
| -            error_report("cannot resolve PID file path: %s: %s",
 | ||||
| -                         pid_file, strerror(errno));
 | ||||
| -            unlink(pid_file);
 | ||||
| -            exit(1);
 | ||||
| +            if (errno != ENOENT) {
 | ||||
| +                warn_report("not removing PID file on exit: cannot resolve PID "
 | ||||
| +                            "file path: %s: %s", pid_file, strerror(errno));
 | ||||
| +            }
 | ||||
| +            return;
 | ||||
|          } | ||||
|   | ||||
|          qemu_unlink_pidfile_notifier = (struct UnlinkPidfileNotifier) { | ||||
| @ -38,7 +38,7 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  3 files changed, 25 insertions(+) | ||||
| 
 | ||||
| diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
 | ||||
| index 785dd5a56e..886f6bb79e 100644
 | ||||
| index bd50ad5ee1..7623703943 100644
 | ||||
| --- a/include/hw/qdev-core.h
 | ||||
| +++ b/include/hw/qdev-core.h
 | ||||
| @@ -162,6 +162,10 @@ struct NamedClockList {
 | ||||
| @ -63,7 +63,7 @@ index 785dd5a56e..886f6bb79e 100644 | ||||
|   | ||||
|  struct DeviceListener { | ||||
| diff --git a/softmmu/memory.c b/softmmu/memory.c
 | ||||
| index bc0be3f62c..7dcb3347aa 100644
 | ||||
| index b1a6cae6f5..e4d2268d32 100644
 | ||||
| --- a/softmmu/memory.c
 | ||||
| +++ b/softmmu/memory.c
 | ||||
| @@ -533,6 +533,7 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
 | ||||
| @ -1,44 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Chenyi Qiang <chenyi.qiang@intel.com> | ||||
| Date: Fri, 16 Dec 2022 14:22:31 +0800 | ||||
| Subject: [PATCH] virtio-mem: Fix the bitmap index of the section offset | ||||
| 
 | ||||
| vmem->bitmap indexes the memory region of the virtio-mem backend at a | ||||
| granularity of block_size. To calculate the index of target section offset, | ||||
| the block_size should be divided instead of the bitmap_size. | ||||
| 
 | ||||
| Fixes: 2044969f0b ("virtio-mem: Implement RamDiscardManager interface") | ||||
| Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> | ||||
| Message-Id: <20221216062231.11181-1-chenyi.qiang@intel.com> | ||||
| Reviewed-by: David Hildenbrand <david@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Signed-off-by: David Hildenbrand <david@redhat.com> | ||||
| (cherry-picked from commit b11cf32e07a2f7ff0d171b89497381a04c9d07e0) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/virtio/virtio-mem.c | 4 ++-- | ||||
|  1 file changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
 | ||||
| index ed170def48..e19ee817fe 100644
 | ||||
| --- a/hw/virtio/virtio-mem.c
 | ||||
| +++ b/hw/virtio/virtio-mem.c
 | ||||
| @@ -235,7 +235,7 @@ static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem,
 | ||||
|      uint64_t offset, size; | ||||
|      int ret = 0; | ||||
|   | ||||
| -    first_bit = s->offset_within_region / vmem->bitmap_size;
 | ||||
| +    first_bit = s->offset_within_region / vmem->block_size;
 | ||||
|      first_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size, first_bit); | ||||
|      while (first_bit < vmem->bitmap_size) { | ||||
|          MemoryRegionSection tmp = *s; | ||||
| @@ -267,7 +267,7 @@ static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem,
 | ||||
|      uint64_t offset, size; | ||||
|      int ret = 0; | ||||
|   | ||||
| -    first_bit = s->offset_within_region / vmem->bitmap_size;
 | ||||
| +    first_bit = s->offset_within_region / vmem->block_size;
 | ||||
|      first_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size, first_bit); | ||||
|      while (first_bit < vmem->bitmap_size) { | ||||
|          MemoryRegionSection tmp = *s; | ||||
| @ -55,10 +55,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 6 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/ide/core.c b/hw/ide/core.c
 | ||||
| index 39afdc0006..b67c1885a8 100644
 | ||||
| index 45d14a25e9..08e1f0c3d7 100644
 | ||||
| --- a/hw/ide/core.c
 | ||||
| +++ b/hw/ide/core.c
 | ||||
| @@ -443,7 +443,7 @@ static void ide_trim_bh_cb(void *opaque)
 | ||||
| @@ -444,7 +444,7 @@ static void ide_trim_bh_cb(void *opaque)
 | ||||
|      iocb->bh = NULL; | ||||
|      qemu_aio_unref(iocb); | ||||
|   | ||||
| @ -67,7 +67,7 @@ index 39afdc0006..b67c1885a8 100644 | ||||
|      blk_dec_in_flight(blk); | ||||
|  } | ||||
|   | ||||
| @@ -503,6 +503,8 @@ static void ide_issue_trim_cb(void *opaque, int ret)
 | ||||
| @@ -504,6 +504,8 @@ static void ide_issue_trim_cb(void *opaque, int ret)
 | ||||
|  done: | ||||
|      iocb->aiocb = NULL; | ||||
|      if (iocb->bh) { | ||||
| @ -76,7 +76,7 @@ index 39afdc0006..b67c1885a8 100644 | ||||
|          replay_bh_schedule_event(iocb->bh); | ||||
|      } | ||||
|  } | ||||
| @@ -514,9 +516,6 @@ BlockAIOCB *ide_issue_trim(
 | ||||
| @@ -515,9 +517,6 @@ BlockAIOCB *ide_issue_trim(
 | ||||
|      IDEState *s = opaque; | ||||
|      TrimAIOCB *iocb; | ||||
|   | ||||
| @ -86,7 +86,7 @@ index 39afdc0006..b67c1885a8 100644 | ||||
|      iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque); | ||||
|      iocb->s = s; | ||||
|      iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); | ||||
| @@ -739,8 +738,9 @@ void ide_cancel_dma_sync(IDEState *s)
 | ||||
| @@ -740,8 +739,9 @@ void ide_cancel_dma_sync(IDEState *s)
 | ||||
|       */ | ||||
|      if (s->bus->dma->aiocb) { | ||||
|          trace_ide_cancel_dma_sync_remaining(); | ||||
| @ -1,36 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Chenyi Qiang <chenyi.qiang@intel.com> | ||||
| Date: Wed, 28 Dec 2022 17:03:12 +0800 | ||||
| Subject: [PATCH] virtio-mem: Fix the iterator variable in a vmem->rdl_list | ||||
|  loop | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| It should be the variable rdl2 to revert the already-notified listeners. | ||||
| 
 | ||||
| Fixes: 2044969f0b ("virtio-mem: Implement RamDiscardManager interface") | ||||
| Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> | ||||
| Message-Id: <20221228090312.17276-1-chenyi.qiang@intel.com> | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||||
| Signed-off-by: David Hildenbrand <david@redhat.com> | ||||
| (cherry-picked from commit 29f1b328e3b767cba2661920a8470738469b9e36) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/virtio/virtio-mem.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
 | ||||
| index e19ee817fe..56db586c89 100644
 | ||||
| --- a/hw/virtio/virtio-mem.c
 | ||||
| +++ b/hw/virtio/virtio-mem.c
 | ||||
| @@ -341,7 +341,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset,
 | ||||
|      if (ret) { | ||||
|          /* Notify all already-notified listeners. */ | ||||
|          QLIST_FOREACH(rdl2, &vmem->rdl_list, next) { | ||||
| -            MemoryRegionSection tmp = *rdl->section;
 | ||||
| +            MemoryRegionSection tmp = *rdl2->section;
 | ||||
|   | ||||
|              if (rdl2 == rdl) { | ||||
|                  break; | ||||
| @ -10,10 +10,10 @@ Signed-off-by: Alexander Bulekov <alxndr@bu.edu> | ||||
|  2 files changed, 4 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/include/exec/memory.h b/include/exec/memory.h
 | ||||
| index 91f8a2395a..d7268d9f39 100644
 | ||||
| index 15ade918ba..e6819e3c39 100644
 | ||||
| --- a/include/exec/memory.h
 | ||||
| +++ b/include/exec/memory.h
 | ||||
| @@ -765,6 +765,9 @@ struct MemoryRegion {
 | ||||
| @@ -791,6 +791,9 @@ struct MemoryRegion {
 | ||||
|      unsigned ioeventfd_nb; | ||||
|      MemoryRegionIoeventfd *ioeventfds; | ||||
|      RamDiscardManager *rdm; /* Only for RAM */ | ||||
| @ -24,7 +24,7 @@ index 91f8a2395a..d7268d9f39 100644 | ||||
|   | ||||
|  struct IOMMUMemoryRegion { | ||||
| diff --git a/softmmu/memory.c b/softmmu/memory.c
 | ||||
| index 7dcb3347aa..2b46714191 100644
 | ||||
| index e4d2268d32..d88acb204b 100644
 | ||||
| --- a/softmmu/memory.c
 | ||||
| +++ b/softmmu/memory.c
 | ||||
| @@ -544,7 +544,7 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
 | ||||
| @ -1,141 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Jason Wang <jasowang@redhat.com> | ||||
| Date: Fri, 16 Dec 2022 11:35:52 +0800 | ||||
| Subject: [PATCH] vhost: fix vq dirty bitmap syncing when vIOMMU is enabled | ||||
| 
 | ||||
| When vIOMMU is enabled, the vq->used_phys is actually the IOVA not | ||||
| GPA. So we need to translate it to GPA before the syncing otherwise we | ||||
| may hit the following crash since IOVA could be out of the scope of | ||||
| the GPA log size. This could be noted when using virtio-IOMMU with | ||||
| vhost using 1G memory. | ||||
| 
 | ||||
| Fixes: c471ad0e9bd46 ("vhost_net: device IOTLB support") | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Tested-by: Lei Yang <leiyang@redhat.com> | ||||
| Reported-by: Yalan Zhang <yalzhang@redhat.com> | ||||
| Signed-off-by: Jason Wang <jasowang@redhat.com> | ||||
| Message-Id: <20221216033552.77087-1-jasowang@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit 345cc1cbcbce2bab00abc2b88338d7d89c702d6b) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/virtio/vhost.c | 84 ++++++++++++++++++++++++++++++++++++----------- | ||||
|  1 file changed, 64 insertions(+), 20 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
 | ||||
| index 7fb008bc9e..fdcd1a8fdf 100644
 | ||||
| --- a/hw/virtio/vhost.c
 | ||||
| +++ b/hw/virtio/vhost.c
 | ||||
| @@ -20,6 +20,7 @@
 | ||||
|  #include "qemu/range.h" | ||||
|  #include "qemu/error-report.h" | ||||
|  #include "qemu/memfd.h" | ||||
| +#include "qemu/log.h"
 | ||||
|  #include "standard-headers/linux/vhost_types.h" | ||||
|  #include "hw/virtio/virtio-bus.h" | ||||
|  #include "hw/virtio/virtio-access.h" | ||||
| @@ -106,6 +107,24 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
 | ||||
|      } | ||||
|  } | ||||
|   | ||||
| +static bool vhost_dev_has_iommu(struct vhost_dev *dev)
 | ||||
| +{
 | ||||
| +    VirtIODevice *vdev = dev->vdev;
 | ||||
| +
 | ||||
| +    /*
 | ||||
| +     * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support
 | ||||
| +     * incremental memory mapping API via IOTLB API. For platform that
 | ||||
| +     * does not have IOMMU, there's no need to enable this feature
 | ||||
| +     * which may cause unnecessary IOTLB miss/update transactions.
 | ||||
| +     */
 | ||||
| +    if (vdev) {
 | ||||
| +        return virtio_bus_device_iommu_enabled(vdev) &&
 | ||||
| +            virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
 | ||||
| +    } else {
 | ||||
| +        return false;
 | ||||
| +    }
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, | ||||
|                                     MemoryRegionSection *section, | ||||
|                                     hwaddr first, | ||||
| @@ -137,8 +156,51 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
 | ||||
|              continue; | ||||
|          } | ||||
|   | ||||
| -        vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys,
 | ||||
| -                              range_get_last(vq->used_phys, vq->used_size));
 | ||||
| +        if (vhost_dev_has_iommu(dev)) {
 | ||||
| +            IOMMUTLBEntry iotlb;
 | ||||
| +            hwaddr used_phys = vq->used_phys, used_size = vq->used_size;
 | ||||
| +            hwaddr phys, s, offset;
 | ||||
| +
 | ||||
| +            while (used_size) {
 | ||||
| +                rcu_read_lock();
 | ||||
| +                iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as,
 | ||||
| +                                                      used_phys,
 | ||||
| +                                                      true,
 | ||||
| +                                                      MEMTXATTRS_UNSPECIFIED);
 | ||||
| +                rcu_read_unlock();
 | ||||
| +
 | ||||
| +                if (!iotlb.target_as) {
 | ||||
| +                    qemu_log_mask(LOG_GUEST_ERROR, "translation "
 | ||||
| +                                  "failure for used_iova %"PRIx64"\n",
 | ||||
| +                                  used_phys);
 | ||||
| +                    return -EINVAL;
 | ||||
| +                }
 | ||||
| +
 | ||||
| +                offset = used_phys & iotlb.addr_mask;
 | ||||
| +                phys = iotlb.translated_addr + offset;
 | ||||
| +
 | ||||
| +                /*
 | ||||
| +                 * Distance from start of used ring until last byte of
 | ||||
| +                 * IOMMU page.
 | ||||
| +                 */
 | ||||
| +                s = iotlb.addr_mask - offset;
 | ||||
| +                /*
 | ||||
| +                 * Size of used ring, or of the part of it until end
 | ||||
| +                 * of IOMMU page. To avoid zero result, do the adding
 | ||||
| +                 * outside of MIN().
 | ||||
| +                 */
 | ||||
| +                s = MIN(s, used_size - 1) + 1;
 | ||||
| +
 | ||||
| +                vhost_dev_sync_region(dev, section, start_addr, end_addr, phys,
 | ||||
| +                                      range_get_last(phys, s));
 | ||||
| +                used_size -= s;
 | ||||
| +                used_phys += s;
 | ||||
| +            }
 | ||||
| +        } else {
 | ||||
| +            vhost_dev_sync_region(dev, section, start_addr,
 | ||||
| +                                  end_addr, vq->used_phys,
 | ||||
| +                                  range_get_last(vq->used_phys, vq->used_size));
 | ||||
| +        }
 | ||||
|      } | ||||
|      return 0; | ||||
|  } | ||||
| @@ -306,24 +368,6 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
 | ||||
|      dev->log_size = size; | ||||
|  } | ||||
|   | ||||
| -static bool vhost_dev_has_iommu(struct vhost_dev *dev)
 | ||||
| -{
 | ||||
| -    VirtIODevice *vdev = dev->vdev;
 | ||||
| -
 | ||||
| -    /*
 | ||||
| -     * For vhost, VIRTIO_F_IOMMU_PLATFORM means the backend support
 | ||||
| -     * incremental memory mapping API via IOTLB API. For platform that
 | ||||
| -     * does not have IOMMU, there's no need to enable this feature
 | ||||
| -     * which may cause unnecessary IOTLB miss/update transactions.
 | ||||
| -     */
 | ||||
| -    if (vdev) {
 | ||||
| -        return virtio_bus_device_iommu_enabled(vdev) &&
 | ||||
| -            virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
 | ||||
| -    } else {
 | ||||
| -        return false;
 | ||||
| -    }
 | ||||
| -}
 | ||||
| -
 | ||||
|  static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr, | ||||
|                                hwaddr *plen, bool is_write) | ||||
|  { | ||||
| @ -15,7 +15,7 @@ Signed-off-by: Alexander Bulekov <alxndr@bu.edu> | ||||
|  1 file changed, 6 insertions(+) | ||||
| 
 | ||||
| diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
 | ||||
| index 50979640c3..894b9311ac 100644
 | ||||
| index af93557a9a..db27872963 100644
 | ||||
| --- a/hw/scsi/lsi53c895a.c
 | ||||
| +++ b/hw/scsi/lsi53c895a.c
 | ||||
| @@ -2302,6 +2302,12 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
 | ||||
| @ -1,42 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | ||||
| Date: Mon, 9 Jan 2023 10:58:09 +0000 | ||||
| Subject: [PATCH] virtio-rng-pci: fix migration compat for vectors | ||||
| 
 | ||||
| Fixup the migration compatibility for existing machine types | ||||
| so that they do not enable msi-x. | ||||
| 
 | ||||
| Symptom: | ||||
| 
 | ||||
| (qemu) qemu: get_pci_config_device: Bad config data: i=0x34 read: 84 device: 98 cmask: ff wmask: 0 w1cmask:0 | ||||
| qemu: Failed to load PCIDevice:config | ||||
| qemu: Failed to load virtio-rng:virtio | ||||
| qemu: error while loading state for instance 0x0 of device '0000:00:03.0/virtio-rng' | ||||
| qemu: load of migration failed: Invalid argument | ||||
| 
 | ||||
| Note: This fix will break migration from 7.2->7.2-fixed with this patch | ||||
| 
 | ||||
| bz: https://bugzilla.redhat.com/show_bug.cgi?id=2155749 | ||||
| Fixes: 9ea02e8f1 ("virtio-rng-pci: Allow setting nvectors, so we can use MSI-X") | ||||
| 
 | ||||
| Reviewed-by: Thomas Huth <thuth@redhat.com> | ||||
| Acked-by: David Daney <david.daney@fungible.com> | ||||
| Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||||
| (picked-up from https://lists.nongnu.org/archive/html/qemu-devel/2023-01/msg01319.html) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/core/machine.c | 1 + | ||||
|  1 file changed, 1 insertion(+) | ||||
| 
 | ||||
| diff --git a/hw/core/machine.c b/hw/core/machine.c
 | ||||
| index 8d34caa31d..77a0a131d1 100644
 | ||||
| --- a/hw/core/machine.c
 | ||||
| +++ b/hw/core/machine.c
 | ||||
| @@ -42,6 +42,7 @@
 | ||||
|   | ||||
|  GlobalProperty hw_compat_7_1[] = { | ||||
|      { "virtio-device", "queue_reset", "false" }, | ||||
| +    { "virtio-rng-pci", "vectors", "0" },
 | ||||
|  }; | ||||
|  const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1); | ||||
|   | ||||
| @ -1,36 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Stefan Hajnoczi <stefanha@redhat.com> | ||||
| Date: Thu, 26 Jan 2023 15:13:58 -0500 | ||||
| Subject: [PATCH] block: fix detect-zeroes= with BDRV_REQ_REGISTERED_BUF | ||||
| 
 | ||||
| When a write request is converted into a write zeroes request by the | ||||
| detect-zeroes= feature, it is no longer associated with an I/O buffer. | ||||
| The BDRV_REQ_REGISTERED_BUF flag doesn't make sense without an I/O | ||||
| buffer and must be cleared because bdrv_co_do_pwrite_zeroes() fails with | ||||
| -EINVAL when it's set.
 | ||||
| 
 | ||||
| Fiona Ebner <f.ebner@proxmox.com> bisected and diagnosed this QEMU 7.2 | ||||
| regression where writes containing zeroes to a blockdev with | ||||
| discard=unmap,detect-zeroes=unmap fail. | ||||
| 
 | ||||
| Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1404 | ||||
| Fixes: e8b6535533be ("block: add BDRV_REQ_REGISTERED_BUF request flag") | ||||
| Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||||
| ---
 | ||||
|  block/io.c | 3 +++ | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| diff --git a/block/io.c b/block/io.c
 | ||||
| index b9424024f9..bbaa0d1b2d 100644
 | ||||
| --- a/block/io.c
 | ||||
| +++ b/block/io.c
 | ||||
| @@ -2087,6 +2087,9 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
 | ||||
|          if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) { | ||||
|              flags |= BDRV_REQ_MAY_UNMAP; | ||||
|          } | ||||
| +
 | ||||
| +        /* Can't use optimization hint with bufferless zero write */
 | ||||
| +        flags &= ~BDRV_REQ_REGISTERED_BUF;
 | ||||
|      } | ||||
|   | ||||
|      if (ret < 0) { | ||||
| @ -1,32 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Paolo Bonzini <pbonzini@redhat.com> | ||||
| Date: Tue, 10 Jan 2023 17:36:33 +0100 | ||||
| Subject: [PATCH] block/iscsi: fix double-free on BUSY or similar statuses | ||||
| 
 | ||||
| Commit 8c460269aa77 ("iscsi: base all handling of check condition on | ||||
| scsi_sense_to_errno", 2019-07-15) removed a "goto out" so that the | ||||
| same coroutine is re-entered twice; once from iscsi_co_generic_cb, | ||||
| once from the timer callback iscsi_retry_timer_expired.  This can | ||||
| cause a crash. | ||||
| 
 | ||||
| Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1378 | ||||
| Reported-by: Grzegorz Zdanowski <https://gitlab.com/kiler129> | ||||
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||||
| (cherry-picked from commit 5080152e2ef6cde7aa692e29880c62bd54acb750) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/iscsi.c | 1 + | ||||
|  1 file changed, 1 insertion(+) | ||||
| 
 | ||||
| diff --git a/block/iscsi.c b/block/iscsi.c
 | ||||
| index 3ed4a50c0d..89cd032c3a 100644
 | ||||
| --- a/block/iscsi.c
 | ||||
| +++ b/block/iscsi.c
 | ||||
| @@ -268,6 +268,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
 | ||||
|                  timer_mod(&iTask->retry_timer, | ||||
|                            qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time); | ||||
|                  iTask->do_retry = 1; | ||||
| +                return;
 | ||||
|              } else if (status == SCSI_STATUS_CHECK_CONDITION) { | ||||
|                  int error = iscsi_translate_sense(&task->sense); | ||||
|                  if (error == EAGAIN) { | ||||
| @ -1,67 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Klaus Jensen <k.jensen@samsung.com> | ||||
| Date: Wed, 8 Mar 2023 19:57:12 +0300 | ||||
| Subject: [PATCH] hw/nvme: fix missing endian conversions for doorbell buffers | ||||
| 
 | ||||
| The eventidx and doorbell value are not handling endianness correctly. | ||||
| Fix this. | ||||
| 
 | ||||
| Fixes: 3f7fe8de3d49 ("hw/nvme: Implement shadow doorbell buffer support") | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Reported-by: Guenter Roeck <linux@roeck-us.net> | ||||
| Reviewed-by: Keith Busch <kbusch@kernel.org> | ||||
| Signed-off-by: Klaus Jensen <k.jensen@samsung.com> | ||||
| (cherry picked from commit 2fda0726e5149e032acfa5fe442db56cd6433c4c) | ||||
| Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> | ||||
| Conflicts: hw/nvme/ctrl.c | ||||
| (picked up from qemu-stable mailing list) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/nvme/ctrl.c | 22 ++++++++++++++++------ | ||||
|  1 file changed, 16 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
 | ||||
| index e54276dc1d..98d8e34109 100644
 | ||||
| --- a/hw/nvme/ctrl.c
 | ||||
| +++ b/hw/nvme/ctrl.c
 | ||||
| @@ -1333,8 +1333,12 @@ static inline void nvme_blk_write(BlockBackend *blk, int64_t offset,
 | ||||
|   | ||||
|  static void nvme_update_cq_head(NvmeCQueue *cq) | ||||
|  { | ||||
| -    pci_dma_read(&cq->ctrl->parent_obj, cq->db_addr, &cq->head,
 | ||||
| -            sizeof(cq->head));
 | ||||
| +    uint32_t v;
 | ||||
| +
 | ||||
| +    pci_dma_read(&cq->ctrl->parent_obj, cq->db_addr, &v, sizeof(v));
 | ||||
| +
 | ||||
| +    cq->head = le32_to_cpu(v);
 | ||||
| +
 | ||||
|      trace_pci_nvme_shadow_doorbell_cq(cq->cqid, cq->head); | ||||
|  } | ||||
|   | ||||
| @@ -6141,15 +6145,21 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
 | ||||
|   | ||||
|  static void nvme_update_sq_eventidx(const NvmeSQueue *sq) | ||||
|  { | ||||
| -    pci_dma_write(&sq->ctrl->parent_obj, sq->ei_addr, &sq->tail,
 | ||||
| -                  sizeof(sq->tail));
 | ||||
| +    uint32_t v = cpu_to_le32(sq->tail);
 | ||||
| +
 | ||||
| +    pci_dma_write(&sq->ctrl->parent_obj, sq->ei_addr, &v, sizeof(v));
 | ||||
| +
 | ||||
|      trace_pci_nvme_eventidx_sq(sq->sqid, sq->tail); | ||||
|  } | ||||
|   | ||||
|  static void nvme_update_sq_tail(NvmeSQueue *sq) | ||||
|  { | ||||
| -    pci_dma_read(&sq->ctrl->parent_obj, sq->db_addr, &sq->tail,
 | ||||
| -                 sizeof(sq->tail));
 | ||||
| +    uint32_t v;
 | ||||
| +
 | ||||
| +    pci_dma_read(&sq->ctrl->parent_obj, sq->db_addr, &v, sizeof(v));
 | ||||
| +
 | ||||
| +    sq->tail = le32_to_cpu(v);
 | ||||
| +
 | ||||
|      trace_pci_nvme_shadow_doorbell_sq(sq->sqid, sq->tail); | ||||
|  } | ||||
|   | ||||
| @ -1,50 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Julia Suvorova <jusual@redhat.com> | ||||
| Date: Thu, 23 Feb 2023 13:57:47 +0100 | ||||
| Subject: [PATCH] hw/smbios: fix field corruption in type 4 table | ||||
| 
 | ||||
| Since table type 4 of SMBIOS version 2.6 is shorter than 3.0, the | ||||
| strings which follow immediately after the struct fields have been | ||||
| overwritten by unconditional filling of later fields such as core_count2. | ||||
| Make these fields dependent on the SMBIOS version. | ||||
| 
 | ||||
| Fixes: 05e27d74c7 ("hw/smbios: add core_count2 to smbios table type 4") | ||||
| Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2169904 | ||||
| 
 | ||||
| Signed-off-by: Julia Suvorova <jusual@redhat.com> | ||||
| Message-Id: <20230223125747.254914-1-jusual@redhat.com> | ||||
| Reviewed-by: Igor Mammedov <imammedo@redhat.com> | ||||
| Reviewed-by: Ani Sinha <ani@anisinha.ca> | ||||
| Reviewed-by: Igor Mammedov <imammedo@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit 60d09b8dc7dd4256d664ad680795cb1327805b2b) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/smbios/smbios.c | 8 +++++--- | ||||
|  1 file changed, 5 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
 | ||||
| index b4243de735..66a020999b 100644
 | ||||
| --- a/hw/smbios/smbios.c
 | ||||
| +++ b/hw/smbios/smbios.c
 | ||||
| @@ -749,14 +749,16 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
 | ||||
|      t->core_count = (ms->smp.cores > 255) ? 0xFF : ms->smp.cores; | ||||
|      t->core_enabled = t->core_count; | ||||
|   | ||||
| -    t->core_count2 = t->core_enabled2 = cpu_to_le16(ms->smp.cores);
 | ||||
| -
 | ||||
|      t->thread_count = (ms->smp.threads > 255) ? 0xFF : ms->smp.threads; | ||||
| -    t->thread_count2 = cpu_to_le16(ms->smp.threads);
 | ||||
|   | ||||
|      t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ | ||||
|      t->processor_family2 = cpu_to_le16(0x01); /* Other */ | ||||
|   | ||||
| +    if (tbl_len == SMBIOS_TYPE_4_LEN_V30) {
 | ||||
| +        t->core_count2 = t->core_enabled2 = cpu_to_le16(ms->smp.cores);
 | ||||
| +        t->thread_count2 = cpu_to_le16(ms->smp.threads);
 | ||||
| +    }
 | ||||
| +
 | ||||
|      SMBIOS_BUILD_TABLE_POST; | ||||
|      smbios_type4_count++; | ||||
|  } | ||||
| @ -1,35 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | ||||
| Date: Tue, 7 Feb 2023 17:49:44 +0000 | ||||
| Subject: [PATCH] virtio-rng-pci: fix transitional migration compat for vectors | ||||
| 
 | ||||
| In bad9c5a516 ("virtio-rng-pci: fix migration compat for vectors") I | ||||
| fixed the virtio-rng-pci migration compatibility, but it was discovered | ||||
| that we also need to fix the other aliases of the device for the | ||||
| transitional cases. | ||||
| 
 | ||||
| Fixes: 9ea02e8f1 ('virtio-rng-pci: Allow setting nvectors, so we can use MSI-X') | ||||
| bz: https://bugzilla.redhat.com/show_bug.cgi?id=2162569 | ||||
| Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||||
| Message-Id: <20230207174944.138255-1-dgilbert@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit 62bdb8871512076841f4464f7e26efdc7783f78d) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/core/machine.c | 2 ++ | ||||
|  1 file changed, 2 insertions(+) | ||||
| 
 | ||||
| diff --git a/hw/core/machine.c b/hw/core/machine.c
 | ||||
| index cd84579591..4297315984 100644
 | ||||
| --- a/hw/core/machine.c
 | ||||
| +++ b/hw/core/machine.c
 | ||||
| @@ -43,6 +43,8 @@
 | ||||
|  GlobalProperty hw_compat_7_1[] = { | ||||
|      { "virtio-device", "queue_reset", "false" }, | ||||
|      { "virtio-rng-pci", "vectors", "0" }, | ||||
| +    { "virtio-rng-pci-transitional", "vectors", "0" },
 | ||||
| +    { "virtio-rng-pci-non-transitional", "vectors", "0" },
 | ||||
|  }; | ||||
|  const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1); | ||||
|   | ||||
| @ -1,80 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Akihiko Odaki <akihiko.odaki@daynix.com> | ||||
| Date: Tue, 31 Jan 2023 12:00:37 +0900 | ||||
| Subject: [PATCH] hw/timer/hpet: Fix expiration time overflow | ||||
| 
 | ||||
| The expiration time provided for timer_mod() can overflow if a | ||||
| ridiculously large value is set to the comparator register. The | ||||
| resulting value can represent a past time after rounded, forcing the | ||||
| timer to fire immediately. If the timer is configured as periodic, it | ||||
| will rearm the timer again, and form an endless loop. | ||||
| 
 | ||||
| Check if the expiration value will overflow, and if it will, stop the | ||||
| timer instead of rearming the timer with the overflowed time. | ||||
| 
 | ||||
| This bug was found by Alexander Bulekov when fuzzing igb, a new | ||||
| network device emulation: | ||||
| https://patchew.org/QEMU/20230129053316.1071513-1-alxndr@bu.edu/ | ||||
| 
 | ||||
| The fixed test case is: | ||||
| fuzz/crash_2d7036941dcda1ad4380bb8a9174ed0c949bcefd | ||||
| 
 | ||||
| Fixes: 16b29ae180 ("Add HPET emulation to qemu (Beth Kon)") | ||||
| Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||||
| Acked-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Message-Id: <20230131030037.18856-1-akihiko.odaki@daynix.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit 37d2bcbc2a4e9c2e9061bec72a32c7e49b9f81ec) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/timer/hpet.c | 19 +++++++++++++------ | ||||
|  1 file changed, 13 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
 | ||||
| index 9520471be2..5f88ffdef8 100644
 | ||||
| --- a/hw/timer/hpet.c
 | ||||
| +++ b/hw/timer/hpet.c
 | ||||
| @@ -352,6 +352,16 @@ static const VMStateDescription vmstate_hpet = {
 | ||||
|      } | ||||
|  }; | ||||
|   | ||||
| +static void hpet_arm(HPETTimer *t, uint64_t ticks)
 | ||||
| +{
 | ||||
| +    if (ticks < ns_to_ticks(INT64_MAX / 2)) {
 | ||||
| +        timer_mod(t->qemu_timer,
 | ||||
| +                  qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_ns(ticks));
 | ||||
| +    } else {
 | ||||
| +        timer_del(t->qemu_timer);
 | ||||
| +    }
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* | ||||
|   * timer expiration callback | ||||
|   */ | ||||
| @@ -374,13 +384,11 @@ static void hpet_timer(void *opaque)
 | ||||
|              } | ||||
|          } | ||||
|          diff = hpet_calculate_diff(t, cur_tick); | ||||
| -        timer_mod(t->qemu_timer,
 | ||||
| -                       qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff));
 | ||||
| +        hpet_arm(t, diff);
 | ||||
|      } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { | ||||
|          if (t->wrap_flag) { | ||||
|              diff = hpet_calculate_diff(t, cur_tick); | ||||
| -            timer_mod(t->qemu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
 | ||||
| -                           (int64_t)ticks_to_ns(diff));
 | ||||
| +            hpet_arm(t, diff);
 | ||||
|              t->wrap_flag = 0; | ||||
|          } | ||||
|      } | ||||
| @@ -407,8 +415,7 @@ static void hpet_set_timer(HPETTimer *t)
 | ||||
|              t->wrap_flag = 1; | ||||
|          } | ||||
|      } | ||||
| -    timer_mod(t->qemu_timer,
 | ||||
| -                   qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff));
 | ||||
| +    hpet_arm(t, diff);
 | ||||
|  } | ||||
|   | ||||
|  static void hpet_del_timer(HPETTimer *t) | ||||
| @ -1,71 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= <eperezma@redhat.com> | ||||
| Date: Thu, 9 Feb 2023 18:00:04 +0100 | ||||
| Subject: [PATCH] vdpa: stop all svq on device deletion | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| Not stopping them leave the device in a bad state when virtio-net | ||||
| fronted device is unplugged with device_del monitor command. | ||||
| 
 | ||||
| This is not triggable in regular poweroff or qemu forces shutdown | ||||
| because cleanup is called right after vhost_vdpa_dev_start(false).  But | ||||
| devices hot unplug does not call vdpa device cleanups.  This lead to all | ||||
| the vhost_vdpa devices without stop the SVQ but the last. | ||||
| 
 | ||||
| Fix it and clean the code, making it symmetric with | ||||
| vhost_vdpa_svqs_start. | ||||
| 
 | ||||
| Fixes: dff4426fa656 ("vhost: Add Shadow VirtQueue kick forwarding capabilities") | ||||
| Reported-by: Lei Yang <leiyang@redhat.com> | ||||
| Signed-off-by: Eugenio Pérez <eperezma@redhat.com> | ||||
| Message-Id: <20230209170004.899472-1-eperezma@redhat.com> | ||||
| Tested-by: Laurent Vivier <lvivier@redhat.com> | ||||
| Acked-by: Jason Wang <jasowang@redhat.com> | ||||
| (cherry-picked from commit 2e1a9de96b487cf818a22d681cad8d3f5d18dcca) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/virtio/vhost-vdpa.c | 17 ++--------------- | ||||
|  1 file changed, 2 insertions(+), 15 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
 | ||||
| index 7468e44b87..03c78d25d8 100644
 | ||||
| --- a/hw/virtio/vhost-vdpa.c
 | ||||
| +++ b/hw/virtio/vhost-vdpa.c
 | ||||
| @@ -707,26 +707,11 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
 | ||||
|      return ret; | ||||
|  } | ||||
|   | ||||
| -static void vhost_vdpa_reset_svq(struct vhost_vdpa *v)
 | ||||
| -{
 | ||||
| -    if (!v->shadow_vqs_enabled) {
 | ||||
| -        return;
 | ||||
| -    }
 | ||||
| -
 | ||||
| -    for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {
 | ||||
| -        VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
 | ||||
| -        vhost_svq_stop(svq);
 | ||||
| -    }
 | ||||
| -}
 | ||||
| -
 | ||||
|  static int vhost_vdpa_reset_device(struct vhost_dev *dev) | ||||
|  { | ||||
| -    struct vhost_vdpa *v = dev->opaque;
 | ||||
|      int ret; | ||||
|      uint8_t status = 0; | ||||
|   | ||||
| -    vhost_vdpa_reset_svq(v);
 | ||||
| -
 | ||||
|      ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); | ||||
|      trace_vhost_vdpa_reset_device(dev, status); | ||||
|      return ret; | ||||
| @@ -1088,6 +1073,8 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev)
 | ||||
|   | ||||
|      for (unsigned i = 0; i < v->shadow_vqs->len; ++i) { | ||||
|          VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i); | ||||
| +
 | ||||
| +        vhost_svq_stop(svq);
 | ||||
|          vhost_vdpa_svq_unmap_rings(dev, svq); | ||||
|      } | ||||
|  } | ||||
| @ -1,132 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: =?UTF-8?q?Carlos=20L=C3=B3pez?= <clopez@suse.de> | ||||
| Date: Mon, 13 Feb 2023 09:57:47 +0100 | ||||
| Subject: [PATCH] vhost: avoid a potential use of an uninitialized variable in | ||||
|  vhost_svq_poll() | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| In vhost_svq_poll(), if vhost_svq_get_buf() fails due to a device | ||||
| providing invalid descriptors, len is left uninitialized and returned | ||||
| to the caller, potentally leaking stack data or causing undefined | ||||
| behavior. | ||||
| 
 | ||||
| Fix this by initializing len to 0. | ||||
| 
 | ||||
| Found with GCC 13 and -fanalyzer (abridged): | ||||
| 
 | ||||
| ../hw/virtio/vhost-shadow-virtqueue.c: In function ‘vhost_svq_poll’: | ||||
| ../hw/virtio/vhost-shadow-virtqueue.c:538:12: warning: use of uninitialized value ‘len’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] | ||||
|   538 |     return len; | ||||
|       |            ^~~ | ||||
|   ‘vhost_svq_poll’: events 1-4 | ||||
|     | | ||||
|     |  522 | size_t vhost_svq_poll(VhostShadowVirtqueue *svq) | ||||
|     |      |        ^~~~~~~~~~~~~~ | ||||
|     |      |        | | ||||
|     |      |        (1) entry to ‘vhost_svq_poll’ | ||||
|     |...... | ||||
|     |  525 |     uint32_t len; | ||||
|     |      |              ~~~ | ||||
|     |      |              | | ||||
|     |      |              (2) region created on stack here | ||||
|     |      |              (3) capacity: 4 bytes | ||||
|     |...... | ||||
|     |  528 |         if (vhost_svq_more_used(svq)) { | ||||
|     |      |             ~ | ||||
|     |      |             | | ||||
|     |      |             (4) inlined call to ‘vhost_svq_more_used’ from ‘vhost_svq_poll’ | ||||
| 
 | ||||
|     (...) | ||||
| 
 | ||||
|     |  528 |         if (vhost_svq_more_used(svq)) { | ||||
|     |      |            ^~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     |      |            || | ||||
|     |      |            |(8) ...to here | ||||
|     |      |            (7) following ‘true’ branch... | ||||
|     |...... | ||||
|     |  537 |     vhost_svq_get_buf(svq, &len); | ||||
|     |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     |      |     | | ||||
|     |      |     (9) calling ‘vhost_svq_get_buf’ from ‘vhost_svq_poll’ | ||||
|     | | ||||
|     +--> ‘vhost_svq_get_buf’: events 10-11 | ||||
|            | | ||||
|            |  416 | static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq, | ||||
|            |      |                          ^~~~~~~~~~~~~~~~~ | ||||
|            |      |                          | | ||||
|            |      |                          (10) entry to ‘vhost_svq_get_buf’ | ||||
|            |...... | ||||
|            |  423 |     if (!vhost_svq_more_used(svq)) { | ||||
|            |      |          ~ | ||||
|            |      |          | | ||||
|            |      |          (11) inlined call to ‘vhost_svq_more_used’ from ‘vhost_svq_get_buf’ | ||||
|            | | ||||
| 
 | ||||
|            (...) | ||||
| 
 | ||||
|            | | ||||
|          ‘vhost_svq_get_buf’: event 14 | ||||
|            | | ||||
|            |  423 |     if (!vhost_svq_more_used(svq)) { | ||||
|            |      |        ^ | ||||
|            |      |        | | ||||
|            |      |        (14) following ‘false’ branch... | ||||
|            | | ||||
|          ‘vhost_svq_get_buf’: event 15 | ||||
|            | | ||||
|            |cc1: | ||||
|            | (15): ...to here | ||||
|            | | ||||
|     <------+ | ||||
|     | | ||||
|   ‘vhost_svq_poll’: events 16-17 | ||||
|     | | ||||
|     |  537 |     vhost_svq_get_buf(svq, &len); | ||||
|     |      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|     |      |     | | ||||
|     |      |     (16) returning to ‘vhost_svq_poll’ from ‘vhost_svq_get_buf’ | ||||
|     |  538 |     return len; | ||||
|     |      |            ~~~ | ||||
|     |      |            | | ||||
|     |      |            (17) use of uninitialized value ‘len’ here | ||||
| 
 | ||||
| Note by  Laurent Vivier <lvivier@redhat.com>: | ||||
| 
 | ||||
|     The return value is only used to detect an error: | ||||
| 
 | ||||
|     vhost_svq_poll | ||||
|         vhost_vdpa_net_cvq_add | ||||
|             vhost_vdpa_net_load_cmd | ||||
|                 vhost_vdpa_net_load_mac | ||||
|                   -> a negative return is only used to detect error | ||||
|                 vhost_vdpa_net_load_mq | ||||
|                   -> a negative return is only used to detect error | ||||
|             vhost_vdpa_net_handle_ctrl_avail | ||||
|               -> a negative return is only used to detect error | ||||
| 
 | ||||
| Fixes: d368c0b052ad ("vhost: Do not depend on !NULL VirtQueueElement on vhost_svq_flush") | ||||
| Signed-off-by: Carlos López <clopez@suse.de> | ||||
| Message-Id: <20230213085747.19956-1-clopez@suse.de> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit e4dd39c699b7d63a06f686ec06ded8adbee989c1) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/virtio/vhost-shadow-virtqueue.c | 2 +- | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
 | ||||
| index 5bd14cad96..a723073747 100644
 | ||||
| --- a/hw/virtio/vhost-shadow-virtqueue.c
 | ||||
| +++ b/hw/virtio/vhost-shadow-virtqueue.c
 | ||||
| @@ -522,7 +522,7 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq,
 | ||||
|  size_t vhost_svq_poll(VhostShadowVirtqueue *svq) | ||||
|  { | ||||
|      int64_t start_us = g_get_monotonic_time(); | ||||
| -    uint32_t len;
 | ||||
| +    uint32_t len = 0;
 | ||||
|   | ||||
|      do { | ||||
|          if (vhost_svq_more_used(svq)) { | ||||
| @ -1,70 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Yajun Wu <yajunw@nvidia.com> | ||||
| Date: Tue, 14 Feb 2023 10:14:30 +0800 | ||||
| Subject: [PATCH] chardev/char-socket: set s->listener = NULL in | ||||
|  char_socket_finalize | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| After live migration with virtio block device, qemu crash at: | ||||
| 
 | ||||
| 	#0  0x000055914f46f795 in object_dynamic_cast_assert (obj=0x559151b7b090, typename=0x55914f80fbc4 "qio-channel", file=0x55914f80fb90 "/images/testvfe/sw/qemu.gerrit/include/io/channel.h", line=30, func=0x55914f80fcb8 <__func__.17257> "QIO_CHANNEL") at ../qom/object.c:872 | ||||
| 	#1  0x000055914f480d68 in QIO_CHANNEL (obj=0x559151b7b090) at /images/testvfe/sw/qemu.gerrit/include/io/channel.h:29 | ||||
| 	#2  0x000055914f4812f8 in qio_net_listener_set_client_func_full (listener=0x559151b7a720, func=0x55914f580b97 <tcp_chr_accept>, data=0x5591519f4ea0, notify=0x0, context=0x0) at ../io/net-listener.c:166 | ||||
| 	#3  0x000055914f580059 in tcp_chr_update_read_handler (chr=0x5591519f4ea0) at ../chardev/char-socket.c:637 | ||||
| 	#4  0x000055914f583dca in qemu_chr_be_update_read_handlers (s=0x5591519f4ea0, context=0x0) at ../chardev/char.c:226 | ||||
| 	#5  0x000055914f57b7c9 in qemu_chr_fe_set_handlers_full (b=0x559152bf23a0, fd_can_read=0x0, fd_read=0x0, fd_event=0x0, be_change=0x0, opaque=0x0, context=0x0, set_open=false, sync_state=true) at ../chardev/char-fe.c:279 | ||||
| 	#6  0x000055914f57b86d in qemu_chr_fe_set_handlers (b=0x559152bf23a0, fd_can_read=0x0, fd_read=0x0, fd_event=0x0, be_change=0x0, opaque=0x0, context=0x0, set_open=false) at ../chardev/char-fe.c:304 | ||||
| 	#7  0x000055914f378caf in vhost_user_async_close (d=0x559152bf21a0, chardev=0x559152bf23a0, vhost=0x559152bf2420, cb=0x55914f2fb8c1 <vhost_user_blk_disconnect>) at ../hw/virtio/vhost-user.c:2725 | ||||
| 	#8  0x000055914f2fba40 in vhost_user_blk_event (opaque=0x559152bf21a0, event=CHR_EVENT_CLOSED) at ../hw/block/vhost-user-blk.c:395 | ||||
| 	#9  0x000055914f58388c in chr_be_event (s=0x5591519f4ea0, event=CHR_EVENT_CLOSED) at ../chardev/char.c:61 | ||||
| 	#10 0x000055914f583905 in qemu_chr_be_event (s=0x5591519f4ea0, event=CHR_EVENT_CLOSED) at ../chardev/char.c:81 | ||||
| 	#11 0x000055914f581275 in char_socket_finalize (obj=0x5591519f4ea0) at ../chardev/char-socket.c:1083 | ||||
| 	#12 0x000055914f46f073 in object_deinit (obj=0x5591519f4ea0, type=0x5591519055c0) at ../qom/object.c:680 | ||||
| 	#13 0x000055914f46f0e5 in object_finalize (data=0x5591519f4ea0) at ../qom/object.c:694 | ||||
| 	#14 0x000055914f46ff06 in object_unref (objptr=0x5591519f4ea0) at ../qom/object.c:1202 | ||||
| 	#15 0x000055914f4715a4 in object_finalize_child_property (obj=0x559151b76c50, name=0x559151b7b250 "char3", opaque=0x5591519f4ea0) at ../qom/object.c:1747 | ||||
| 	#16 0x000055914f46ee86 in object_property_del_all (obj=0x559151b76c50) at ../qom/object.c:632 | ||||
| 	#17 0x000055914f46f0d2 in object_finalize (data=0x559151b76c50) at ../qom/object.c:693 | ||||
| 	#18 0x000055914f46ff06 in object_unref (objptr=0x559151b76c50) at ../qom/object.c:1202 | ||||
| 	#19 0x000055914f4715a4 in object_finalize_child_property (obj=0x559151b6b560, name=0x559151b76630 "chardevs", opaque=0x559151b76c50) at ../qom/object.c:1747 | ||||
| 	#20 0x000055914f46ef67 in object_property_del_child (obj=0x559151b6b560, child=0x559151b76c50) at ../qom/object.c:654 | ||||
| 	#21 0x000055914f46f042 in object_unparent (obj=0x559151b76c50) at ../qom/object.c:673 | ||||
| 	#22 0x000055914f58632a in qemu_chr_cleanup () at ../chardev/char.c:1189 | ||||
| 	#23 0x000055914f16c66c in qemu_cleanup () at ../softmmu/runstate.c:830 | ||||
| 	#24 0x000055914eee7b9e in qemu_default_main () at ../softmmu/main.c:38 | ||||
| 	#25 0x000055914eee7bcc in main (argc=86, argv=0x7ffc97cb8d88) at ../softmmu/main.c:48 | ||||
| 
 | ||||
| In char_socket_finalize after s->listener freed, event callback function | ||||
| vhost_user_blk_event will be called to handle CHR_EVENT_CLOSED. | ||||
| vhost_user_blk_event is calling qio_net_listener_set_client_func_full which | ||||
| is still using s->listener. | ||||
| 
 | ||||
| Setting s->listener = NULL after object_unref(OBJECT(s->listener)) can | ||||
| solve this issue. | ||||
| 
 | ||||
| Signed-off-by: Yajun Wu <yajunw@nvidia.com> | ||||
| Acked-by: Jiri Pirko <jiri@nvidia.com> | ||||
| Message-Id: <20230214021430.3638579-1-yajunw@nvidia.com> | ||||
| Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit b8a7f51f59e28d5a8e0c07ed3919cc9695560ed2) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  chardev/char-socket.c | 1 + | ||||
|  1 file changed, 1 insertion(+) | ||||
| 
 | ||||
| diff --git a/chardev/char-socket.c b/chardev/char-socket.c
 | ||||
| index 879564aa8a..b00efb1482 100644
 | ||||
| --- a/chardev/char-socket.c
 | ||||
| +++ b/chardev/char-socket.c
 | ||||
| @@ -1065,6 +1065,7 @@ static void char_socket_finalize(Object *obj)
 | ||||
|          qio_net_listener_set_client_func_full(s->listener, NULL, NULL, | ||||
|                                                NULL, chr->gcontext); | ||||
|          object_unref(OBJECT(s->listener)); | ||||
| +        s->listener = NULL;
 | ||||
|      } | ||||
|      if (s->tls_creds) { | ||||
|          object_unref(OBJECT(s->tls_creds)); | ||||
| @ -1,41 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Jason Wang <jasowang@redhat.com> | ||||
| Date: Thu, 23 Feb 2023 14:59:20 +0800 | ||||
| Subject: [PATCH] intel-iommu: fail MAP notifier without caching mode | ||||
| 
 | ||||
| Without caching mode, MAP notifier won't work correctly since guest | ||||
| won't send IOTLB update event when it establishes new mappings in the | ||||
| I/O page tables. Let's fail the IOMMU notifiers early instead of | ||||
| misbehaving silently. | ||||
| 
 | ||||
| Reviewed-by: Eric Auger <eric.auger@redhat.com> | ||||
| Tested-by: Viktor Prutyanov <viktor@daynix.com> | ||||
| Signed-off-by: Jason Wang <jasowang@redhat.com> | ||||
| Message-Id: <20230223065924.42503-2-jasowang@redhat.com> | ||||
| Reviewed-by: Peter Xu <peterx@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit b8d78277c091f26fdd64f239bc8bb7e55d74cecf) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/i386/intel_iommu.c | 7 +++++++ | ||||
|  1 file changed, 7 insertions(+) | ||||
| 
 | ||||
| diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
 | ||||
| index a08ee85edf..9143376677 100644
 | ||||
| --- a/hw/i386/intel_iommu.c
 | ||||
| +++ b/hw/i386/intel_iommu.c
 | ||||
| @@ -3186,6 +3186,13 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
 | ||||
|                           "Snoop Control with vhost or VFIO is not supported"); | ||||
|          return -ENOTSUP; | ||||
|      } | ||||
| +    if (!s->caching_mode && (new & IOMMU_NOTIFIER_MAP)) {
 | ||||
| +        error_setg_errno(errp, ENOTSUP,
 | ||||
| +                         "device %02x.%02x.%x requires caching mode",
 | ||||
| +                         pci_bus_num(vtd_as->bus), PCI_SLOT(vtd_as->devfn),
 | ||||
| +                         PCI_FUNC(vtd_as->devfn));
 | ||||
| +        return -ENOTSUP;
 | ||||
| +    }
 | ||||
|   | ||||
|      /* Update per-address-space notifier flags */ | ||||
|      vtd_as->notifier_flags = new; | ||||
| @ -1,50 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Jason Wang <jasowang@redhat.com> | ||||
| Date: Thu, 23 Feb 2023 14:59:21 +0800 | ||||
| Subject: [PATCH] intel-iommu: fail DEVIOTLB_UNMAP without dt mode | ||||
| 
 | ||||
| Without dt mode, device IOTLB notifier won't work since guest won't | ||||
| send device IOTLB invalidation descriptor in this case. Let's fail | ||||
| early instead of misbehaving silently. | ||||
| 
 | ||||
| Reviewed-by: Laurent Vivier <lvivier@redhat.com> | ||||
| Tested-by: Laurent Vivier <lvivier@redhat.com> | ||||
| Tested-by: Viktor Prutyanov <viktor@daynix.com> | ||||
| Buglink: https://bugzilla.redhat.com/2156876 | ||||
| Signed-off-by: Jason Wang <jasowang@redhat.com> | ||||
| Message-Id: <20230223065924.42503-3-jasowang@redhat.com> | ||||
| Reviewed-by: Peter Xu <peterx@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit 09adb0e021207b60a0c51a68939b4539d98d3ef3) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/i386/intel_iommu.c | 8 ++++++++ | ||||
|  1 file changed, 8 insertions(+) | ||||
| 
 | ||||
| diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
 | ||||
| index 9143376677..d025ef2873 100644
 | ||||
| --- a/hw/i386/intel_iommu.c
 | ||||
| +++ b/hw/i386/intel_iommu.c
 | ||||
| @@ -3179,6 +3179,7 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
 | ||||
|  { | ||||
|      VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); | ||||
|      IntelIOMMUState *s = vtd_as->iommu_state; | ||||
| +    X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
 | ||||
|   | ||||
|      /* TODO: add support for VFIO and vhost users */ | ||||
|      if (s->snoop_control) { | ||||
| @@ -3193,6 +3194,13 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
 | ||||
|                           PCI_FUNC(vtd_as->devfn)); | ||||
|          return -ENOTSUP; | ||||
|      } | ||||
| +    if (!x86_iommu->dt_supported && (new & IOMMU_NOTIFIER_DEVIOTLB_UNMAP)) {
 | ||||
| +        error_setg_errno(errp, ENOTSUP,
 | ||||
| +                         "device %02x.%02x.%x requires device IOTLB mode",
 | ||||
| +                         pci_bus_num(vtd_as->bus), PCI_SLOT(vtd_as->devfn),
 | ||||
| +                         PCI_FUNC(vtd_as->devfn));
 | ||||
| +        return -ENOTSUP;
 | ||||
| +    }
 | ||||
|   | ||||
|      /* Update per-address-space notifier flags */ | ||||
|      vtd_as->notifier_flags = new; | ||||
| @ -1,166 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Laszlo Ersek <lersek@redhat.com> | ||||
| Date: Thu, 5 Jan 2023 17:18:04 +0100 | ||||
| Subject: [PATCH] acpi: cpuhp: fix guest-visible maximum access size to the | ||||
|  legacy reg block | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| The modern ACPI CPU hotplug interface was introduced in the following | ||||
| series (aa1dd39ca307..679dd1a957df), released in v2.7.0: | ||||
| 
 | ||||
|   1  abd49bc2ed2f docs: update ACPI CPU hotplug spec with new protocol | ||||
|   2  16bcab97eb9f pc: piix4/ich9: add 'cpu-hotplug-legacy' property | ||||
|   3  5e1b5d93887b acpi: cpuhp: add CPU devices AML with _STA method | ||||
|   4  ac35f13ba8f8 pc: acpi: introduce AcpiDeviceIfClass.madt_cpu hook | ||||
|   5  d2238cb6781d acpi: cpuhp: implement hot-add parts of CPU hotplug | ||||
|                   interface | ||||
|   6  8872c25a26cc acpi: cpuhp: implement hot-remove parts of CPU hotplug | ||||
|                   interface | ||||
|   7  76623d00ae57 acpi: cpuhp: add cpu._OST handling | ||||
|   8  679dd1a957df pc: use new CPU hotplug interface since 2.7 machine type | ||||
| 
 | ||||
| Before patch#1, "docs/specs/acpi_cpu_hotplug.txt" only specified 1-byte | ||||
| accesses for the hotplug register block.  Patch#1 preserved the same | ||||
| restriction for the legacy register block, but: | ||||
| 
 | ||||
| - it specified DWORD accesses for some of the modern registers,
 | ||||
| 
 | ||||
| - in particular, the switch from the legacy block to the modern block
 | ||||
|   would require a DWORD write to the *legacy* block. | ||||
| 
 | ||||
| The latter functionality was then implemented in cpu_status_write() | ||||
| [hw/acpi/cpu_hotplug.c], in patch#8. | ||||
| 
 | ||||
| Unfortunately, all DWORD accesses depended on a dormant bug: the one | ||||
| introduced in earlier commit a014ed07bd5a ("memory: accept mismatching | ||||
| sizes in memory_region_access_valid", 2013-05-29); first released in | ||||
| v1.6.0.  Due to commit a014ed07bd5a, the DWORD accesses to the *legacy* | ||||
| CPU hotplug register block would work in spite of the above series *not* | ||||
| relaxing "valid.max_access_size = 1" in "hw/acpi/cpu_hotplug.c": | ||||
| 
 | ||||
| > static const MemoryRegionOps AcpiCpuHotplug_ops = {
 | ||||
| >     .read = cpu_status_read,
 | ||||
| >     .write = cpu_status_write,
 | ||||
| >     .endianness = DEVICE_LITTLE_ENDIAN,
 | ||||
| >     .valid = {
 | ||||
| >         .min_access_size = 1,
 | ||||
| >         .max_access_size = 1,
 | ||||
| >     },
 | ||||
| > };
 | ||||
| 
 | ||||
| Later, in commits e6d0c3ce6895 ("acpi: cpuhp: introduce 'Command data 2' | ||||
| field", 2020-01-22) and ae340aa3d256 ("acpi: cpuhp: spec: add typical | ||||
| usecases", 2020-01-22), first released in v5.0.0, the modern CPU hotplug | ||||
| interface (including the documentation) was extended with another DWORD | ||||
| *read* access, namely to the "Command data 2" register, which would be | ||||
| important for the guest to confirm whether it managed to switch the | ||||
| register block from legacy to modern. | ||||
| 
 | ||||
| This functionality too silently depended on the bug from commit | ||||
| a014ed07bd5a. | ||||
| 
 | ||||
| In commit 5d971f9e6725 ('memory: Revert "memory: accept mismatching sizes | ||||
| in memory_region_access_valid"', 2020-06-26), first released in v5.1.0, | ||||
| the bug from commit a014ed07bd5a was fixed (the commit was reverted). | ||||
| That swiftly exposed the bug in "AcpiCpuHotplug_ops", still present from | ||||
| the v2.7.0 series quoted at the top -- namely the fact that | ||||
| "valid.max_access_size = 1" didn't match what the guest was supposed to | ||||
| do, according to the spec ("docs/specs/acpi_cpu_hotplug.txt"). | ||||
| 
 | ||||
| The symptom is that the "modern interface negotiation protocol" | ||||
| described in commit ae340aa3d256: | ||||
| 
 | ||||
| > +      Use following steps to detect and enable modern CPU hotplug interface:
 | ||||
| > +        1. Store 0x0 to the 'CPU selector' register,
 | ||||
| > +           attempting to switch to modern mode
 | ||||
| > +        2. Store 0x0 to the 'CPU selector' register,
 | ||||
| > +           to ensure valid selector value
 | ||||
| > +        3. Store 0x0 to the 'Command field' register,
 | ||||
| > +        4. Read the 'Command data 2' register.
 | ||||
| > +           If read value is 0x0, the modern interface is enabled.
 | ||||
| > +           Otherwise legacy or no CPU hotplug interface available
 | ||||
| 
 | ||||
| falls apart for the guest: steps 1 and 2 are lost, because they are DWORD | ||||
| writes; so no switching happens.  Step 3 (a single-byte write) is not | ||||
| lost, but it has no effect; see the condition in cpu_status_write() in | ||||
| patch#8.  And step 4 *misleads* the guest into thinking that the switch | ||||
| worked: the DWORD read is lost again -- it returns zero to the guest | ||||
| without ever reaching the device model, so the guest never learns the | ||||
| switch didn't work. | ||||
| 
 | ||||
| This means that guest behavior centered on the "Command data 2" register | ||||
| worked *only* in the v5.0.0 release; it got effectively regressed in | ||||
| v5.1.0. | ||||
| 
 | ||||
| To make things *even more* complicated, the breakage was (and remains, as | ||||
| of today) visible with TCG acceleration only.  Commit 5d971f9e6725 makes | ||||
| no difference with KVM acceleration -- the DWORD accesses still work, | ||||
| despite "valid.max_access_size = 1". | ||||
| 
 | ||||
| As commit 5d971f9e6725 suggests, fix the problem by raising | ||||
| "valid.max_access_size" to 4 -- the spec now clearly instructs the guest | ||||
| to perform DWORD accesses to the legacy register block too, for enabling | ||||
| (and verifying!) the modern block.  In order to keep compatibility for the | ||||
| device model implementation though, set "impl.max_access_size = 1", so | ||||
| that wide accesses be split before they reach the legacy read/write | ||||
| handlers, like they always have been on KVM, and like they were on TCG | ||||
| before 5d971f9e6725 (v5.1.0). | ||||
| 
 | ||||
| Tested with: | ||||
| 
 | ||||
| - OVMF IA32 + qemu-system-i386, CPU hotplug/hot-unplug with SMM,
 | ||||
|   intermixed with ACPI S3 suspend/resume, using KVM accel | ||||
|   (regression-test); | ||||
| 
 | ||||
| - OVMF IA32X64 + qemu-system-x86_64, CPU hotplug/hot-unplug with SMM,
 | ||||
|   intermixed with ACPI S3 suspend/resume, using KVM accel | ||||
|   (regression-test); | ||||
| 
 | ||||
| - OVMF IA32 + qemu-system-i386, SMM enabled, using TCG accel; verified the
 | ||||
|   register block switch and the present/possible CPU counting through the | ||||
|   modern hotplug interface, during OVMF boot (bugfix test); | ||||
| 
 | ||||
| - I do not have any testcase (guest payload) for regression-testing CPU
 | ||||
|   hotplug through the *legacy* CPU hotplug register block. | ||||
| 
 | ||||
| Cc: "Michael S. Tsirkin" <mst@redhat.com> | ||||
| Cc: Ani Sinha <ani@anisinha.ca> | ||||
| Cc: Ard Biesheuvel <ardb@kernel.org> | ||||
| Cc: Igor Mammedov <imammedo@redhat.com> | ||||
| Cc: Paolo Bonzini <pbonzini@redhat.com> | ||||
| Cc: Peter Maydell <peter.maydell@linaro.org> | ||||
| Cc: Philippe Mathieu-Daudé <philmd@linaro.org> | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Ref: "IO port write width clamping differs between TCG and KVM" | ||||
| Link: http://mid.mail-archive.com/aaedee84-d3ed-a4f9-21e7-d221a28d1683@redhat.com | ||||
| Link: https://lists.gnu.org/archive/html/qemu-devel/2023-01/msg00199.html | ||||
| Reported-by: Ard Biesheuvel <ardb@kernel.org> | ||||
| Signed-off-by: Laszlo Ersek <lersek@redhat.com> | ||||
| Tested-by: Ard Biesheuvel <ardb@kernel.org> | ||||
| Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||||
| Tested-by: Igor Mammedov <imammedo@redhat.com> | ||||
| Message-Id: <20230105161804.82486-1-lersek@redhat.com> | ||||
| Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | ||||
| (cherry-picked from commit dab30fbef3896bb652a09d46c37d3f55657cbcbb) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/acpi/cpu_hotplug.c | 3 +++ | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c
 | ||||
| index 53654f8638..ff14c3f410 100644
 | ||||
| --- a/hw/acpi/cpu_hotplug.c
 | ||||
| +++ b/hw/acpi/cpu_hotplug.c
 | ||||
| @@ -52,6 +52,9 @@ static const MemoryRegionOps AcpiCpuHotplug_ops = {
 | ||||
|      .endianness = DEVICE_LITTLE_ENDIAN, | ||||
|      .valid = { | ||||
|          .min_access_size = 1, | ||||
| +        .max_access_size = 4,
 | ||||
| +    },
 | ||||
| +    .impl = {
 | ||||
|          .max_access_size = 1, | ||||
|      }, | ||||
|  }; | ||||
| @ -1,286 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Richard Henderson <richard.henderson@linaro.org> | ||||
| Date: Sat, 14 Jan 2023 13:05:41 -1000 | ||||
| Subject: [PATCH] tests/tcg/i386: Introduce and use reg_t consistently | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| Define reg_t based on the actual register width. | ||||
| Define the inlines using that type.  This will allow | ||||
| input registers to 32-bit insns to be set to 64-bit | ||||
| values on x86-64, which allows testing various edge cases. | ||||
| 
 | ||||
| Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||||
| Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||||
| Message-Id: <20230114230542.3116013-2-richard.henderson@linaro.org> | ||||
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||||
| (cherry-picked from commit 5d62d6649cd367b5b4a3676e7514d2f9ca86cb03) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  tests/tcg/i386/test-i386-bmi2.c | 182 ++++++++++++++++---------------- | ||||
|  1 file changed, 93 insertions(+), 89 deletions(-) | ||||
| 
 | ||||
| diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| index 5fadf47510..3c3ef85513 100644
 | ||||
| --- a/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| +++ b/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| @@ -3,34 +3,40 @@
 | ||||
|  #include <stdint.h> | ||||
|  #include <stdio.h> | ||||
|   | ||||
| +#ifdef __x86_64
 | ||||
| +typedef uint64_t reg_t;
 | ||||
| +#else
 | ||||
| +typedef uint32_t reg_t;
 | ||||
| +#endif
 | ||||
| +
 | ||||
|  #define insn1q(name, arg0)                                                           \ | ||||
| -static inline uint64_t name##q(uint64_t arg0)                                        \
 | ||||
| +static inline reg_t name##q(reg_t arg0)                                              \
 | ||||
|  {                                                                                    \ | ||||
| -    uint64_t result64;                                                               \
 | ||||
| +    reg_t result64;                                                                  \
 | ||||
|      asm volatile (#name "q   %1, %0" : "=r"(result64) : "rm"(arg0));                 \ | ||||
|      return result64;                                                                 \ | ||||
|  } | ||||
|   | ||||
|  #define insn1l(name, arg0)                                                           \ | ||||
| -static inline uint32_t name##l(uint32_t arg0)                                        \
 | ||||
| +static inline reg_t name##l(reg_t arg0)                                              \
 | ||||
|  {                                                                                    \ | ||||
| -    uint32_t result32;                                                               \
 | ||||
| +    reg_t result32;                                                                  \
 | ||||
|      asm volatile (#name "l   %k1, %k0" : "=r"(result32) : "rm"(arg0));               \ | ||||
|      return result32;                                                                 \ | ||||
|  } | ||||
|   | ||||
|  #define insn2q(name, arg0, c0, arg1, c1)                                             \ | ||||
| -static inline uint64_t name##q(uint64_t arg0, uint64_t arg1)                         \
 | ||||
| +static inline reg_t name##q(reg_t arg0, reg_t arg1)                                  \
 | ||||
|  {                                                                                    \ | ||||
| -    uint64_t result64;                                                               \
 | ||||
| +    reg_t result64;                                                                  \
 | ||||
|      asm volatile (#name "q   %2, %1, %0" : "=r"(result64) : c0(arg0), c1(arg1));     \ | ||||
|      return result64;                                                                 \ | ||||
|  } | ||||
|   | ||||
|  #define insn2l(name, arg0, c0, arg1, c1)                                             \ | ||||
| -static inline uint32_t name##l(uint32_t arg0, uint32_t arg1)                         \
 | ||||
| +static inline reg_t name##l(reg_t arg0, reg_t arg1)                                  \
 | ||||
|  {                                                                                    \ | ||||
| -    uint32_t result32;                                                               \
 | ||||
| +    reg_t result32;                                                                  \
 | ||||
|      asm volatile (#name "l   %k2, %k1, %k0" : "=r"(result32) : c0(arg0), c1(arg1));  \ | ||||
|      return result32;                                                                 \ | ||||
|  } | ||||
| @@ -65,130 +71,128 @@ insn1l(blsr, src)
 | ||||
|  int main(int argc, char *argv[]) { | ||||
|      uint64_t ehlo = 0x202020204f4c4845ull; | ||||
|      uint64_t mask = 0xa080800302020001ull; | ||||
| -    uint32_t result32;
 | ||||
| +    reg_t result;
 | ||||
|   | ||||
|  #ifdef __x86_64 | ||||
| -    uint64_t result64;
 | ||||
| -
 | ||||
|      /* 64 bits */ | ||||
| -    result64 = andnq(mask, ehlo);
 | ||||
| -    assert(result64 == 0x002020204d4c4844);
 | ||||
| +    result = andnq(mask, ehlo);
 | ||||
| +    assert(result == 0x002020204d4c4844);
 | ||||
|   | ||||
| -    result64 = pextq(ehlo, mask);
 | ||||
| -    assert(result64 == 133);
 | ||||
| +    result = pextq(ehlo, mask);
 | ||||
| +    assert(result == 133);
 | ||||
|   | ||||
| -    result64 = pdepq(result64, mask);
 | ||||
| -    assert(result64 == (ehlo & mask));
 | ||||
| +    result = pdepq(result, mask);
 | ||||
| +    assert(result == (ehlo & mask));
 | ||||
|   | ||||
| -    result64 = pextq(-1ull, mask);
 | ||||
| -    assert(result64 == 511); /* mask has 9 bits set */
 | ||||
| +    result = pextq(-1ull, mask);
 | ||||
| +    assert(result == 511); /* mask has 9 bits set */
 | ||||
|   | ||||
| -    result64 = pdepq(-1ull, mask);
 | ||||
| -    assert(result64 == mask);
 | ||||
| +    result = pdepq(-1ull, mask);
 | ||||
| +    assert(result == mask);
 | ||||
|   | ||||
| -    result64 = bextrq(mask, 0x3f00);
 | ||||
| -    assert(result64 == (mask & ~INT64_MIN));
 | ||||
| +    result = bextrq(mask, 0x3f00);
 | ||||
| +    assert(result == (mask & ~INT64_MIN));
 | ||||
|   | ||||
| -    result64 = bextrq(mask, 0x1038);
 | ||||
| -    assert(result64 == 0xa0);
 | ||||
| +    result = bextrq(mask, 0x1038);
 | ||||
| +    assert(result == 0xa0);
 | ||||
|   | ||||
| -    result64 = bextrq(mask, 0x10f8);
 | ||||
| -    assert(result64 == 0);
 | ||||
| +    result = bextrq(mask, 0x10f8);
 | ||||
| +    assert(result == 0);
 | ||||
|   | ||||
| -    result64 = blsiq(0x30);
 | ||||
| -    assert(result64 == 0x10);
 | ||||
| +    result = blsiq(0x30);
 | ||||
| +    assert(result == 0x10);
 | ||||
|   | ||||
| -    result64 = blsiq(0x30ull << 32);
 | ||||
| -    assert(result64 == 0x10ull << 32);
 | ||||
| +    result = blsiq(0x30ull << 32);
 | ||||
| +    assert(result == 0x10ull << 32);
 | ||||
|   | ||||
| -    result64 = blsmskq(0x30);
 | ||||
| -    assert(result64 == 0x1f);
 | ||||
| +    result = blsmskq(0x30);
 | ||||
| +    assert(result == 0x1f);
 | ||||
|   | ||||
| -    result64 = blsrq(0x30);
 | ||||
| -    assert(result64 == 0x20);
 | ||||
| +    result = blsrq(0x30);
 | ||||
| +    assert(result == 0x20);
 | ||||
|   | ||||
| -    result64 = blsrq(0x30ull << 32);
 | ||||
| -    assert(result64 == 0x20ull << 32);
 | ||||
| +    result = blsrq(0x30ull << 32);
 | ||||
| +    assert(result == 0x20ull << 32);
 | ||||
|   | ||||
| -    result64 = bzhiq(mask, 0x3f);
 | ||||
| -    assert(result64 == (mask & ~INT64_MIN));
 | ||||
| +    result = bzhiq(mask, 0x3f);
 | ||||
| +    assert(result == (mask & ~INT64_MIN));
 | ||||
|   | ||||
| -    result64 = bzhiq(mask, 0x1f);
 | ||||
| -    assert(result64 == (mask & ~(-1 << 30)));
 | ||||
| +    result = bzhiq(mask, 0x1f);
 | ||||
| +    assert(result == (mask & ~(-1 << 30)));
 | ||||
|   | ||||
| -    result64 = rorxq(0x2132435465768798, 8);
 | ||||
| -    assert(result64 == 0x9821324354657687);
 | ||||
| +    result = rorxq(0x2132435465768798, 8);
 | ||||
| +    assert(result == 0x9821324354657687);
 | ||||
|   | ||||
| -    result64 = sarxq(0xffeeddccbbaa9988, 8);
 | ||||
| -    assert(result64 == 0xffffeeddccbbaa99);
 | ||||
| +    result = sarxq(0xffeeddccbbaa9988, 8);
 | ||||
| +    assert(result == 0xffffeeddccbbaa99);
 | ||||
|   | ||||
| -    result64 = sarxq(0x77eeddccbbaa9988, 8 | 64);
 | ||||
| -    assert(result64 == 0x0077eeddccbbaa99);
 | ||||
| +    result = sarxq(0x77eeddccbbaa9988, 8 | 64);
 | ||||
| +    assert(result == 0x0077eeddccbbaa99);
 | ||||
|   | ||||
| -    result64 = shrxq(0xffeeddccbbaa9988, 8);
 | ||||
| -    assert(result64 == 0x00ffeeddccbbaa99);
 | ||||
| +    result = shrxq(0xffeeddccbbaa9988, 8);
 | ||||
| +    assert(result == 0x00ffeeddccbbaa99);
 | ||||
|   | ||||
| -    result64 = shrxq(0x77eeddccbbaa9988, 8 | 192);
 | ||||
| -    assert(result64 == 0x0077eeddccbbaa99);
 | ||||
| +    result = shrxq(0x77eeddccbbaa9988, 8 | 192);
 | ||||
| +    assert(result == 0x0077eeddccbbaa99);
 | ||||
|   | ||||
| -    result64 = shlxq(0xffeeddccbbaa9988, 8);
 | ||||
| -    assert(result64 == 0xeeddccbbaa998800);
 | ||||
| +    result = shlxq(0xffeeddccbbaa9988, 8);
 | ||||
| +    assert(result == 0xeeddccbbaa998800);
 | ||||
|  #endif | ||||
|   | ||||
|      /* 32 bits */ | ||||
| -    result32 = andnl(mask, ehlo);
 | ||||
| -    assert(result32 == 0x04d4c4844);
 | ||||
| +    result = andnl(mask, ehlo);
 | ||||
| +    assert(result == 0x04d4c4844);
 | ||||
|   | ||||
| -    result32 = pextl((uint32_t) ehlo, mask);
 | ||||
| -    assert(result32 == 5);
 | ||||
| +    result = pextl((uint32_t) ehlo, mask);
 | ||||
| +    assert(result == 5);
 | ||||
|   | ||||
| -    result32 = pdepl(result32, mask);
 | ||||
| -    assert(result32 == (uint32_t)(ehlo & mask));
 | ||||
| +    result = pdepl(result, mask);
 | ||||
| +    assert(result == (uint32_t)(ehlo & mask));
 | ||||
|   | ||||
| -    result32 = pextl(-1u, mask);
 | ||||
| -    assert(result32 == 7); /* mask has 3 bits set */
 | ||||
| +    result = pextl(-1u, mask);
 | ||||
| +    assert(result == 7); /* mask has 3 bits set */
 | ||||
|   | ||||
| -    result32 = pdepl(-1u, mask);
 | ||||
| -    assert(result32 == (uint32_t)mask);
 | ||||
| +    result = pdepl(-1u, mask);
 | ||||
| +    assert(result == (uint32_t)mask);
 | ||||
|   | ||||
| -    result32 = bextrl(mask, 0x1f00);
 | ||||
| -    assert(result32 == (mask & ~INT32_MIN));
 | ||||
| +    result = bextrl(mask, 0x1f00);
 | ||||
| +    assert(result == (mask & ~INT32_MIN));
 | ||||
|   | ||||
| -    result32 = bextrl(ehlo, 0x1018);
 | ||||
| -    assert(result32 == 0x4f);
 | ||||
| +    result = bextrl(ehlo, 0x1018);
 | ||||
| +    assert(result == 0x4f);
 | ||||
|   | ||||
| -    result32 = bextrl(mask, 0x1038);
 | ||||
| -    assert(result32 == 0);
 | ||||
| +    result = bextrl(mask, 0x1038);
 | ||||
| +    assert(result == 0);
 | ||||
|   | ||||
| -    result32 = blsil(0xffff);
 | ||||
| -    assert(result32 == 1);
 | ||||
| +    result = blsil(0xffff);
 | ||||
| +    assert(result == 1);
 | ||||
|   | ||||
| -    result32 = blsmskl(0x300);
 | ||||
| -    assert(result32 == 0x1ff);
 | ||||
| +    result = blsmskl(0x300);
 | ||||
| +    assert(result == 0x1ff);
 | ||||
|   | ||||
| -    result32 = blsrl(0xffc);
 | ||||
| -    assert(result32 == 0xff8);
 | ||||
| +    result = blsrl(0xffc);
 | ||||
| +    assert(result == 0xff8);
 | ||||
|   | ||||
| -    result32 = bzhil(mask, 0xf);
 | ||||
| -    assert(result32 == 1);
 | ||||
| +    result = bzhil(mask, 0xf);
 | ||||
| +    assert(result == 1);
 | ||||
|   | ||||
| -    result32 = rorxl(0x65768798, 8);
 | ||||
| -    assert(result32 == 0x98657687);
 | ||||
| +    result = rorxl(0x65768798, 8);
 | ||||
| +    assert(result == 0x98657687);
 | ||||
|   | ||||
| -    result32 = sarxl(0xffeeddcc, 8);
 | ||||
| -    assert(result32 == 0xffffeedd);
 | ||||
| +    result = sarxl(0xffeeddcc, 8);
 | ||||
| +    assert(result == 0xffffeedd);
 | ||||
|   | ||||
| -    result32 = sarxl(0x77eeddcc, 8 | 32);
 | ||||
| -    assert(result32 == 0x0077eedd);
 | ||||
| +    result = sarxl(0x77eeddcc, 8 | 32);
 | ||||
| +    assert(result == 0x0077eedd);
 | ||||
|   | ||||
| -    result32 = shrxl(0xffeeddcc, 8);
 | ||||
| -    assert(result32 == 0x00ffeedd);
 | ||||
| +    result = shrxl(0xffeeddcc, 8);
 | ||||
| +    assert(result == 0x00ffeedd);
 | ||||
|   | ||||
| -    result32 = shrxl(0x77eeddcc, 8 | 128);
 | ||||
| -    assert(result32 == 0x0077eedd);
 | ||||
| +    result = shrxl(0x77eeddcc, 8 | 128);
 | ||||
| +    assert(result == 0x0077eedd);
 | ||||
|   | ||||
| -    result32 = shlxl(0xffeeddcc, 8);
 | ||||
| -    assert(result32 == 0xeeddcc00);
 | ||||
| +    result = shlxl(0xffeeddcc, 8);
 | ||||
| +    assert(result == 0xeeddcc00);
 | ||||
|   | ||||
|      return 0; | ||||
|  } | ||||
| @ -1,97 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Richard Henderson <richard.henderson@linaro.org> | ||||
| Date: Sat, 14 Jan 2023 13:05:42 -1000 | ||||
| Subject: [PATCH] target/i386: Fix BEXTR instruction | ||||
| 
 | ||||
| There were two problems here: not limiting the input to operand bits, | ||||
| and not correctly handling large extraction length. | ||||
| 
 | ||||
| Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1372 | ||||
| Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||||
| Message-Id: <20230114230542.3116013-3-richard.henderson@linaro.org> | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Fixes: 1d0b926150e5 ("target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder", 2022-10-18) | ||||
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||||
| (cherry-picked from commit b14c0098975264ed03144f145bca0179a6763a07) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  target/i386/tcg/emit.c.inc      | 22 +++++++++++----------- | ||||
|  tests/tcg/i386/test-i386-bmi2.c | 12 ++++++++++++ | ||||
|  2 files changed, 23 insertions(+), 11 deletions(-) | ||||
| 
 | ||||
| diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
 | ||||
| index 7037ff91c6..99f6ba6e19 100644
 | ||||
| --- a/target/i386/tcg/emit.c.inc
 | ||||
| +++ b/target/i386/tcg/emit.c.inc
 | ||||
| @@ -1078,30 +1078,30 @@ static void gen_ANDN(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
 | ||||
|  static void gen_BEXTR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) | ||||
|  { | ||||
|      MemOp ot = decode->op[0].ot; | ||||
| -    TCGv bound, zero;
 | ||||
| +    TCGv bound = tcg_constant_tl(ot == MO_64 ? 63 : 31);
 | ||||
| +    TCGv zero = tcg_constant_tl(0);
 | ||||
| +    TCGv mone = tcg_constant_tl(-1);
 | ||||
|   | ||||
|      /* | ||||
|       * Extract START, and shift the operand. | ||||
|       * Shifts larger than operand size get zeros. | ||||
|       */ | ||||
|      tcg_gen_ext8u_tl(s->A0, s->T1); | ||||
| +    if (TARGET_LONG_BITS == 64 && ot == MO_32) {
 | ||||
| +        tcg_gen_ext32u_tl(s->T0, s->T0);
 | ||||
| +    }
 | ||||
|      tcg_gen_shr_tl(s->T0, s->T0, s->A0); | ||||
|   | ||||
| -    bound = tcg_constant_tl(ot == MO_64 ? 63 : 31);
 | ||||
| -    zero = tcg_constant_tl(0);
 | ||||
|      tcg_gen_movcond_tl(TCG_COND_LEU, s->T0, s->A0, bound, s->T0, zero); | ||||
|   | ||||
|      /* | ||||
| -     * Extract the LEN into a mask.  Lengths larger than
 | ||||
| -     * operand size get all ones.
 | ||||
| +     * Extract the LEN into an inverse mask.  Lengths larger than
 | ||||
| +     * operand size get all zeros, length 0 gets all ones.
 | ||||
|       */ | ||||
|      tcg_gen_extract_tl(s->A0, s->T1, 8, 8); | ||||
| -    tcg_gen_movcond_tl(TCG_COND_LEU, s->A0, s->A0, bound, s->A0, bound);
 | ||||
| -
 | ||||
| -    tcg_gen_movi_tl(s->T1, 1);
 | ||||
| -    tcg_gen_shl_tl(s->T1, s->T1, s->A0);
 | ||||
| -    tcg_gen_subi_tl(s->T1, s->T1, 1);
 | ||||
| -    tcg_gen_and_tl(s->T0, s->T0, s->T1);
 | ||||
| +    tcg_gen_shl_tl(s->T1, mone, s->A0);
 | ||||
| +    tcg_gen_movcond_tl(TCG_COND_LEU, s->T1, s->A0, bound, s->T1, zero);
 | ||||
| +    tcg_gen_andc_tl(s->T0, s->T0, s->T1);
 | ||||
|   | ||||
|      gen_op_update1_cc(s); | ||||
|      set_cc_op(s, CC_OP_LOGICB + ot); | ||||
| diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| index 3c3ef85513..982d4abda4 100644
 | ||||
| --- a/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| +++ b/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| @@ -99,6 +99,9 @@ int main(int argc, char *argv[]) {
 | ||||
|      result = bextrq(mask, 0x10f8); | ||||
|      assert(result == 0); | ||||
|   | ||||
| +    result = bextrq(0xfedcba9876543210ull, 0x7f00);
 | ||||
| +    assert(result == 0xfedcba9876543210ull);
 | ||||
| +
 | ||||
|      result = blsiq(0x30); | ||||
|      assert(result == 0x10); | ||||
|   | ||||
| @@ -164,6 +167,15 @@ int main(int argc, char *argv[]) {
 | ||||
|      result = bextrl(mask, 0x1038); | ||||
|      assert(result == 0); | ||||
|   | ||||
| +    result = bextrl((reg_t)0x8f635a775ad3b9b4ull, 0x3018);
 | ||||
| +    assert(result == 0x5a);
 | ||||
| +
 | ||||
| +    result = bextrl((reg_t)0xfedcba9876543210ull, 0x7f00);
 | ||||
| +    assert(result == 0x76543210u);
 | ||||
| +
 | ||||
| +    result = bextrl(-1, 0);
 | ||||
| +    assert(result == 0);
 | ||||
| +
 | ||||
|      result = blsil(0xffff); | ||||
|      assert(result == 1); | ||||
|   | ||||
| @ -1,47 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Richard Henderson <richard.henderson@linaro.org> | ||||
| Date: Sat, 14 Jan 2023 08:06:01 -1000 | ||||
| Subject: [PATCH] target/i386: Fix C flag for BLSI, BLSMSK, BLSR | ||||
| 
 | ||||
| We forgot to set cc_src, which is used for computing C. | ||||
| 
 | ||||
| Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1370 | ||||
| Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||||
| Message-Id: <20230114180601.2993644-1-richard.henderson@linaro.org> | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Fixes: 1d0b926150e5 ("target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder", 2022-10-18) | ||||
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||||
| (cherry-picked from commit 99282098dc74c2055bde5652bde6cf0067d0c370) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  target/i386/tcg/emit.c.inc | 3 +++ | ||||
|  1 file changed, 3 insertions(+) | ||||
| 
 | ||||
| diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
 | ||||
| index 99f6ba6e19..4d7702c106 100644
 | ||||
| --- a/target/i386/tcg/emit.c.inc
 | ||||
| +++ b/target/i386/tcg/emit.c.inc
 | ||||
| @@ -1111,6 +1111,7 @@ static void gen_BLSI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
 | ||||
|  { | ||||
|      MemOp ot = decode->op[0].ot; | ||||
|   | ||||
| +    tcg_gen_mov_tl(cpu_cc_src, s->T0);
 | ||||
|      tcg_gen_neg_tl(s->T1, s->T0); | ||||
|      tcg_gen_and_tl(s->T0, s->T0, s->T1); | ||||
|      tcg_gen_mov_tl(cpu_cc_dst, s->T0); | ||||
| @@ -1121,6 +1122,7 @@ static void gen_BLSMSK(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode
 | ||||
|  { | ||||
|      MemOp ot = decode->op[0].ot; | ||||
|   | ||||
| +    tcg_gen_mov_tl(cpu_cc_src, s->T0);
 | ||||
|      tcg_gen_subi_tl(s->T1, s->T0, 1); | ||||
|      tcg_gen_xor_tl(s->T0, s->T0, s->T1); | ||||
|      tcg_gen_mov_tl(cpu_cc_dst, s->T0); | ||||
| @@ -1131,6 +1133,7 @@ static void gen_BLSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
 | ||||
|  { | ||||
|      MemOp ot = decode->op[0].ot; | ||||
|   | ||||
| +    tcg_gen_mov_tl(cpu_cc_src, s->T0);
 | ||||
|      tcg_gen_subi_tl(s->T1, s->T0, 1); | ||||
|      tcg_gen_and_tl(s->T0, s->T0, s->T1); | ||||
|      tcg_gen_mov_tl(cpu_cc_dst, s->T0); | ||||
| @ -1,192 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Paolo Bonzini <pbonzini@redhat.com> | ||||
| Date: Tue, 31 Jan 2023 09:48:03 +0100 | ||||
| Subject: [PATCH] target/i386: fix ADOX followed by ADCX | ||||
| 
 | ||||
| When ADCX is followed by ADOX or vice versa, the second instruction's | ||||
| carry comes from EFLAGS and the condition codes use the CC_OP_ADCOX | ||||
| operation.  Retrieving the carry from EFLAGS is handled by this bit | ||||
| of gen_ADCOX: | ||||
| 
 | ||||
|         tcg_gen_extract_tl(carry_in, cpu_cc_src, | ||||
|             ctz32(cc_op == CC_OP_ADCX ? CC_C : CC_O), 1); | ||||
| 
 | ||||
| Unfortunately, in this case cc_op has been overwritten by the previous | ||||
| "if" statement to CC_OP_ADCOX.  This works by chance when the first | ||||
| instruction is ADCX; however, if the first instruction is ADOX, | ||||
| ADCX will incorrectly take its carry from OF instead of CF. | ||||
| 
 | ||||
| Fix by moving the computation of the new cc_op at the end of the function. | ||||
| The included exhaustive test case fails without this patch and passes | ||||
| afterwards. | ||||
| 
 | ||||
| Because ADCX/ADOX need not be invoked through the VEX prefix, this | ||||
| regression bisects to commit 16fc5726a6e2 ("target/i386: reimplement | ||||
| 0x0f 0x38, add AVX", 2022-10-18).  However, the mistake happened a | ||||
| little earlier, when BMI instructions were rewritten using the new | ||||
| decoder framework. | ||||
| 
 | ||||
| Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1471 | ||||
| Reported-by: Paul Jolly <https://gitlab.com/myitcv> | ||||
| Fixes: 1d0b926150e5 ("target/i386: move scalar 0F 38 and 0F 3A instruction to new decoder", 2022-10-18) | ||||
| Cc: qemu-stable@nongnu.org | ||||
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||||
| (cherry-picked from commit 60c7dd22e1383754d5f150bc9f7c2785c662a7b6) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  target/i386/tcg/emit.c.inc       | 20 +++++---- | ||||
|  tests/tcg/i386/Makefile.target   |  6 ++- | ||||
|  tests/tcg/i386/test-i386-adcox.c | 75 ++++++++++++++++++++++++++++++++ | ||||
|  3 files changed, 91 insertions(+), 10 deletions(-) | ||||
|  create mode 100644 tests/tcg/i386/test-i386-adcox.c | ||||
| 
 | ||||
| diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
 | ||||
| index 4d7702c106..0d7c6e80ae 100644
 | ||||
| --- a/target/i386/tcg/emit.c.inc
 | ||||
| +++ b/target/i386/tcg/emit.c.inc
 | ||||
| @@ -1015,6 +1015,7 @@ VSIB_AVX(VPGATHERQ, vpgatherq)
 | ||||
|   | ||||
|  static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op) | ||||
|  { | ||||
| +    int opposite_cc_op;
 | ||||
|      TCGv carry_in = NULL; | ||||
|      TCGv carry_out = (cc_op == CC_OP_ADCX ? cpu_cc_dst : cpu_cc_src2); | ||||
|      TCGv zero; | ||||
| @@ -1022,14 +1023,8 @@ static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op)
 | ||||
|      if (cc_op == s->cc_op || s->cc_op == CC_OP_ADCOX) { | ||||
|          /* Re-use the carry-out from a previous round.  */ | ||||
|          carry_in = carry_out; | ||||
| -        cc_op = s->cc_op;
 | ||||
| -    } else if (s->cc_op == CC_OP_ADCX || s->cc_op == CC_OP_ADOX) {
 | ||||
| -        /* Merge with the carry-out from the opposite instruction.  */
 | ||||
| -        cc_op = CC_OP_ADCOX;
 | ||||
| -    }
 | ||||
| -
 | ||||
| -    /* If we don't have a carry-in, get it out of EFLAGS.  */
 | ||||
| -    if (!carry_in) {
 | ||||
| +    } else {
 | ||||
| +        /* We don't have a carry-in, get it out of EFLAGS.  */
 | ||||
|          if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) { | ||||
|              gen_compute_eflags(s); | ||||
|          } | ||||
| @@ -1053,7 +1048,14 @@ static void gen_ADCOX(DisasContext *s, CPUX86State *env, MemOp ot, int cc_op)
 | ||||
|          tcg_gen_add2_tl(s->T0, carry_out, s->T0, carry_out, s->T1, zero); | ||||
|          break; | ||||
|      } | ||||
| -    set_cc_op(s, cc_op);
 | ||||
| +
 | ||||
| +    opposite_cc_op = cc_op == CC_OP_ADCX ? CC_OP_ADOX : CC_OP_ADCX;
 | ||||
| +    if (s->cc_op == CC_OP_ADCOX || s->cc_op == opposite_cc_op) {
 | ||||
| +        /* Merge with the carry-out from the opposite instruction.  */
 | ||||
| +        set_cc_op(s, CC_OP_ADCOX);
 | ||||
| +    } else {
 | ||||
| +        set_cc_op(s, cc_op);
 | ||||
| +    }
 | ||||
|  } | ||||
|   | ||||
|  static void gen_ADCX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) | ||||
| diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target
 | ||||
| index 81831cafbc..bafd8c2180 100644
 | ||||
| --- a/tests/tcg/i386/Makefile.target
 | ||||
| +++ b/tests/tcg/i386/Makefile.target
 | ||||
| @@ -14,7 +14,7 @@ config-cc.mak: Makefile
 | ||||
|  I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c)) | ||||
|  ALL_X86_TESTS=$(I386_SRCS:.c=) | ||||
|  SKIP_I386_TESTS=test-i386-ssse3 test-avx test-3dnow test-mmx | ||||
| -X86_64_TESTS:=$(filter test-i386-bmi2 $(SKIP_I386_TESTS), $(ALL_X86_TESTS))
 | ||||
| +X86_64_TESTS:=$(filter test-i386-adcox test-i386-bmi2 $(SKIP_I386_TESTS), $(ALL_X86_TESTS))
 | ||||
|   | ||||
|  test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse | ||||
|  run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max | ||||
| @@ -28,6 +28,10 @@ test-i386-bmi2: CFLAGS=-O2
 | ||||
|  run-test-i386-bmi2: QEMU_OPTS += -cpu max | ||||
|  run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max | ||||
|   | ||||
| +test-i386-adcox: CFLAGS=-O2
 | ||||
| +run-test-i386-adcox: QEMU_OPTS += -cpu max
 | ||||
| +run-plugin-test-i386-adcox-%: QEMU_OPTS += -cpu max
 | ||||
| +
 | ||||
|  # | ||||
|  # hello-i386 is a barebones app | ||||
|  # | ||||
| diff --git a/tests/tcg/i386/test-i386-adcox.c b/tests/tcg/i386/test-i386-adcox.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..16169efff8
 | ||||
| --- /dev/null
 | ||||
| +++ b/tests/tcg/i386/test-i386-adcox.c
 | ||||
| @@ -0,0 +1,75 @@
 | ||||
| +/* See if various BMI2 instructions give expected results */
 | ||||
| +#include <assert.h>
 | ||||
| +#include <stdint.h>
 | ||||
| +#include <stdio.h>
 | ||||
| +
 | ||||
| +#define CC_C 1
 | ||||
| +#define CC_O (1 << 11)
 | ||||
| +
 | ||||
| +#ifdef __x86_64__
 | ||||
| +#define REG uint64_t
 | ||||
| +#else
 | ||||
| +#define REG uint32_t
 | ||||
| +#endif
 | ||||
| +
 | ||||
| +void test_adox_adcx(uint32_t in_c, uint32_t in_o, REG adcx_operand, REG adox_operand)
 | ||||
| +{
 | ||||
| +    REG flags;
 | ||||
| +    REG out_adcx, out_adox;
 | ||||
| +
 | ||||
| +    asm("pushf; pop %0" : "=r"(flags));
 | ||||
| +    flags &= ~(CC_C | CC_O);
 | ||||
| +    flags |= (in_c ? CC_C : 0);
 | ||||
| +    flags |= (in_o ? CC_O : 0);
 | ||||
| +
 | ||||
| +    out_adcx = adcx_operand;
 | ||||
| +    out_adox = adox_operand;
 | ||||
| +    asm("push %0; popf;"
 | ||||
| +        "adox %3, %2;"
 | ||||
| +        "adcx %3, %1;"
 | ||||
| +        "pushf; pop %0"
 | ||||
| +        : "+r" (flags), "+r" (out_adcx), "+r" (out_adox)
 | ||||
| +        : "r" ((REG)-1), "0" (flags), "1" (out_adcx), "2" (out_adox));
 | ||||
| +
 | ||||
| +    assert(out_adcx == in_c + adcx_operand - 1);
 | ||||
| +    assert(out_adox == in_o + adox_operand - 1);
 | ||||
| +    assert(!!(flags & CC_C) == (in_c || adcx_operand));
 | ||||
| +    assert(!!(flags & CC_O) == (in_o || adox_operand));
 | ||||
| +}
 | ||||
| +
 | ||||
| +void test_adcx_adox(uint32_t in_c, uint32_t in_o, REG adcx_operand, REG adox_operand)
 | ||||
| +{
 | ||||
| +    REG flags;
 | ||||
| +    REG out_adcx, out_adox;
 | ||||
| +
 | ||||
| +    asm("pushf; pop %0" : "=r"(flags));
 | ||||
| +    flags &= ~(CC_C | CC_O);
 | ||||
| +    flags |= (in_c ? CC_C : 0);
 | ||||
| +    flags |= (in_o ? CC_O : 0);
 | ||||
| +
 | ||||
| +    out_adcx = adcx_operand;
 | ||||
| +    out_adox = adox_operand;
 | ||||
| +    asm("push %0; popf;"
 | ||||
| +        "adcx %3, %1;"
 | ||||
| +        "adox %3, %2;"
 | ||||
| +        "pushf; pop %0"
 | ||||
| +        : "+r" (flags), "+r" (out_adcx), "+r" (out_adox)
 | ||||
| +        : "r" ((REG)-1), "0" (flags), "1" (out_adcx), "2" (out_adox));
 | ||||
| +
 | ||||
| +    assert(out_adcx == in_c + adcx_operand - 1);
 | ||||
| +    assert(out_adox == in_o + adox_operand - 1);
 | ||||
| +    assert(!!(flags & CC_C) == (in_c || adcx_operand));
 | ||||
| +    assert(!!(flags & CC_O) == (in_o || adox_operand));
 | ||||
| +}
 | ||||
| +
 | ||||
| +int main(int argc, char *argv[]) {
 | ||||
| +    /* try all combinations of input CF, input OF, CF from op1+op2,  OF from op2+op1 */
 | ||||
| +    int i;
 | ||||
| +    for (i = 0; i <= 15; i++) {
 | ||||
| +        printf("%d\n", i);
 | ||||
| +        test_adcx_adox(!!(i & 1), !!(i & 2), !!(i & 4), !!(i & 8));
 | ||||
| +        test_adox_adcx(!!(i & 1), !!(i & 2), !!(i & 4), !!(i & 8));
 | ||||
| +    }
 | ||||
| +    return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
| @ -1,64 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Richard Henderson <richard.henderson@linaro.org> | ||||
| Date: Sat, 14 Jan 2023 13:32:06 -1000 | ||||
| Subject: [PATCH] target/i386: Fix BZHI instruction | ||||
| 
 | ||||
| We did not correctly handle N >= operand size. | ||||
| 
 | ||||
| Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1374 | ||||
| Signed-off-by: Richard Henderson <richard.henderson@linaro.org> | ||||
| Message-Id: <20230114233206.3118472-1-richard.henderson@linaro.org> | ||||
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||||
| (cherry-picked from commit 9ad2ba6e8e7fc195d0dd0b76ab38bd2fceb1bdd4) | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  target/i386/tcg/emit.c.inc      | 14 +++++++------- | ||||
|  tests/tcg/i386/test-i386-bmi2.c |  3 +++ | ||||
|  2 files changed, 10 insertions(+), 7 deletions(-) | ||||
| 
 | ||||
| diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
 | ||||
| index 0d7c6e80ae..7296f3952c 100644
 | ||||
| --- a/target/i386/tcg/emit.c.inc
 | ||||
| +++ b/target/i386/tcg/emit.c.inc
 | ||||
| @@ -1145,20 +1145,20 @@ static void gen_BLSR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
 | ||||
|  static void gen_BZHI(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) | ||||
|  { | ||||
|      MemOp ot = decode->op[0].ot; | ||||
| -    TCGv bound;
 | ||||
| +    TCGv bound = tcg_constant_tl(ot == MO_64 ? 63 : 31);
 | ||||
| +    TCGv zero = tcg_constant_tl(0);
 | ||||
| +    TCGv mone = tcg_constant_tl(-1);
 | ||||
|   | ||||
| -    tcg_gen_ext8u_tl(s->T1, cpu_regs[s->vex_v]);
 | ||||
| -    bound = tcg_constant_tl(ot == MO_64 ? 63 : 31);
 | ||||
| +    tcg_gen_ext8u_tl(s->T1, s->T1);
 | ||||
|   | ||||
|      /* | ||||
|       * Note that since we're using BMILG (in order to get O | ||||
|       * cleared) we need to store the inverse into C. | ||||
|       */ | ||||
| -    tcg_gen_setcond_tl(TCG_COND_LT, cpu_cc_src, s->T1, bound);
 | ||||
| -    tcg_gen_movcond_tl(TCG_COND_GT, s->T1, s->T1, bound, bound, s->T1);
 | ||||
| +    tcg_gen_setcond_tl(TCG_COND_LEU, cpu_cc_src, s->T1, bound);
 | ||||
|   | ||||
| -    tcg_gen_movi_tl(s->A0, -1);
 | ||||
| -    tcg_gen_shl_tl(s->A0, s->A0, s->T1);
 | ||||
| +    tcg_gen_shl_tl(s->A0, mone, s->T1);
 | ||||
| +    tcg_gen_movcond_tl(TCG_COND_LEU, s->A0, s->T1, bound, s->A0, zero);
 | ||||
|      tcg_gen_andc_tl(s->T0, s->T0, s->A0); | ||||
|   | ||||
|      gen_op_update1_cc(s); | ||||
| diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| index 982d4abda4..0244df7987 100644
 | ||||
| --- a/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| +++ b/tests/tcg/i386/test-i386-bmi2.c
 | ||||
| @@ -123,6 +123,9 @@ int main(int argc, char *argv[]) {
 | ||||
|      result = bzhiq(mask, 0x1f); | ||||
|      assert(result == (mask & ~(-1 << 30))); | ||||
|   | ||||
| +    result = bzhiq(mask, 0x40);
 | ||||
| +    assert(result == mask);
 | ||||
| +
 | ||||
|      result = rorxq(0x2132435465768798, 8); | ||||
|      assert(result == 0x9821324354657687); | ||||
|   | ||||
| @ -14,10 +14,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/file-posix.c b/block/file-posix.c
 | ||||
| index b9647c5ffc..9a16d86344 100644
 | ||||
| index c2dee3f056..9681bd0434 100644
 | ||||
| --- a/block/file-posix.c
 | ||||
| +++ b/block/file-posix.c
 | ||||
| @@ -552,7 +552,7 @@ static QemuOptsList raw_runtime_opts = {
 | ||||
| @@ -553,7 +553,7 @@ static QemuOptsList raw_runtime_opts = {
 | ||||
|          { | ||||
|              .name = "locking", | ||||
|              .type = QEMU_OPT_STRING, | ||||
| @ -26,7 +26,7 @@ index b9647c5ffc..9a16d86344 100644 | ||||
|          }, | ||||
|          { | ||||
|              .name = "pr-manager", | ||||
| @@ -652,7 +652,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
 | ||||
| @@ -653,7 +653,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
 | ||||
|          s->use_lock = false; | ||||
|          break; | ||||
|      case ON_OFF_AUTO_AUTO: | ||||
|  | ||||
| @ -9,10 +9,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/include/net/net.h b/include/net/net.h
 | ||||
| index dc20b31e9f..5ae04a8693 100644
 | ||||
| index 1448d00afb..d1601d32c1 100644
 | ||||
| --- a/include/net/net.h
 | ||||
| +++ b/include/net/net.h
 | ||||
| @@ -236,8 +236,8 @@ void netdev_add(QemuOpts *opts, Error **errp);
 | ||||
| @@ -258,8 +258,8 @@ void netdev_add(QemuOpts *opts, Error **errp);
 | ||||
|  int net_hub_id_for_client(NetClientState *nc, int *id); | ||||
|  NetClientState *net_hub_port_find(int hub_id); | ||||
|   | ||||
|  | ||||
| @ -10,10 +10,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/target/i386/cpu.h b/target/i386/cpu.h
 | ||||
| index d4bc19577a..be7da64f38 100644
 | ||||
| index d243e290d3..3489b05ec4 100644
 | ||||
| --- a/target/i386/cpu.h
 | ||||
| +++ b/target/i386/cpu.h
 | ||||
| @@ -2174,9 +2174,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 | ||||
| @@ -2203,9 +2203,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 | ||||
|  #define CPU_RESOLVING_TYPE TYPE_X86_CPU | ||||
|   | ||||
|  #ifdef TARGET_X86_64 | ||||
|  | ||||
| @ -9,10 +9,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 9 insertions(+), 6 deletions(-) | ||||
| 
 | ||||
| diff --git a/ui/spice-core.c b/ui/spice-core.c
 | ||||
| index c3ac20ad43..37774f1c0a 100644
 | ||||
| index 52a59386d7..b20c25aee0 100644
 | ||||
| --- a/ui/spice-core.c
 | ||||
| +++ b/ui/spice-core.c
 | ||||
| @@ -689,32 +689,35 @@ static void qemu_spice_init(void)
 | ||||
| @@ -691,32 +691,35 @@ static void qemu_spice_init(void)
 | ||||
|   | ||||
|      if (tls_port) { | ||||
|          x509_dir = qemu_opt_get(opts, "x509-dir"); | ||||
|  | ||||
| @ -9,10 +9,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 11 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/gluster.c b/block/gluster.c
 | ||||
| index 7c90f7ba4b..2e03102f00 100644
 | ||||
| index 185a83e5e5..f11a40aa9e 100644
 | ||||
| --- a/block/gluster.c
 | ||||
| +++ b/block/gluster.c
 | ||||
| @@ -42,7 +42,7 @@
 | ||||
| @@ -43,7 +43,7 @@
 | ||||
|  #define GLUSTER_DEBUG_DEFAULT       4 | ||||
|  #define GLUSTER_DEBUG_MAX           9 | ||||
|  #define GLUSTER_OPT_LOGFILE         "logfile" | ||||
| @ -21,7 +21,7 @@ index 7c90f7ba4b..2e03102f00 100644 | ||||
|  /* | ||||
|   * Several versions of GlusterFS (3.12? -> 6.0.1) fail when the transfer size | ||||
|   * is greater or equal to 1024 MiB, so we are limiting the transfer size to 512 | ||||
| @@ -424,6 +424,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
 | ||||
| @@ -425,6 +425,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
 | ||||
|      int old_errno; | ||||
|      SocketAddressList *server; | ||||
|      unsigned long long port; | ||||
| @ -29,7 +29,7 @@ index 7c90f7ba4b..2e03102f00 100644 | ||||
|   | ||||
|      glfs = glfs_find_preopened(gconf->volume); | ||||
|      if (glfs) { | ||||
| @@ -466,9 +467,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
 | ||||
| @@ -467,9 +468,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
 | ||||
|          } | ||||
|      } | ||||
|   | ||||
|  | ||||
| @ -18,10 +18,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 2 insertions(+) | ||||
| 
 | ||||
| diff --git a/block/rbd.c b/block/rbd.c
 | ||||
| index f826410f40..64a8d7d48b 100644
 | ||||
| index 978671411e..a4749f3b1b 100644
 | ||||
| --- a/block/rbd.c
 | ||||
| +++ b/block/rbd.c
 | ||||
| @@ -820,6 +820,8 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
 | ||||
| @@ -963,6 +963,8 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
 | ||||
|          rados_conf_set(*cluster, "rbd_cache", "false"); | ||||
|      } | ||||
|   | ||||
|  | ||||
| @ -13,11 +13,11 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  3 files changed, 44 insertions(+) | ||||
| 
 | ||||
| diff --git a/net/net.c b/net/net.c
 | ||||
| index 840ad9dca5..28e97c5d85 100644
 | ||||
| index 6492ad530e..33e901cba8 100644
 | ||||
| --- a/net/net.c
 | ||||
| +++ b/net/net.c
 | ||||
| @@ -1372,6 +1372,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
 | ||||
|      } | ||||
| @@ -1397,6 +1397,33 @@ RxFilterInfoList *qmp_query_rx_filter(const char *name, Error **errp)
 | ||||
|      return filter_list; | ||||
|  } | ||||
|   | ||||
| +int64_t qmp_get_link_status(const char *name, Error **errp)
 | ||||
| @ -51,7 +51,7 @@ index 840ad9dca5..28e97c5d85 100644 | ||||
|  { | ||||
|      NetClientState *nc; | ||||
| diff --git a/qapi/net.json b/qapi/net.json
 | ||||
| index 522ac582ed..327d7c5a37 100644
 | ||||
| index d6eb30008b..4fe71b149d 100644
 | ||||
| --- a/qapi/net.json
 | ||||
| +++ b/qapi/net.json
 | ||||
| @@ -36,6 +36,21 @@
 | ||||
|  | ||||
| @ -16,10 +16,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 9 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/block/gluster.c b/block/gluster.c
 | ||||
| index 2e03102f00..7886c5fe8c 100644
 | ||||
| index f11a40aa9e..6756e6b886 100644
 | ||||
| --- a/block/gluster.c
 | ||||
| +++ b/block/gluster.c
 | ||||
| @@ -57,6 +57,7 @@ typedef struct GlusterAIOCB {
 | ||||
| @@ -58,6 +58,7 @@ typedef struct GlusterAIOCB {
 | ||||
|      int ret; | ||||
|      Coroutine *coroutine; | ||||
|      AioContext *aio_context; | ||||
| @ -27,7 +27,7 @@ index 2e03102f00..7886c5fe8c 100644 | ||||
|  } GlusterAIOCB; | ||||
|   | ||||
|  typedef struct BDRVGlusterState { | ||||
| @@ -752,8 +753,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
 | ||||
| @@ -753,8 +754,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
 | ||||
|          acb->ret = 0; /* Success */ | ||||
|      } else if (ret < 0) { | ||||
|          acb->ret = -errno; /* Read/Write failed */ | ||||
| @ -39,7 +39,7 @@ index 2e03102f00..7886c5fe8c 100644 | ||||
|      } | ||||
|   | ||||
|      aio_co_schedule(acb->aio_context, acb->coroutine); | ||||
| @@ -1022,6 +1025,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
 | ||||
| @@ -1021,6 +1024,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
 | ||||
|      acb.ret = 0; | ||||
|      acb.coroutine = qemu_coroutine_self(); | ||||
|      acb.aio_context = bdrv_get_aio_context(bs); | ||||
| @ -47,7 +47,7 @@ index 2e03102f00..7886c5fe8c 100644 | ||||
|   | ||||
|      ret = glfs_zerofill_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb); | ||||
|      if (ret < 0) { | ||||
| @@ -1203,9 +1207,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
 | ||||
| @@ -1201,9 +1205,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
 | ||||
|      acb.aio_context = bdrv_get_aio_context(bs); | ||||
|   | ||||
|      if (write) { | ||||
| @ -59,7 +59,7 @@ index 2e03102f00..7886c5fe8c 100644 | ||||
|          ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0, | ||||
|                                  gluster_finish_aiocb, &acb); | ||||
|      } | ||||
| @@ -1268,6 +1274,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
 | ||||
| @@ -1266,6 +1272,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
 | ||||
|      acb.ret = 0; | ||||
|      acb.coroutine = qemu_coroutine_self(); | ||||
|      acb.aio_context = bdrv_get_aio_context(bs); | ||||
| @ -67,7 +67,7 @@ index 2e03102f00..7886c5fe8c 100644 | ||||
|   | ||||
|      ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb); | ||||
|      if (ret < 0) { | ||||
| @@ -1316,6 +1323,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
 | ||||
| @@ -1314,6 +1321,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
 | ||||
|      acb.ret = 0; | ||||
|      acb.coroutine = qemu_coroutine_self(); | ||||
|      acb.aio_context = bdrv_get_aio_context(bs); | ||||
|  | ||||
| @ -9,10 +9,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/qemu-img.c b/qemu-img.c
 | ||||
| index a9b3a8103c..0bc9f1af59 100644
 | ||||
| index 9aeac69fa6..0919fac1f1 100644
 | ||||
| --- a/qemu-img.c
 | ||||
| +++ b/qemu-img.c
 | ||||
| @@ -3013,7 +3013,8 @@ static int img_info(int argc, char **argv)
 | ||||
| @@ -3059,7 +3059,8 @@ static int img_info(int argc, char **argv)
 | ||||
|      list = collect_image_info_list(image_opts, filename, fmt, chain, | ||||
|                                     force_share); | ||||
|      if (!list) { | ||||
|  | ||||
| @ -54,10 +54,10 @@ index 1b1dab5b17..d1616c045a 100644 | ||||
|   | ||||
|  DEF("info", img_info, | ||||
| diff --git a/qemu-img.c b/qemu-img.c
 | ||||
| index 0bc9f1af59..221b9d6a16 100644
 | ||||
| index 0919fac1f1..c584de648c 100644
 | ||||
| --- a/qemu-img.c
 | ||||
| +++ b/qemu-img.c
 | ||||
| @@ -4829,10 +4829,12 @@ static int img_bitmap(int argc, char **argv)
 | ||||
| @@ -4885,10 +4885,12 @@ static int img_bitmap(int argc, char **argv)
 | ||||
|  #define C_IF      04 | ||||
|  #define C_OF      010 | ||||
|  #define C_SKIP    020 | ||||
| @ -70,7 +70,7 @@ index 0bc9f1af59..221b9d6a16 100644 | ||||
|  }; | ||||
|   | ||||
|  struct DdIo { | ||||
| @@ -4908,6 +4910,19 @@ static int img_dd_skip(const char *arg,
 | ||||
| @@ -4964,6 +4966,19 @@ static int img_dd_skip(const char *arg,
 | ||||
|      return 0; | ||||
|  } | ||||
|   | ||||
| @ -90,7 +90,7 @@ index 0bc9f1af59..221b9d6a16 100644 | ||||
|  static int img_dd(int argc, char **argv) | ||||
|  { | ||||
|      int ret = 0; | ||||
| @@ -4948,6 +4963,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5004,6 +5019,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|          { "if", img_dd_if, C_IF }, | ||||
|          { "of", img_dd_of, C_OF }, | ||||
|          { "skip", img_dd_skip, C_SKIP }, | ||||
| @ -98,7 +98,7 @@ index 0bc9f1af59..221b9d6a16 100644 | ||||
|          { NULL, NULL, 0 } | ||||
|      }; | ||||
|      const struct option long_options[] = { | ||||
| @@ -5023,91 +5039,112 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5079,91 +5095,112 @@ static int img_dd(int argc, char **argv)
 | ||||
|          arg = NULL; | ||||
|      } | ||||
|   | ||||
| @ -275,7 +275,7 @@ index 0bc9f1af59..221b9d6a16 100644 | ||||
|      } | ||||
|   | ||||
|      if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || | ||||
| @@ -5124,20 +5161,43 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5180,20 +5217,43 @@ static int img_dd(int argc, char **argv)
 | ||||
|      in.buf = g_new(uint8_t, in.bsz); | ||||
|   | ||||
|      for (out_pos = 0; in_pos < size; ) { | ||||
|  | ||||
| @ -16,10 +16,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 25 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/qemu-img.c b/qemu-img.c
 | ||||
| index 221b9d6a16..c1306385a8 100644
 | ||||
| index c584de648c..a57ceeddfe 100644
 | ||||
| --- a/qemu-img.c
 | ||||
| +++ b/qemu-img.c
 | ||||
| @@ -4830,11 +4830,13 @@ static int img_bitmap(int argc, char **argv)
 | ||||
| @@ -4886,11 +4886,13 @@ static int img_bitmap(int argc, char **argv)
 | ||||
|  #define C_OF      010 | ||||
|  #define C_SKIP    020 | ||||
|  #define C_OSIZE   040 | ||||
| @ -33,7 +33,7 @@ index 221b9d6a16..c1306385a8 100644 | ||||
|  }; | ||||
|   | ||||
|  struct DdIo { | ||||
| @@ -4923,6 +4925,19 @@ static int img_dd_osize(const char *arg,
 | ||||
| @@ -4979,6 +4981,19 @@ static int img_dd_osize(const char *arg,
 | ||||
|      return 0; | ||||
|  } | ||||
|   | ||||
| @ -53,7 +53,7 @@ index 221b9d6a16..c1306385a8 100644 | ||||
|  static int img_dd(int argc, char **argv) | ||||
|  { | ||||
|      int ret = 0; | ||||
| @@ -4937,12 +4952,14 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -4993,12 +5008,14 @@ static int img_dd(int argc, char **argv)
 | ||||
|      int c, i; | ||||
|      const char *out_fmt = "raw"; | ||||
|      const char *fmt = NULL; | ||||
| @ -69,7 +69,7 @@ index 221b9d6a16..c1306385a8 100644 | ||||
|      }; | ||||
|      struct DdIo in = { | ||||
|          .bsz = 512, /* Block size is by default 512 bytes */ | ||||
| @@ -4964,6 +4981,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5020,6 +5037,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|          { "of", img_dd_of, C_OF }, | ||||
|          { "skip", img_dd_skip, C_SKIP }, | ||||
|          { "osize", img_dd_osize, C_OSIZE }, | ||||
| @ -77,7 +77,7 @@ index 221b9d6a16..c1306385a8 100644 | ||||
|          { NULL, NULL, 0 } | ||||
|      }; | ||||
|      const struct option long_options[] = { | ||||
| @@ -5160,9 +5178,10 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5216,9 +5234,10 @@ static int img_dd(int argc, char **argv)
 | ||||
|   | ||||
|      in.buf = g_new(uint8_t, in.bsz); | ||||
|   | ||||
| @ -90,7 +90,7 @@ index 221b9d6a16..c1306385a8 100644 | ||||
|          if (blk1) { | ||||
|              in_ret = blk_pread(blk1, in_pos, bytes, in.buf, 0); | ||||
|              if (in_ret == 0) { | ||||
| @@ -5171,6 +5190,9 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5227,6 +5246,9 @@ static int img_dd(int argc, char **argv)
 | ||||
|          } else { | ||||
|              in_ret = read(STDIN_FILENO, in.buf, bytes); | ||||
|              if (in_ret == 0) { | ||||
|  | ||||
| @ -65,10 +65,10 @@ index d1616c045a..b5b0bb4467 100644 | ||||
|   | ||||
|  DEF("info", img_info, | ||||
| diff --git a/qemu-img.c b/qemu-img.c
 | ||||
| index c1306385a8..59c403373b 100644
 | ||||
| index a57ceeddfe..06d814e39c 100644
 | ||||
| --- a/qemu-img.c
 | ||||
| +++ b/qemu-img.c
 | ||||
| @@ -4954,7 +4954,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5010,7 +5010,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|      const char *fmt = NULL; | ||||
|      int64_t size = 0, readsize = 0; | ||||
|      int64_t out_pos, in_pos; | ||||
| @ -77,7 +77,7 @@ index c1306385a8..59c403373b 100644 | ||||
|      struct DdInfo dd = { | ||||
|          .flags = 0, | ||||
|          .count = 0, | ||||
| @@ -4992,7 +4992,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5048,7 +5048,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|          { 0, 0, 0, 0 } | ||||
|      }; | ||||
|   | ||||
| @ -86,7 +86,7 @@ index c1306385a8..59c403373b 100644 | ||||
|          if (c == EOF) { | ||||
|              break; | ||||
|          } | ||||
| @@ -5012,6 +5012,9 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5068,6 +5068,9 @@ static int img_dd(int argc, char **argv)
 | ||||
|          case 'h': | ||||
|              help(); | ||||
|              break; | ||||
| @ -96,7 +96,7 @@ index c1306385a8..59c403373b 100644 | ||||
|          case 'U': | ||||
|              force_share = true; | ||||
|              break; | ||||
| @@ -5142,13 +5145,15 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5198,13 +5201,15 @@ static int img_dd(int argc, char **argv)
 | ||||
|                                  size - in.bsz * in.offset, &error_abort); | ||||
|          } | ||||
|   | ||||
|  | ||||
| @ -7,20 +7,62 @@ Actually provide memory information via the query-balloon | ||||
| command. | ||||
| 
 | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: add BalloonInfo to member name exceptions list] | ||||
| [FE: add BalloonInfo to member name exceptions list | ||||
|      rebase for 8.0 - moved to hw/core/machine-hmp-cmds.c] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/core/machine-hmp-cmds.c | 30 +++++++++++++++++++++++++++++- | ||||
|  hw/virtio/virtio-balloon.c | 33 +++++++++++++++++++++++++++++++-- | ||||
|  monitor/hmp-cmds.c         | 30 +++++++++++++++++++++++++++++- | ||||
|  qapi/machine.json          | 22 +++++++++++++++++++++- | ||||
|  qapi/pragma.json           |  1 + | ||||
|  4 files changed, 82 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
 | ||||
| index c3e55ef9e9..0e32e6201f 100644
 | ||||
| --- a/hw/core/machine-hmp-cmds.c
 | ||||
| +++ b/hw/core/machine-hmp-cmds.c
 | ||||
| @@ -169,7 +169,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
 | ||||
|          return; | ||||
|      } | ||||
|   | ||||
| -    monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
 | ||||
| +    monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
 | ||||
| +    monitor_printf(mon, " max_mem=%" PRId64, info->max_mem >> 20);
 | ||||
| +    if (info->has_total_mem) {
 | ||||
| +        monitor_printf(mon, " total_mem=%" PRId64, info->total_mem >> 20);
 | ||||
| +    }
 | ||||
| +    if (info->has_free_mem) {
 | ||||
| +        monitor_printf(mon, " free_mem=%" PRId64, info->free_mem >> 20);
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    if (info->has_mem_swapped_in) {
 | ||||
| +        monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
 | ||||
| +    }
 | ||||
| +    if (info->has_mem_swapped_out) {
 | ||||
| +        monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
 | ||||
| +    }
 | ||||
| +    if (info->has_major_page_faults) {
 | ||||
| +        monitor_printf(mon, " major_page_faults=%" PRId64,
 | ||||
| +                       info->major_page_faults);
 | ||||
| +    }
 | ||||
| +    if (info->has_minor_page_faults) {
 | ||||
| +        monitor_printf(mon, " minor_page_faults=%" PRId64,
 | ||||
| +                       info->minor_page_faults);
 | ||||
| +    }
 | ||||
| +    if (info->has_last_update) {
 | ||||
| +        monitor_printf(mon, " last_update=%" PRId64,
 | ||||
| +                       info->last_update);
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    monitor_printf(mon, "\n");
 | ||||
|   | ||||
|      qapi_free_BalloonInfo(info); | ||||
|  } | ||||
| diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
 | ||||
| index 73ac5eb675..bbfe7eca62 100644
 | ||||
| index 746f07c4d2..a41854b902 100644
 | ||||
| --- a/hw/virtio/virtio-balloon.c
 | ||||
| +++ b/hw/virtio/virtio-balloon.c
 | ||||
| @@ -806,8 +806,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
 | ||||
| @@ -804,8 +804,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
 | ||||
|  static void virtio_balloon_stat(void *opaque, BalloonInfo *info) | ||||
|  { | ||||
|      VirtIOBalloon *dev = opaque; | ||||
| @ -60,52 +102,11 @@ index 73ac5eb675..bbfe7eca62 100644 | ||||
|  } | ||||
|   | ||||
|  static void virtio_balloon_to_target(void *opaque, ram_addr_t target) | ||||
| diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
 | ||||
| index 01b789a79e..480b798963 100644
 | ||||
| --- a/monitor/hmp-cmds.c
 | ||||
| +++ b/monitor/hmp-cmds.c
 | ||||
| @@ -696,7 +696,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
 | ||||
|          return; | ||||
|      } | ||||
|   | ||||
| -    monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
 | ||||
| +    monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20);
 | ||||
| +    monitor_printf(mon, " max_mem=%" PRId64, info->max_mem >> 20);
 | ||||
| +    if (info->has_total_mem) {
 | ||||
| +        monitor_printf(mon, " total_mem=%" PRId64, info->total_mem >> 20);
 | ||||
| +    }
 | ||||
| +    if (info->has_free_mem) {
 | ||||
| +        monitor_printf(mon, " free_mem=%" PRId64, info->free_mem >> 20);
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    if (info->has_mem_swapped_in) {
 | ||||
| +        monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in);
 | ||||
| +    }
 | ||||
| +    if (info->has_mem_swapped_out) {
 | ||||
| +        monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out);
 | ||||
| +    }
 | ||||
| +    if (info->has_major_page_faults) {
 | ||||
| +        monitor_printf(mon, " major_page_faults=%" PRId64,
 | ||||
| +                       info->major_page_faults);
 | ||||
| +    }
 | ||||
| +    if (info->has_minor_page_faults) {
 | ||||
| +        monitor_printf(mon, " minor_page_faults=%" PRId64,
 | ||||
| +                       info->minor_page_faults);
 | ||||
| +    }
 | ||||
| +    if (info->has_last_update) {
 | ||||
| +        monitor_printf(mon, " last_update=%" PRId64,
 | ||||
| +                       info->last_update);
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    monitor_printf(mon, "\n");
 | ||||
|   | ||||
|      qapi_free_BalloonInfo(info); | ||||
|  } | ||||
| diff --git a/qapi/machine.json b/qapi/machine.json
 | ||||
| index b9228a5e46..10e77a9af3 100644
 | ||||
| index 604b686e59..15f5f86683 100644
 | ||||
| --- a/qapi/machine.json
 | ||||
| +++ b/qapi/machine.json
 | ||||
| @@ -1054,9 +1054,29 @@
 | ||||
| @@ -1056,9 +1056,29 @@
 | ||||
|  # @actual: the logical size of the VM in bytes | ||||
|  #          Formula used: logical_vm_size = vm_ram_size - balloon_size | ||||
|  # | ||||
|  | ||||
| @ -13,13 +13,13 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com> | ||||
|  2 files changed, 9 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
 | ||||
| index 4f4ab30f8c..76fff60a6b 100644
 | ||||
| index b98ff15089..24595f618c 100644
 | ||||
| --- a/hw/core/machine-qmp-cmds.c
 | ||||
| +++ b/hw/core/machine-qmp-cmds.c
 | ||||
| @@ -99,6 +99,12 @@ MachineInfoList *qmp_query_machines(Error **errp)
 | ||||
|          info->hotpluggable_cpus = mc->has_hotpluggable_cpus; | ||||
| @@ -103,6 +103,12 @@ MachineInfoList *qmp_query_machines(Error **errp)
 | ||||
|          info->numa_mem_supported = mc->numa_mem_supported; | ||||
|          info->deprecated = !!mc->deprecation_reason; | ||||
|          info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi"); | ||||
| +
 | ||||
| +        if (strcmp(mc->name, MACHINE_GET_CLASS(current_machine)->name) == 0) {
 | ||||
| +            info->has_is_current = true;
 | ||||
| @ -28,9 +28,9 @@ index 4f4ab30f8c..76fff60a6b 100644 | ||||
| +
 | ||||
|          if (mc->default_cpu_type) { | ||||
|              info->default_cpu_type = g_strdup(mc->default_cpu_type); | ||||
|              info->has_default_cpu_type = true; | ||||
|          } | ||||
| diff --git a/qapi/machine.json b/qapi/machine.json
 | ||||
| index 10e77a9af3..9156103c8f 100644
 | ||||
| index 15f5f86683..c904280085 100644
 | ||||
| --- a/qapi/machine.json
 | ||||
| +++ b/qapi/machine.json
 | ||||
| @@ -138,6 +138,8 @@
 | ||||
| @ -42,7 +42,7 @@ index 10e77a9af3..9156103c8f 100644 | ||||
|  # @cpu-max: maximum number of CPUs supported by the machine type | ||||
|  #           (since 1.5) | ||||
|  # | ||||
| @@ -159,7 +161,7 @@
 | ||||
| @@ -161,7 +163,7 @@
 | ||||
|  ## | ||||
|  { 'struct': 'MachineInfo', | ||||
|    'data': { 'name': 'str', '*alias': 'str', | ||||
| @ -50,4 +50,4 @@ index 10e77a9af3..9156103c8f 100644 | ||||
| +            '*is-default': 'bool', '*is-current': 'bool', 'cpu-max': 'int',
 | ||||
|              'hotpluggable-cpus': 'bool',  'numa-mem-supported': 'bool', | ||||
|              'deprecated': 'bool', '*default-cpu-type': 'str', | ||||
|              '*default-ram-id': 'str' } } | ||||
|              '*default-ram-id': 'str', 'acpi': 'bool' } } | ||||
|  | ||||
| @ -6,13 +6,15 @@ Subject: [PATCH] PVE: qapi: modify spice query | ||||
| Provide the last ticket in the SpiceInfo struct optionally. | ||||
| 
 | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to QAPI change] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  qapi/ui.json    | 3 +++ | ||||
|  ui/spice-core.c | 5 +++++ | ||||
|  2 files changed, 8 insertions(+) | ||||
|  ui/spice-core.c | 4 ++++ | ||||
|  2 files changed, 7 insertions(+) | ||||
| 
 | ||||
| diff --git a/qapi/ui.json b/qapi/ui.json
 | ||||
| index 0abba3e930..bf8f441227 100644
 | ||||
| index 98322342f7..316d4dc933 100644
 | ||||
| --- a/qapi/ui.json
 | ||||
| +++ b/qapi/ui.json
 | ||||
| @@ -310,11 +310,14 @@
 | ||||
| @ -31,15 +33,14 @@ index 0abba3e930..bf8f441227 100644 | ||||
|    'if': 'CONFIG_SPICE' } | ||||
|   | ||||
| diff --git a/ui/spice-core.c b/ui/spice-core.c
 | ||||
| index 37774f1c0a..367f77f2b4 100644
 | ||||
| index b20c25aee0..26baeb7846 100644
 | ||||
| --- a/ui/spice-core.c
 | ||||
| +++ b/ui/spice-core.c
 | ||||
| @@ -534,6 +534,11 @@ static SpiceInfo *qmp_query_spice_real(Error **errp)
 | ||||
| @@ -548,6 +548,10 @@ static SpiceInfo *qmp_query_spice_real(Error **errp)
 | ||||
|      micro = SPICE_SERVER_VERSION & 0xff; | ||||
|      info->compiled_version = g_strdup_printf("%d.%d.%d", major, minor, micro); | ||||
|   | ||||
| +    if (auth_passwd) {
 | ||||
| +        info->has_ticket = true;
 | ||||
| +        info->ticket =  g_strdup(auth_passwd);
 | ||||
| +    }
 | ||||
| +
 | ||||
|  | ||||
| @ -15,19 +15,19 @@ Additionally, allows tracking the current position from the outside | ||||
| 
 | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  migration/channel-savevm-async.c | 182 +++++++++++++++++++++++++++++++ | ||||
|  migration/channel-savevm-async.c | 183 +++++++++++++++++++++++++++++++ | ||||
|  migration/channel-savevm-async.h |  51 +++++++++ | ||||
|  migration/meson.build            |   1 + | ||||
|  3 files changed, 234 insertions(+) | ||||
|  3 files changed, 235 insertions(+) | ||||
|  create mode 100644 migration/channel-savevm-async.c | ||||
|  create mode 100644 migration/channel-savevm-async.h | ||||
| 
 | ||||
| diff --git a/migration/channel-savevm-async.c b/migration/channel-savevm-async.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..06d5484778
 | ||||
| index 0000000000..aab081ce07
 | ||||
| --- /dev/null
 | ||||
| +++ b/migration/channel-savevm-async.c
 | ||||
| @@ -0,0 +1,182 @@
 | ||||
| @@ -0,0 +1,183 @@
 | ||||
| +/*
 | ||||
| + * QIO Channel implementation to be used by savevm-async QMP calls
 | ||||
| + */
 | ||||
| @ -71,6 +71,7 @@ index 0000000000..06d5484778 | ||||
| +                               size_t niov,
 | ||||
| +                               int **fds,
 | ||||
| +                               size_t *nfds,
 | ||||
| +                               int flags,
 | ||||
| +                               Error **errp)
 | ||||
| +{
 | ||||
| +    QIOChannelSavevmAsync *saioc = QIO_CHANNEL_SAVEVM_ASYNC(ioc);
 | ||||
| @ -268,7 +269,7 @@ index 0000000000..17ae2cb261 | ||||
| +
 | ||||
| +#endif /* QIO_CHANNEL_SAVEVM_ASYNC_H */
 | ||||
| diff --git a/migration/meson.build b/migration/meson.build
 | ||||
| index 690487cf1a..8cac83c06c 100644
 | ||||
| index 0d1bb9f96e..8a142fc7a9 100644
 | ||||
| --- a/migration/meson.build
 | ||||
| +++ b/migration/meson.build
 | ||||
| @@ -13,6 +13,7 @@ softmmu_ss.add(files(
 | ||||
|  | ||||
| @ -25,7 +25,8 @@ Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| [FE: further improve aborting | ||||
|      adapt to removal of QEMUFileOps | ||||
|      improve condition for entering final stage] | ||||
|      improve condition for entering final stage | ||||
|      adapt to QAPI and other changes for 8.0] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hmp-commands-info.hx         |  13 + | ||||
| @ -33,17 +34,17 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  include/migration/snapshot.h |   2 + | ||||
|  include/monitor/hmp.h        |   5 + | ||||
|  migration/meson.build        |   1 + | ||||
|  migration/savevm-async.c     | 538 +++++++++++++++++++++++++++++++++++ | ||||
|  monitor/hmp-cmds.c           |  57 ++++ | ||||
|  migration/savevm-async.c     | 535 +++++++++++++++++++++++++++++++++++ | ||||
|  monitor/hmp-cmds.c           |  58 ++++ | ||||
|  qapi/migration.json          |  34 +++ | ||||
|  qapi/misc.json               |  32 +++ | ||||
|  qemu-options.hx              |  12 + | ||||
|  softmmu/vl.c                 |  10 + | ||||
|  11 files changed, 737 insertions(+) | ||||
|  11 files changed, 735 insertions(+) | ||||
|  create mode 100644 migration/savevm-async.c | ||||
| 
 | ||||
| diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
 | ||||
| index 754b1e8408..489c524e9e 100644
 | ||||
| index 47d63d26db..a166bff3d5 100644
 | ||||
| --- a/hmp-commands-info.hx
 | ||||
| +++ b/hmp-commands-info.hx
 | ||||
| @@ -540,6 +540,19 @@ SRST
 | ||||
| @ -67,11 +68,11 @@ index 754b1e8408..489c524e9e 100644 | ||||
|          .name       = "balloon", | ||||
|          .args_type  = "", | ||||
| diff --git a/hmp-commands.hx b/hmp-commands.hx
 | ||||
| index 673e39a697..039be0033d 100644
 | ||||
| index bb85ee1d26..b66d7fc4ab 100644
 | ||||
| --- a/hmp-commands.hx
 | ||||
| +++ b/hmp-commands.hx
 | ||||
| @@ -1815,3 +1815,36 @@ SRST
 | ||||
|    Dump the FDT in dtb format to *filename*. | ||||
| @@ -1846,3 +1846,36 @@ SRST
 | ||||
|    List event channels in the guest | ||||
|  ERST | ||||
|  #endif | ||||
| +
 | ||||
| @ -119,10 +120,10 @@ index e72083b117..c846d37806 100644 | ||||
| +
 | ||||
|  #endif | ||||
| diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
 | ||||
| index dfbc0c9a2f..440f86aba8 100644
 | ||||
| index fdb69b7f9c..c012bad741 100644
 | ||||
| --- a/include/monitor/hmp.h
 | ||||
| +++ b/include/monitor/hmp.h
 | ||||
| @@ -27,6 +27,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict);
 | ||||
| @@ -28,6 +28,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict);
 | ||||
|  void hmp_info_uuid(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_chardev(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_mice(Monitor *mon, const QDict *qdict); | ||||
| @ -130,10 +131,10 @@ index dfbc0c9a2f..440f86aba8 100644 | ||||
|  void hmp_info_migrate(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict); | ||||
| @@ -81,6 +82,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
 | ||||
|  void hmp_netdev_del(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_getfd(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_closefd(Monitor *mon, const QDict *qdict); | ||||
| @@ -94,6 +95,10 @@ void hmp_closefd(Monitor *mon, const QDict *qdict);
 | ||||
|  void hmp_mouse_move(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_mouse_button(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_mouse_set(Monitor *mon, const QDict *qdict); | ||||
| +void hmp_savevm_start(Monitor *mon, const QDict *qdict);
 | ||||
| +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
 | ||||
| +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
 | ||||
| @ -142,23 +143,23 @@ index dfbc0c9a2f..440f86aba8 100644 | ||||
|  void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_chardev_add(Monitor *mon, const QDict *qdict); | ||||
| diff --git a/migration/meson.build b/migration/meson.build
 | ||||
| index 8cac83c06c..0842d00cd2 100644
 | ||||
| index 8a142fc7a9..a7824b5266 100644
 | ||||
| --- a/migration/meson.build
 | ||||
| +++ b/migration/meson.build
 | ||||
| @@ -24,6 +24,7 @@ softmmu_ss.add(files(
 | ||||
| @@ -25,6 +25,7 @@ softmmu_ss.add(files(
 | ||||
|    'multifd-zlib.c', | ||||
|    'postcopy-ram.c', | ||||
|    'savevm.c', | ||||
| +  'savevm-async.c',
 | ||||
|    'socket.c', | ||||
|    'tls.c', | ||||
|  ), gnutls) | ||||
|    'threadinfo.c', | ||||
| diff --git a/migration/savevm-async.c b/migration/savevm-async.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..dc30558713
 | ||||
| index 0000000000..24660af014
 | ||||
| --- /dev/null
 | ||||
| +++ b/migration/savevm-async.c
 | ||||
| @@ -0,0 +1,538 @@
 | ||||
| @@ -0,0 +1,535 @@
 | ||||
| +#include "qemu/osdep.h"
 | ||||
| +#include "migration/channel-savevm-async.h"
 | ||||
| +#include "migration/migration.h"
 | ||||
| @ -231,24 +232,20 @@ index 0000000000..dc30558713 | ||||
| +        info->bytes = s->bs_pos;
 | ||||
| +        switch (s->state) {
 | ||||
| +        case SAVE_STATE_ERROR:
 | ||||
| +            info->has_status = true;
 | ||||
| +            info->status = g_strdup("failed");
 | ||||
| +            info->has_total_time = true;
 | ||||
| +            info->total_time = s->total_time;
 | ||||
| +            if (s->error) {
 | ||||
| +                info->has_error = true;
 | ||||
| +                info->error = g_strdup(error_get_pretty(s->error));
 | ||||
| +            }
 | ||||
| +            break;
 | ||||
| +        case SAVE_STATE_ACTIVE:
 | ||||
| +            info->has_status = true;
 | ||||
| +            info->status = g_strdup("active");
 | ||||
| +            info->has_total_time = true;
 | ||||
| +            info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
 | ||||
| +                - s->total_time;
 | ||||
| +            break;
 | ||||
| +        case SAVE_STATE_COMPLETED:
 | ||||
| +            info->has_status = true;
 | ||||
| +            info->status = g_strdup("completed");
 | ||||
| +            info->has_total_time = true;
 | ||||
| +            info->total_time = s->total_time;
 | ||||
| @ -405,14 +402,14 @@ index 0000000000..dc30558713 | ||||
| +    }
 | ||||
| +
 | ||||
| +    while (snap_state.state == SAVE_STATE_ACTIVE) {
 | ||||
| +        uint64_t pending_size, pend_precopy, pend_compatible, pend_postcopy;
 | ||||
| +        uint64_t pending_size, pend_precopy, pend_postcopy;
 | ||||
| +
 | ||||
| +        /* pending is expected to be called without iothread lock */
 | ||||
| +        qemu_mutex_unlock_iothread();
 | ||||
| +        qemu_savevm_state_pending(snap_state.file, 0, &pend_precopy, &pend_compatible, &pend_postcopy);
 | ||||
| +        qemu_savevm_state_pending_exact(&pend_precopy, &pend_postcopy);
 | ||||
| +        qemu_mutex_lock_iothread();
 | ||||
| +
 | ||||
| +        pending_size = pend_precopy + pend_compatible + pend_postcopy;
 | ||||
| +        pending_size = pend_precopy + pend_postcopy;
 | ||||
| +
 | ||||
| +        /*
 | ||||
| +         * A guest reaching this cutoff is dirtying lots of RAM. It should be
 | ||||
| @ -465,7 +462,9 @@ index 0000000000..dc30558713 | ||||
| +        if (bs_ctx != qemu_get_aio_context()) {
 | ||||
| +            DPRINTF("savevm: async flushing drive %s\n", bs->filename);
 | ||||
| +            aio_co_reschedule_self(bs_ctx);
 | ||||
| +            bdrv_graph_co_rdlock();
 | ||||
| +            bdrv_flush(bs);
 | ||||
| +            bdrv_graph_co_rdunlock();
 | ||||
| +            aio_co_reschedule_self(qemu_get_aio_context());
 | ||||
| +        }
 | ||||
| +    }
 | ||||
| @ -476,7 +475,7 @@ index 0000000000..dc30558713 | ||||
| +    qemu_bh_schedule(snap_state.finalize_bh);
 | ||||
| +}
 | ||||
| +
 | ||||
| +void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
 | ||||
| +void qmp_savevm_start(const char *statefile, Error **errp)
 | ||||
| +{
 | ||||
| +    Error *local_err = NULL;
 | ||||
| +    MigrationState *ms = migrate_get_current();
 | ||||
| @ -513,7 +512,7 @@ index 0000000000..dc30558713 | ||||
| +        snap_state.error = NULL;
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    if (!has_statefile) {
 | ||||
| +    if (!statefile) {
 | ||||
| +        vm_stop(RUN_STATE_SAVE_VM);
 | ||||
| +        snap_state.state = SAVE_STATE_COMPLETED;
 | ||||
| +        return;
 | ||||
| @ -643,8 +642,7 @@ index 0000000000..dc30558713 | ||||
| +                               Error **errp)
 | ||||
| +{
 | ||||
| +    // Compatibility to older qemu-server.
 | ||||
| +    (void)qmp_blockdev_snapshot_delete_internal_sync(device, false, NULL,
 | ||||
| +                                                     true, name, errp);
 | ||||
| +    (void)qmp_blockdev_snapshot_delete_internal_sync(device, NULL, name, errp);
 | ||||
| +}
 | ||||
| +
 | ||||
| +int load_snapshot_from_blockdev(const char *filename, Error **errp)
 | ||||
| @ -698,19 +696,28 @@ index 0000000000..dc30558713 | ||||
| +    return ret;
 | ||||
| +}
 | ||||
| diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
 | ||||
| index 480b798963..cfebfd1db5 100644
 | ||||
| index 6c559b48c8..435f9334f9 100644
 | ||||
| --- a/monitor/hmp-cmds.c
 | ||||
| +++ b/monitor/hmp-cmds.c
 | ||||
| @@ -1906,6 +1906,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
 | ||||
|      hmp_handle_error(mon, err); | ||||
|  } | ||||
| @@ -22,6 +22,7 @@
 | ||||
|  #include "monitor/monitor-internal.h" | ||||
|  #include "qapi/error.h" | ||||
|  #include "qapi/qapi-commands-control.h" | ||||
| +#include "qapi/qapi-commands-migration.h"
 | ||||
|  #include "qapi/qapi-commands-misc.h" | ||||
|  #include "qapi/qmp/qdict.h" | ||||
|  #include "qapi/qmp/qerror.h" | ||||
| @@ -443,3 +444,60 @@ void hmp_info_mtree(Monitor *mon, const QDict *qdict)
 | ||||
|   | ||||
|      mtree_info(flatview, dispatch_tree, owner, disabled); | ||||
|  } | ||||
| +
 | ||||
| +void hmp_savevm_start(Monitor *mon, const QDict *qdict)
 | ||||
| +{
 | ||||
| +    Error *errp = NULL;
 | ||||
| +    const char *statefile = qdict_get_try_str(qdict, "statefile");
 | ||||
| +
 | ||||
| +    qmp_savevm_start(statefile != NULL, statefile, &errp);
 | ||||
| +    qmp_savevm_start(statefile, &errp);
 | ||||
| +    hmp_handle_error(mon, errp);
 | ||||
| +}
 | ||||
| +
 | ||||
| @ -747,7 +754,7 @@ index 480b798963..cfebfd1db5 100644 | ||||
| +    SaveVMInfo *info;
 | ||||
| +    info = qmp_query_savevm(NULL);
 | ||||
| +
 | ||||
| +    if (info->has_status) {
 | ||||
| +    if (info->status) {
 | ||||
| +        monitor_printf(mon, "savevm status: %s\n", info->status);
 | ||||
| +        monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
 | ||||
| +                       info->total_time);
 | ||||
| @ -757,16 +764,12 @@ index 480b798963..cfebfd1db5 100644 | ||||
| +    if (info->has_bytes) {
 | ||||
| +        monitor_printf(mon, "Bytes saved: %"PRIu64"\n", info->bytes);
 | ||||
| +    }
 | ||||
| +    if (info->has_error) {
 | ||||
| +    if (info->error) {
 | ||||
| +        monitor_printf(mon, "Error: %s\n", info->error);
 | ||||
| +    }
 | ||||
| +}
 | ||||
| +
 | ||||
|  void hmp_info_iothreads(Monitor *mon, const QDict *qdict) | ||||
|  { | ||||
|      IOThreadInfoList *info_list = qmp_query_iothreads(NULL); | ||||
| diff --git a/qapi/migration.json b/qapi/migration.json
 | ||||
| index 88ecf86ac8..4435866379 100644
 | ||||
| index c84fa10e86..1702b92553 100644
 | ||||
| --- a/qapi/migration.json
 | ||||
| +++ b/qapi/migration.json
 | ||||
| @@ -261,6 +261,40 @@
 | ||||
| @ -811,10 +814,10 @@ index 88ecf86ac8..4435866379 100644 | ||||
|  # @query-migrate: | ||||
|  # | ||||
| diff --git a/qapi/misc.json b/qapi/misc.json
 | ||||
| index 27ef5a2b20..b3ce75dcae 100644
 | ||||
| index 6ddd16ea28..098c9bbe93 100644
 | ||||
| --- a/qapi/misc.json
 | ||||
| +++ b/qapi/misc.json
 | ||||
| @@ -435,6 +435,38 @@
 | ||||
| @@ -469,6 +469,38 @@
 | ||||
|  ## | ||||
|  { 'command': 'query-fdsets', 'returns': ['FdsetInfo'] } | ||||
|   | ||||
| @ -854,10 +857,10 @@ index 27ef5a2b20..b3ce75dcae 100644 | ||||
|  # @CommandLineParameterType: | ||||
|  # | ||||
| diff --git a/qemu-options.hx b/qemu-options.hx
 | ||||
| index 7f99d15b23..54efb127c4 100644
 | ||||
| index 59bdf67a2c..fc6cb23dd9 100644
 | ||||
| --- a/qemu-options.hx
 | ||||
| +++ b/qemu-options.hx
 | ||||
| @@ -4391,6 +4391,18 @@ SRST
 | ||||
| @@ -4378,6 +4378,18 @@ SRST
 | ||||
|      Start right away with a saved state (``loadvm`` in monitor) | ||||
|  ERST | ||||
|   | ||||
| @ -877,7 +880,7 @@ index 7f99d15b23..54efb127c4 100644 | ||||
|  DEF("daemonize", 0, QEMU_OPTION_daemonize, \ | ||||
|      "-daemonize      daemonize QEMU after initializing\n", QEMU_ARCH_ALL) | ||||
| diff --git a/softmmu/vl.c b/softmmu/vl.c
 | ||||
| index 5f7f6ca981..21f067d115 100644
 | ||||
| index ea20b23e4c..0eabc71b68 100644
 | ||||
| --- a/softmmu/vl.c
 | ||||
| +++ b/softmmu/vl.c
 | ||||
| @@ -164,6 +164,7 @@ static const char *accelerators;
 | ||||
| @ -888,7 +891,7 @@ index 5f7f6ca981..21f067d115 100644 | ||||
|  static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts); | ||||
|  static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts); | ||||
|  static int display_remote; | ||||
| @@ -2607,6 +2608,12 @@ void qmp_x_exit_preconfig(Error **errp)
 | ||||
| @@ -2612,6 +2613,12 @@ void qmp_x_exit_preconfig(Error **errp)
 | ||||
|   | ||||
|      if (loadvm) { | ||||
|          load_snapshot(loadvm, NULL, false, NULL, &error_fatal); | ||||
| @ -901,7 +904,7 @@ index 5f7f6ca981..21f067d115 100644 | ||||
|      } | ||||
|      if (replay_mode != REPLAY_MODE_NONE) { | ||||
|          replay_vmstate_init(); | ||||
| @@ -3151,6 +3158,9 @@ void qemu_init(int argc, char **argv)
 | ||||
| @@ -3159,6 +3166,9 @@ void qemu_init(int argc, char **argv)
 | ||||
|              case QEMU_OPTION_loadvm: | ||||
|                  loadvm = optarg; | ||||
|                  break; | ||||
|  | ||||
| @ -19,7 +19,7 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  3 files changed, 38 insertions(+), 18 deletions(-) | ||||
| 
 | ||||
| diff --git a/migration/qemu-file.c b/migration/qemu-file.c
 | ||||
| index 2d5f74ffc2..9fd97e6fe1 100644
 | ||||
| index 102ab3b439..5ced17aba4 100644
 | ||||
| --- a/migration/qemu-file.c
 | ||||
| +++ b/migration/qemu-file.c
 | ||||
| @@ -31,8 +31,8 @@
 | ||||
| @ -178,7 +178,7 @@ index 2d5f74ffc2..9fd97e6fe1 100644 | ||||
|      if (blen < compressBound(size)) { | ||||
|          return -1; | ||||
| diff --git a/migration/qemu-file.h b/migration/qemu-file.h
 | ||||
| index fa13d04d78..914f1a63a8 100644
 | ||||
| index 9d0155a2a1..cc06240e8d 100644
 | ||||
| --- a/migration/qemu-file.h
 | ||||
| +++ b/migration/qemu-file.h
 | ||||
| @@ -63,7 +63,9 @@ typedef struct QEMUFileHooks {
 | ||||
| @ -192,10 +192,10 @@ index fa13d04d78..914f1a63a8 100644 | ||||
|  int qemu_fclose(QEMUFile *f); | ||||
|   | ||||
| diff --git a/migration/savevm-async.c b/migration/savevm-async.c
 | ||||
| index dc30558713..a38e7351c1 100644
 | ||||
| index 24660af014..70273a2996 100644
 | ||||
| --- a/migration/savevm-async.c
 | ||||
| +++ b/migration/savevm-async.c
 | ||||
| @@ -374,7 +374,7 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
 | ||||
| @@ -372,7 +372,7 @@ void qmp_savevm_start(const char *statefile, Error **errp)
 | ||||
|   | ||||
|      QIOChannel *ioc = QIO_CHANNEL(qio_channel_savevm_async_new(snap_state.target, | ||||
|                                                                 &snap_state.bs_pos)); | ||||
| @ -204,7 +204,7 @@ index dc30558713..a38e7351c1 100644 | ||||
|   | ||||
|      if (!snap_state.file) { | ||||
|          error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile); | ||||
| @@ -507,7 +507,8 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp)
 | ||||
| @@ -504,7 +504,8 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp)
 | ||||
|      blk_op_block_all(be, blocker); | ||||
|   | ||||
|      /* restore the VM state */ | ||||
|  | ||||
| @ -4,19 +4,19 @@ Date: Mon, 6 Apr 2020 12:16:47 +0200 | ||||
| Subject: [PATCH] PVE: block: add the zeroinit block driver filter | ||||
| 
 | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [adapt to changed function signatures] | ||||
| Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | ||||
| [FE: adapt to changed function signatures] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/meson.build |   1 + | ||||
|  block/zeroinit.c  | 198 ++++++++++++++++++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 199 insertions(+) | ||||
|  block/zeroinit.c  | 200 ++++++++++++++++++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 201 insertions(+) | ||||
|  create mode 100644 block/zeroinit.c | ||||
| 
 | ||||
| diff --git a/block/meson.build b/block/meson.build
 | ||||
| index b7c68b83a3..020a89ae07 100644
 | ||||
| index 382bec0e7d..253fe49fa2 100644
 | ||||
| --- a/block/meson.build
 | ||||
| +++ b/block/meson.build
 | ||||
| @@ -43,6 +43,7 @@ block_ss.add(files(
 | ||||
| @@ -44,6 +44,7 @@ block_ss.add(files(
 | ||||
|    'vmdk.c', | ||||
|    'vpc.c', | ||||
|    'write-threshold.c', | ||||
| @ -26,10 +26,10 @@ index b7c68b83a3..020a89ae07 100644 | ||||
|  softmmu_ss.add(when: 'CONFIG_TCG', if_true: files('blkreplay.c')) | ||||
| diff --git a/block/zeroinit.c b/block/zeroinit.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..b60e1b84dc
 | ||||
| index 0000000000..1257342724
 | ||||
| --- /dev/null
 | ||||
| +++ b/block/zeroinit.c
 | ||||
| @@ -0,0 +1,198 @@
 | ||||
| @@ -0,0 +1,200 @@
 | ||||
| +/*
 | ||||
| + * Filter to fake a zero-initialized block device.
 | ||||
| + *
 | ||||
| @ -43,6 +43,7 @@ index 0000000000..b60e1b84dc | ||||
| +#include "qemu/osdep.h"
 | ||||
| +#include "qapi/error.h"
 | ||||
| +#include "block/block_int.h"
 | ||||
| +#include "block/block-io.h"
 | ||||
| +#include "qapi/qmp/qdict.h"
 | ||||
| +#include "qapi/qmp/qstring.h"
 | ||||
| +#include "qemu/cutils.h"
 | ||||
| @ -136,9 +137,9 @@ index 0000000000..b60e1b84dc | ||||
| +    (void)s;
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int64_t zeroinit_getlength(BlockDriverState *bs)
 | ||||
| +static coroutine_fn int64_t zeroinit_co_getlength(BlockDriverState *bs)
 | ||||
| +{
 | ||||
| +    return bdrv_getlength(bs->file->bs);
 | ||||
| +    return bdrv_co_getlength(bs->file->bs);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int coroutine_fn zeroinit_co_preadv(BlockDriverState *bs,
 | ||||
| @ -190,9 +191,10 @@ index 0000000000..b60e1b84dc | ||||
| +    return bdrv_co_truncate(bs->file, offset, exact, prealloc, req_flags, errp);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int zeroinit_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | ||||
| +static coroutine_fn int zeroinit_co_get_info(BlockDriverState *bs,
 | ||||
| +                                             BlockDriverInfo *bdi)
 | ||||
| +{
 | ||||
| +    return bdrv_get_info(bs->file->bs, bdi);
 | ||||
| +    return bdrv_co_get_info(bs->file->bs, bdi);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static BlockDriver bdrv_zeroinit = {
 | ||||
| @ -203,7 +205,7 @@ index 0000000000..b60e1b84dc | ||||
| +    .bdrv_parse_filename              = zeroinit_parse_filename,
 | ||||
| +    .bdrv_file_open                   = zeroinit_open,
 | ||||
| +    .bdrv_close                       = zeroinit_close,
 | ||||
| +    .bdrv_getlength                   = zeroinit_getlength,
 | ||||
| +    .bdrv_co_getlength                = zeroinit_co_getlength,
 | ||||
| +    .bdrv_child_perm                  = bdrv_default_perms,
 | ||||
| +    .bdrv_co_flush_to_disk            = zeroinit_co_flush,
 | ||||
| +
 | ||||
| @ -219,7 +221,7 @@ index 0000000000..b60e1b84dc | ||||
| +    .bdrv_co_pdiscard                 = zeroinit_co_pdiscard,
 | ||||
| +
 | ||||
| +    .bdrv_co_truncate                 = zeroinit_co_truncate,
 | ||||
| +    .bdrv_get_info                    = zeroinit_get_info,
 | ||||
| +    .bdrv_co_get_info                 = zeroinit_co_get_info,
 | ||||
| +};
 | ||||
| +
 | ||||
| +static void bdrv_zeroinit_init(void)
 | ||||
|  | ||||
| @ -14,10 +14,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  2 files changed, 11 insertions(+) | ||||
| 
 | ||||
| diff --git a/qemu-options.hx b/qemu-options.hx
 | ||||
| index 54efb127c4..ef456d03ec 100644
 | ||||
| index fc6cb23dd9..3ccedf7c45 100644
 | ||||
| --- a/qemu-options.hx
 | ||||
| +++ b/qemu-options.hx
 | ||||
| @@ -1147,6 +1147,9 @@ backend describes how QEMU handles the data.
 | ||||
| @@ -1150,6 +1150,9 @@ backend describes how QEMU handles the data.
 | ||||
|   | ||||
|  ERST | ||||
|   | ||||
| @ -28,10 +28,10 @@ index 54efb127c4..ef456d03ec 100644 | ||||
|      "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL) | ||||
|  DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL) | ||||
| diff --git a/softmmu/vl.c b/softmmu/vl.c
 | ||||
| index 21f067d115..9d737e7914 100644
 | ||||
| index 0eabc71b68..323f6a23d4 100644
 | ||||
| --- a/softmmu/vl.c
 | ||||
| +++ b/softmmu/vl.c
 | ||||
| @@ -2643,6 +2643,7 @@ void qemu_init(int argc, char **argv)
 | ||||
| @@ -2648,6 +2648,7 @@ void qemu_init(int argc, char **argv)
 | ||||
|      MachineClass *machine_class; | ||||
|      bool userconfig = true; | ||||
|      FILE *vmstate_dump_file = NULL; | ||||
| @ -39,7 +39,7 @@ index 21f067d115..9d737e7914 100644 | ||||
|   | ||||
|      qemu_add_opts(&qemu_drive_opts); | ||||
|      qemu_add_drive_opts(&qemu_legacy_drive_opts); | ||||
| @@ -3263,6 +3264,13 @@ void qemu_init(int argc, char **argv)
 | ||||
| @@ -3271,6 +3272,13 @@ void qemu_init(int argc, char **argv)
 | ||||
|                  machine_parse_property_opt(qemu_find_opts("smp-opts"), | ||||
|                                             "smp", optarg); | ||||
|                  break; | ||||
|  | ||||
| @ -11,10 +11,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 9 insertions(+) | ||||
| 
 | ||||
| diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
 | ||||
| index 2a20982066..7968ad5a93 100644
 | ||||
| index 4a34f03047..59b917e50c 100644
 | ||||
| --- a/hw/intc/apic_common.c
 | ||||
| +++ b/hw/intc/apic_common.c
 | ||||
| @@ -278,6 +278,15 @@ static void apic_reset_common(DeviceState *dev)
 | ||||
| @@ -252,6 +252,15 @@ static void apic_reset_common(DeviceState *dev)
 | ||||
|      info->vapic_base_update(s); | ||||
|   | ||||
|      apic_init_reset(dev); | ||||
|  | ||||
| @ -13,10 +13,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  2 files changed, 42 insertions(+), 20 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/file-posix.c b/block/file-posix.c
 | ||||
| index 9a16d86344..bd68df57ad 100644
 | ||||
| index 9681bd0434..044890822d 100644
 | ||||
| --- a/block/file-posix.c
 | ||||
| +++ b/block/file-posix.c
 | ||||
| @@ -2487,6 +2487,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
 | ||||
| @@ -2483,6 +2483,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
 | ||||
|      int fd; | ||||
|      uint64_t perm, shared; | ||||
|      int result = 0; | ||||
| @ -24,7 +24,7 @@ index 9a16d86344..bd68df57ad 100644 | ||||
|   | ||||
|      /* Validate options and set default values */ | ||||
|      assert(options->driver == BLOCKDEV_DRIVER_FILE); | ||||
| @@ -2527,19 +2528,22 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
 | ||||
| @@ -2523,19 +2524,22 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
 | ||||
|      perm = BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||||
|      shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; | ||||
|   | ||||
| @ -59,7 +59,7 @@ index 9a16d86344..bd68df57ad 100644 | ||||
|      } | ||||
|   | ||||
|      /* Clear the file by truncating it to 0 */ | ||||
| @@ -2593,13 +2597,15 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
 | ||||
| @@ -2589,13 +2593,15 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
 | ||||
|      } | ||||
|   | ||||
|  out_unlock: | ||||
| @ -82,7 +82,7 @@ index 9a16d86344..bd68df57ad 100644 | ||||
|      } | ||||
|   | ||||
|  out_close: | ||||
| @@ -2624,6 +2630,7 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
 | ||||
| @@ -2619,6 +2625,7 @@ raw_co_create_opts(BlockDriver *drv, const char *filename,
 | ||||
|      PreallocMode prealloc; | ||||
|      char *buf = NULL; | ||||
|      Error *local_err = NULL; | ||||
| @ -90,7 +90,7 @@ index 9a16d86344..bd68df57ad 100644 | ||||
|   | ||||
|      /* Skip file: protocol prefix */ | ||||
|      strstart(filename, "file:", &filename); | ||||
| @@ -2646,6 +2653,18 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
 | ||||
| @@ -2641,6 +2648,18 @@ raw_co_create_opts(BlockDriver *drv, const char *filename,
 | ||||
|          return -EINVAL; | ||||
|      } | ||||
|   | ||||
| @ -109,7 +109,7 @@ index 9a16d86344..bd68df57ad 100644 | ||||
|      options = (BlockdevCreateOptions) { | ||||
|          .driver     = BLOCKDEV_DRIVER_FILE, | ||||
|          .u.file     = { | ||||
| @@ -2657,6 +2676,8 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
 | ||||
| @@ -2652,6 +2671,8 @@ raw_co_create_opts(BlockDriver *drv, const char *filename,
 | ||||
|              .nocow              = nocow, | ||||
|              .has_extent_size_hint = has_extent_size_hint, | ||||
|              .extent_size_hint   = extent_size_hint, | ||||
| @ -119,10 +119,10 @@ index 9a16d86344..bd68df57ad 100644 | ||||
|      }; | ||||
|      return raw_co_create(&options, errp); | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 7daaf545be..9e902b96bb 100644
 | ||||
| index 3c945c1f93..542add004b 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -4624,7 +4624,8 @@
 | ||||
| @@ -4740,7 +4740,8 @@
 | ||||
|              'size':                 'size', | ||||
|              '*preallocation':       'PreallocMode', | ||||
|              '*nocow':               'bool', | ||||
|  | ||||
| @ -26,10 +26,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/hw/core/machine.c b/hw/core/machine.c
 | ||||
| index 8d34caa31d..2df9037c4e 100644
 | ||||
| index cd13b8b0a3..cb1d334bcb 100644
 | ||||
| --- a/hw/core/machine.c
 | ||||
| +++ b/hw/core/machine.c
 | ||||
| @@ -132,7 +132,8 @@ GlobalProperty hw_compat_4_0[] = {
 | ||||
| @@ -141,7 +141,8 @@ GlobalProperty hw_compat_4_0[] = {
 | ||||
|      { "virtio-vga",     "edid", "false" }, | ||||
|      { "virtio-gpu-device", "edid", "false" }, | ||||
|      { "virtio-device", "use-started", "false" }, | ||||
|  | ||||
| @ -11,35 +11,36 @@ and only if 'is-current'). | ||||
| 
 | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to QAPI changes] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  hw/core/machine-qmp-cmds.c |  6 ++++++ | ||||
|  hw/core/machine-qmp-cmds.c |  5 +++++ | ||||
|  include/hw/boards.h        |  2 ++ | ||||
|  qapi/machine.json          |  4 +++- | ||||
|  softmmu/vl.c               | 25 +++++++++++++++++++++++++ | ||||
|  4 files changed, 36 insertions(+), 1 deletion(-) | ||||
|  4 files changed, 35 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
 | ||||
| index 76fff60a6b..ec9201fb9a 100644
 | ||||
| index 24595f618c..ee9cb0cd04 100644
 | ||||
| --- a/hw/core/machine-qmp-cmds.c
 | ||||
| +++ b/hw/core/machine-qmp-cmds.c
 | ||||
| @@ -103,6 +103,12 @@ MachineInfoList *qmp_query_machines(Error **errp)
 | ||||
| @@ -107,6 +107,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
 | ||||
|          if (strcmp(mc->name, MACHINE_GET_CLASS(current_machine)->name) == 0) { | ||||
|              info->has_is_current = true; | ||||
|              info->is_current = true; | ||||
| +
 | ||||
| +            // PVE version string only exists for current machine
 | ||||
| +            if (mc->pve_version) {
 | ||||
| +                info->has_pve_version = true;
 | ||||
| +                info->pve_version = g_strdup(mc->pve_version);
 | ||||
| +            }
 | ||||
|          } | ||||
|   | ||||
|          if (mc->default_cpu_type) { | ||||
| diff --git a/include/hw/boards.h b/include/hw/boards.h
 | ||||
| index 90f1dd3aeb..14d60520d9 100644
 | ||||
| index 6fbbfd56c8..61a526e97d 100644
 | ||||
| --- a/include/hw/boards.h
 | ||||
| +++ b/include/hw/boards.h
 | ||||
| @@ -230,6 +230,8 @@ struct MachineClass {
 | ||||
| @@ -232,6 +232,8 @@ struct MachineClass {
 | ||||
|      const char *desc; | ||||
|      const char *deprecation_reason; | ||||
|   | ||||
| @ -49,29 +50,29 @@ index 90f1dd3aeb..14d60520d9 100644 | ||||
|      void (*reset)(MachineState *state, ShutdownCause reason); | ||||
|      void (*wakeup)(MachineState *state); | ||||
| diff --git a/qapi/machine.json b/qapi/machine.json
 | ||||
| index 9156103c8f..f4fb1b2c9c 100644
 | ||||
| index c904280085..47f3facdb2 100644
 | ||||
| --- a/qapi/machine.json
 | ||||
| +++ b/qapi/machine.json
 | ||||
| @@ -157,6 +157,8 @@
 | ||||
| @@ -159,6 +159,8 @@
 | ||||
|  # | ||||
|  # @default-ram-id: the default ID of initial RAM memory backend (since 5.2) | ||||
|  # @acpi: machine type supports ACPI (since 8.0) | ||||
|  # | ||||
| +# @pve-version: custom PVE version suffix specified as 'machine+pveN'
 | ||||
| +#
 | ||||
|  # Since: 1.2 | ||||
|  ## | ||||
|  { 'struct': 'MachineInfo', | ||||
| @@ -164,7 +166,7 @@
 | ||||
| @@ -166,7 +168,7 @@
 | ||||
|              '*is-default': 'bool', '*is-current': 'bool', 'cpu-max': 'int', | ||||
|              'hotpluggable-cpus': 'bool',  'numa-mem-supported': 'bool', | ||||
|              'deprecated': 'bool', '*default-cpu-type': 'str', | ||||
| -            '*default-ram-id': 'str' } }
 | ||||
| +            '*default-ram-id': 'str', '*pve-version': 'str' } }
 | ||||
| -            '*default-ram-id': 'str', 'acpi': 'bool' } }
 | ||||
| +            '*default-ram-id': 'str', 'acpi': 'bool', '*pve-version': 'str' } }
 | ||||
|   | ||||
|  ## | ||||
|  # @query-machines: | ||||
| diff --git a/softmmu/vl.c b/softmmu/vl.c
 | ||||
| index 9d737e7914..a64eee2fad 100644
 | ||||
| index 323f6a23d4..25abdc9da7 100644
 | ||||
| --- a/softmmu/vl.c
 | ||||
| +++ b/softmmu/vl.c
 | ||||
| @@ -1578,6 +1578,7 @@ static const QEMUOption *lookup_opt(int argc, char **argv,
 | ||||
| @ -94,7 +95,7 @@ index 9d737e7914..a64eee2fad 100644 | ||||
|      g_slist_free(machines); | ||||
|      if (local_err) { | ||||
|          error_append_hint(&local_err, "Use -machine help to list supported machines\n"); | ||||
| @@ -3205,12 +3211,31 @@ void qemu_init(int argc, char **argv)
 | ||||
| @@ -3213,12 +3219,31 @@ void qemu_init(int argc, char **argv)
 | ||||
|              case QEMU_OPTION_machine: | ||||
|                  { | ||||
|                      bool help; | ||||
|  | ||||
| @ -25,7 +25,7 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 4 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/backup.c b/block/backup.c
 | ||||
| index 6a9ad97a53..9b0151c5be 100644
 | ||||
| index db3791f4d1..39410dcf8d 100644
 | ||||
| --- a/block/backup.c
 | ||||
| +++ b/block/backup.c
 | ||||
| @@ -237,8 +237,8 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job)
 | ||||
| @ -48,7 +48,7 @@ index 6a9ad97a53..9b0151c5be 100644 | ||||
|      if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { | ||||
|          int64_t offset = 0; | ||||
|          int64_t count; | ||||
| @@ -492,6 +490,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -495,6 +493,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | ||||
|      block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, | ||||
|                         &error_abort); | ||||
|   | ||||
|  | ||||
| @ -20,10 +20,10 @@ Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | ||||
|  create mode 100644 vma.h | ||||
| 
 | ||||
| diff --git a/block/meson.build b/block/meson.build
 | ||||
| index 020a89ae07..4feae20e37 100644
 | ||||
| index 253fe49fa2..744b698a82 100644
 | ||||
| --- a/block/meson.build
 | ||||
| +++ b/block/meson.build
 | ||||
| @@ -46,6 +46,8 @@ block_ss.add(files(
 | ||||
| @@ -47,6 +47,8 @@ block_ss.add(files(
 | ||||
|    'zeroinit.c', | ||||
|  ), zstd, zlib, gnutls) | ||||
|   | ||||
| @ -33,10 +33,10 @@ index 020a89ae07..4feae20e37 100644 | ||||
|  softmmu_ss.add(files('block-ram-registrar.c')) | ||||
|   | ||||
| diff --git a/meson.build b/meson.build
 | ||||
| index 5c6b5a1c75..e8cf7e3d78 100644
 | ||||
| index c44d05a13f..b9bc31b01c 100644
 | ||||
| --- a/meson.build
 | ||||
| +++ b/meson.build
 | ||||
| @@ -1525,6 +1525,8 @@ keyutils = dependency('libkeyutils', required: false,
 | ||||
| @@ -1527,6 +1527,8 @@ keyutils = dependency('libkeyutils', required: false,
 | ||||
|   | ||||
|  has_gettid = cc.has_function('gettid') | ||||
|   | ||||
| @ -45,7 +45,7 @@ index 5c6b5a1c75..e8cf7e3d78 100644 | ||||
|  # libselinux | ||||
|  selinux = dependency('libselinux', | ||||
|                       required: get_option('selinux'), | ||||
| @@ -3596,6 +3598,9 @@ if have_tools
 | ||||
| @@ -3645,6 +3647,9 @@ if have_tools
 | ||||
|                 dependencies: [blockdev, qemuutil, gnutls, selinux], | ||||
|                 install: true) | ||||
|   | ||||
|  | ||||
| @ -9,21 +9,23 @@ Subject: [PATCH] PVE-Backup: add backup-dump block driver | ||||
| - job.c: make job_should_pause non-static
 | ||||
| 
 | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to coroutine changes] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/backup-dump.c              | 167 +++++++++++++++++++++++++++++++ | ||||
|  block/backup-dump.c              | 168 +++++++++++++++++++++++++++++++ | ||||
|  block/backup.c                   |  30 ++---- | ||||
|  block/meson.build                |   1 + | ||||
|  include/block/block_int-common.h |  35 +++++++ | ||||
|  job.c                            |   3 +- | ||||
|  5 files changed, 213 insertions(+), 23 deletions(-) | ||||
|  5 files changed, 214 insertions(+), 23 deletions(-) | ||||
|  create mode 100644 block/backup-dump.c | ||||
| 
 | ||||
| diff --git a/block/backup-dump.c b/block/backup-dump.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..04718a94e2
 | ||||
| index 0000000000..232a094426
 | ||||
| --- /dev/null
 | ||||
| +++ b/block/backup-dump.c
 | ||||
| @@ -0,0 +1,167 @@
 | ||||
| @@ -0,0 +1,168 @@
 | ||||
| +/*
 | ||||
| + * BlockDriver to send backup data stream to a callback function
 | ||||
| + *
 | ||||
| @ -45,7 +47,8 @@ index 0000000000..04718a94e2 | ||||
| +    void           *dump_cb_data;
 | ||||
| +} BDRVBackupDumpState;
 | ||||
| +
 | ||||
| +static int qemu_backup_dump_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 | ||||
| +static coroutine_fn int qemu_backup_dump_co_get_info(BlockDriverState *bs,
 | ||||
| +                                                     BlockDriverInfo *bdi)
 | ||||
| +{
 | ||||
| +    BDRVBackupDumpState *s = bs->opaque;
 | ||||
| +
 | ||||
| @ -86,7 +89,7 @@ index 0000000000..04718a94e2 | ||||
| +    /* Nothing to do. */
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int64_t qemu_backup_dump_getlength(BlockDriverState *bs)
 | ||||
| +static coroutine_fn int64_t qemu_backup_dump_co_getlength(BlockDriverState *bs)
 | ||||
| +{
 | ||||
| +    BDRVBackupDumpState *s = bs->opaque;
 | ||||
| +
 | ||||
| @ -146,8 +149,8 @@ index 0000000000..04718a94e2 | ||||
| +
 | ||||
| +    .bdrv_close                   = qemu_backup_dump_close,
 | ||||
| +    .bdrv_has_zero_init           = bdrv_has_zero_init_1,
 | ||||
| +    .bdrv_getlength               = qemu_backup_dump_getlength,
 | ||||
| +    .bdrv_get_info                = qemu_backup_dump_get_info,
 | ||||
| +    .bdrv_co_getlength            = qemu_backup_dump_co_getlength,
 | ||||
| +    .bdrv_co_get_info             = qemu_backup_dump_co_get_info,
 | ||||
| +
 | ||||
| +    .bdrv_co_writev               = qemu_backup_dump_co_writev,
 | ||||
| +
 | ||||
| @ -192,7 +195,7 @@ index 0000000000..04718a94e2 | ||||
| +    return bs;
 | ||||
| +}
 | ||||
| diff --git a/block/backup.c b/block/backup.c
 | ||||
| index 9b0151c5be..6e8f6e67b3 100644
 | ||||
| index 39410dcf8d..af87fa6aa9 100644
 | ||||
| --- a/block/backup.c
 | ||||
| +++ b/block/backup.c
 | ||||
| @@ -29,28 +29,6 @@
 | ||||
| @ -224,7 +227,7 @@ index 9b0151c5be..6e8f6e67b3 100644 | ||||
|  static const BlockJobDriver backup_job_driver; | ||||
|   | ||||
|  static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) | ||||
| @@ -454,6 +432,14 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | ||||
| @@ -457,6 +435,14 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 | ||||
|      } | ||||
|   | ||||
|      cluster_size = block_copy_cluster_size(bcs); | ||||
| @ -240,7 +243,7 @@ index 9b0151c5be..6e8f6e67b3 100644 | ||||
|      if (perf->max_chunk && perf->max_chunk < cluster_size) { | ||||
|          error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup " | ||||
| diff --git a/block/meson.build b/block/meson.build
 | ||||
| index 4feae20e37..0d7023fc82 100644
 | ||||
| index 744b698a82..f580f95395 100644
 | ||||
| --- a/block/meson.build
 | ||||
| +++ b/block/meson.build
 | ||||
| @@ -4,6 +4,7 @@ block_ss.add(files(
 | ||||
| @ -252,18 +255,18 @@ index 4feae20e37..0d7023fc82 100644 | ||||
|    'blkdebug.c', | ||||
|    'blklogwrites.c', | ||||
| diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
 | ||||
| index 31ae91e56e..37b64bcd93 100644
 | ||||
| index f01bb8b617..d7ffd1826e 100644
 | ||||
| --- a/include/block/block_int-common.h
 | ||||
| +++ b/include/block/block_int-common.h
 | ||||
| @@ -26,6 +26,7 @@
 | ||||
|   | ||||
|  #include "block/accounting.h" | ||||
|  #include "block/block.h" | ||||
|  #include "block/aio.h" | ||||
|  #include "block/block-common.h" | ||||
| +#include "block/block-copy.h"
 | ||||
|  #include "block/aio-wait.h" | ||||
|  #include "qemu/queue.h" | ||||
|  #include "qemu/coroutine.h" | ||||
| @@ -64,6 +65,40 @@
 | ||||
|  #include "block/block-global-state.h" | ||||
|  #include "block/snapshot.h" | ||||
|  #include "qemu/iov.h" | ||||
| @@ -60,6 +61,40 @@
 | ||||
|   | ||||
|  #define BLOCK_PROBE_BUF_SIZE        512 | ||||
|   | ||||
|  | ||||
| @ -8,7 +8,8 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com> | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: add new force parameter to job_cancel_sync calls | ||||
|      adapt for new job lock mechanism replacing AioContext locks] | ||||
|      adapt for new job lock mechanism replacing AioContext locks | ||||
|      adapt to QAPI changes] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/meson.build              |   5 + | ||||
| @ -18,23 +19,23 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  hmp-commands.hx                |  29 + | ||||
|  include/monitor/hmp.h          |   3 + | ||||
|  meson.build                    |   1 + | ||||
|  monitor/hmp-cmds.c             |  44 ++ | ||||
|  proxmox-backup-client.c        | 176 ++++++ | ||||
|  proxmox-backup-client.h        |  59 ++ | ||||
|  pve-backup.c                   | 956 +++++++++++++++++++++++++++++++++ | ||||
|  monitor/hmp-cmds.c             |  45 ++ | ||||
|  proxmox-backup-client.c        | 176 +++++++ | ||||
|  proxmox-backup-client.h        |  59 +++ | ||||
|  pve-backup.c                   | 938 +++++++++++++++++++++++++++++++++ | ||||
|  qapi/block-core.json           | 109 ++++ | ||||
|  qapi/common.json               |  13 + | ||||
|  qapi/machine.json              |  15 +- | ||||
|  14 files changed, 1445 insertions(+), 13 deletions(-) | ||||
|  14 files changed, 1428 insertions(+), 13 deletions(-) | ||||
|  create mode 100644 proxmox-backup-client.c | ||||
|  create mode 100644 proxmox-backup-client.h | ||||
|  create mode 100644 pve-backup.c | ||||
| 
 | ||||
| diff --git a/block/meson.build b/block/meson.build
 | ||||
| index 0d7023fc82..e995ae72b9 100644
 | ||||
| index f580f95395..5bcebb934b 100644
 | ||||
| --- a/block/meson.build
 | ||||
| +++ b/block/meson.build
 | ||||
| @@ -48,6 +48,11 @@ block_ss.add(files(
 | ||||
| @@ -49,6 +49,11 @@ block_ss.add(files(
 | ||||
|  ), zstd, zlib, gnutls) | ||||
|   | ||||
|  block_ss.add(files('../vma-writer.c'), libuuid) | ||||
| @ -47,12 +48,12 @@ index 0d7023fc82..e995ae72b9 100644 | ||||
|  softmmu_ss.add(when: 'CONFIG_TCG', if_true: files('blkreplay.c')) | ||||
|  softmmu_ss.add(files('block-ram-registrar.c')) | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index b6135e9bfe..477044c54a 100644
 | ||||
| index 2846083546..947d4f3df0 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1015,3 +1015,36 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
 | ||||
|      g_free(sn_tab); | ||||
|      g_free(global_snapshots); | ||||
| @@ -1027,3 +1027,36 @@ void hmp_change_medium(Monitor *mon, const char *device, const char *target,
 | ||||
|      qmp_blockdev_change_medium(device, NULL, target, arg, true, force, | ||||
|                                 !!read_only, read_only_mode, errp); | ||||
|  } | ||||
| +
 | ||||
| +void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
 | ||||
| @ -75,32 +76,32 @@ index b6135e9bfe..477044c54a 100644 | ||||
| +
 | ||||
| +    qmp_backup(
 | ||||
| +        backup_file,
 | ||||
| +        false, NULL, // PBS password
 | ||||
| +        false, NULL, // PBS keyfile
 | ||||
| +        false, NULL, // PBS key_password
 | ||||
| +        false, NULL, // PBS fingerprint
 | ||||
| +        false, NULL, // PBS backup-id
 | ||||
| +        NULL, // PBS password
 | ||||
| +        NULL, // PBS keyfile
 | ||||
| +        NULL, // PBS key_password
 | ||||
| +        NULL, // PBS fingerprint
 | ||||
| +        NULL, // PBS backup-id
 | ||||
| +        false, 0, // PBS backup-time
 | ||||
| +        true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA,
 | ||||
| +        false, NULL, false, NULL, !!devlist,
 | ||||
| +        NULL, NULL,
 | ||||
| +        devlist, qdict_haskey(qdict, "speed"), speed, &error);
 | ||||
| +
 | ||||
| +    hmp_handle_error(mon, error);
 | ||||
| +}
 | ||||
| diff --git a/blockdev.c b/blockdev.c
 | ||||
| index 756e980889..bc8d67b290 100644
 | ||||
| index 47c70eeb91..3b95f54b64 100644
 | ||||
| --- a/blockdev.c
 | ||||
| +++ b/blockdev.c
 | ||||
| @@ -36,6 +36,7 @@
 | ||||
|  #include "hw/block/block.h" | ||||
| @@ -37,6 +37,7 @@
 | ||||
|  #include "block/blockjob.h" | ||||
|  #include "block/dirty-bitmap.h" | ||||
|  #include "block/qdict.h" | ||||
| +#include "block/blockjob_int.h"
 | ||||
|  #include "block/throttle-groups.h" | ||||
|  #include "monitor/monitor.h" | ||||
|  #include "qemu/error-report.h" | ||||
| diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
 | ||||
| index 489c524e9e..bc1d46d845 100644
 | ||||
| index a166bff3d5..4b75966c2e 100644
 | ||||
| --- a/hmp-commands-info.hx
 | ||||
| +++ b/hmp-commands-info.hx
 | ||||
| @@ -486,6 +486,20 @@ SRST
 | ||||
| @ -125,7 +126,7 @@ index 489c524e9e..bc1d46d845 100644 | ||||
|      { | ||||
|          .name       = "usernet", | ||||
| diff --git a/hmp-commands.hx b/hmp-commands.hx
 | ||||
| index 039be0033d..fcf9461295 100644
 | ||||
| index b66d7fc4ab..9b6b8e2e9c 100644
 | ||||
| --- a/hmp-commands.hx
 | ||||
| +++ b/hmp-commands.hx
 | ||||
| @@ -101,6 +101,35 @@ ERST
 | ||||
| @ -165,10 +166,10 @@ index 039be0033d..fcf9461295 100644 | ||||
|   | ||||
|      { | ||||
| diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
 | ||||
| index 440f86aba8..350527e599 100644
 | ||||
| index c012bad741..2e504db706 100644
 | ||||
| --- a/include/monitor/hmp.h
 | ||||
| +++ b/include/monitor/hmp.h
 | ||||
| @@ -31,6 +31,7 @@ void hmp_info_savevm(Monitor *mon, const QDict *qdict);
 | ||||
| @@ -32,6 +32,7 @@ void hmp_info_savevm(Monitor *mon, const QDict *qdict);
 | ||||
|  void hmp_info_migrate(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict); | ||||
| @ -176,20 +177,20 @@ index 440f86aba8..350527e599 100644 | ||||
|  void hmp_info_cpus(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_vnc(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_info_spice(Monitor *mon, const QDict *qdict); | ||||
| @@ -74,6 +75,8 @@ void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict);
 | ||||
|  void hmp_set_password(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_expire_password(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_change(Monitor *mon, const QDict *qdict); | ||||
| @@ -84,6 +85,8 @@ void hmp_change_vnc(Monitor *mon, const char *device, const char *target,
 | ||||
|  void hmp_change_medium(Monitor *mon, const char *device, const char *target, | ||||
|                         const char *arg, const char *read_only, bool force, | ||||
|                         Error **errp); | ||||
| +void hmp_backup(Monitor *mon, const QDict *qdict);
 | ||||
| +void hmp_backup_cancel(Monitor *mon, const QDict *qdict);
 | ||||
|  void hmp_migrate(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_device_add(Monitor *mon, const QDict *qdict); | ||||
|  void hmp_device_del(Monitor *mon, const QDict *qdict); | ||||
| diff --git a/meson.build b/meson.build
 | ||||
| index e8cf7e3d78..782756162c 100644
 | ||||
| index b9bc31b01c..b12ef9f8d4 100644
 | ||||
| --- a/meson.build
 | ||||
| +++ b/meson.build
 | ||||
| @@ -1526,6 +1526,7 @@ keyutils = dependency('libkeyutils', required: false,
 | ||||
| @@ -1528,6 +1528,7 @@ keyutils = dependency('libkeyutils', required: false,
 | ||||
|  has_gettid = cc.has_function('gettid') | ||||
|   | ||||
|  libuuid = cc.find_library('uuid', required: true) | ||||
| @ -198,11 +199,19 @@ index e8cf7e3d78..782756162c 100644 | ||||
|  # libselinux | ||||
|  selinux = dependency('libselinux', | ||||
| diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
 | ||||
| index cfebfd1db5..a40b25e906 100644
 | ||||
| index 435f9334f9..9e1bd57aeb 100644
 | ||||
| --- a/monitor/hmp-cmds.c
 | ||||
| +++ b/monitor/hmp-cmds.c
 | ||||
| @@ -199,6 +199,50 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
 | ||||
|      qapi_free_MouseInfoList(mice_list); | ||||
| @@ -21,6 +21,7 @@
 | ||||
|  #include "qemu/help_option.h" | ||||
|  #include "monitor/monitor-internal.h" | ||||
|  #include "qapi/error.h" | ||||
| +#include "qapi/qapi-commands-block-core.h"
 | ||||
|  #include "qapi/qapi-commands-control.h" | ||||
|  #include "qapi/qapi-commands-migration.h" | ||||
|  #include "qapi/qapi-commands-misc.h" | ||||
| @@ -144,6 +145,50 @@ void hmp_sync_profile(Monitor *mon, const QDict *qdict)
 | ||||
|      } | ||||
|  } | ||||
|   | ||||
| +void hmp_info_backup(Monitor *mon, const QDict *qdict)
 | ||||
| @ -216,8 +225,8 @@ index cfebfd1db5..a40b25e906 100644 | ||||
| +       return;
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    if (info->has_status) {
 | ||||
| +        if (info->has_errmsg) {
 | ||||
| +    if (info->status) {
 | ||||
| +        if (info->errmsg) {
 | ||||
| +            monitor_printf(mon, "Backup status: %s - %s\n",
 | ||||
| +                           info->status, info->errmsg);
 | ||||
| +        } else {
 | ||||
| @ -225,7 +234,7 @@ index cfebfd1db5..a40b25e906 100644 | ||||
| +        }
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    if (info->has_backup_file) {
 | ||||
| +    if (info->backup_file) {
 | ||||
| +        monitor_printf(mon, "Start time: %s", ctime(&info->start_time));
 | ||||
| +        if (info->end_time) {
 | ||||
| +            monitor_printf(mon, "End time: %s", ctime(&info->end_time));
 | ||||
| @ -249,9 +258,9 @@ index cfebfd1db5..a40b25e906 100644 | ||||
| +    qapi_free_BackupStatus(info);
 | ||||
| +}
 | ||||
| +
 | ||||
|  void hmp_info_migrate(Monitor *mon, const QDict *qdict) | ||||
|  void hmp_exit_preconfig(Monitor *mon, const QDict *qdict) | ||||
|  { | ||||
|      MigrationInfo *info; | ||||
|      Error *err = NULL; | ||||
| diff --git a/proxmox-backup-client.c b/proxmox-backup-client.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..a8f6653a81
 | ||||
| @ -501,10 +510,10 @@ index 0000000000..1dda8b7d8f | ||||
| +#endif /* PROXMOX_BACKUP_CLIENT_H */
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..6af212b9b4
 | ||||
| index 0000000000..bb51c030bd
 | ||||
| --- /dev/null
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -0,0 +1,956 @@
 | ||||
| @@ -0,0 +1,938 @@
 | ||||
| +#include "proxmox-backup-client.h"
 | ||||
| +#include "vma.h"
 | ||||
| +
 | ||||
| @ -512,6 +521,7 @@ index 0000000000..6af212b9b4 | ||||
| +#include "qemu/module.h"
 | ||||
| +#include "sysemu/block-backend.h"
 | ||||
| +#include "sysemu/blockdev.h"
 | ||||
| +#include "block/block_int-global-state.h"
 | ||||
| +#include "block/blockjob.h"
 | ||||
| +#include "qapi/qapi-commands-block.h"
 | ||||
| +#include "qapi/qmp/qerror.h"
 | ||||
| @ -1020,25 +1030,17 @@ index 0000000000..6af212b9b4 | ||||
| +
 | ||||
| +typedef struct QmpBackupTask {
 | ||||
| +    const char *backup_file;
 | ||||
| +    bool has_password;
 | ||||
| +    const char *password;
 | ||||
| +    bool has_keyfile;
 | ||||
| +    const char *keyfile;
 | ||||
| +    bool has_key_password;
 | ||||
| +    const char *key_password;
 | ||||
| +    bool has_backup_id;
 | ||||
| +    const char *backup_id;
 | ||||
| +    bool has_backup_time;
 | ||||
| +    const char *fingerprint;
 | ||||
| +    bool has_fingerprint;
 | ||||
| +    int64_t backup_time;
 | ||||
| +    bool has_format;
 | ||||
| +    BackupFormat format;
 | ||||
| +    bool has_config_file;
 | ||||
| +    const char *config_file;
 | ||||
| +    bool has_firewall_file;
 | ||||
| +    const char *firewall_file;
 | ||||
| +    bool has_devlist;
 | ||||
| +    const char *devlist;
 | ||||
| +    bool has_speed;
 | ||||
| +    int64_t speed;
 | ||||
| @ -1079,7 +1081,7 @@ index 0000000000..6af212b9b4 | ||||
| +    /* Todo: try to auto-detect format based on file name */
 | ||||
| +    BackupFormat format = task->has_format ? task->format : BACKUP_FORMAT_VMA;
 | ||||
| +
 | ||||
| +    if (task->has_devlist) {
 | ||||
| +    if (task->devlist) {
 | ||||
| +        devs = g_strsplit_set(task->devlist, ",;:", -1);
 | ||||
| +
 | ||||
| +        gchar **d = devs;
 | ||||
| @ -1144,11 +1146,11 @@ index 0000000000..6af212b9b4 | ||||
| +    uuid_generate(uuid);
 | ||||
| +
 | ||||
| +    if (format == BACKUP_FORMAT_PBS) {
 | ||||
| +        if (!task->has_password) {
 | ||||
| +        if (!task->password) {
 | ||||
| +            error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'password'");
 | ||||
| +            goto err;
 | ||||
| +        }
 | ||||
| +        if (!task->has_backup_id) {
 | ||||
| +        if (!task->backup_id) {
 | ||||
| +            error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-id'");
 | ||||
| +            goto err;
 | ||||
| +        }
 | ||||
| @ -1166,10 +1168,10 @@ index 0000000000..6af212b9b4 | ||||
| +            task->backup_id,
 | ||||
| +            task->backup_time,
 | ||||
| +            dump_cb_block_size,
 | ||||
| +            task->has_password ? task->password : NULL,
 | ||||
| +            task->has_keyfile ? task->keyfile : NULL,
 | ||||
| +            task->has_key_password ? task->key_password : NULL,
 | ||||
| +            task->has_fingerprint ? task->fingerprint : NULL,
 | ||||
| +            task->password,
 | ||||
| +            task->keyfile,
 | ||||
| +            task->key_password,
 | ||||
| +            task->fingerprint,
 | ||||
| +            &pbs_err);
 | ||||
| +
 | ||||
| +        if (!pbs) {
 | ||||
| @ -1264,7 +1266,7 @@ index 0000000000..6af212b9b4 | ||||
| +
 | ||||
| +
 | ||||
| +    /* add configuration file to archive */
 | ||||
| +    if (task->has_config_file) {
 | ||||
| +    if (task->config_file) {
 | ||||
| +        if (pvebackup_co_add_config(task->config_file, config_name, format, backup_dir,
 | ||||
| +                                    vmaw, pbs, task->errp) != 0) {
 | ||||
| +            goto err;
 | ||||
| @ -1272,7 +1274,7 @@ index 0000000000..6af212b9b4 | ||||
| +    }
 | ||||
| +
 | ||||
| +    /* add firewall file to archive */
 | ||||
| +    if (task->has_firewall_file) {
 | ||||
| +    if (task->firewall_file) {
 | ||||
| +        if (pvebackup_co_add_config(task->firewall_file, firewall_name, format, backup_dir,
 | ||||
| +                                    vmaw, pbs, task->errp) != 0) {
 | ||||
| +            goto err;
 | ||||
| @ -1360,37 +1362,30 @@ index 0000000000..6af212b9b4 | ||||
| +
 | ||||
| +UuidInfo *qmp_backup(
 | ||||
| +    const char *backup_file,
 | ||||
| +    bool has_password, const char *password,
 | ||||
| +    bool has_keyfile, const char *keyfile,
 | ||||
| +    bool has_key_password, const char *key_password,
 | ||||
| +    bool has_fingerprint, const char *fingerprint,
 | ||||
| +    bool has_backup_id, const char *backup_id,
 | ||||
| +    const char *password,
 | ||||
| +    const char *keyfile,
 | ||||
| +    const char *key_password,
 | ||||
| +    const char *fingerprint,
 | ||||
| +    const char *backup_id,
 | ||||
| +    bool has_backup_time, int64_t backup_time,
 | ||||
| +    bool has_format, BackupFormat format,
 | ||||
| +    bool has_config_file, const char *config_file,
 | ||||
| +    bool has_firewall_file, const char *firewall_file,
 | ||||
| +    bool has_devlist, const char *devlist,
 | ||||
| +    const char *config_file,
 | ||||
| +    const char *firewall_file,
 | ||||
| +    const char *devlist,
 | ||||
| +    bool has_speed, int64_t speed, Error **errp)
 | ||||
| +{
 | ||||
| +    QmpBackupTask task = {
 | ||||
| +        .backup_file = backup_file,
 | ||||
| +        .has_password = has_password,
 | ||||
| +        .password = password,
 | ||||
| +        .has_key_password = has_key_password,
 | ||||
| +        .key_password = key_password,
 | ||||
| +        .has_fingerprint = has_fingerprint,
 | ||||
| +        .fingerprint = fingerprint,
 | ||||
| +        .has_backup_id = has_backup_id,
 | ||||
| +        .backup_id = backup_id,
 | ||||
| +        .has_backup_time = has_backup_time,
 | ||||
| +        .backup_time = backup_time,
 | ||||
| +        .has_format = has_format,
 | ||||
| +        .format = format,
 | ||||
| +        .has_config_file = has_config_file,
 | ||||
| +        .config_file = config_file,
 | ||||
| +        .has_firewall_file = has_firewall_file,
 | ||||
| +        .firewall_file = firewall_file,
 | ||||
| +        .has_devlist = has_devlist,
 | ||||
| +        .devlist = devlist,
 | ||||
| +        .has_speed = has_speed,
 | ||||
| +        .speed = speed,
 | ||||
| @ -1424,22 +1419,18 @@ index 0000000000..6af212b9b4 | ||||
| +        return info;
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    info->has_status = true;
 | ||||
| +    info->has_start_time = true;
 | ||||
| +    info->start_time = backup_state.stat.start_time;
 | ||||
| +
 | ||||
| +    if (backup_state.stat.backup_file) {
 | ||||
| +        info->has_backup_file = true;
 | ||||
| +        info->backup_file = g_strdup(backup_state.stat.backup_file);
 | ||||
| +    }
 | ||||
| +
 | ||||
| +    info->has_uuid = true;
 | ||||
| +    info->uuid = g_strdup(backup_state.stat.uuid_str);
 | ||||
| +
 | ||||
| +    if (backup_state.stat.end_time) {
 | ||||
| +        if (backup_state.stat.error) {
 | ||||
| +            info->status = g_strdup("error");
 | ||||
| +            info->has_errmsg = true;
 | ||||
| +            info->errmsg = g_strdup(error_get_pretty(backup_state.stat.error));
 | ||||
| +        } else {
 | ||||
| +            info->status = g_strdup("done");
 | ||||
| @ -1462,10 +1453,10 @@ index 0000000000..6af212b9b4 | ||||
| +    return info;
 | ||||
| +}
 | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 9e902b96bb..c3b6b93472 100644
 | ||||
| index 542add004b..16fb4c5ea0 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -740,6 +740,115 @@
 | ||||
| @@ -835,6 +835,115 @@
 | ||||
|  { 'command': 'query-block', 'returns': ['BlockInfo'], | ||||
|    'allow-preconfig': true } | ||||
|   | ||||
| @ -1603,7 +1594,7 @@ index 356db3f670..aae8a3b682 100644 | ||||
| +##
 | ||||
| +{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} }
 | ||||
| diff --git a/qapi/machine.json b/qapi/machine.json
 | ||||
| index f4fb1b2c9c..0d6ee836ed 100644
 | ||||
| index 47f3facdb2..46760978ae 100644
 | ||||
| --- a/qapi/machine.json
 | ||||
| +++ b/qapi/machine.json
 | ||||
| @@ -4,6 +4,8 @@
 | ||||
| @ -1615,7 +1606,7 @@ index f4fb1b2c9c..0d6ee836ed 100644 | ||||
|  ## | ||||
|  # = Machines | ||||
|  ## | ||||
| @@ -226,19 +228,6 @@
 | ||||
| @@ -228,19 +230,6 @@
 | ||||
|  ## | ||||
|  { 'command': 'query-target', 'returns': 'TargetInfo' } | ||||
|   | ||||
|  | ||||
| @ -12,10 +12,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  create mode 100644 pbs-restore.c | ||||
| 
 | ||||
| diff --git a/meson.build b/meson.build
 | ||||
| index 782756162c..63ea813a9a 100644
 | ||||
| index b12ef9f8d4..8ec21bba90 100644
 | ||||
| --- a/meson.build
 | ||||
| +++ b/meson.build
 | ||||
| @@ -3602,6 +3602,10 @@ if have_tools
 | ||||
| @@ -3651,6 +3651,10 @@ if have_tools
 | ||||
|    vma = executable('vma', files('vma.c', 'vma-reader.c') + genh, | ||||
|                     dependencies: [authz, block, crypto, io, qom], install: true) | ||||
|   | ||||
|  | ||||
| @ -24,27 +24,27 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  monitor/hmp-cmds.c             |  45 ++++++++++---- | ||||
|  proxmox-backup-client.c        |   3 +- | ||||
|  proxmox-backup-client.h        |   1 + | ||||
|  pve-backup.c                   | 103 ++++++++++++++++++++++++++++++--- | ||||
|  pve-backup.c                   | 104 ++++++++++++++++++++++++++++++--- | ||||
|  qapi/block-core.json           |  12 +++- | ||||
|  6 files changed, 142 insertions(+), 23 deletions(-) | ||||
|  6 files changed, 143 insertions(+), 23 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index 477044c54a..556af25861 100644
 | ||||
| index 947d4f3df0..bcba630f12 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1042,6 +1042,7 @@ void hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          false, NULL, // PBS fingerprint | ||||
|          false, NULL, // PBS backup-id | ||||
| @@ -1054,6 +1054,7 @@ void hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          NULL, // PBS fingerprint | ||||
|          NULL, // PBS backup-id | ||||
|          false, 0, // PBS backup-time | ||||
| +        false, false, // PBS incremental
 | ||||
|          true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, | ||||
|          false, NULL, false, NULL, !!devlist, | ||||
|          NULL, NULL, | ||||
|          devlist, qdict_haskey(qdict, "speed"), speed, &error); | ||||
| diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
 | ||||
| index a40b25e906..670f783515 100644
 | ||||
| index 9e1bd57aeb..087161a967 100644
 | ||||
| --- a/monitor/hmp-cmds.c
 | ||||
| +++ b/monitor/hmp-cmds.c
 | ||||
| @@ -225,19 +225,42 @@ void hmp_info_backup(Monitor *mon, const QDict *qdict)
 | ||||
| @@ -171,19 +171,42 @@ void hmp_info_backup(Monitor *mon, const QDict *qdict)
 | ||||
|              monitor_printf(mon, "End time: %s", ctime(&info->end_time)); | ||||
|          } | ||||
|   | ||||
| @ -132,10 +132,18 @@ index 1dda8b7d8f..8cbf645b2c 100644 | ||||
|   | ||||
|   | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 3d28975eaa..abd7062afe 100644
 | ||||
| index bb51c030bd..cfdeb50f23 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -28,6 +28,8 @@
 | ||||
| @@ -7,6 +7,7 @@
 | ||||
|  #include "sysemu/blockdev.h" | ||||
|  #include "block/block_int-global-state.h" | ||||
|  #include "block/blockjob.h" | ||||
| +#include "block/dirty-bitmap.h"
 | ||||
|  #include "qapi/qapi-commands-block.h" | ||||
|  #include "qapi/qmp/qerror.h" | ||||
|   | ||||
| @@ -29,6 +30,8 @@
 | ||||
|   * | ||||
|   */ | ||||
|   | ||||
| @ -144,7 +152,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|  static struct PVEBackupState { | ||||
|      struct { | ||||
|          // Everithing accessed from qmp_backup_query command is protected using lock | ||||
| @@ -39,7 +41,9 @@ static struct PVEBackupState {
 | ||||
| @@ -40,7 +43,9 @@ static struct PVEBackupState {
 | ||||
|          uuid_t uuid; | ||||
|          char uuid_str[37]; | ||||
|          size_t total; | ||||
| @ -154,7 +162,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|          size_t zero_bytes; | ||||
|      } stat; | ||||
|      int64_t speed; | ||||
| @@ -66,6 +70,7 @@ typedef struct PVEBackupDevInfo {
 | ||||
| @@ -67,6 +72,7 @@ typedef struct PVEBackupDevInfo {
 | ||||
|      uint8_t dev_id; | ||||
|      bool completed; | ||||
|      char targetfile[PATH_MAX]; | ||||
| @ -162,7 +170,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|      BlockDriverState *target; | ||||
|  } PVEBackupDevInfo; | ||||
|   | ||||
| @@ -107,11 +112,12 @@ static bool pvebackup_error_or_canceled(void)
 | ||||
| @@ -108,11 +114,12 @@ static bool pvebackup_error_or_canceled(void)
 | ||||
|      return error_or_canceled; | ||||
|  } | ||||
|   | ||||
| @ -176,7 +184,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|  } | ||||
|   | ||||
| @@ -150,7 +156,8 @@ pvebackup_co_dump_pbs_cb(
 | ||||
| @@ -151,7 +158,8 @@ pvebackup_co_dump_pbs_cb(
 | ||||
|          pvebackup_propagate_error(local_err); | ||||
|          return pbs_res; | ||||
|      } else { | ||||
| @ -186,7 +194,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|      } | ||||
|   | ||||
|      return size; | ||||
| @@ -210,11 +217,11 @@ pvebackup_co_dump_vma_cb(
 | ||||
| @@ -211,11 +219,11 @@ pvebackup_co_dump_vma_cb(
 | ||||
|          } else { | ||||
|              if (remaining >= VMA_CLUSTER_SIZE) { | ||||
|                  assert(ret == VMA_CLUSTER_SIZE); | ||||
| @ -200,7 +208,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|                  remaining = 0; | ||||
|              } | ||||
|          } | ||||
| @@ -250,6 +257,18 @@ static void coroutine_fn pvebackup_co_cleanup(void *unused)
 | ||||
| @@ -251,6 +259,18 @@ static void coroutine_fn pvebackup_co_cleanup(void *unused)
 | ||||
|              if (local_err != NULL) { | ||||
|                  pvebackup_propagate_error(local_err); | ||||
|              } | ||||
| @ -219,7 +227,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|          } | ||||
|   | ||||
|          proxmox_backup_disconnect(backup_state.pbs); | ||||
| @@ -305,6 +324,12 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
| @@ -306,6 +326,12 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
|      // remove self from job queue | ||||
|      backup_state.di_list = g_list_remove(backup_state.di_list, di); | ||||
|   | ||||
| @ -232,7 +240,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|      g_free(di); | ||||
|   | ||||
|      qemu_mutex_unlock(&backup_state.backup_mutex); | ||||
| @@ -469,12 +494,18 @@ static bool create_backup_jobs(void) {
 | ||||
| @@ -470,12 +496,18 @@ static bool create_backup_jobs(void) {
 | ||||
|   | ||||
|          assert(di->target != NULL); | ||||
|   | ||||
| @ -253,16 +261,16 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|              JOB_DEFAULT, pvebackup_complete_cb, di, NULL, &local_err); | ||||
|   | ||||
|          aio_context_release(aio_context); | ||||
| @@ -525,6 +556,8 @@ typedef struct QmpBackupTask {
 | ||||
| @@ -521,6 +553,8 @@ typedef struct QmpBackupTask {
 | ||||
|      bool has_backup_time; | ||||
|      const char *fingerprint; | ||||
|      bool has_fingerprint; | ||||
|      int64_t backup_time; | ||||
| +    bool has_use_dirty_bitmap;
 | ||||
| +    bool use_dirty_bitmap;
 | ||||
|      bool has_format; | ||||
|      BackupFormat format; | ||||
|      bool has_config_file; | ||||
| @@ -616,6 +649,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      const char *config_file; | ||||
| @@ -609,6 +643,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      } | ||||
|   | ||||
|      size_t total = 0; | ||||
| @ -270,7 +278,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|   | ||||
|      l = di_list; | ||||
|      while (l) { | ||||
| @@ -653,6 +687,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -646,6 +681,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|          int dump_cb_block_size = PROXMOX_BACKUP_DEFAULT_CHUNK_SIZE; // Hardcoded (4M) | ||||
|          firewall_name = "fw.conf"; | ||||
|   | ||||
| @ -279,7 +287,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|          char *pbs_err = NULL; | ||||
|          pbs = proxmox_backup_new( | ||||
|              task->backup_file, | ||||
| @@ -672,7 +708,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -665,7 +702,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              goto err; | ||||
|          } | ||||
|   | ||||
| @ -289,7 +297,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|              goto err; | ||||
|   | ||||
|          /* register all devices */ | ||||
| @@ -683,9 +720,40 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -676,9 +714,40 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|   | ||||
|              const char *devname = bdrv_get_device_name(di->bs); | ||||
|   | ||||
| @ -332,7 +340,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|   | ||||
|              if (!(di->target = bdrv_backup_dump_create(dump_cb_block_size, di->size, pvebackup_co_dump_pbs_cb, di, task->errp))) { | ||||
|                  goto err; | ||||
| @@ -694,6 +762,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -687,6 +756,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              di->dev_id = dev_id; | ||||
|          } | ||||
|      } else if (format == BACKUP_FORMAT_VMA) { | ||||
| @ -341,7 +349,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|          vmaw = vma_writer_create(task->backup_file, uuid, &local_err); | ||||
|          if (!vmaw) { | ||||
|              if (local_err) { | ||||
| @@ -721,6 +791,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -714,6 +785,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              } | ||||
|          } | ||||
|      } else if (format == BACKUP_FORMAT_DIR) { | ||||
| @ -350,7 +358,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|          if (mkdir(task->backup_file, 0640) != 0) { | ||||
|              error_setg_errno(task->errp, errno, "can't create directory '%s'\n", | ||||
|                               task->backup_file); | ||||
| @@ -793,8 +865,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -786,8 +859,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      char *uuid_str = g_strdup(backup_state.stat.uuid_str); | ||||
|   | ||||
|      backup_state.stat.total = total; | ||||
| @ -361,7 +369,7 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|   | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
| @@ -818,6 +892,10 @@ err:
 | ||||
| @@ -811,6 +886,10 @@ err:
 | ||||
|          PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
|          l = g_list_next(l); | ||||
|   | ||||
| @ -372,15 +380,15 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|          if (di->target) { | ||||
|              bdrv_unref(di->target); | ||||
|          } | ||||
| @@ -859,6 +937,7 @@ UuidInfo *qmp_backup(
 | ||||
|      bool has_fingerprint, const char *fingerprint, | ||||
|      bool has_backup_id, const char *backup_id, | ||||
| @@ -852,6 +931,7 @@ UuidInfo *qmp_backup(
 | ||||
|      const char *fingerprint, | ||||
|      const char *backup_id, | ||||
|      bool has_backup_time, int64_t backup_time, | ||||
| +    bool has_use_dirty_bitmap, bool use_dirty_bitmap,
 | ||||
|      bool has_format, BackupFormat format, | ||||
|      bool has_config_file, const char *config_file, | ||||
|      bool has_firewall_file, const char *firewall_file, | ||||
| @@ -877,6 +956,8 @@ UuidInfo *qmp_backup(
 | ||||
|      const char *config_file, | ||||
|      const char *firewall_file, | ||||
| @@ -866,6 +946,8 @@ UuidInfo *qmp_backup(
 | ||||
|          .backup_id = backup_id, | ||||
|          .has_backup_time = has_backup_time, | ||||
|          .backup_time = backup_time, | ||||
| @ -388,8 +396,8 @@ index 3d28975eaa..abd7062afe 100644 | ||||
| +        .use_dirty_bitmap = use_dirty_bitmap,
 | ||||
|          .has_format = has_format, | ||||
|          .format = format, | ||||
|          .has_config_file = has_config_file, | ||||
| @@ -945,10 +1026,14 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
|          .config_file = config_file, | ||||
| @@ -927,10 +1009,14 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
|   | ||||
|      info->has_total = true; | ||||
|      info->total = backup_state.stat.total; | ||||
| @ -405,10 +413,10 @@ index 3d28975eaa..abd7062afe 100644 | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index c3b6b93472..992e6c1e3f 100644
 | ||||
| index 16fb4c5ea0..92f90a898a 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -753,8 +753,13 @@
 | ||||
| @@ -848,8 +848,13 @@
 | ||||
|  # | ||||
|  # @total: total amount of bytes involved in the backup process | ||||
|  # | ||||
| @ -422,7 +430,7 @@ index c3b6b93472..992e6c1e3f 100644 | ||||
|  # @zero-bytes: amount of 'zero' bytes detected. | ||||
|  # | ||||
|  # @start-time: time (epoch) when backup job started. | ||||
| @@ -767,8 +772,8 @@
 | ||||
| @@ -862,8 +867,8 @@
 | ||||
|  # | ||||
|  ## | ||||
|  { 'struct': 'BackupStatus', | ||||
| @ -433,7 +441,7 @@ index c3b6b93472..992e6c1e3f 100644 | ||||
|             '*start-time': 'int', '*end-time': 'int', | ||||
|             '*backup-file': 'str', '*uuid': 'str' } } | ||||
|   | ||||
| @@ -811,6 +816,8 @@
 | ||||
| @@ -906,6 +911,8 @@
 | ||||
|  # | ||||
|  # @backup-time: backup timestamp (Unix epoch, required for format 'pbs') | ||||
|  # | ||||
| @ -442,7 +450,7 @@ index c3b6b93472..992e6c1e3f 100644 | ||||
|  # Returns: the uuid of the backup job | ||||
|  # | ||||
|  ## | ||||
| @@ -821,6 +828,7 @@
 | ||||
| @@ -916,6 +923,7 @@
 | ||||
|                                      '*fingerprint': 'str', | ||||
|                                      '*backup-id': 'str', | ||||
|                                      '*backup-time': 'int', | ||||
|  | ||||
| @ -12,40 +12,42 @@ Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| PVE: add zero block handling to PBS dump callback | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to QAPI change dropping redundant has_*] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/monitor/block-hmp-cmds.c |  4 ++- | ||||
|  pve-backup.c                   | 57 +++++++++++++++++++++++++++------- | ||||
|  pve-backup.c                   | 54 +++++++++++++++++++++++++++------- | ||||
|  qapi/block-core.json           |  6 ++++ | ||||
|  3 files changed, 54 insertions(+), 13 deletions(-) | ||||
|  3 files changed, 52 insertions(+), 12 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index 556af25861..a09f722fea 100644
 | ||||
| index bcba630f12..6a6ed6d0e7 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1042,7 +1042,9 @@ void hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          false, NULL, // PBS fingerprint | ||||
|          false, NULL, // PBS backup-id | ||||
| @@ -1054,7 +1054,9 @@ void hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          NULL, // PBS fingerprint | ||||
|          NULL, // PBS backup-id | ||||
|          false, 0, // PBS backup-time | ||||
| -        false, false, // PBS incremental
 | ||||
| +        false, false, // PBS use-dirty-bitmap
 | ||||
| +        false, false, // PBS compress
 | ||||
| +        false, false, // PBS encrypt
 | ||||
|          true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, | ||||
|          false, NULL, false, NULL, !!devlist, | ||||
|          NULL, NULL, | ||||
|          devlist, qdict_haskey(qdict, "speed"), speed, &error); | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index abd7062afe..e113ab61b9 100644
 | ||||
| index cfdeb50f23..f1eacbcaf6 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -8,6 +8,7 @@
 | ||||
|  #include "block/blockjob.h" | ||||
| @@ -10,6 +10,7 @@
 | ||||
|  #include "block/dirty-bitmap.h" | ||||
|  #include "qapi/qapi-commands-block.h" | ||||
|  #include "qapi/qmp/qerror.h" | ||||
| +#include "qemu/cutils.h"
 | ||||
|   | ||||
|  /* PVE backup state and related function */ | ||||
|   | ||||
| @@ -67,6 +68,7 @@ opts_init(pvebackup_init);
 | ||||
| @@ -69,6 +70,7 @@ opts_init(pvebackup_init);
 | ||||
|  typedef struct PVEBackupDevInfo { | ||||
|      BlockDriverState *bs; | ||||
|      size_t size; | ||||
| @ -53,7 +55,7 @@ index abd7062afe..e113ab61b9 100644 | ||||
|      uint8_t dev_id; | ||||
|      bool completed; | ||||
|      char targetfile[PATH_MAX]; | ||||
| @@ -137,10 +139,13 @@ pvebackup_co_dump_pbs_cb(
 | ||||
| @@ -139,10 +141,13 @@ pvebackup_co_dump_pbs_cb(
 | ||||
|      PVEBackupDevInfo *di = opaque; | ||||
|   | ||||
|      assert(backup_state.pbs); | ||||
| @ -67,7 +69,7 @@ index abd7062afe..e113ab61b9 100644 | ||||
|      qemu_co_mutex_lock(&backup_state.dump_callback_mutex); | ||||
|   | ||||
|      // avoid deadlock if job is cancelled | ||||
| @@ -149,17 +154,29 @@ pvebackup_co_dump_pbs_cb(
 | ||||
| @@ -151,17 +156,29 @@ pvebackup_co_dump_pbs_cb(
 | ||||
|          return -1; | ||||
|      } | ||||
|   | ||||
| @ -105,7 +107,7 @@ index abd7062afe..e113ab61b9 100644 | ||||
|      return size; | ||||
|  } | ||||
|   | ||||
| @@ -180,6 +197,7 @@ pvebackup_co_dump_vma_cb(
 | ||||
| @@ -182,6 +199,7 @@ pvebackup_co_dump_vma_cb(
 | ||||
|      int ret = -1; | ||||
|   | ||||
|      assert(backup_state.vmaw); | ||||
| @ -113,7 +115,7 @@ index abd7062afe..e113ab61b9 100644 | ||||
|   | ||||
|      uint64_t remaining = size; | ||||
|   | ||||
| @@ -206,9 +224,7 @@ pvebackup_co_dump_vma_cb(
 | ||||
| @@ -208,9 +226,7 @@ pvebackup_co_dump_vma_cb(
 | ||||
|          qemu_co_mutex_unlock(&backup_state.dump_callback_mutex); | ||||
|   | ||||
|          ++cluster_num; | ||||
| @ -124,9 +126,9 @@ index abd7062afe..e113ab61b9 100644 | ||||
|          if (ret < 0) { | ||||
|              Error *local_err = NULL; | ||||
|              vma_writer_error_propagate(backup_state.vmaw, &local_err); | ||||
| @@ -566,6 +582,10 @@ typedef struct QmpBackupTask {
 | ||||
| @@ -560,6 +576,10 @@ typedef struct QmpBackupTask {
 | ||||
|      const char *config_file; | ||||
|      const char *firewall_file; | ||||
|      bool has_devlist; | ||||
|      const char *devlist; | ||||
| +    bool has_compress;
 | ||||
| +    bool compress;
 | ||||
| @ -135,7 +137,7 @@ index abd7062afe..e113ab61b9 100644 | ||||
|      bool has_speed; | ||||
|      int64_t speed; | ||||
|      Error **errp; | ||||
| @@ -689,6 +709,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -683,6 +703,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|   | ||||
|          bool use_dirty_bitmap = task->has_use_dirty_bitmap && task->use_dirty_bitmap; | ||||
|   | ||||
| @ -143,19 +145,16 @@ index abd7062afe..e113ab61b9 100644 | ||||
|          char *pbs_err = NULL; | ||||
|          pbs = proxmox_backup_new( | ||||
|              task->backup_file, | ||||
| @@ -698,8 +719,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              task->has_password ? task->password : NULL, | ||||
|              task->has_keyfile ? task->keyfile : NULL, | ||||
|              task->has_key_password ? task->key_password : NULL, | ||||
| @@ -692,6 +713,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              task->password, | ||||
|              task->keyfile, | ||||
|              task->key_password, | ||||
| +            task->has_compress ? task->compress : true,
 | ||||
| +            task->has_encrypt ? task->encrypt : task->has_keyfile,
 | ||||
|              task->has_fingerprint ? task->fingerprint : NULL, | ||||
| -            &pbs_err);
 | ||||
| +             &pbs_err);
 | ||||
| +            task->has_encrypt ? task->encrypt : !!task->keyfile,
 | ||||
|              task->fingerprint, | ||||
|              &pbs_err); | ||||
|   | ||||
|          if (!pbs) { | ||||
|              error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, | ||||
| @@ -718,6 +741,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -712,6 +735,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
|              l = g_list_next(l); | ||||
|   | ||||
| @ -164,25 +163,24 @@ index abd7062afe..e113ab61b9 100644 | ||||
|              const char *devname = bdrv_get_device_name(di->bs); | ||||
|   | ||||
|              BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(di->bs, PBS_BITMAP_NAME); | ||||
| @@ -938,6 +963,8 @@ UuidInfo *qmp_backup(
 | ||||
|      bool has_backup_id, const char *backup_id, | ||||
| @@ -932,6 +957,8 @@ UuidInfo *qmp_backup(
 | ||||
|      const char *backup_id, | ||||
|      bool has_backup_time, int64_t backup_time, | ||||
|      bool has_use_dirty_bitmap, bool use_dirty_bitmap, | ||||
| +    bool has_compress, bool compress,
 | ||||
| +    bool has_encrypt, bool encrypt,
 | ||||
|      bool has_format, BackupFormat format, | ||||
|      bool has_config_file, const char *config_file, | ||||
|      bool has_firewall_file, const char *firewall_file, | ||||
| @@ -948,6 +975,8 @@ UuidInfo *qmp_backup(
 | ||||
|      const char *config_file, | ||||
|      const char *firewall_file, | ||||
| @@ -941,6 +968,7 @@ UuidInfo *qmp_backup(
 | ||||
|      QmpBackupTask task = { | ||||
|          .backup_file = backup_file, | ||||
|          .has_password = has_password, | ||||
|          .password = password, | ||||
| +        .has_keyfile = has_keyfile,
 | ||||
| +        .keyfile = keyfile,
 | ||||
|          .has_key_password = has_key_password, | ||||
|          .key_password = key_password, | ||||
|          .has_fingerprint = has_fingerprint, | ||||
| @@ -958,6 +987,10 @@ UuidInfo *qmp_backup(
 | ||||
|          .fingerprint = fingerprint, | ||||
|          .backup_id = backup_id, | ||||
| @@ -948,6 +976,10 @@ UuidInfo *qmp_backup(
 | ||||
|          .backup_time = backup_time, | ||||
|          .has_use_dirty_bitmap = has_use_dirty_bitmap, | ||||
|          .use_dirty_bitmap = use_dirty_bitmap, | ||||
| @ -192,12 +190,12 @@ index abd7062afe..e113ab61b9 100644 | ||||
| +        .encrypt = encrypt,
 | ||||
|          .has_format = has_format, | ||||
|          .format = format, | ||||
|          .has_config_file = has_config_file, | ||||
|          .config_file = config_file, | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 992e6c1e3f..5ac6276dc1 100644
 | ||||
| index 92f90a898a..864b8ce97c 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -818,6 +818,10 @@
 | ||||
| @@ -913,6 +913,10 @@
 | ||||
|  # | ||||
|  # @use-dirty-bitmap: use dirty bitmap to detect incremental changes since last job (optional for format 'pbs') | ||||
|  # | ||||
| @ -208,7 +206,7 @@ index 992e6c1e3f..5ac6276dc1 100644 | ||||
|  # Returns: the uuid of the backup job | ||||
|  # | ||||
|  ## | ||||
| @@ -829,6 +833,8 @@
 | ||||
| @@ -924,6 +928,8 @@
 | ||||
|                                      '*backup-id': 'str', | ||||
|                                      '*backup-time': 'int', | ||||
|                                      '*use-dirty-bitmap': 'bool', | ||||
|  | ||||
| @ -8,23 +8,24 @@ Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Dietmar Maurer <dietmar@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to changed function signatures | ||||
|      make pbs_co_preadv return values consistent with QEMU] | ||||
|      make pbs_co_preadv return values consistent with QEMU | ||||
|      getlength is now a coroutine function] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/meson.build    |   3 + | ||||
|  block/pbs.c          | 276 +++++++++++++++++++++++++++++++++++++++++++ | ||||
|  block/pbs.c          | 277 +++++++++++++++++++++++++++++++++++++++++++ | ||||
|  configure            |   9 ++ | ||||
|  meson.build          |   2 +- | ||||
|  qapi/block-core.json |  13 ++ | ||||
|  qapi/pragma.json     |   1 + | ||||
|  6 files changed, 303 insertions(+), 1 deletion(-) | ||||
|  6 files changed, 304 insertions(+), 1 deletion(-) | ||||
|  create mode 100644 block/pbs.c | ||||
| 
 | ||||
| diff --git a/block/meson.build b/block/meson.build
 | ||||
| index e995ae72b9..7ef2fa72d5 100644
 | ||||
| index 5bcebb934b..eece0d5743 100644
 | ||||
| --- a/block/meson.build
 | ||||
| +++ b/block/meson.build
 | ||||
| @@ -53,6 +53,9 @@ block_ss.add(files(
 | ||||
| @@ -54,6 +54,9 @@ block_ss.add(files(
 | ||||
|    '../pve-backup.c', | ||||
|  ), libproxmox_backup_qemu) | ||||
|   | ||||
| @ -36,10 +37,10 @@ index e995ae72b9..7ef2fa72d5 100644 | ||||
|  softmmu_ss.add(files('block-ram-registrar.c')) | ||||
| diff --git a/block/pbs.c b/block/pbs.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..9d1f1f39d4
 | ||||
| index 0000000000..43e69ada46
 | ||||
| --- /dev/null
 | ||||
| +++ b/block/pbs.c
 | ||||
| @@ -0,0 +1,276 @@
 | ||||
| @@ -0,0 +1,277 @@
 | ||||
| +/*
 | ||||
| + * Proxmox Backup Server read-only block driver
 | ||||
| + */
 | ||||
| @ -52,6 +53,7 @@ index 0000000000..9d1f1f39d4 | ||||
| +#include "qemu/option.h"
 | ||||
| +#include "qemu/cutils.h"
 | ||||
| +#include "block/block_int.h"
 | ||||
| +#include "block/block-io.h"
 | ||||
| +
 | ||||
| +#include <proxmox-backup-qemu.h>
 | ||||
| +
 | ||||
| @ -218,7 +220,7 @@ index 0000000000..9d1f1f39d4 | ||||
| +    proxmox_restore_disconnect(s->conn);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int64_t pbs_getlength(BlockDriverState *bs)
 | ||||
| +static coroutine_fn int64_t pbs_co_getlength(BlockDriverState *bs)
 | ||||
| +{
 | ||||
| +    BDRVPBSState *s = bs->opaque;
 | ||||
| +    return s->length;
 | ||||
| @ -301,7 +303,7 @@ index 0000000000..9d1f1f39d4 | ||||
| +    .bdrv_file_open         = pbs_file_open,
 | ||||
| +    .bdrv_open              = pbs_open,
 | ||||
| +    .bdrv_close             = pbs_close,
 | ||||
| +    .bdrv_getlength         = pbs_getlength,
 | ||||
| +    .bdrv_co_getlength      = pbs_co_getlength,
 | ||||
| +
 | ||||
| +    .bdrv_co_preadv         = pbs_co_preadv,
 | ||||
| +    .bdrv_co_pwritev        = pbs_co_pwritev,
 | ||||
| @ -317,10 +319,10 @@ index 0000000000..9d1f1f39d4 | ||||
| +
 | ||||
| +block_init(bdrv_pbs_init);
 | ||||
| diff --git a/configure b/configure
 | ||||
| index 26c7bc5154..c587e986c7 100755
 | ||||
| index 800b5850f4..37e12a3dce 100755
 | ||||
| --- a/configure
 | ||||
| +++ b/configure
 | ||||
| @@ -285,6 +285,7 @@ linux_user=""
 | ||||
| @@ -288,6 +288,7 @@ linux_user=""
 | ||||
|  bsd_user="" | ||||
|  pie="" | ||||
|  coroutine="" | ||||
| @ -328,9 +330,9 @@ index 26c7bc5154..c587e986c7 100755 | ||||
|  plugins="$default_feature" | ||||
|  meson="" | ||||
|  ninja="" | ||||
| @@ -864,6 +865,10 @@ for opt do
 | ||||
|    --enable-uuid|--disable-uuid) | ||||
|        echo "$0: $opt is obsolete, UUID support is always built" >&2 | ||||
| @@ -872,6 +873,10 @@ for opt do
 | ||||
|    ;; | ||||
|    --with-coroutine=*) coroutine="$optarg" | ||||
|    ;; | ||||
| +  --disable-pbs-bdrv) pbs_bdrv="no"
 | ||||
| +  ;;
 | ||||
| @ -339,15 +341,15 @@ index 26c7bc5154..c587e986c7 100755 | ||||
|    --with-git=*) git="$optarg" | ||||
|    ;; | ||||
|    --with-git-submodules=*) | ||||
| @@ -1049,6 +1054,7 @@ cat << EOF
 | ||||
| @@ -1048,6 +1053,7 @@ cat << EOF
 | ||||
|    debug-info      debugging information | ||||
|    safe-stack      SafeStack Stack Smash Protection. Depends on | ||||
|                    clang/llvm >= 3.7 and requires coroutine backend ucontext. | ||||
|                    clang/llvm and requires coroutine backend ucontext. | ||||
| +  pbs-bdrv        Proxmox backup server read-only block driver support
 | ||||
|   | ||||
|  NOTE: The object files are built at the place where configure is launched | ||||
|  EOF | ||||
| @@ -2372,6 +2378,9 @@ echo "TARGET_DIRS=$target_list" >> $config_host_mak
 | ||||
| @@ -2385,6 +2391,9 @@ echo "TARGET_DIRS=$target_list" >> $config_host_mak
 | ||||
|  if test "$modules" = "yes"; then | ||||
|    echo "CONFIG_MODULES=y" >> $config_host_mak | ||||
|  fi | ||||
| @ -358,10 +360,10 @@ index 26c7bc5154..c587e986c7 100755 | ||||
|  # XXX: suppress that | ||||
|  if [ "$bsd" = "yes" ] ; then | ||||
| diff --git a/meson.build b/meson.build
 | ||||
| index 63ea813a9a..f7f5b3f253 100644
 | ||||
| index 8ec21bba90..419bea5cf4 100644
 | ||||
| --- a/meson.build
 | ||||
| +++ b/meson.build
 | ||||
| @@ -3978,7 +3978,7 @@ summary_info += {'bzip2 support':     libbzip2}
 | ||||
| @@ -4035,7 +4035,7 @@ summary_info += {'bzip2 support':     libbzip2}
 | ||||
|  summary_info += {'lzfse support':     liblzfse} | ||||
|  summary_info += {'zstd support':      zstd} | ||||
|  summary_info += {'NUMA host support': numa} | ||||
| @ -371,10 +373,10 @@ index 63ea813a9a..f7f5b3f253 100644 | ||||
|  summary_info += {'libdaxctl support': libdaxctl} | ||||
|  summary_info += {'libudev':           libudev} | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 5ac6276dc1..45b63dfe26 100644
 | ||||
| index 864b8ce97c..705a65ab1a 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -3103,6 +3103,7 @@
 | ||||
| @@ -3198,6 +3198,7 @@
 | ||||
|              'parallels', 'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', | ||||
|              'raw', 'rbd', | ||||
|              { 'name': 'replication', 'if': 'CONFIG_REPLICATION' }, | ||||
| @ -382,7 +384,7 @@ index 5ac6276dc1..45b63dfe26 100644 | ||||
|              'ssh', 'throttle', 'vdi', 'vhdx', | ||||
|              { 'name': 'virtio-blk-vfio-pci', 'if': 'CONFIG_BLKIO' }, | ||||
|              { 'name': 'virtio-blk-vhost-user', 'if': 'CONFIG_BLKIO' }, | ||||
| @@ -3179,6 +3180,17 @@
 | ||||
| @@ -3274,6 +3275,17 @@
 | ||||
|  { 'struct': 'BlockdevOptionsNull', | ||||
|    'data': { '*size': 'int', '*latency-ns': 'uint64', '*read-zeroes': 'bool' } } | ||||
|   | ||||
| @ -400,7 +402,7 @@ index 5ac6276dc1..45b63dfe26 100644 | ||||
|  ## | ||||
|  # @BlockdevOptionsNVMe: | ||||
|  # | ||||
| @@ -4531,6 +4543,7 @@
 | ||||
| @@ -4647,6 +4659,7 @@
 | ||||
|        'nfs':        'BlockdevOptionsNfs', | ||||
|        'null-aio':   'BlockdevOptionsNull', | ||||
|        'null-co':    'BlockdevOptionsNull', | ||||
|  | ||||
| @ -16,10 +16,10 @@ Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
|  2 files changed, 38 insertions(+) | ||||
| 
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index e113ab61b9..9318ca4f0c 100644
 | ||||
| index f1eacbcaf6..c6fee40a67 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -1072,3 +1072,12 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
| @@ -1054,3 +1054,12 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
|   | ||||
|      return info; | ||||
|  } | ||||
| @ -33,10 +33,10 @@ index e113ab61b9..9318ca4f0c 100644 | ||||
| +    return ret;
 | ||||
| +}
 | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 45b63dfe26..8b0e0d92de 100644
 | ||||
| index 705a65ab1a..1ac535fcf2 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -863,6 +863,35 @@
 | ||||
| @@ -958,6 +958,35 @@
 | ||||
|  ## | ||||
|  { 'command': 'backup-cancel' } | ||||
|   | ||||
|  | ||||
| @ -15,10 +15,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  3 files changed, 159 insertions(+), 42 deletions(-) | ||||
| 
 | ||||
| diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
 | ||||
| index 670f783515..d819e5fc36 100644
 | ||||
| index 087161a967..9a67e544ce 100644
 | ||||
| --- a/monitor/hmp-cmds.c
 | ||||
| +++ b/monitor/hmp-cmds.c
 | ||||
| @@ -202,6 +202,7 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
 | ||||
| @@ -148,6 +148,7 @@ void hmp_sync_profile(Monitor *mon, const QDict *qdict)
 | ||||
|  void hmp_info_backup(Monitor *mon, const QDict *qdict) | ||||
|  { | ||||
|      BackupStatus *info; | ||||
| @ -26,7 +26,7 @@ index 670f783515..d819e5fc36 100644 | ||||
|   | ||||
|      info = qmp_query_backup(NULL); | ||||
|   | ||||
| @@ -232,26 +233,29 @@ void hmp_info_backup(Monitor *mon, const QDict *qdict)
 | ||||
| @@ -178,26 +179,29 @@ void hmp_info_backup(Monitor *mon, const QDict *qdict)
 | ||||
|              // this should not happen normally | ||||
|              monitor_printf(mon, "Total size: %d\n", 0); | ||||
|          } else { | ||||
| @ -69,10 +69,10 @@ index 670f783515..d819e5fc36 100644 | ||||
|                             info->zero_bytes, zero_per); | ||||
|   | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 9318ca4f0c..c85b2ecd83 100644
 | ||||
| index c6fee40a67..d4abe6e703 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -46,6 +46,7 @@ static struct PVEBackupState {
 | ||||
| @@ -48,6 +48,7 @@ static struct PVEBackupState {
 | ||||
|          size_t transferred; | ||||
|          size_t reused; | ||||
|          size_t zero_bytes; | ||||
| @ -80,7 +80,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|      } stat; | ||||
|      int64_t speed; | ||||
|      VmaWriter *vmaw; | ||||
| @@ -669,7 +670,6 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -663,7 +664,6 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      } | ||||
|   | ||||
|      size_t total = 0; | ||||
| @ -88,7 +88,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|   | ||||
|      l = di_list; | ||||
|      while (l) { | ||||
| @@ -690,18 +690,33 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -684,18 +684,33 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|   | ||||
|      uuid_generate(uuid); | ||||
|   | ||||
| @ -108,12 +108,12 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
| +    }
 | ||||
| +
 | ||||
|      if (format == BACKUP_FORMAT_PBS) { | ||||
|          if (!task->has_password) { | ||||
|          if (!task->password) { | ||||
|              error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'password'"); | ||||
| -            goto err;
 | ||||
| +            goto err_mutex;
 | ||||
|          } | ||||
|          if (!task->has_backup_id) { | ||||
|          if (!task->backup_id) { | ||||
|              error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-id'"); | ||||
| -            goto err;
 | ||||
| +            goto err_mutex;
 | ||||
| @ -125,7 +125,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|          } | ||||
|   | ||||
|          int dump_cb_block_size = PROXMOX_BACKUP_DEFAULT_CHUNK_SIZE; // Hardcoded (4M) | ||||
| @@ -728,12 +743,12 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -722,12 +737,12 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                        "proxmox_backup_new failed: %s", pbs_err); | ||||
|              proxmox_backup_free_error(pbs_err); | ||||
| @ -140,7 +140,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|   | ||||
|          /* register all devices */ | ||||
|          l = di_list; | ||||
| @@ -744,6 +759,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -738,6 +753,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              di->block_size = dump_cb_block_size; | ||||
|   | ||||
|              const char *devname = bdrv_get_device_name(di->bs); | ||||
| @ -149,7 +149,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|   | ||||
|              BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(di->bs, PBS_BITMAP_NAME); | ||||
|              bool expect_only_dirty = false; | ||||
| @@ -752,49 +769,59 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -746,49 +763,59 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|                  if (bitmap == NULL) { | ||||
|                      bitmap = bdrv_create_dirty_bitmap(di->bs, dump_cb_block_size, PBS_BITMAP_NAME, task->errp); | ||||
|                      if (!bitmap) { | ||||
| @ -219,7 +219,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|          } | ||||
|   | ||||
|          /* register all devices for vma writer */ | ||||
| @@ -804,7 +831,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -798,7 +825,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              l = g_list_next(l); | ||||
|   | ||||
|              if (!(di->target = bdrv_backup_dump_create(VMA_CLUSTER_SIZE, di->size, pvebackup_co_dump_vma_cb, di, task->errp))) { | ||||
| @ -228,7 +228,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|              } | ||||
|   | ||||
|              const char *devname = bdrv_get_device_name(di->bs); | ||||
| @@ -812,16 +839,14 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -806,16 +833,14 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              if (di->dev_id <= 0) { | ||||
|                  error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                            "register_stream failed"); | ||||
| @ -247,7 +247,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|          } | ||||
|          backup_dir = task->backup_file; | ||||
|   | ||||
| @@ -838,18 +863,18 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -832,18 +857,18 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|                              di->size, flags, false, &local_err); | ||||
|              if (local_err) { | ||||
|                  error_propagate(task->errp, local_err); | ||||
| @ -269,8 +269,8 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|      } | ||||
|   | ||||
|   | ||||
| @@ -857,7 +882,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      if (task->has_config_file) { | ||||
| @@ -851,7 +876,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      if (task->config_file) { | ||||
|          if (pvebackup_co_add_config(task->config_file, config_name, format, backup_dir, | ||||
|                                      vmaw, pbs, task->errp) != 0) { | ||||
| -            goto err;
 | ||||
| @ -278,8 +278,8 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|          } | ||||
|      } | ||||
|   | ||||
| @@ -865,12 +890,11 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      if (task->has_firewall_file) { | ||||
| @@ -859,12 +884,11 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      if (task->firewall_file) { | ||||
|          if (pvebackup_co_add_config(task->firewall_file, firewall_name, format, backup_dir, | ||||
|                                      vmaw, pbs, task->errp) != 0) { | ||||
| -            goto err;
 | ||||
| @ -293,7 +293,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|   | ||||
|      if (backup_state.stat.error) { | ||||
|          error_free(backup_state.stat.error); | ||||
| @@ -890,10 +914,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -884,10 +908,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      char *uuid_str = g_strdup(backup_state.stat.uuid_str); | ||||
|   | ||||
|      backup_state.stat.total = total; | ||||
| @ -305,7 +305,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|   | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
| @@ -910,6 +933,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -904,6 +927,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      task->result = uuid_info; | ||||
|      return; | ||||
|   | ||||
| @ -315,7 +315,7 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|  err: | ||||
|   | ||||
|      l = di_list; | ||||
| @@ -1073,11 +1099,42 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
| @@ -1055,11 +1081,42 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
|      return info; | ||||
|  } | ||||
|   | ||||
| @ -359,10 +359,10 @@ index 9318ca4f0c..c85b2ecd83 100644 | ||||
|      return ret; | ||||
|  } | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 8b0e0d92de..7fde927621 100644
 | ||||
| index 1ac535fcf2..130d5f065f 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -871,6 +871,8 @@
 | ||||
| @@ -966,6 +966,8 @@
 | ||||
|  # @pbs-dirty-bitmap: True if dirty-bitmap-incremental backups to PBS are | ||||
|  #                    supported. | ||||
|  # | ||||
| @ -371,7 +371,7 @@ index 8b0e0d92de..7fde927621 100644 | ||||
|  # @pbs-dirty-bitmap-savevm: True if 'dirty-bitmaps' migration capability can | ||||
|  #                           safely be set for savevm-async. | ||||
|  # | ||||
| @@ -879,6 +881,7 @@
 | ||||
| @@ -974,6 +976,7 @@
 | ||||
|  ## | ||||
|  { 'struct': 'ProxmoxSupportStatus', | ||||
|    'data': { 'pbs-dirty-bitmap': 'bool', | ||||
| @ -379,7 +379,7 @@ index 8b0e0d92de..7fde927621 100644 | ||||
|              'pbs-dirty-bitmap-savevm': 'bool', | ||||
|              'pbs-library-version': 'str' } } | ||||
|   | ||||
| @@ -892,6 +895,59 @@
 | ||||
| @@ -987,6 +990,59 @@
 | ||||
|  ## | ||||
|  { 'command': 'query-proxmox-support', 'returns': 'ProxmoxSupportStatus' } | ||||
|   | ||||
|  | ||||
| @ -14,10 +14,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  2 files changed, 7 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/meson.build b/meson.build
 | ||||
| index f7f5b3f253..283b0e356e 100644
 | ||||
| index 419bea5cf4..c39c6054ee 100644
 | ||||
| --- a/meson.build
 | ||||
| +++ b/meson.build
 | ||||
| @@ -1526,6 +1526,7 @@ keyutils = dependency('libkeyutils', required: false,
 | ||||
| @@ -1528,6 +1528,7 @@ keyutils = dependency('libkeyutils', required: false,
 | ||||
|  has_gettid = cc.has_function('gettid') | ||||
|   | ||||
|  libuuid = cc.find_library('uuid', required: true) | ||||
| @ -25,7 +25,7 @@ index f7f5b3f253..283b0e356e 100644 | ||||
|  libproxmox_backup_qemu = cc.find_library('proxmox_backup_qemu', required: true) | ||||
|   | ||||
|  # libselinux | ||||
| @@ -3096,6 +3097,7 @@ if have_block
 | ||||
| @@ -3143,6 +3144,7 @@ if have_block
 | ||||
|    # os-posix.c contains POSIX-specific functions used by qemu-storage-daemon, | ||||
|    # os-win32.c does not | ||||
|    blockdev_ss.add(when: 'CONFIG_POSIX', if_true: files('os-posix.c')) | ||||
| @ -34,7 +34,7 @@ index f7f5b3f253..283b0e356e 100644 | ||||
|  endif | ||||
|   | ||||
| diff --git a/os-posix.c b/os-posix.c
 | ||||
| index 4858650c3e..c5cb12226a 100644
 | ||||
| index 5adc69f560..80c7777f10 100644
 | ||||
| --- a/os-posix.c
 | ||||
| +++ b/os-posix.c
 | ||||
| @@ -28,6 +28,8 @@
 | ||||
|  | ||||
| @ -20,10 +20,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 50 insertions(+), 113 deletions(-) | ||||
| 
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index c85b2ecd83..b5fb844434 100644
 | ||||
| index d4abe6e703..214c839c0b 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -52,6 +52,7 @@ static struct PVEBackupState {
 | ||||
| @@ -54,6 +54,7 @@ static struct PVEBackupState {
 | ||||
|      VmaWriter *vmaw; | ||||
|      ProxmoxBackupHandle *pbs; | ||||
|      GList *di_list; | ||||
| @ -31,7 +31,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|      QemuMutex backup_mutex; | ||||
|      CoMutex dump_callback_mutex; | ||||
|  } backup_state; | ||||
| @@ -71,34 +72,12 @@ typedef struct PVEBackupDevInfo {
 | ||||
| @@ -73,34 +74,12 @@ typedef struct PVEBackupDevInfo {
 | ||||
|      size_t size; | ||||
|      uint64_t block_size; | ||||
|      uint8_t dev_id; | ||||
| @ -67,7 +67,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|  static void pvebackup_propagate_error(Error *err) | ||||
|  { | ||||
|      qemu_mutex_lock(&backup_state.stat.lock); | ||||
| @@ -274,18 +253,6 @@ static void coroutine_fn pvebackup_co_cleanup(void *unused)
 | ||||
| @@ -276,18 +255,6 @@ static void coroutine_fn pvebackup_co_cleanup(void *unused)
 | ||||
|              if (local_err != NULL) { | ||||
|                  pvebackup_propagate_error(local_err); | ||||
|              } | ||||
| @ -86,7 +86,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|          } | ||||
|   | ||||
|          proxmox_backup_disconnect(backup_state.pbs); | ||||
| @@ -324,8 +291,6 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
| @@ -326,8 +293,6 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
|   | ||||
|      qemu_mutex_lock(&backup_state.backup_mutex); | ||||
|   | ||||
| @ -95,7 +95,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|      if (ret < 0) { | ||||
|          Error *local_err = NULL; | ||||
|          error_setg(&local_err, "job failed with err %d - %s", ret, strerror(-ret)); | ||||
| @@ -338,20 +303,17 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
| @@ -340,20 +305,17 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
|   | ||||
|      block_on_coroutine_fn(pvebackup_complete_stream, di); | ||||
|   | ||||
| @ -122,7 +122,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|  } | ||||
|   | ||||
|  static void pvebackup_cancel(void) | ||||
| @@ -373,32 +335,28 @@ static void pvebackup_cancel(void)
 | ||||
| @@ -375,32 +337,28 @@ static void pvebackup_cancel(void)
 | ||||
|          proxmox_backup_abort(backup_state.pbs, "backup canceled"); | ||||
|      } | ||||
|   | ||||
| @ -173,7 +173,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|          } | ||||
|      } | ||||
|  } | ||||
| @@ -458,49 +416,19 @@ static int coroutine_fn pvebackup_co_add_config(
 | ||||
| @@ -460,49 +418,19 @@ static int coroutine_fn pvebackup_co_add_config(
 | ||||
|      goto out; | ||||
|  } | ||||
|   | ||||
| @ -230,7 +230,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|      BackupPerf perf = { .max_workers = 16 }; | ||||
|   | ||||
|      /* create and start all jobs (paused state) */ | ||||
| @@ -523,7 +451,7 @@ static bool create_backup_jobs(void) {
 | ||||
| @@ -525,7 +453,7 @@ static bool create_backup_jobs(void) {
 | ||||
|          BlockJob *job = backup_job_create( | ||||
|              NULL, di->bs, di->target, backup_state.speed, sync_mode, di->bitmap, | ||||
|              bitmap_mode, false, NULL, &perf, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | ||||
| @ -239,7 +239,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|   | ||||
|          aio_context_release(aio_context); | ||||
|   | ||||
| @@ -535,7 +463,8 @@ static bool create_backup_jobs(void) {
 | ||||
| @@ -537,7 +465,8 @@ static bool create_backup_jobs(void) {
 | ||||
|              pvebackup_propagate_error(create_job_err); | ||||
|              break; | ||||
|          } | ||||
| @ -249,7 +249,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|   | ||||
|          bdrv_unref(di->target); | ||||
|          di->target = NULL; | ||||
| @@ -553,6 +482,12 @@ static bool create_backup_jobs(void) {
 | ||||
| @@ -555,6 +484,12 @@ static bool create_backup_jobs(void) {
 | ||||
|                  bdrv_unref(di->target); | ||||
|                  di->target = NULL; | ||||
|              } | ||||
| @ -262,7 +262,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|          } | ||||
|      } | ||||
|   | ||||
| @@ -943,10 +878,6 @@ err:
 | ||||
| @@ -937,10 +872,6 @@ err:
 | ||||
|          PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
|          l = g_list_next(l); | ||||
|   | ||||
| @ -273,7 +273,7 @@ index c85b2ecd83..b5fb844434 100644 | ||||
|          if (di->target) { | ||||
|              bdrv_unref(di->target); | ||||
|          } | ||||
| @@ -1035,9 +966,15 @@ UuidInfo *qmp_backup(
 | ||||
| @@ -1021,9 +952,15 @@ UuidInfo *qmp_backup(
 | ||||
|      block_on_coroutine_fn(pvebackup_co_prepare, &task); | ||||
|   | ||||
|      if (*errp == NULL) { | ||||
|  | ||||
| @ -57,10 +57,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  2 files changed, 138 insertions(+), 79 deletions(-) | ||||
| 
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index b5fb844434..88268bb586 100644
 | ||||
| index 214c839c0b..1d233dac93 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -33,7 +33,9 @@ const char *PBS_BITMAP_NAME = "pbs-incremental-dirty-bitmap";
 | ||||
| @@ -35,7 +35,9 @@ const char *PBS_BITMAP_NAME = "pbs-incremental-dirty-bitmap";
 | ||||
|   | ||||
|  static struct PVEBackupState { | ||||
|      struct { | ||||
| @ -71,7 +71,7 @@ index b5fb844434..88268bb586 100644 | ||||
|          QemuMutex lock; | ||||
|          Error *error; | ||||
|          time_t start_time; | ||||
| @@ -47,20 +49,22 @@ static struct PVEBackupState {
 | ||||
| @@ -49,20 +51,22 @@ static struct PVEBackupState {
 | ||||
|          size_t reused; | ||||
|          size_t zero_bytes; | ||||
|          GList *bitmap_list; | ||||
| @ -96,7 +96,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      qemu_co_mutex_init(&backup_state.dump_callback_mutex); | ||||
|  } | ||||
|   | ||||
| @@ -72,6 +76,7 @@ typedef struct PVEBackupDevInfo {
 | ||||
| @@ -74,6 +78,7 @@ typedef struct PVEBackupDevInfo {
 | ||||
|      size_t size; | ||||
|      uint64_t block_size; | ||||
|      uint8_t dev_id; | ||||
| @ -104,7 +104,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      char targetfile[PATH_MAX]; | ||||
|      BdrvDirtyBitmap *bitmap; | ||||
|      BlockDriverState *target; | ||||
| @@ -227,12 +232,12 @@ pvebackup_co_dump_vma_cb(
 | ||||
| @@ -229,12 +234,12 @@ pvebackup_co_dump_vma_cb(
 | ||||
|  } | ||||
|   | ||||
|  // assumes the caller holds backup_mutex | ||||
| @ -119,7 +119,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
|      if (backup_state.vmaw) { | ||||
| @@ -261,35 +266,29 @@ static void coroutine_fn pvebackup_co_cleanup(void *unused)
 | ||||
| @@ -263,35 +268,29 @@ static void coroutine_fn pvebackup_co_cleanup(void *unused)
 | ||||
|   | ||||
|      g_list_free(backup_state.di_list); | ||||
|      backup_state.di_list = NULL; | ||||
| @ -171,7 +171,7 @@ index b5fb844434..88268bb586 100644 | ||||
|   | ||||
|      if (ret < 0) { | ||||
|          Error *local_err = NULL; | ||||
| @@ -301,7 +300,19 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
| @@ -303,7 +302,19 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
|   | ||||
|      assert(di->target == NULL); | ||||
|   | ||||
| @ -192,7 +192,7 @@ index b5fb844434..88268bb586 100644 | ||||
|   | ||||
|      // remove self from job list | ||||
|      backup_state.di_list = g_list_remove(backup_state.di_list, di); | ||||
| @@ -310,21 +321,46 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
| @@ -312,21 +323,46 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
|   | ||||
|      /* call cleanup if we're the last job */ | ||||
|      if (!g_list_first(backup_state.di_list)) { | ||||
| @ -244,7 +244,7 @@ index b5fb844434..88268bb586 100644 | ||||
|   | ||||
|      if (backup_state.vmaw) { | ||||
|          /* make sure vma writer does not block anymore */ | ||||
| @@ -342,28 +378,22 @@ static void pvebackup_cancel(void)
 | ||||
| @@ -344,28 +380,22 @@ static void pvebackup_cancel(void)
 | ||||
|          ((PVEBackupDevInfo *)bdi->data)->job : | ||||
|          NULL; | ||||
|   | ||||
| @ -282,7 +282,7 @@ index b5fb844434..88268bb586 100644 | ||||
|  } | ||||
|   | ||||
|  // assumes the caller holds backup_mutex | ||||
| @@ -416,10 +446,18 @@ static int coroutine_fn pvebackup_co_add_config(
 | ||||
| @@ -418,10 +448,18 @@ static int coroutine_fn pvebackup_co_add_config(
 | ||||
|      goto out; | ||||
|  } | ||||
|   | ||||
| @ -302,7 +302,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      Error *local_err = NULL; | ||||
|   | ||||
|      /* create job transaction to synchronize bitmap commit and cancel all | ||||
| @@ -455,24 +493,19 @@ static bool create_backup_jobs(void) {
 | ||||
| @@ -457,24 +495,19 @@ static bool create_backup_jobs(void) {
 | ||||
|   | ||||
|          aio_context_release(aio_context); | ||||
|   | ||||
| @ -332,7 +332,7 @@ index b5fb844434..88268bb586 100644 | ||||
|          l = backup_state.di_list; | ||||
|          while (l) { | ||||
|              PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
| @@ -485,13 +518,15 @@ static bool create_backup_jobs(void) {
 | ||||
| @@ -487,13 +520,15 @@ static bool create_backup_jobs(void) {
 | ||||
|   | ||||
|              if (di->job) { | ||||
|                  WITH_JOB_LOCK_GUARD() { | ||||
| @ -349,7 +349,7 @@ index b5fb844434..88268bb586 100644 | ||||
|  } | ||||
|   | ||||
|  typedef struct QmpBackupTask { | ||||
| @@ -528,11 +563,12 @@ typedef struct QmpBackupTask {
 | ||||
| @@ -522,11 +557,12 @@ typedef struct QmpBackupTask {
 | ||||
|      UuidInfo *result; | ||||
|  } QmpBackupTask; | ||||
|   | ||||
| @ -363,7 +363,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      QmpBackupTask *task = opaque; | ||||
|   | ||||
|      task->result = NULL; // just to be sure | ||||
| @@ -553,8 +589,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -547,8 +583,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      const char *firewall_name = "qemu-server.fw"; | ||||
|   | ||||
|      if (backup_state.di_list) { | ||||
| @ -374,7 +374,7 @@ index b5fb844434..88268bb586 100644 | ||||
|          return; | ||||
|      } | ||||
|   | ||||
| @@ -621,6 +658,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -615,6 +652,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|          } | ||||
|          di->size = size; | ||||
|          total += size; | ||||
| @ -383,7 +383,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      } | ||||
|   | ||||
|      uuid_generate(uuid); | ||||
| @@ -852,6 +891,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -846,6 +885,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      backup_state.stat.dirty = total - backup_state.stat.reused; | ||||
|      backup_state.stat.transferred = 0; | ||||
|      backup_state.stat.zero_bytes = 0; | ||||
| @ -392,7 +392,7 @@ index b5fb844434..88268bb586 100644 | ||||
|   | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
| @@ -866,6 +907,33 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -860,6 +901,33 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      uuid_info->UUID = uuid_str; | ||||
|   | ||||
|      task->result = uuid_info; | ||||
| @ -426,7 +426,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      return; | ||||
|   | ||||
|  err_mutex: | ||||
| @@ -888,6 +956,7 @@ err:
 | ||||
| @@ -882,6 +950,7 @@ err:
 | ||||
|          g_free(di); | ||||
|      } | ||||
|      g_list_free(di_list); | ||||
| @ -434,7 +434,7 @@ index b5fb844434..88268bb586 100644 | ||||
|   | ||||
|      if (devs) { | ||||
|          g_strfreev(devs); | ||||
| @@ -908,6 +977,8 @@ err:
 | ||||
| @@ -902,6 +971,8 @@ err:
 | ||||
|      } | ||||
|   | ||||
|      task->result = NULL; | ||||
| @ -443,7 +443,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      return; | ||||
|  } | ||||
|   | ||||
| @@ -961,24 +1032,8 @@ UuidInfo *qmp_backup(
 | ||||
| @@ -947,24 +1018,8 @@ UuidInfo *qmp_backup(
 | ||||
|          .errp = errp, | ||||
|      }; | ||||
|   | ||||
| @ -468,7 +468,7 @@ index b5fb844434..88268bb586 100644 | ||||
|      return task.result; | ||||
|  } | ||||
|   | ||||
| @@ -1030,6 +1085,7 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
| @@ -1012,6 +1067,7 @@ BackupStatus *qmp_query_backup(Error **errp)
 | ||||
|      info->transferred = backup_state.stat.transferred; | ||||
|      info->has_reused = true; | ||||
|      info->reused = backup_state.stat.reused; | ||||
| @ -477,10 +477,10 @@ index b5fb844434..88268bb586 100644 | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 7fde927621..bf559c6d52 100644
 | ||||
| index 130d5f065f..43838212e3 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -770,12 +770,15 @@
 | ||||
| @@ -865,12 +865,15 @@
 | ||||
|  # | ||||
|  # @uuid: uuid for this backup job | ||||
|  # | ||||
|  | ||||
| @ -13,21 +13,23 @@ safe migration is possible and makes sense. | ||||
| 
 | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: split up state_pending for 8.0] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  include/migration/misc.h |   3 ++ | ||||
|  migration/meson.build    |   2 + | ||||
|  migration/migration.c    |   1 + | ||||
|  migration/pbs-state.c    | 106 +++++++++++++++++++++++++++++++++++++++ | ||||
|  migration/pbs-state.c    | 104 +++++++++++++++++++++++++++++++++++++++ | ||||
|  pve-backup.c             |   1 + | ||||
|  qapi/block-core.json     |   6 +++ | ||||
|  6 files changed, 119 insertions(+) | ||||
|  6 files changed, 117 insertions(+) | ||||
|  create mode 100644 migration/pbs-state.c | ||||
| 
 | ||||
| diff --git a/include/migration/misc.h b/include/migration/misc.h
 | ||||
| index 465906710d..4f0aeceb6f 100644
 | ||||
| index 8b49841016..78f63ca400 100644
 | ||||
| --- a/include/migration/misc.h
 | ||||
| +++ b/include/migration/misc.h
 | ||||
| @@ -75,4 +75,7 @@ bool migration_in_bg_snapshot(void);
 | ||||
| @@ -77,4 +77,7 @@ bool migration_in_bg_snapshot(void);
 | ||||
|  /* migration/block-dirty-bitmap.c */ | ||||
|  void dirty_bitmap_mig_init(void); | ||||
|   | ||||
| @ -36,7 +38,7 @@ index 465906710d..4f0aeceb6f 100644 | ||||
| +
 | ||||
|  #endif | ||||
| diff --git a/migration/meson.build b/migration/meson.build
 | ||||
| index 0842d00cd2..d012f4d8d3 100644
 | ||||
| index a7824b5266..de6a271b58 100644
 | ||||
| --- a/migration/meson.build
 | ||||
| +++ b/migration/meson.build
 | ||||
| @@ -6,8 +6,10 @@ migration_files = files(
 | ||||
| @ -51,10 +53,10 @@ index 0842d00cd2..d012f4d8d3 100644 | ||||
|  softmmu_ss.add(files( | ||||
|    'block-dirty-bitmap.c', | ||||
| diff --git a/migration/migration.c b/migration/migration.c
 | ||||
| index f485eea5fb..89b287180f 100644
 | ||||
| index bda4789193..c8318aa258 100644
 | ||||
| --- a/migration/migration.c
 | ||||
| +++ b/migration/migration.c
 | ||||
| @@ -229,6 +229,7 @@ void migration_object_init(void)
 | ||||
| @@ -245,6 +245,7 @@ void migration_object_init(void)
 | ||||
|      blk_mig_init(); | ||||
|      ram_mig_init(); | ||||
|      dirty_bitmap_mig_init(); | ||||
| @ -64,10 +66,10 @@ index f485eea5fb..89b287180f 100644 | ||||
|  void migration_cancel(const Error *error) | ||||
| diff --git a/migration/pbs-state.c b/migration/pbs-state.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..29f2b3860d
 | ||||
| index 0000000000..887e998b9e
 | ||||
| --- /dev/null
 | ||||
| +++ b/migration/pbs-state.c
 | ||||
| @@ -0,0 +1,106 @@
 | ||||
| @@ -0,0 +1,104 @@
 | ||||
| +/*
 | ||||
| + * PBS (dirty-bitmap) state migration
 | ||||
| + */
 | ||||
| @ -86,11 +88,8 @@ index 0000000000..29f2b3860d | ||||
| +/* state is accessed via this static variable directly, 'opaque' is NULL */
 | ||||
| +static PBSState pbs_state;
 | ||||
| +
 | ||||
| +static void pbs_state_save_pending(QEMUFile *f, void *opaque,
 | ||||
| +                                      uint64_t max_size,
 | ||||
| +                                      uint64_t *res_precopy_only,
 | ||||
| +                                      uint64_t *res_compatible,
 | ||||
| +                                      uint64_t *res_postcopy_only)
 | ||||
| +static void pbs_state_pending(void *opaque, uint64_t *must_precopy,
 | ||||
| +                              uint64_t *can_postcopy)
 | ||||
| +{
 | ||||
| +    /* we send everything in save_setup, so nothing is ever pending */
 | ||||
| +}
 | ||||
| @ -160,7 +159,8 @@ index 0000000000..29f2b3860d | ||||
| +static SaveVMHandlers savevm_pbs_state_handlers = {
 | ||||
| +    .save_setup = pbs_state_save_setup,
 | ||||
| +    .has_postcopy = pbs_state_has_postcopy,
 | ||||
| +    .save_live_pending = pbs_state_save_pending,
 | ||||
| +    .state_pending_exact = pbs_state_pending,
 | ||||
| +    .state_pending_estimate = pbs_state_pending,
 | ||||
| +    .is_active_iterate = pbs_state_is_active_iterate,
 | ||||
| +    .load_state = pbs_state_load,
 | ||||
| +    .is_active = pbs_state_is_active,
 | ||||
| @ -175,10 +175,10 @@ index 0000000000..29f2b3860d | ||||
| +                         NULL);
 | ||||
| +}
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 88268bb586..fa9c6c4493 100644
 | ||||
| index 1d233dac93..5c9c153e31 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -1128,6 +1128,7 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | ||||
| @@ -1110,6 +1110,7 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | ||||
|      ret->pbs_library_version = g_strdup(proxmox_backup_qemu_version()); | ||||
|      ret->pbs_dirty_bitmap = true; | ||||
|      ret->pbs_dirty_bitmap_savevm = true; | ||||
| @ -187,10 +187,10 @@ index 88268bb586..fa9c6c4493 100644 | ||||
|      return ret; | ||||
|  } | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index bf559c6d52..24f30260c8 100644
 | ||||
| index 43838212e3..e7412f6322 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -879,6 +879,11 @@
 | ||||
| @@ -974,6 +974,11 @@
 | ||||
|  # @pbs-dirty-bitmap-savevm: True if 'dirty-bitmaps' migration capability can | ||||
|  #                           safely be set for savevm-async. | ||||
|  # | ||||
| @ -202,7 +202,7 @@ index bf559c6d52..24f30260c8 100644 | ||||
|  # @pbs-library-version: Running version of libproxmox-backup-qemu0 library. | ||||
|  # | ||||
|  ## | ||||
| @@ -886,6 +891,7 @@
 | ||||
| @@ -981,6 +986,7 @@
 | ||||
|    'data': { 'pbs-dirty-bitmap': 'bool', | ||||
|              'query-bitmap-info': 'bool', | ||||
|              'pbs-dirty-bitmap-savevm': 'bool', | ||||
|  | ||||
| @ -19,10 +19,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
 | ||||
| index 9aba7d9c22..f4ecf9c9f9 100644
 | ||||
| index fe73aa94b1..a6440929fa 100644
 | ||||
| --- a/migration/block-dirty-bitmap.c
 | ||||
| +++ b/migration/block-dirty-bitmap.c
 | ||||
| @@ -538,7 +538,7 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs,
 | ||||
| @@ -539,7 +539,7 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs,
 | ||||
|   | ||||
|          if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, &local_err)) { | ||||
|              error_report_err(local_err); | ||||
|  | ||||
| @ -21,10 +21,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 30 insertions(+) | ||||
| 
 | ||||
| diff --git a/block/iscsi.c b/block/iscsi.c
 | ||||
| index a316d46d96..3ed4a50c0d 100644
 | ||||
| index 9fc0bed90b..1d40933165 100644
 | ||||
| --- a/block/iscsi.c
 | ||||
| +++ b/block/iscsi.c
 | ||||
| @@ -1387,12 +1387,42 @@ static char *get_initiator_name(QemuOpts *opts)
 | ||||
| @@ -1392,12 +1392,42 @@ static char *get_initiator_name(QemuOpts *opts)
 | ||||
|      const char *name; | ||||
|      char *iscsi_name; | ||||
|      UuidInfo *uuid_info; | ||||
|  | ||||
| @ -23,20 +23,23 @@ way instead) | ||||
| 
 | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to QAPI changes | ||||
|      call coroutine version of is_inserted()] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/monitor/block-hmp-cmds.c |   4 +- | ||||
|  hmp-commands.hx                |   2 + | ||||
|  proxmox-backup-client.c        |  31 ----- | ||||
|  pve-backup.c                   | 232 ++++++++++----------------------- | ||||
|  pve-backup.c                   | 220 +++++++++++---------------------- | ||||
|  qapi/block-core.json           |   4 +- | ||||
|  5 files changed, 77 insertions(+), 196 deletions(-) | ||||
|  5 files changed, 79 insertions(+), 182 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index a09f722fea..71ed202491 100644
 | ||||
| index 6a6ed6d0e7..bcf5849196 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1016,7 +1016,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
 | ||||
|      g_free(global_snapshots); | ||||
| @@ -1028,7 +1028,7 @@ void hmp_change_medium(Monitor *mon, const char *device, const char *target,
 | ||||
|                                 !!read_only, read_only_mode, errp); | ||||
|  } | ||||
|   | ||||
| -void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
 | ||||
| @ -44,7 +47,7 @@ index a09f722fea..71ed202491 100644 | ||||
|  { | ||||
|      Error *error = NULL; | ||||
|   | ||||
| @@ -1025,7 +1025,7 @@ void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
 | ||||
| @@ -1037,7 +1037,7 @@ void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
 | ||||
|      hmp_handle_error(mon, error); | ||||
|  } | ||||
|   | ||||
| @ -54,7 +57,7 @@ index a09f722fea..71ed202491 100644 | ||||
|      Error *error = NULL; | ||||
|   | ||||
| diff --git a/hmp-commands.hx b/hmp-commands.hx
 | ||||
| index fcf9461295..5fdb198ca4 100644
 | ||||
| index 9b6b8e2e9c..896430dae8 100644
 | ||||
| --- a/hmp-commands.hx
 | ||||
| +++ b/hmp-commands.hx
 | ||||
| @@ -111,6 +111,7 @@ ERST
 | ||||
| @ -116,10 +119,10 @@ index 4ce7bc0b5e..0923037dec 100644 | ||||
|  static void proxmox_backup_schedule_wake(void *data) { | ||||
|      CoCtxData *waker = (CoCtxData *)data; | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 5662f48b72..e4fe1b601d 100644
 | ||||
| index 5c9c153e31..378e4a9a63 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -354,7 +354,7 @@ static void job_cancel_bh(void *opaque) {
 | ||||
| @@ -356,7 +356,7 @@ static void job_cancel_bh(void *opaque) {
 | ||||
|      aio_co_enter(data->ctx, data->co); | ||||
|  } | ||||
|   | ||||
| @ -128,7 +131,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|  { | ||||
|      Error *cancel_err = NULL; | ||||
|      error_setg(&cancel_err, "backup canceled"); | ||||
| @@ -391,11 +391,6 @@ static void coroutine_fn pvebackup_co_cancel(void *opaque)
 | ||||
| @@ -393,11 +393,6 @@ static void coroutine_fn pvebackup_co_cancel(void *opaque)
 | ||||
|      qemu_co_mutex_unlock(&backup_state.backup_mutex); | ||||
|  } | ||||
|   | ||||
| @ -140,33 +143,25 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|  // assumes the caller holds backup_mutex | ||||
|  static int coroutine_fn pvebackup_co_add_config( | ||||
|      const char *file, | ||||
| @@ -529,50 +524,27 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -531,42 +526,27 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|      aio_co_enter(data->ctx, data->co); | ||||
|  } | ||||
|   | ||||
| -typedef struct QmpBackupTask {
 | ||||
| -    const char *backup_file;
 | ||||
| -    bool has_password;
 | ||||
| -    const char *password;
 | ||||
| -    bool has_keyfile;
 | ||||
| -    const char *keyfile;
 | ||||
| -    bool has_key_password;
 | ||||
| -    const char *key_password;
 | ||||
| -    bool has_backup_id;
 | ||||
| -    const char *backup_id;
 | ||||
| -    bool has_backup_time;
 | ||||
| -    const char *fingerprint;
 | ||||
| -    bool has_fingerprint;
 | ||||
| -    int64_t backup_time;
 | ||||
| -    bool has_use_dirty_bitmap;
 | ||||
| -    bool use_dirty_bitmap;
 | ||||
| -    bool has_format;
 | ||||
| -    BackupFormat format;
 | ||||
| -    bool has_config_file;
 | ||||
| -    const char *config_file;
 | ||||
| -    bool has_firewall_file;
 | ||||
| -    const char *firewall_file;
 | ||||
| -    bool has_devlist;
 | ||||
| -    const char *devlist;
 | ||||
| -    bool has_compress;
 | ||||
| -    bool compress;
 | ||||
| @ -181,19 +176,19 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
| -static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| +UuidInfo coroutine_fn *qmp_backup(
 | ||||
| +    const char *backup_file,
 | ||||
| +    bool has_password, const char *password,
 | ||||
| +    bool has_keyfile, const char *keyfile,
 | ||||
| +    bool has_key_password, const char *key_password,
 | ||||
| +    bool has_fingerprint, const char *fingerprint,
 | ||||
| +    bool has_backup_id, const char *backup_id,
 | ||||
| +    const char *password,
 | ||||
| +    const char *keyfile,
 | ||||
| +    const char *key_password,
 | ||||
| +    const char *fingerprint,
 | ||||
| +    const char *backup_id,
 | ||||
| +    bool has_backup_time, int64_t backup_time,
 | ||||
| +    bool has_use_dirty_bitmap, bool use_dirty_bitmap,
 | ||||
| +    bool has_compress, bool compress,
 | ||||
| +    bool has_encrypt, bool encrypt,
 | ||||
| +    bool has_format, BackupFormat format,
 | ||||
| +    bool has_config_file, const char *config_file,
 | ||||
| +    bool has_firewall_file, const char *firewall_file,
 | ||||
| +    bool has_devlist, const char *devlist,
 | ||||
| +    const char *config_file,
 | ||||
| +    const char *firewall_file,
 | ||||
| +    const char *devlist,
 | ||||
| +    bool has_speed, int64_t speed, Error **errp)
 | ||||
|  { | ||||
|      assert(qemu_in_coroutine()); | ||||
| @ -207,7 +202,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|      BlockBackend *blk; | ||||
|      BlockDriverState *bs = NULL; | ||||
|      const char *backup_dir = NULL; | ||||
| @@ -589,17 +561,17 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -583,32 +563,32 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      const char *firewall_name = "qemu-server.fw"; | ||||
|   | ||||
|      if (backup_state.di_list) { | ||||
| @ -223,18 +218,19 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
| -    BackupFormat format = task->has_format ? task->format : BACKUP_FORMAT_VMA;
 | ||||
| +    format = has_format ? format : BACKUP_FORMAT_VMA;
 | ||||
|   | ||||
| -    if (task->has_devlist) {
 | ||||
| -    if (task->devlist) {
 | ||||
| -        devs = g_strsplit_set(task->devlist, ",;:", -1);
 | ||||
| +    if (has_devlist) {
 | ||||
| +    if (devlist) {
 | ||||
| +        devs = g_strsplit_set(devlist, ",;:", -1);
 | ||||
|   | ||||
|          gchar **d = devs; | ||||
|          while (d && *d) { | ||||
| @@ -607,14 +579,14 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              blk = blk_by_name(*d); | ||||
|              if (blk) { | ||||
|                  bs = blk_bs(blk); | ||||
|                  if (!bdrv_is_inserted(bs)) { | ||||
| -                if (!bdrv_is_inserted(bs)) {
 | ||||
| -                    error_setg(task->errp, QERR_DEVICE_HAS_NO_MEDIUM, *d);
 | ||||
| +                if (!bdrv_co_is_inserted(bs)) {
 | ||||
| +                    error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d);
 | ||||
|                      goto err; | ||||
|                  } | ||||
| @ -247,7 +243,16 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|                            "Device '%s' not found", *d); | ||||
|                  goto err; | ||||
|              } | ||||
| @@ -637,7 +609,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -620,7 +600,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|   | ||||
|          bs = NULL; | ||||
|          for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ||||
| -            if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
 | ||||
| +            if (!bdrv_co_is_inserted(bs) || bdrv_is_read_only(bs)) {
 | ||||
|                  continue; | ||||
|              } | ||||
|   | ||||
| @@ -631,7 +611,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      } | ||||
|   | ||||
|      if (!di_list) { | ||||
| @ -256,7 +261,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|          goto err; | ||||
|      } | ||||
|   | ||||
| @@ -647,13 +619,13 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -641,13 +621,13 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      while (l) { | ||||
|          PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
|          l = g_list_next(l); | ||||
| @ -272,19 +277,19 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|              goto err; | ||||
|          } | ||||
|          di->size = size; | ||||
| @@ -680,47 +652,44 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -674,47 +654,44 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      } | ||||
|   | ||||
|      if (format == BACKUP_FORMAT_PBS) { | ||||
| -        if (!task->has_password) {
 | ||||
| -        if (!task->password) {
 | ||||
| -            error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'password'");
 | ||||
| +        if (!has_password) {
 | ||||
| +        if (!password) {
 | ||||
| +            error_set(errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'password'");
 | ||||
|              goto err_mutex; | ||||
|          } | ||||
| -        if (!task->has_backup_id) {
 | ||||
| -        if (!task->backup_id) {
 | ||||
| -            error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-id'");
 | ||||
| +        if (!has_backup_id) {
 | ||||
| +        if (!backup_id) {
 | ||||
| +            error_set(errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-id'");
 | ||||
|              goto err_mutex; | ||||
|          } | ||||
| @ -310,19 +315,19 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
| +            backup_id,
 | ||||
| +            backup_time,
 | ||||
|              dump_cb_block_size, | ||||
| -            task->has_password ? task->password : NULL,
 | ||||
| -            task->has_keyfile ? task->keyfile : NULL,
 | ||||
| -            task->has_key_password ? task->key_password : NULL,
 | ||||
| -            task->password,
 | ||||
| -            task->keyfile,
 | ||||
| -            task->key_password,
 | ||||
| -            task->has_compress ? task->compress : true,
 | ||||
| -            task->has_encrypt ? task->encrypt : task->has_keyfile,
 | ||||
| -            task->has_fingerprint ? task->fingerprint : NULL,
 | ||||
| +            has_password ? password : NULL,
 | ||||
| +            has_keyfile ? keyfile : NULL,
 | ||||
| +            has_key_password ? key_password : NULL,
 | ||||
| -            task->has_encrypt ? task->encrypt : !!task->keyfile,
 | ||||
| -            task->fingerprint,
 | ||||
| +            password,
 | ||||
| +            keyfile,
 | ||||
| +            key_password,
 | ||||
| +            has_compress ? compress : true,
 | ||||
| +            has_encrypt ? encrypt : has_keyfile,
 | ||||
| +            has_fingerprint ? fingerprint : NULL,
 | ||||
|               &pbs_err); | ||||
| +            has_encrypt ? encrypt : !!keyfile,
 | ||||
| +            fingerprint,
 | ||||
|              &pbs_err); | ||||
|   | ||||
|          if (!pbs) { | ||||
| -            error_set(task->errp, ERROR_CLASS_GENERIC_ERROR,
 | ||||
| @ -337,7 +342,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|          if (connect_result < 0) | ||||
|              goto err_mutex; | ||||
|   | ||||
| @@ -739,9 +708,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -733,9 +710,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(di->bs, PBS_BITMAP_NAME); | ||||
|              bool expect_only_dirty = false; | ||||
|   | ||||
| @ -349,7 +354,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|                      if (!bitmap) { | ||||
|                          goto err_mutex; | ||||
|                      } | ||||
| @@ -771,12 +740,12 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -765,12 +742,12 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|                  } | ||||
|              } | ||||
|   | ||||
| @ -364,7 +369,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|                  goto err_mutex; | ||||
|              } | ||||
|   | ||||
| @@ -790,10 +759,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -784,10 +761,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              backup_state.stat.bitmap_list = g_list_append(backup_state.stat.bitmap_list, info); | ||||
|          } | ||||
|      } else if (format == BACKUP_FORMAT_VMA) { | ||||
| @ -377,7 +382,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|              } | ||||
|              goto err_mutex; | ||||
|          } | ||||
| @@ -804,25 +773,25 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -798,25 +775,25 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
|              l = g_list_next(l); | ||||
|   | ||||
| @ -409,7 +414,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|   | ||||
|          l = di_list; | ||||
|          while (l) { | ||||
| @@ -836,34 +805,34 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -830,34 +807,34 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|              bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL, | ||||
|                              di->size, flags, false, &local_err); | ||||
|              if (local_err) { | ||||
| @ -433,10 +438,10 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|   | ||||
|   | ||||
|      /* add configuration file to archive */ | ||||
| -    if (task->has_config_file) {
 | ||||
| -    if (task->config_file) {
 | ||||
| -        if (pvebackup_co_add_config(task->config_file, config_name, format, backup_dir,
 | ||||
| -                                    vmaw, pbs, task->errp) != 0) {
 | ||||
| +    if (has_config_file) {
 | ||||
| +    if (config_file) {
 | ||||
| +        if (pvebackup_co_add_config(config_file, config_name, format, backup_dir,
 | ||||
| +                                    vmaw, pbs, errp) != 0) {
 | ||||
|              goto err_mutex; | ||||
| @ -444,16 +449,16 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|      } | ||||
|   | ||||
|      /* add firewall file to archive */ | ||||
| -    if (task->has_firewall_file) {
 | ||||
| -    if (task->firewall_file) {
 | ||||
| -        if (pvebackup_co_add_config(task->firewall_file, firewall_name, format, backup_dir,
 | ||||
| -                                    vmaw, pbs, task->errp) != 0) {
 | ||||
| +    if (has_firewall_file) {
 | ||||
| +    if (firewall_file) {
 | ||||
| +        if (pvebackup_co_add_config(firewall_file, firewall_name, format, backup_dir,
 | ||||
| +                                    vmaw, pbs, errp) != 0) {
 | ||||
|              goto err_mutex; | ||||
|          } | ||||
|      } | ||||
| @@ -881,7 +850,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -875,7 +852,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      if (backup_state.stat.backup_file) { | ||||
|          g_free(backup_state.stat.backup_file); | ||||
|      } | ||||
| @ -462,7 +467,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|   | ||||
|      uuid_copy(backup_state.stat.uuid, uuid); | ||||
|      uuid_unparse_lower(uuid, backup_state.stat.uuid_str); | ||||
| @@ -896,7 +865,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -890,7 +867,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|   | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
|   | ||||
| @ -471,7 +476,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|   | ||||
|      backup_state.vmaw = vmaw; | ||||
|      backup_state.pbs = pbs; | ||||
| @@ -906,8 +875,6 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -900,8 +877,6 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      uuid_info = g_malloc0(sizeof(*uuid_info)); | ||||
|      uuid_info->UUID = uuid_str; | ||||
|   | ||||
| @ -480,7 +485,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|      /* Run create_backup_jobs_bh outside of coroutine (in BH) but keep | ||||
|      * backup_mutex locked. This is fine, a CoMutex can be held across yield | ||||
|      * points, and we'll release it as soon as the BH reschedules us. | ||||
| @@ -921,7 +888,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -915,7 +890,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      qemu_coroutine_yield(); | ||||
|   | ||||
|      if (local_err) { | ||||
| @ -489,7 +494,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|          goto err; | ||||
|      } | ||||
|   | ||||
| @@ -934,7 +901,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
| @@ -928,7 +903,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
 | ||||
|      /* start the first job in the transaction */ | ||||
|      job_txn_start_seq(backup_state.txn); | ||||
|   | ||||
| @ -498,7 +503,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|   | ||||
|  err_mutex: | ||||
|      qemu_mutex_unlock(&backup_state.stat.lock); | ||||
| @@ -965,7 +932,7 @@ err:
 | ||||
| @@ -959,7 +934,7 @@ err:
 | ||||
|      if (vmaw) { | ||||
|          Error *err = NULL; | ||||
|          vma_writer_close(vmaw, &err); | ||||
| @ -507,7 +512,7 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|      } | ||||
|   | ||||
|      if (pbs) { | ||||
| @@ -976,65 +943,8 @@ err:
 | ||||
| @@ -970,57 +945,8 @@ err:
 | ||||
|          rmdir(backup_dir); | ||||
|      } | ||||
|   | ||||
| @ -519,32 +524,27 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
| -
 | ||||
| -UuidInfo *qmp_backup(
 | ||||
| -    const char *backup_file,
 | ||||
| -    bool has_password, const char *password,
 | ||||
| -    bool has_keyfile, const char *keyfile,
 | ||||
| -    bool has_key_password, const char *key_password,
 | ||||
| -    bool has_fingerprint, const char *fingerprint,
 | ||||
| -    bool has_backup_id, const char *backup_id,
 | ||||
| -    const char *password,
 | ||||
| -    const char *keyfile,
 | ||||
| -    const char *key_password,
 | ||||
| -    const char *fingerprint,
 | ||||
| -    const char *backup_id,
 | ||||
| -    bool has_backup_time, int64_t backup_time,
 | ||||
| -    bool has_use_dirty_bitmap, bool use_dirty_bitmap,
 | ||||
| -    bool has_compress, bool compress,
 | ||||
| -    bool has_encrypt, bool encrypt,
 | ||||
| -    bool has_format, BackupFormat format,
 | ||||
| -    bool has_config_file, const char *config_file,
 | ||||
| -    bool has_firewall_file, const char *firewall_file,
 | ||||
| -    bool has_devlist, const char *devlist,
 | ||||
| -    const char *config_file,
 | ||||
| -    const char *firewall_file,
 | ||||
| -    const char *devlist,
 | ||||
| -    bool has_speed, int64_t speed, Error **errp)
 | ||||
| -{
 | ||||
| -    QmpBackupTask task = {
 | ||||
| -        .backup_file = backup_file,
 | ||||
| -        .has_password = has_password,
 | ||||
| -        .password = password,
 | ||||
| -        .has_keyfile = has_keyfile,
 | ||||
| -        .keyfile = keyfile,
 | ||||
| -        .has_key_password = has_key_password,
 | ||||
| -        .key_password = key_password,
 | ||||
| -        .has_fingerprint = has_fingerprint,
 | ||||
| -        .fingerprint = fingerprint,
 | ||||
| -        .has_backup_id = has_backup_id,
 | ||||
| -        .backup_id = backup_id,
 | ||||
| -        .has_backup_time = has_backup_time,
 | ||||
| -        .backup_time = backup_time,
 | ||||
| @ -556,11 +556,8 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
| -        .encrypt = encrypt,
 | ||||
| -        .has_format = has_format,
 | ||||
| -        .format = format,
 | ||||
| -        .has_config_file = has_config_file,
 | ||||
| -        .config_file = config_file,
 | ||||
| -        .has_firewall_file = has_firewall_file,
 | ||||
| -        .firewall_file = firewall_file,
 | ||||
| -        .has_devlist = has_devlist,
 | ||||
| -        .devlist = devlist,
 | ||||
| -        .has_speed = has_speed,
 | ||||
| -        .speed = speed,
 | ||||
| @ -575,10 +572,10 @@ index 5662f48b72..e4fe1b601d 100644 | ||||
|   | ||||
|  BackupStatus *qmp_query_backup(Error **errp) | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 24f30260c8..4e8c35a3a2 100644
 | ||||
| index e7412f6322..93d924ef79 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -842,7 +842,7 @@
 | ||||
| @@ -937,7 +937,7 @@
 | ||||
|                                      '*config-file': 'str', | ||||
|                                      '*firewall-file': 'str', | ||||
|                                      '*devlist': 'str', '*speed': 'int' }, | ||||
| @ -587,7 +584,7 @@ index 24f30260c8..4e8c35a3a2 100644 | ||||
|   | ||||
|  ## | ||||
|  # @query-backup: | ||||
| @@ -864,7 +864,7 @@
 | ||||
| @@ -959,7 +959,7 @@
 | ||||
|  # Notes: This command succeeds even if there is no backup process running. | ||||
|  # | ||||
|  ## | ||||
|  | ||||
| @ -12,6 +12,8 @@ from the PVE side to avoid QMP calls with unsupported parameters. | ||||
| Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | ||||
| Signed-off-by: Stefan Reiter <s.reiter@proxmox.com> | ||||
| Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
| [FE: adapt to QAPI change dropping redundant has_*] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/monitor/block-hmp-cmds.c | 1 + | ||||
|  pve-backup.c                   | 3 +++ | ||||
| @ -19,38 +21,38 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  3 files changed, 11 insertions(+) | ||||
| 
 | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index 71ed202491..c7468e5d3b 100644
 | ||||
| index bcf5849196..fb881056e9 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1039,6 +1039,7 @@ void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          false, NULL, // PBS password | ||||
|          false, NULL, // PBS keyfile | ||||
|          false, NULL, // PBS key_password | ||||
| +        false, NULL, // PBS master_keyfile
 | ||||
|          false, NULL, // PBS fingerprint | ||||
|          false, NULL, // PBS backup-id | ||||
| @@ -1051,6 +1051,7 @@ void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          NULL, // PBS password | ||||
|          NULL, // PBS keyfile | ||||
|          NULL, // PBS key_password | ||||
| +        NULL, // PBS master_keyfile
 | ||||
|          NULL, // PBS fingerprint | ||||
|          NULL, // PBS backup-id | ||||
|          false, 0, // PBS backup-time | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 109498eaf9..4b5134ed27 100644
 | ||||
| index 378e4a9a63..504c11657a 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -529,6 +529,7 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|      bool has_password, const char *password, | ||||
|      bool has_keyfile, const char *keyfile, | ||||
|      bool has_key_password, const char *key_password, | ||||
| +    bool has_master_keyfile, const char *master_keyfile,
 | ||||
|      bool has_fingerprint, const char *fingerprint, | ||||
|      bool has_backup_id, const char *backup_id, | ||||
| @@ -531,6 +531,7 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|      const char *password, | ||||
|      const char *keyfile, | ||||
|      const char *key_password, | ||||
| +    const char *master_keyfile,
 | ||||
|      const char *fingerprint, | ||||
|      const char *backup_id, | ||||
|      bool has_backup_time, int64_t backup_time, | ||||
| @@ -677,6 +678,7 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|              has_password ? password : NULL, | ||||
|              has_keyfile ? keyfile : NULL, | ||||
|              has_key_password ? key_password : NULL, | ||||
| +            has_master_keyfile ? master_keyfile : NULL,
 | ||||
| @@ -679,6 +680,7 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|              password, | ||||
|              keyfile, | ||||
|              key_password, | ||||
| +            master_keyfile,
 | ||||
|              has_compress ? compress : true, | ||||
|              has_encrypt ? encrypt : has_keyfile, | ||||
|              has_fingerprint ? fingerprint : NULL, | ||||
| @@ -1040,5 +1042,6 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | ||||
|              has_encrypt ? encrypt : !!keyfile, | ||||
|              fingerprint, | ||||
| @@ -1038,5 +1040,6 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | ||||
|      ret->pbs_dirty_bitmap_savevm = true; | ||||
|      ret->pbs_dirty_bitmap_migration = true; | ||||
|      ret->query_bitmap_info = true; | ||||
| @ -58,10 +60,10 @@ index 109498eaf9..4b5134ed27 100644 | ||||
|      return ret; | ||||
|  } | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 4e8c35a3a2..d8c7331090 100644
 | ||||
| index 93d924ef79..568feb63ad 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -813,6 +813,8 @@
 | ||||
| @@ -908,6 +908,8 @@
 | ||||
|  # | ||||
|  # @key-password: password for keyfile (optional for format 'pbs') | ||||
|  # | ||||
| @ -70,7 +72,7 @@ index 4e8c35a3a2..d8c7331090 100644 | ||||
|  # @fingerprint: server cert fingerprint (optional for format 'pbs') | ||||
|  # | ||||
|  # @backup-id: backup ID (required for format 'pbs') | ||||
| @@ -832,6 +834,7 @@
 | ||||
| @@ -927,6 +929,7 @@
 | ||||
|                                      '*password': 'str', | ||||
|                                      '*keyfile': 'str', | ||||
|                                      '*key-password': 'str', | ||||
| @ -78,7 +80,7 @@ index 4e8c35a3a2..d8c7331090 100644 | ||||
|                                      '*fingerprint': 'str', | ||||
|                                      '*backup-id': 'str', | ||||
|                                      '*backup-time': 'int', | ||||
| @@ -884,6 +887,9 @@
 | ||||
| @@ -979,6 +982,9 @@
 | ||||
|  #                              migration cap if this is false/unset may lead | ||||
|  #                              to crashes on migration! | ||||
|  # | ||||
| @ -88,7 +90,7 @@ index 4e8c35a3a2..d8c7331090 100644 | ||||
|  # @pbs-library-version: Running version of libproxmox-backup-qemu0 library. | ||||
|  # | ||||
|  ## | ||||
| @@ -892,6 +898,7 @@
 | ||||
| @@ -987,6 +993,7 @@
 | ||||
|              'query-bitmap-info': 'bool', | ||||
|              'pbs-dirty-bitmap-savevm': 'bool', | ||||
|              'pbs-dirty-bitmap-migration': 'bool', | ||||
|  | ||||
| @ -17,10 +17,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 14 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/pbs.c b/block/pbs.c
 | ||||
| index 9d1f1f39d4..ce9a870885 100644
 | ||||
| index 43e69ada46..5d20789084 100644
 | ||||
| --- a/block/pbs.c
 | ||||
| +++ b/block/pbs.c
 | ||||
| @@ -200,7 +200,16 @@ static coroutine_fn int pbs_co_preadv(BlockDriverState *bs,
 | ||||
| @@ -201,7 +201,16 @@ static coroutine_fn int pbs_co_preadv(BlockDriverState *bs,
 | ||||
|      BDRVPBSState *s = bs->opaque; | ||||
|      int ret; | ||||
|      char *pbs_error = NULL; | ||||
| @ -38,7 +38,7 @@ index 9d1f1f39d4..ce9a870885 100644 | ||||
|   | ||||
|      if (offset < 0 || bytes < 0) { | ||||
|          fprintf(stderr, "unexpected negative 'offset' or 'bytes' value!\n"); | ||||
| @@ -223,8 +232,10 @@ static coroutine_fn int pbs_co_preadv(BlockDriverState *bs,
 | ||||
| @@ -224,8 +233,10 @@ static coroutine_fn int pbs_co_preadv(BlockDriverState *bs,
 | ||||
|          return -EIO; | ||||
|      } | ||||
|   | ||||
|  | ||||
| @ -11,10 +11,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 1 insertion(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/block/stream.c b/block/stream.c
 | ||||
| index 694709bd25..e09bd5c4ef 100644
 | ||||
| index 7f9e1ecdbb..6a29d80398 100644
 | ||||
| --- a/block/stream.c
 | ||||
| +++ b/block/stream.c
 | ||||
| @@ -28,7 +28,7 @@ enum {
 | ||||
| @@ -27,7 +27,7 @@ enum {
 | ||||
|       * large enough to process multiple clusters in a single call, so | ||||
|       * that populating contiguous regions of the image is efficient. | ||||
|       */ | ||||
|  | ||||
| @ -17,10 +17,10 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 4 insertions(+) | ||||
| 
 | ||||
| diff --git a/block/io.c b/block/io.c
 | ||||
| index b9424024f9..01f50d28c8 100644
 | ||||
| index 2e267a85ab..449a44bf20 100644
 | ||||
| --- a/block/io.c
 | ||||
| +++ b/block/io.c
 | ||||
| @@ -1730,6 +1730,10 @@ static int bdrv_pad_request(BlockDriverState *bs,
 | ||||
| @@ -1576,6 +1576,10 @@ static int bdrv_pad_request(BlockDriverState *bs,
 | ||||
|  { | ||||
|      int ret; | ||||
|   | ||||
|  | ||||
| @ -28,17 +28,17 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|      make error return value consistent with QEMU] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/alloc-track.c | 350 ++++++++++++++++++++++++++++++++++++++++++++ | ||||
|  block/alloc-track.c | 351 ++++++++++++++++++++++++++++++++++++++++++++ | ||||
|  block/meson.build   |   1 + | ||||
|  2 files changed, 351 insertions(+) | ||||
|  2 files changed, 352 insertions(+) | ||||
|  create mode 100644 block/alloc-track.c | ||||
| 
 | ||||
| diff --git a/block/alloc-track.c b/block/alloc-track.c
 | ||||
| new file mode 100644 | ||||
| index 0000000000..43d40d11af
 | ||||
| index 0000000000..113bbd7058
 | ||||
| --- /dev/null
 | ||||
| +++ b/block/alloc-track.c
 | ||||
| @@ -0,0 +1,350 @@
 | ||||
| @@ -0,0 +1,351 @@
 | ||||
| +/*
 | ||||
| + * Node to allow backing images to be applied to any node. Assumes a blank
 | ||||
| + * image to begin with, only new writes are tracked as allocated, thus this
 | ||||
| @ -54,6 +54,7 @@ index 0000000000..43d40d11af | ||||
| +#include "qemu/osdep.h"
 | ||||
| +#include "qapi/error.h"
 | ||||
| +#include "block/block_int.h"
 | ||||
| +#include "block/dirty-bitmap.h"
 | ||||
| +#include "qapi/qmp/qdict.h"
 | ||||
| +#include "qapi/qmp/qstring.h"
 | ||||
| +#include "qemu/cutils.h"
 | ||||
| @ -163,9 +164,9 @@ index 0000000000..43d40d11af | ||||
| +    }
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int64_t track_getlength(BlockDriverState *bs)
 | ||||
| +static coroutine_fn int64_t track_co_getlength(BlockDriverState *bs)
 | ||||
| +{
 | ||||
| +    return bdrv_getlength(bs->file->bs);
 | ||||
| +    return bdrv_co_getlength(bs->file->bs);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static int coroutine_fn track_co_preadv(BlockDriverState *bs,
 | ||||
| @ -365,7 +366,7 @@ index 0000000000..43d40d11af | ||||
| +
 | ||||
| +    .bdrv_file_open                   = track_open,
 | ||||
| +    .bdrv_close                       = track_close,
 | ||||
| +    .bdrv_getlength                   = track_getlength,
 | ||||
| +    .bdrv_co_getlength                = track_co_getlength,
 | ||||
| +    .bdrv_child_perm                  = track_child_perm,
 | ||||
| +    .bdrv_refresh_limits              = track_refresh_limits,
 | ||||
| +
 | ||||
| @ -390,7 +391,7 @@ index 0000000000..43d40d11af | ||||
| +
 | ||||
| +block_init(bdrv_alloc_track_init);
 | ||||
| diff --git a/block/meson.build b/block/meson.build
 | ||||
| index 7ef2fa72d5..15352f579f 100644
 | ||||
| index eece0d5743..8a68162cc0 100644
 | ||||
| --- a/block/meson.build
 | ||||
| +++ b/block/meson.build
 | ||||
| @@ -2,6 +2,7 @@ block_ss.add(genh)
 | ||||
|  | ||||
| @ -11,7 +11,7 @@ Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> | ||||
|  1 file changed, 5 insertions(+) | ||||
| 
 | ||||
| diff --git a/migration/savevm-async.c b/migration/savevm-async.c
 | ||||
| index a38e7351c1..0b1b60c6ae 100644
 | ||||
| index 70273a2996..fab1dc32d2 100644
 | ||||
| --- a/migration/savevm-async.c
 | ||||
| +++ b/migration/savevm-async.c
 | ||||
| @@ -20,6 +20,7 @@
 | ||||
| @ -22,7 +22,7 @@ index a38e7351c1..0b1b60c6ae 100644 | ||||
|   | ||||
|  /* #define DEBUG_SAVEVM_STATE */ | ||||
|   | ||||
| @@ -521,6 +522,10 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp)
 | ||||
| @@ -518,6 +519,10 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp)
 | ||||
|      dirty_bitmap_mig_before_vm_start(); | ||||
|   | ||||
|      qemu_fclose(f); | ||||
|  | ||||
| @ -46,10 +46,10 @@ index b5b0bb4467..36f97e1f19 100644 | ||||
|   | ||||
|  DEF("info", img_info, | ||||
| diff --git a/qemu-img.c b/qemu-img.c
 | ||||
| index 59c403373b..065a54cc42 100644
 | ||||
| index 06d814e39c..e2c06c496d 100644
 | ||||
| --- a/qemu-img.c
 | ||||
| +++ b/qemu-img.c
 | ||||
| @@ -4946,6 +4946,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5002,6 +5002,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|      BlockDriver *drv = NULL, *proto_drv = NULL; | ||||
|      BlockBackend *blk1 = NULL, *blk2 = NULL; | ||||
|      QemuOpts *opts = NULL; | ||||
| @ -57,7 +57,7 @@ index 59c403373b..065a54cc42 100644 | ||||
|      QemuOptsList *create_opts = NULL; | ||||
|      Error *local_err = NULL; | ||||
|      bool image_opts = false; | ||||
| @@ -4955,6 +4956,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5011,6 +5012,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|      int64_t size = 0, readsize = 0; | ||||
|      int64_t out_pos, in_pos; | ||||
|      bool force_share = false, skip_create = false; | ||||
| @ -65,7 +65,7 @@ index 59c403373b..065a54cc42 100644 | ||||
|      struct DdInfo dd = { | ||||
|          .flags = 0, | ||||
|          .count = 0, | ||||
| @@ -4992,7 +4994,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5048,7 +5050,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|          { 0, 0, 0, 0 } | ||||
|      }; | ||||
|   | ||||
| @ -74,7 +74,7 @@ index 59c403373b..065a54cc42 100644 | ||||
|          if (c == EOF) { | ||||
|              break; | ||||
|          } | ||||
| @@ -5015,6 +5017,19 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5071,6 +5073,19 @@ static int img_dd(int argc, char **argv)
 | ||||
|          case 'n': | ||||
|              skip_create = true; | ||||
|              break; | ||||
| @ -94,7 +94,7 @@ index 59c403373b..065a54cc42 100644 | ||||
|          case 'U': | ||||
|              force_share = true; | ||||
|              break; | ||||
| @@ -5074,11 +5089,24 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5130,11 +5145,24 @@ static int img_dd(int argc, char **argv)
 | ||||
|      if (dd.flags & C_IF) { | ||||
|          blk1 = img_open(image_opts, in.filename, fmt, 0, false, false, | ||||
|                          force_share); | ||||
| @ -120,7 +120,7 @@ index 59c403373b..065a54cc42 100644 | ||||
|      } | ||||
|   | ||||
|      if (dd.flags & C_OSIZE) { | ||||
| @@ -5233,6 +5261,7 @@ static int img_dd(int argc, char **argv)
 | ||||
| @@ -5289,6 +5317,7 @@ static int img_dd(int argc, char **argv)
 | ||||
|  out: | ||||
|      g_free(arg); | ||||
|      qemu_opts_del(opts); | ||||
|  | ||||
| @ -4,6 +4,8 @@ Date: Tue, 26 Apr 2022 16:06:28 +0200 | ||||
| Subject: [PATCH] pbs: namespace support | ||||
| 
 | ||||
| Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> | ||||
| [FE: adapt to QAPI change dropping redundant has_*] | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/monitor/block-hmp-cmds.c |  1 + | ||||
|  block/pbs.c                    | 25 +++++++++++++++++++++---- | ||||
| @ -13,22 +15,22 @@ Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> | ||||
|  5 files changed, 47 insertions(+), 9 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index c7468e5d3b..57b2457f1e 100644
 | ||||
| index fb881056e9..25ac598980 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1041,6 +1041,7 @@ void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          false, NULL, // PBS key_password | ||||
|          false, NULL, // PBS master_keyfile | ||||
|          false, NULL, // PBS fingerprint | ||||
| +        false, NULL, // PBS backup-ns
 | ||||
|          false, NULL, // PBS backup-id | ||||
| @@ -1053,6 +1053,7 @@ void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          NULL, // PBS key_password | ||||
|          NULL, // PBS master_keyfile | ||||
|          NULL, // PBS fingerprint | ||||
| +        NULL, // PBS backup-ns
 | ||||
|          NULL, // PBS backup-id | ||||
|          false, 0, // PBS backup-time | ||||
|          false, false, // PBS use-dirty-bitmap | ||||
| diff --git a/block/pbs.c b/block/pbs.c
 | ||||
| index ce9a870885..9192f3e41b 100644
 | ||||
| index 5d20789084..a2211e0f3b 100644
 | ||||
| --- a/block/pbs.c
 | ||||
| +++ b/block/pbs.c
 | ||||
| @@ -14,6 +14,7 @@
 | ||||
| @@ -15,6 +15,7 @@
 | ||||
|  #include <proxmox-backup-qemu.h> | ||||
|   | ||||
|  #define PBS_OPT_REPOSITORY "repository" | ||||
| @ -36,7 +38,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|  #define PBS_OPT_SNAPSHOT "snapshot" | ||||
|  #define PBS_OPT_ARCHIVE "archive" | ||||
|  #define PBS_OPT_KEYFILE "keyfile" | ||||
| @@ -27,6 +28,7 @@ typedef struct {
 | ||||
| @@ -28,6 +29,7 @@ typedef struct {
 | ||||
|      int64_t length; | ||||
|   | ||||
|      char *repository; | ||||
| @ -44,7 +46,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|      char *snapshot; | ||||
|      char *archive; | ||||
|  } BDRVPBSState; | ||||
| @@ -40,6 +42,11 @@ static QemuOptsList runtime_opts = {
 | ||||
| @@ -41,6 +43,11 @@ static QemuOptsList runtime_opts = {
 | ||||
|              .type = QEMU_OPT_STRING, | ||||
|              .help = "The server address and repository to connect to.", | ||||
|          }, | ||||
| @ -56,7 +58,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|          { | ||||
|              .name = PBS_OPT_SNAPSHOT, | ||||
|              .type = QEMU_OPT_STRING, | ||||
| @@ -76,7 +83,7 @@ static QemuOptsList runtime_opts = {
 | ||||
| @@ -77,7 +84,7 @@ static QemuOptsList runtime_opts = {
 | ||||
|   | ||||
|   | ||||
|  // filename format: | ||||
| @ -65,7 +67,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|  static void pbs_parse_filename(const char *filename, QDict *options, | ||||
|                                       Error **errp) | ||||
|  { | ||||
| @@ -112,6 +119,7 @@ static int pbs_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
| @@ -113,6 +120,7 @@ static int pbs_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
|      s->archive = g_strdup(qemu_opt_get(opts, PBS_OPT_ARCHIVE)); | ||||
|      const char *keyfile = qemu_opt_get(opts, PBS_OPT_KEYFILE); | ||||
|      const char *password = qemu_opt_get(opts, PBS_OPT_PASSWORD); | ||||
| @ -73,7 +75,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|      const char *fingerprint = qemu_opt_get(opts, PBS_OPT_FINGERPRINT); | ||||
|      const char *key_password = qemu_opt_get(opts, PBS_OPT_ENCRYPTION_PASSWORD); | ||||
|   | ||||
| @@ -124,9 +132,12 @@ static int pbs_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
| @@ -125,9 +133,12 @@ static int pbs_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
|      if (!key_password) { | ||||
|          key_password = getenv("PBS_ENCRYPTION_PASSWORD"); | ||||
|      } | ||||
| @ -87,7 +89,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|          keyfile, key_password, fingerprint, &pbs_error); | ||||
|   | ||||
|      /* invalidates qemu_opt_get char pointers from above */ | ||||
| @@ -171,6 +182,7 @@ static int pbs_file_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
| @@ -172,6 +183,7 @@ static int pbs_file_open(BlockDriverState *bs, QDict *options, int flags,
 | ||||
|  static void pbs_close(BlockDriverState *bs) { | ||||
|      BDRVPBSState *s = bs->opaque; | ||||
|      g_free(s->repository); | ||||
| @ -95,7 +97,7 @@ index ce9a870885..9192f3e41b 100644 | ||||
|      g_free(s->snapshot); | ||||
|      g_free(s->archive); | ||||
|      proxmox_restore_disconnect(s->conn); | ||||
| @@ -252,8 +264,13 @@ static coroutine_fn int pbs_co_pwritev(BlockDriverState *bs,
 | ||||
| @@ -253,8 +265,13 @@ static coroutine_fn int pbs_co_pwritev(BlockDriverState *bs,
 | ||||
|  static void pbs_refresh_filename(BlockDriverState *bs) | ||||
|  { | ||||
|      BDRVPBSState *s = bs->opaque; | ||||
| @ -170,10 +172,10 @@ index 2f834cf42e..f03d9bab8d 100644 | ||||
|          fprintf(stderr, "restore failed: %s\n", pbs_error); | ||||
|          return -1; | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 4b5134ed27..262e7d3894 100644
 | ||||
| index 504c11657a..809ff6d134 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -10,6 +10,8 @@
 | ||||
| @@ -12,6 +12,8 @@
 | ||||
|  #include "qapi/qmp/qerror.h" | ||||
|  #include "qemu/cutils.h" | ||||
|   | ||||
| @ -182,30 +184,30 @@ index 4b5134ed27..262e7d3894 100644 | ||||
|  /* PVE backup state and related function */ | ||||
|   | ||||
|  /* | ||||
| @@ -531,6 +533,7 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|      bool has_key_password, const char *key_password, | ||||
|      bool has_master_keyfile, const char *master_keyfile, | ||||
|      bool has_fingerprint, const char *fingerprint, | ||||
| +    bool has_backup_ns, const char *backup_ns,
 | ||||
|      bool has_backup_id, const char *backup_id, | ||||
| @@ -533,6 +535,7 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|      const char *key_password, | ||||
|      const char *master_keyfile, | ||||
|      const char *fingerprint, | ||||
| +    const char *backup_ns,
 | ||||
|      const char *backup_id, | ||||
|      bool has_backup_time, int64_t backup_time, | ||||
|      bool has_use_dirty_bitmap, bool use_dirty_bitmap, | ||||
| @@ -670,8 +673,9 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
| @@ -672,8 +675,9 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|          firewall_name = "fw.conf"; | ||||
|   | ||||
|          char *pbs_err = NULL; | ||||
| -        pbs = proxmox_backup_new(
 | ||||
| +        pbs = proxmox_backup_new_ns(
 | ||||
|              backup_file, | ||||
| +            has_backup_ns ? backup_ns : NULL,
 | ||||
| +            backup_ns,
 | ||||
|              backup_id, | ||||
|              backup_time, | ||||
|              dump_cb_block_size, | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index d8c7331090..889726fc26 100644
 | ||||
| index 568feb63ad..9edeb33d82 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -817,6 +817,8 @@
 | ||||
| @@ -912,6 +912,8 @@
 | ||||
|  # | ||||
|  # @fingerprint: server cert fingerprint (optional for format 'pbs') | ||||
|  # | ||||
| @ -214,7 +216,7 @@ index d8c7331090..889726fc26 100644 | ||||
|  # @backup-id: backup ID (required for format 'pbs') | ||||
|  # | ||||
|  # @backup-time: backup timestamp (Unix epoch, required for format 'pbs') | ||||
| @@ -836,6 +838,7 @@
 | ||||
| @@ -931,6 +933,7 @@
 | ||||
|                                      '*key-password': 'str', | ||||
|                                      '*master-keyfile': 'str', | ||||
|                                      '*fingerprint': 'str', | ||||
| @ -222,7 +224,7 @@ index d8c7331090..889726fc26 100644 | ||||
|                                      '*backup-id': 'str', | ||||
|                                      '*backup-time': 'int', | ||||
|                                      '*use-dirty-bitmap': 'bool', | ||||
| @@ -3290,7 +3293,7 @@
 | ||||
| @@ -3385,7 +3388,7 @@
 | ||||
|  { 'struct': 'BlockdevOptionsPbs', | ||||
|    'data': { 'repository': 'str', 'snapshot': 'str', 'archive': 'str', | ||||
|              '*keyfile': 'str', '*password': 'str', '*fingerprint': 'str', | ||||
|  | ||||
| @ -12,10 +12,10 @@ Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 40 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/rbd.c b/block/rbd.c
 | ||||
| index 64a8d7d48b..9fc6dcb957 100644
 | ||||
| index a4749f3b1b..53e0396b51 100644
 | ||||
| --- a/block/rbd.c
 | ||||
| +++ b/block/rbd.c
 | ||||
| @@ -1348,7 +1348,6 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
 | ||||
| @@ -1511,7 +1511,6 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
 | ||||
|      int status, r; | ||||
|      RBDDiffIterateReq req = { .offs = offset }; | ||||
|      uint64_t features, flags; | ||||
| @ -23,7 +23,7 @@ index 64a8d7d48b..9fc6dcb957 100644 | ||||
|   | ||||
|      assert(offset + bytes <= s->image_size); | ||||
|   | ||||
| @@ -1376,43 +1375,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
 | ||||
| @@ -1539,43 +1538,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
 | ||||
|          return status; | ||||
|      } | ||||
|   | ||||
| @ -68,7 +68,7 @@ index 64a8d7d48b..9fc6dcb957 100644 | ||||
|                            qemu_rbd_diff_iterate_cb, &req); | ||||
|      if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) { | ||||
|          return status; | ||||
| @@ -1431,8 +1394,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
 | ||||
| @@ -1594,8 +1557,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
 | ||||
|          status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID; | ||||
|      } | ||||
|   | ||||
|  | ||||
| @ -13,10 +13,10 @@ Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 5 insertions(+), 5 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/rbd.c b/block/rbd.c
 | ||||
| index 9fc6dcb957..98f4ba2620 100644
 | ||||
| index 53e0396b51..0913a0af39 100644
 | ||||
| --- a/block/rbd.c
 | ||||
| +++ b/block/rbd.c
 | ||||
| @@ -1307,11 +1307,11 @@ static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len,
 | ||||
| @@ -1470,11 +1470,11 @@ static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len,
 | ||||
|      RBDDiffIterateReq *req = opaque; | ||||
|   | ||||
|      assert(req->offs + req->bytes <= offs); | ||||
|  | ||||
| @ -23,10 +23,10 @@ Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 112 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/rbd.c b/block/rbd.c
 | ||||
| index 98f4ba2620..efcbbe5949 100644
 | ||||
| index 0913a0af39..1dab254517 100644
 | ||||
| --- a/block/rbd.c
 | ||||
| +++ b/block/rbd.c
 | ||||
| @@ -97,12 +97,6 @@ typedef struct RBDTask {
 | ||||
| @@ -108,12 +108,6 @@ typedef struct RBDTask {
 | ||||
|      int64_t ret; | ||||
|  } RBDTask; | ||||
|   | ||||
| @ -39,7 +39,7 @@ index 98f4ba2620..efcbbe5949 100644 | ||||
|  static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, | ||||
|                              BlockdevOptionsRbd *opts, bool cache, | ||||
|                              const char *keypairs, const char *secretid, | ||||
| @@ -1293,111 +1287,6 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
 | ||||
| @@ -1456,111 +1450,6 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
 | ||||
|      return spec_info; | ||||
|  } | ||||
|   | ||||
| @ -148,10 +148,10 @@ index 98f4ba2620..efcbbe5949 100644 | ||||
| -    return status;
 | ||||
| -}
 | ||||
| -
 | ||||
|  static int64_t qemu_rbd_getlength(BlockDriverState *bs) | ||||
|  static int64_t coroutine_fn qemu_rbd_co_getlength(BlockDriverState *bs) | ||||
|  { | ||||
|      BDRVRBDState *s = bs->opaque; | ||||
| @@ -1633,7 +1522,6 @@ static BlockDriver bdrv_rbd = {
 | ||||
| @@ -1796,7 +1685,6 @@ static BlockDriver bdrv_rbd = {
 | ||||
|  #ifdef LIBRBD_SUPPORTS_WRITE_ZEROES | ||||
|      .bdrv_co_pwrite_zeroes  = qemu_rbd_co_pwrite_zeroes, | ||||
|  #endif | ||||
|  | ||||
| @ -21,10 +21,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 8 insertions(+), 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 262e7d3894..fde3554133 100644
 | ||||
| index 809ff6d134..221e45ed0e 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -503,6 +503,11 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -505,6 +505,11 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|      } | ||||
|   | ||||
|      if (*errp) { | ||||
| @ -36,7 +36,7 @@ index 262e7d3894..fde3554133 100644 | ||||
|          l = backup_state.di_list; | ||||
|          while (l) { | ||||
|              PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; | ||||
| @@ -513,11 +518,11 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -515,11 +520,11 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|                  di->target = NULL; | ||||
|              } | ||||
|   | ||||
| @ -50,7 +50,7 @@ index 262e7d3894..fde3554133 100644 | ||||
|              } | ||||
|          } | ||||
|      } | ||||
| @@ -943,6 +948,7 @@ err:
 | ||||
| @@ -945,6 +950,7 @@ err:
 | ||||
|   | ||||
|      if (pbs) { | ||||
|          proxmox_backup_disconnect(pbs); | ||||
|  | ||||
| @ -23,10 +23,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 19 insertions(+), 3 deletions(-) | ||||
| 
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index fde3554133..0cf30e1ced 100644
 | ||||
| index 221e45ed0e..a20fa38ee8 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -316,6 +316,13 @@ static void coroutine_fn pvebackup_co_complete_stream(void *opaque)
 | ||||
| @@ -318,6 +318,13 @@ static void coroutine_fn pvebackup_co_complete_stream(void *opaque)
 | ||||
|          } | ||||
|      } | ||||
|   | ||||
| @ -40,7 +40,7 @@ index fde3554133..0cf30e1ced 100644 | ||||
|      // remove self from job list | ||||
|      backup_state.di_list = g_list_remove(backup_state.di_list, di); | ||||
|   | ||||
| @@ -491,6 +498,11 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -493,6 +500,11 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|          aio_context_release(aio_context); | ||||
|   | ||||
|          di->job = job; | ||||
| @ -52,7 +52,7 @@ index fde3554133..0cf30e1ced 100644 | ||||
|   | ||||
|          if (!job || local_err) { | ||||
|              error_setg(errp, "backup_job_create failed: %s", | ||||
| @@ -518,11 +530,15 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -520,11 +532,15 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|                  di->target = NULL; | ||||
|              } | ||||
|   | ||||
|  | ||||
| @ -39,10 +39,10 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 38 insertions(+), 19 deletions(-) | ||||
| 
 | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 0cf30e1ced..4067018dbe 100644
 | ||||
| index a20fa38ee8..3509f46ed8 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -354,12 +354,41 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
| @@ -356,12 +356,41 @@ static void pvebackup_complete_cb(void *opaque, int ret)
 | ||||
|   | ||||
|  /* | ||||
|   * job_cancel(_sync) does not like to be called from coroutines, so defer to | ||||
| @ -87,7 +87,7 @@ index 0cf30e1ced..4067018dbe 100644 | ||||
|      aio_co_enter(data->ctx, data->co); | ||||
|  } | ||||
|   | ||||
| @@ -380,22 +409,12 @@ void coroutine_fn qmp_backup_cancel(Error **errp)
 | ||||
| @@ -382,22 +411,12 @@ void coroutine_fn qmp_backup_cancel(Error **errp)
 | ||||
|          proxmox_backup_abort(backup_state.pbs, "backup canceled"); | ||||
|      } | ||||
|   | ||||
|  | ||||
| @ -21,10 +21,10 @@ Signed-off-by: Fabian Ebner <f.ebner@proxmox.com> | ||||
|  1 file changed, 2 insertions(+), 1 deletion(-) | ||||
| 
 | ||||
| diff --git a/block/alloc-track.c b/block/alloc-track.c
 | ||||
| index 43d40d11af..95c9c67cd8 100644
 | ||||
| index 113bbd7058..b75d7c6460 100644
 | ||||
| --- a/block/alloc-track.c
 | ||||
| +++ b/block/alloc-track.c
 | ||||
| @@ -174,7 +174,8 @@ static int coroutine_fn track_co_preadv(BlockDriverState *bs,
 | ||||
| @@ -175,7 +175,8 @@ static int coroutine_fn track_co_preadv(BlockDriverState *bs,
 | ||||
|              ret = bdrv_co_preadv(bs->backing, local_offset, local_bytes, | ||||
|                                   &local_qiov, flags); | ||||
|          } else { | ||||
|  | ||||
| @ -31,13 +31,13 @@ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
|  3 files changed, 23 insertions(+), 8 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
 | ||||
| index 57b2457f1e..ab0c988ae9 100644
 | ||||
| index 25ac598980..74e43a757f 100644
 | ||||
| --- a/block/monitor/block-hmp-cmds.c
 | ||||
| +++ b/block/monitor/block-hmp-cmds.c
 | ||||
| @@ -1049,7 +1049,9 @@ void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
| @@ -1061,7 +1061,9 @@ void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
 | ||||
|          false, false, // PBS encrypt | ||||
|          true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, | ||||
|          false, NULL, false, NULL, !!devlist, | ||||
|          NULL, NULL, | ||||
| -        devlist, qdict_haskey(qdict, "speed"), speed, &error);
 | ||||
| +        devlist, qdict_haskey(qdict, "speed"), speed,
 | ||||
| +        false, 0, // BackupPerf max-workers
 | ||||
| @ -46,10 +46,10 @@ index 57b2457f1e..ab0c988ae9 100644 | ||||
|      hmp_handle_error(mon, error); | ||||
|  } | ||||
| diff --git a/pve-backup.c b/pve-backup.c
 | ||||
| index 4067018dbe..3ca4f74cb8 100644
 | ||||
| index 3509f46ed8..a343d63586 100644
 | ||||
| --- a/pve-backup.c
 | ||||
| +++ b/pve-backup.c
 | ||||
| @@ -55,6 +55,7 @@ static struct PVEBackupState {
 | ||||
| @@ -57,6 +57,7 @@ static struct PVEBackupState {
 | ||||
|          bool starting; | ||||
|      } stat; | ||||
|      int64_t speed; | ||||
| @ -57,7 +57,7 @@ index 4067018dbe..3ca4f74cb8 100644 | ||||
|      VmaWriter *vmaw; | ||||
|      ProxmoxBackupHandle *pbs; | ||||
|      GList *di_list; | ||||
| @@ -490,8 +491,6 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -492,8 +493,6 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|      } | ||||
|      backup_state.txn = job_txn_new_seq(); | ||||
|   | ||||
| @ -66,7 +66,7 @@ index 4067018dbe..3ca4f74cb8 100644 | ||||
|      /* create and start all jobs (paused state) */ | ||||
|      GList *l =  backup_state.di_list; | ||||
|      while (l) { | ||||
| @@ -511,8 +510,9 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
| @@ -513,8 +512,9 @@ static void create_backup_jobs_bh(void *opaque) {
 | ||||
|   | ||||
|          BlockJob *job = backup_job_create( | ||||
|              NULL, di->bs, di->target, backup_state.speed, sync_mode, di->bitmap, | ||||
| @ -78,10 +78,10 @@ index 4067018dbe..3ca4f74cb8 100644 | ||||
|   | ||||
|          aio_context_release(aio_context); | ||||
|   | ||||
| @@ -583,7 +583,9 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|      bool has_config_file, const char *config_file, | ||||
|      bool has_firewall_file, const char *firewall_file, | ||||
|      bool has_devlist, const char *devlist, | ||||
| @@ -585,7 +585,9 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|      const char *config_file, | ||||
|      const char *firewall_file, | ||||
|      const char *devlist, | ||||
| -    bool has_speed, int64_t speed, Error **errp)
 | ||||
| +    bool has_speed, int64_t speed,
 | ||||
| +    bool has_max_workers, int64_t max_workers,
 | ||||
| @ -89,7 +89,7 @@ index 4067018dbe..3ca4f74cb8 100644 | ||||
|  { | ||||
|      assert(qemu_in_coroutine()); | ||||
|   | ||||
| @@ -913,6 +915,11 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
| @@ -915,6 +917,11 @@ UuidInfo coroutine_fn *qmp_backup(
 | ||||
|   | ||||
|      backup_state.speed = (has_speed && speed > 0) ? speed : 0; | ||||
|   | ||||
| @ -101,7 +101,7 @@ index 4067018dbe..3ca4f74cb8 100644 | ||||
|      backup_state.vmaw = vmaw; | ||||
|      backup_state.pbs = pbs; | ||||
|   | ||||
| @@ -1088,5 +1095,6 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | ||||
| @@ -1086,5 +1093,6 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp)
 | ||||
|      ret->pbs_dirty_bitmap_migration = true; | ||||
|      ret->query_bitmap_info = true; | ||||
|      ret->pbs_masterkey = true; | ||||
| @ -109,10 +109,10 @@ index 4067018dbe..3ca4f74cb8 100644 | ||||
|      return ret; | ||||
|  } | ||||
| diff --git a/qapi/block-core.json b/qapi/block-core.json
 | ||||
| index 889726fc26..65795b7204 100644
 | ||||
| index 9edeb33d82..809f3c61bc 100644
 | ||||
| --- a/qapi/block-core.json
 | ||||
| +++ b/qapi/block-core.json
 | ||||
| @@ -829,6 +829,8 @@
 | ||||
| @@ -924,6 +924,8 @@
 | ||||
|  # | ||||
|  # @encrypt: use encryption ((optional for format 'pbs', defaults to true if there is a keyfile) | ||||
|  # | ||||
| @ -121,7 +121,7 @@ index 889726fc26..65795b7204 100644 | ||||
|  # Returns: the uuid of the backup job | ||||
|  # | ||||
|  ## | ||||
| @@ -847,7 +849,9 @@
 | ||||
| @@ -942,7 +944,9 @@
 | ||||
|                                      '*format': 'BackupFormat', | ||||
|                                      '*config-file': 'str', | ||||
|                                      '*firewall-file': 'str', | ||||
| @ -132,7 +132,7 @@ index 889726fc26..65795b7204 100644 | ||||
|    'returns': 'UuidInfo', 'coroutine': true } | ||||
|   | ||||
|  ## | ||||
| @@ -902,7 +906,8 @@
 | ||||
| @@ -997,7 +1001,8 @@
 | ||||
|              'pbs-dirty-bitmap-savevm': 'bool', | ||||
|              'pbs-dirty-bitmap-migration': 'bool', | ||||
|              'pbs-masterkey': 'bool', | ||||
|  | ||||
							
								
								
									
										153
									
								
								debian/patches/pve/0063-alloc-track-fix-deadlock-during-drop.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								debian/patches/pve/0063-alloc-track-fix-deadlock-during-drop.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Fiona Ebner <f.ebner@proxmox.com> | ||||
| Date: Thu, 6 Apr 2023 14:59:31 +0200 | ||||
| Subject: [PATCH] alloc-track: fix deadlock during drop | ||||
| 
 | ||||
| by replacing the block node directly after changing the backing file | ||||
| instead of rescheduling it. | ||||
| 
 | ||||
| With changes in QEMU 8.0, calling bdrv_get_info (and bdrv_unref) | ||||
| during drop can lead to a deadlock when using iothread (only triggered | ||||
| with multiple disks, except during debugging where it also triggered | ||||
| with one disk sometimes): | ||||
| 1. job_unref_locked acquires the AioContext and calls job->driver->free | ||||
| 2. track_drop gets scheduled | ||||
| 3. bdrv_graph_wrlock is called and polls which leads to track_drop being | ||||
|    called | ||||
| 4. track_drop acquires the AioContext recursively | ||||
| 5. bdrv_get_info is a wrapped coroutine (since 8.0) and thus polls for | ||||
|    bdrv_co_get_info. This releases the AioContext, but only once! The | ||||
|    documentation for the AIO_WAIT_WHILE macro states that the | ||||
|    AioContext lock needs to be acquired exactly once, but there does | ||||
|    not seem to be a way for track_drop to know if it acquired the lock | ||||
|    recursively or not (without adding further hacks). | ||||
| 6. Because the AioContext is still held by the main thread once, it can't | ||||
|    be acquired before entering bdrv_co_get_info in co_schedule_bh_cb | ||||
|    which happens in the iothread | ||||
| 
 | ||||
| When doing the operation in change_backing_file, the AioContext has | ||||
| already been acquired by the caller, so the issue with the recursive | ||||
| lock goes away. | ||||
| 
 | ||||
| The comment explaining why delaying the replace is necessary is | ||||
| > we need to schedule this for later however, since when this function
 | ||||
| > is called, the blockjob modifying us is probably not done yet and
 | ||||
| > has a blocker on 'bs'
 | ||||
| 
 | ||||
| However, there is no check for blockers in bdrv_replace_node. It would | ||||
| need to be done by us, the caller, with check_to_replace_node. | ||||
| Furthermore, the mirror job also does its call to bdrv_replace_node | ||||
| while there is an active blocker (inserted by mirror itself) and they | ||||
| use a specialized version to check for blockers instead of | ||||
| check_to_replace_node there. Alloc-track could also do something | ||||
| similar to check for other blockers, but it should be fine to rely on | ||||
| Proxmox VE that no other operation with the blockdev is going on. | ||||
| 
 | ||||
| Mirror also drains the target before replacing the node, but the | ||||
| target can have other users. In case of alloc-track the file child | ||||
| should not be accessible by anybody else and so there can't be an | ||||
| in-flight operation for the file child when alloc-track is drained. | ||||
| 
 | ||||
| The rescheduling based on refcounting is a hack and it doesn't seem to | ||||
| be necessary anymore. It's not clear what the original issue from the | ||||
| comment was. Testing with older builds with track_drop done directly | ||||
| without rescheduling also didn't lead to any noticable issue for me. | ||||
| 
 | ||||
| One issue it might have been is the one fixed by b1e1af394d | ||||
| ("block/stream: Drain subtree around graph change"), where | ||||
| block-stream had a use-after-free if the base node changed at an | ||||
| inconvenient time (which alloc-track's auto-drop does). | ||||
| 
 | ||||
| It's also not possible to just not auto-replace the alloc-track. Not | ||||
| replacing it at all leads to other operations like block resize | ||||
| hanging, and there is no good way to replace it manually via QMP | ||||
| (there is x-blockdev-change, but it is experimental and doesn't | ||||
| implement the required operation yet). Also, it's just cleaner in | ||||
| general to not leave unnecessary block nodes lying around. | ||||
| 
 | ||||
| Suggested-by: Wolfgang Bumiller <w.bumiller@proxmox.com> | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  block/alloc-track.c | 54 ++++++++++++++------------------------------- | ||||
|  1 file changed, 16 insertions(+), 38 deletions(-) | ||||
| 
 | ||||
| diff --git a/block/alloc-track.c b/block/alloc-track.c
 | ||||
| index b75d7c6460..76da140a68 100644
 | ||||
| --- a/block/alloc-track.c
 | ||||
| +++ b/block/alloc-track.c
 | ||||
| @@ -25,7 +25,6 @@
 | ||||
|   | ||||
|  typedef enum DropState { | ||||
|      DropNone, | ||||
| -    DropRequested,
 | ||||
|      DropInProgress, | ||||
|  } DropState; | ||||
|   | ||||
| @@ -268,37 +267,6 @@ static void track_child_perm(BlockDriverState *bs, BdrvChild *c,
 | ||||
|      } | ||||
|  } | ||||
|   | ||||
| -static void track_drop(void *opaque)
 | ||||
| -{
 | ||||
| -    BlockDriverState *bs = (BlockDriverState*)opaque;
 | ||||
| -    BlockDriverState *file = bs->file->bs;
 | ||||
| -    BDRVAllocTrackState *s = bs->opaque;
 | ||||
| -
 | ||||
| -    assert(file);
 | ||||
| -
 | ||||
| -    /* we rely on the fact that we're not used anywhere else, so let's wait
 | ||||
| -     * until we're only used once - in the drive connected to the guest (and one
 | ||||
| -     * ref is held by bdrv_ref in track_change_backing_file) */
 | ||||
| -    if (bs->refcnt > 2) {
 | ||||
| -        aio_bh_schedule_oneshot(qemu_get_aio_context(), track_drop, opaque);
 | ||||
| -        return;
 | ||||
| -    }
 | ||||
| -    AioContext *aio_context = bdrv_get_aio_context(bs);
 | ||||
| -    aio_context_acquire(aio_context);
 | ||||
| -
 | ||||
| -    bdrv_drained_begin(bs);
 | ||||
| -
 | ||||
| -    /* now that we're drained, we can safely set 'DropInProgress' */
 | ||||
| -    s->drop_state = DropInProgress;
 | ||||
| -    bdrv_child_refresh_perms(bs, bs->file, &error_abort);
 | ||||
| -
 | ||||
| -    bdrv_replace_node(bs, file, &error_abort);
 | ||||
| -    bdrv_set_backing_hd(bs, NULL, &error_abort);
 | ||||
| -    bdrv_drained_end(bs);
 | ||||
| -    bdrv_unref(bs);
 | ||||
| -    aio_context_release(aio_context);
 | ||||
| -}
 | ||||
| -
 | ||||
|  static int track_change_backing_file(BlockDriverState *bs, | ||||
|                                       const char *backing_file, | ||||
|                                       const char *backing_fmt) | ||||
| @@ -308,13 +276,23 @@ static int track_change_backing_file(BlockDriverState *bs,
 | ||||
|          backing_file == NULL && backing_fmt == NULL) | ||||
|      { | ||||
|          /* backing file has been disconnected, there's no longer any use for | ||||
| -         * this node, so let's remove ourselves from the block graph - we need
 | ||||
| -         * to schedule this for later however, since when this function is
 | ||||
| -         * called, the blockjob modifying us is probably not done yet and has a
 | ||||
| -         * blocker on 'bs' */
 | ||||
| -        s->drop_state = DropRequested;
 | ||||
| +         * this node, so let's remove ourselves from the block graph */
 | ||||
| +        BlockDriverState *file = bs->file->bs;
 | ||||
| +
 | ||||
| +        /* Just to be sure, because bdrv_replace_node unrefs it */
 | ||||
|          bdrv_ref(bs); | ||||
| -        aio_bh_schedule_oneshot(qemu_get_aio_context(), track_drop, (void*)bs);
 | ||||
| +        bdrv_drained_begin(bs);
 | ||||
| +
 | ||||
| +        /* now that we're drained, we can safely set 'DropInProgress' */
 | ||||
| +        s->drop_state = DropInProgress;
 | ||||
| +
 | ||||
| +        bdrv_child_refresh_perms(bs, bs->file, &error_abort);
 | ||||
| +
 | ||||
| +        bdrv_replace_node(bs, file, &error_abort);
 | ||||
| +        bdrv_set_backing_hd(bs, NULL, &error_abort);
 | ||||
| +
 | ||||
| +        bdrv_drained_end(bs);
 | ||||
| +        bdrv_unref(bs);
 | ||||
|      } | ||||
|   | ||||
|      return 0; | ||||
							
								
								
									
										49
									
								
								debian/patches/pve/0064-savevm-async-optimize-querying-pending.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								debian/patches/pve/0064-savevm-async-optimize-querying-pending.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Fiona Ebner <f.ebner@proxmox.com> | ||||
| Date: Fri, 31 Mar 2023 14:13:01 +0200 | ||||
| Subject: [PATCH] savevm-async: optimize querying pending | ||||
| 
 | ||||
| by using the estimate variant until the precopy estimate is below the | ||||
| threshold. This is similar to what is done in migration.c | ||||
| 
 | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  migration/savevm-async.c | 15 +++++++++++---- | ||||
|  1 file changed, 11 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/migration/savevm-async.c b/migration/savevm-async.c
 | ||||
| index fab1dc32d2..de91506821 100644
 | ||||
| --- a/migration/savevm-async.c
 | ||||
| +++ b/migration/savevm-async.c
 | ||||
| @@ -242,12 +242,19 @@ static void coroutine_fn process_savevm_co(void *opaque)
 | ||||
|   | ||||
|      while (snap_state.state == SAVE_STATE_ACTIVE) { | ||||
|          uint64_t pending_size, pend_precopy, pend_postcopy; | ||||
| +        uint64_t threshold = 400 * 1000;
 | ||||
|   | ||||
| -        /* pending is expected to be called without iothread lock */
 | ||||
| +        /*
 | ||||
| +         * pending_{estimate,exact} are expected to be called without iothread
 | ||||
| +         * lock. Similar to what is done in migration.c, call the exact variant
 | ||||
| +         * only once pend_precopy in the estimate is below the threshold.
 | ||||
| +         */
 | ||||
|          qemu_mutex_unlock_iothread(); | ||||
| -        qemu_savevm_state_pending_exact(&pend_precopy, &pend_postcopy);
 | ||||
| +        qemu_savevm_state_pending_estimate(&pend_precopy, &pend_postcopy);
 | ||||
| +        if (pend_precopy <= threshold) {
 | ||||
| +            qemu_savevm_state_pending_exact(&pend_precopy, &pend_postcopy);
 | ||||
| +        }
 | ||||
|          qemu_mutex_lock_iothread(); | ||||
| -
 | ||||
|          pending_size = pend_precopy + pend_postcopy; | ||||
|   | ||||
|          /* | ||||
| @@ -259,7 +266,7 @@ static void coroutine_fn process_savevm_co(void *opaque)
 | ||||
|          maxlen = blk_getlength(snap_state.target) - 100*1024*1024; | ||||
|   | ||||
|          /* Note that there is no progress for pend_postcopy when iterating */ | ||||
| -        if (pending_size - pend_postcopy > 400000 && snap_state.bs_pos + pending_size < maxlen) {
 | ||||
| +        if (pend_precopy > threshold && snap_state.bs_pos + pending_size < maxlen) {
 | ||||
|              ret = qemu_savevm_state_iterate(snap_state.file, false); | ||||
|              if (ret < 0) { | ||||
|                  save_snapshot_error("qemu_savevm_state_iterate error %d", ret); | ||||
							
								
								
									
										26
									
								
								debian/patches/pve/0065-savevm-async-also-initialize-compression-counters.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								debian/patches/pve/0065-savevm-async-also-initialize-compression-counters.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Fiona Ebner <f.ebner@proxmox.com> | ||||
| Date: Thu, 27 Apr 2023 10:28:08 +0200 | ||||
| Subject: [PATCH] savevm-async: also initialize compression counters | ||||
| 
 | ||||
| Like is done in the migration code. While the compression migration | ||||
| capability is not used by Proxmox VE currently, it's still worth to | ||||
| be prepared for the future. | ||||
| 
 | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  migration/savevm-async.c | 1 + | ||||
|  1 file changed, 1 insertion(+) | ||||
| 
 | ||||
| diff --git a/migration/savevm-async.c b/migration/savevm-async.c
 | ||||
| index de91506821..effe6d1e0d 100644
 | ||||
| --- a/migration/savevm-async.c
 | ||||
| +++ b/migration/savevm-async.c
 | ||||
| @@ -394,6 +394,7 @@ void qmp_savevm_start(const char *statefile, Error **errp)
 | ||||
|       */ | ||||
|      migrate_init(ms); | ||||
|      memset(&ram_counters, 0, sizeof(ram_counters)); | ||||
| +    memset(&compression_counters, 0, sizeof(compression_counters));
 | ||||
|      ms->to_dst_file = snap_state.file; | ||||
|   | ||||
|      error_setg(&snap_state.blocker, "block device is in use by savevm"); | ||||
							
								
								
									
										190
									
								
								debian/patches/pve/0066-migration-for-snapshots-hold-the-BQL-during-setup-ca.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								debian/patches/pve/0066-migration-for-snapshots-hold-the-BQL-during-setup-ca.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,190 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Fiona Ebner <f.ebner@proxmox.com> | ||||
| Date: Fri, 5 May 2023 13:39:53 +0200 | ||||
| Subject: [PATCH] migration: for snapshots, hold the BQL during setup callbacks | ||||
| 
 | ||||
| In spirit, this is a partial revert of commit 9b09503752 ("migration: | ||||
| run setup callbacks out of big lock"), but only for the snapshot case. | ||||
| 
 | ||||
| For snapshots, the bdrv_writev_vmstate() function is used during setup | ||||
| (in QIOChannelBlock backing the QEMUFile), but not holding the BQL | ||||
| while calling it could lead to an assertion failure. To understand | ||||
| how, first note the following: | ||||
| 
 | ||||
| 1. Generated coroutine wrappers for block layer functions spawn the | ||||
| coroutine and use AIO_WAIT_WHILE()/aio_poll() to wait for it. | ||||
| 2. If the host OS switches threads at an inconvenient time, it can | ||||
| happen that a bottom half scheduled for the main thread's AioContext | ||||
| is executed as part of a vCPU thread's aio_poll(). | ||||
| 
 | ||||
| An example leading to the assertion failure is as follows: | ||||
| 
 | ||||
| main thread: | ||||
| 1. A snapshot-save QMP command gets issued. | ||||
| 2. snapshot_save_job_bh() is scheduled. | ||||
| 
 | ||||
| vCPU thread: | ||||
| 3. aio_poll() for the main thread's AioContext is called (e.g. when | ||||
| the guest writes to a pflash device, as part of blk_pwrite which is a | ||||
| generated coroutine wrapper). | ||||
| 4. snapshot_save_job_bh() is executed as part of aio_poll(). | ||||
| 3. qemu_savevm_state() is called. | ||||
| 4. qemu_mutex_unlock_iothread() is called. Now | ||||
| qemu_get_current_aio_context() returns 0x0. | ||||
| 5. bdrv_writev_vmstate() is executed during the usual savevm setup. | ||||
| But this function is a generated coroutine wrapper, so it uses | ||||
| AIO_WAIT_WHILE. There, the assertion | ||||
| assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||||
| will fail. | ||||
| 
 | ||||
| To fix it, ensure that the BQL is held during setup. To avoid changing | ||||
| the behavior for migration too, introduce conditionals for the setup | ||||
| callbacks that need the BQL and only take the lock if it's not already | ||||
| held. | ||||
| 
 | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  include/migration/register.h   |  2 +- | ||||
|  migration/block-dirty-bitmap.c | 15 ++++++++++++--- | ||||
|  migration/block.c              | 15 ++++++++++++--- | ||||
|  migration/ram.c                | 16 +++++++++++++--- | ||||
|  migration/savevm.c             |  2 -- | ||||
|  5 files changed, 38 insertions(+), 12 deletions(-) | ||||
| 
 | ||||
| diff --git a/include/migration/register.h b/include/migration/register.h
 | ||||
| index a8dfd8fefd..fa9b0b0f10 100644
 | ||||
| --- a/include/migration/register.h
 | ||||
| +++ b/include/migration/register.h
 | ||||
| @@ -43,9 +43,9 @@ typedef struct SaveVMHandlers {
 | ||||
|       * by other locks. | ||||
|       */ | ||||
|      int (*save_live_iterate)(QEMUFile *f, void *opaque); | ||||
| +    int (*save_setup)(QEMUFile *f, void *opaque);
 | ||||
|   | ||||
|      /* This runs outside the iothread lock!  */ | ||||
| -    int (*save_setup)(QEMUFile *f, void *opaque);
 | ||||
|      /* Note for save_live_pending: | ||||
|       * must_precopy: | ||||
|       * - must be migrated in precopy or in stopped state | ||||
| diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
 | ||||
| index a6440929fa..69fab3275c 100644
 | ||||
| --- a/migration/block-dirty-bitmap.c
 | ||||
| +++ b/migration/block-dirty-bitmap.c
 | ||||
| @@ -1214,10 +1214,17 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque)
 | ||||
|  { | ||||
|      DBMSaveState *s = &((DBMState *)opaque)->save; | ||||
|      SaveBitmapState *dbms = NULL; | ||||
| +    bool release_lock = false;
 | ||||
|   | ||||
| -    qemu_mutex_lock_iothread();
 | ||||
| +    /* For snapshots, the BQL is held during setup. */
 | ||||
| +    if (!qemu_mutex_iothread_locked()) {
 | ||||
| +        qemu_mutex_lock_iothread();
 | ||||
| +        release_lock = true;
 | ||||
| +    }
 | ||||
|      if (init_dirty_bitmap_migration(s) < 0) { | ||||
| -        qemu_mutex_unlock_iothread();
 | ||||
| +        if (release_lock) {
 | ||||
| +            qemu_mutex_unlock_iothread();
 | ||||
| +        }
 | ||||
|          return -1; | ||||
|      } | ||||
|   | ||||
| @@ -1225,7 +1232,9 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque)
 | ||||
|          send_bitmap_start(f, s, dbms); | ||||
|      } | ||||
|      qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS); | ||||
| -    qemu_mutex_unlock_iothread();
 | ||||
| +    if (release_lock) {
 | ||||
| +        qemu_mutex_unlock_iothread();
 | ||||
| +    }
 | ||||
|      return 0; | ||||
|  } | ||||
|   | ||||
| diff --git a/migration/block.c b/migration/block.c
 | ||||
| index b2497bbd32..c9d55be642 100644
 | ||||
| --- a/migration/block.c
 | ||||
| +++ b/migration/block.c
 | ||||
| @@ -716,21 +716,30 @@ static void block_migration_cleanup(void *opaque)
 | ||||
|  static int block_save_setup(QEMUFile *f, void *opaque) | ||||
|  { | ||||
|      int ret; | ||||
| +    bool release_lock = false;
 | ||||
|   | ||||
|      trace_migration_block_save("setup", block_mig_state.submitted, | ||||
|                                 block_mig_state.transferred); | ||||
|   | ||||
| -    qemu_mutex_lock_iothread();
 | ||||
| +    /* For snapshots, the BQL is held during setup. */
 | ||||
| +    if (!qemu_mutex_iothread_locked()) {
 | ||||
| +        qemu_mutex_lock_iothread();
 | ||||
| +        release_lock = true;
 | ||||
| +    }
 | ||||
|      ret = init_blk_migration(f); | ||||
|      if (ret < 0) { | ||||
| -        qemu_mutex_unlock_iothread();
 | ||||
| +        if (release_lock) {
 | ||||
| +            qemu_mutex_unlock_iothread();
 | ||||
| +        }
 | ||||
|          return ret; | ||||
|      } | ||||
|   | ||||
|      /* start track dirty blocks */ | ||||
|      ret = set_dirty_tracking(); | ||||
|   | ||||
| -    qemu_mutex_unlock_iothread();
 | ||||
| +    if (release_lock) {
 | ||||
| +        qemu_mutex_unlock_iothread();
 | ||||
| +    }
 | ||||
|   | ||||
|      if (ret) { | ||||
|          return ret; | ||||
| diff --git a/migration/ram.c b/migration/ram.c
 | ||||
| index 79d881f735..0ecbbc3202 100644
 | ||||
| --- a/migration/ram.c
 | ||||
| +++ b/migration/ram.c
 | ||||
| @@ -3117,8 +3117,16 @@ static void migration_bitmap_clear_discarded_pages(RAMState *rs)
 | ||||
|   | ||||
|  static void ram_init_bitmaps(RAMState *rs) | ||||
|  { | ||||
| -    /* For memory_global_dirty_log_start below.  */
 | ||||
| -    qemu_mutex_lock_iothread();
 | ||||
| +    bool release_lock = false;
 | ||||
| +
 | ||||
| +    /*
 | ||||
| +     * For memory_global_dirty_log_start below.
 | ||||
| +     * For snapshots, the BQL is held during setup.
 | ||||
| +     */
 | ||||
| +    if (!qemu_mutex_iothread_locked()) {
 | ||||
| +        qemu_mutex_lock_iothread();
 | ||||
| +        release_lock = true;
 | ||||
| +    }
 | ||||
|      qemu_mutex_lock_ramlist(); | ||||
|   | ||||
|      WITH_RCU_READ_LOCK_GUARD() { | ||||
| @@ -3130,7 +3138,9 @@ static void ram_init_bitmaps(RAMState *rs)
 | ||||
|          } | ||||
|      } | ||||
|      qemu_mutex_unlock_ramlist(); | ||||
| -    qemu_mutex_unlock_iothread();
 | ||||
| +    if (release_lock) {
 | ||||
| +        qemu_mutex_unlock_iothread();
 | ||||
| +    }
 | ||||
|   | ||||
|      /* | ||||
|       * After an eventual first bitmap sync, fixup the initial bitmap | ||||
| diff --git a/migration/savevm.c b/migration/savevm.c
 | ||||
| index aa54a67fda..fc6a82a555 100644
 | ||||
| --- a/migration/savevm.c
 | ||||
| +++ b/migration/savevm.c
 | ||||
| @@ -1621,10 +1621,8 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
 | ||||
|      memset(&compression_counters, 0, sizeof(compression_counters)); | ||||
|      ms->to_dst_file = f; | ||||
|   | ||||
| -    qemu_mutex_unlock_iothread();
 | ||||
|      qemu_savevm_state_header(f); | ||||
|      qemu_savevm_state_setup(f); | ||||
| -    qemu_mutex_lock_iothread();
 | ||||
|   | ||||
|      while (qemu_file_get_error(f) == 0) { | ||||
|          if (qemu_savevm_state_iterate(f, false) > 0) { | ||||
							
								
								
									
										29
									
								
								debian/patches/pve/0067-savevm-async-don-t-hold-BQL-during-setup.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								debian/patches/pve/0067-savevm-async-don-t-hold-BQL-during-setup.patch
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Fiona Ebner <f.ebner@proxmox.com> | ||||
| Date: Fri, 5 May 2023 15:30:16 +0200 | ||||
| Subject: [PATCH] savevm-async: don't hold BQL during setup | ||||
| 
 | ||||
| See commit "migration: for snapshots, hold the BQL during setup | ||||
| callbacks" for why. This is separate, because a version of that one | ||||
| will hopefully land upstream. | ||||
| 
 | ||||
| Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||||
| ---
 | ||||
|  migration/savevm-async.c | 2 -- | ||||
|  1 file changed, 2 deletions(-) | ||||
| 
 | ||||
| diff --git a/migration/savevm-async.c b/migration/savevm-async.c
 | ||||
| index effe6d1e0d..f006a8e4d4 100644
 | ||||
| --- a/migration/savevm-async.c
 | ||||
| +++ b/migration/savevm-async.c
 | ||||
| @@ -403,10 +403,8 @@ void qmp_savevm_start(const char *statefile, Error **errp)
 | ||||
|      snap_state.state = SAVE_STATE_ACTIVE; | ||||
|      snap_state.finalize_bh = qemu_bh_new(process_savevm_finalize, &snap_state); | ||||
|      snap_state.co = qemu_coroutine_create(&process_savevm_co, NULL); | ||||
| -    qemu_mutex_unlock_iothread();
 | ||||
|      qemu_savevm_state_header(snap_state.file); | ||||
|      qemu_savevm_state_setup(snap_state.file); | ||||
| -    qemu_mutex_lock_iothread();
 | ||||
|   | ||||
|      /* Async processing from here on out happens in iohandler context, so let | ||||
|       * the target bdrv have its home there. | ||||
							
								
								
									
										37
									
								
								debian/patches/series
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								debian/patches/series
									
									
									
									
										vendored
									
									
								
							| @ -1,31 +1,9 @@ | ||||
| extra/0001-monitor-qmp-fix-race-with-clients-disconnecting-earl.patch | ||||
| extra/0002-init-daemonize-defuse-PID-file-resolve-error.patch | ||||
| extra/0003-virtio-mem-Fix-the-bitmap-index-of-the-section-offse.patch | ||||
| extra/0004-virtio-mem-Fix-the-iterator-variable-in-a-vmem-rdl_l.patch | ||||
| extra/0005-vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch | ||||
| extra/0006-virtio-rng-pci-fix-migration-compat-for-vectors.patch | ||||
| extra/0007-block-fix-detect-zeroes-with-BDRV_REQ_REGISTERED_BUF.patch | ||||
| extra/0008-memory-prevent-dma-reentracy-issues.patch | ||||
| extra/0009-block-iscsi-fix-double-free-on-BUSY-or-similar-statu.patch | ||||
| extra/0010-scsi-megasas-Internal-cdbs-have-16-byte-length.patch | ||||
| extra/0011-ide-avoid-potential-deadlock-when-draining-during-tr.patch | ||||
| extra/0012-hw-nvme-fix-missing-endian-conversions-for-doorbell-.patch | ||||
| extra/0013-hw-smbios-fix-field-corruption-in-type-4-table.patch | ||||
| extra/0014-virtio-rng-pci-fix-transitional-migration-compat-for.patch | ||||
| extra/0015-hw-timer-hpet-Fix-expiration-time-overflow.patch | ||||
| extra/0016-vdpa-stop-all-svq-on-device-deletion.patch | ||||
| extra/0017-vhost-avoid-a-potential-use-of-an-uninitialized-vari.patch | ||||
| extra/0018-chardev-char-socket-set-s-listener-NULL-in-char_sock.patch | ||||
| extra/0019-intel-iommu-fail-MAP-notifier-without-caching-mode.patch | ||||
| extra/0020-intel-iommu-fail-DEVIOTLB_UNMAP-without-dt-mode.patch | ||||
| extra/0021-memory-Allow-disabling-re-entrancy-checking-per-MR.patch | ||||
| extra/0022-lsi53c895a-disable-reentrancy-detection-for-script-R.patch | ||||
| extra/0023-acpi-cpuhp-fix-guest-visible-maximum-access-size-to-.patch | ||||
| extra/0024-tests-tcg-i386-Introduce-and-use-reg_t-consistently.patch | ||||
| extra/0025-target-i386-Fix-BEXTR-instruction.patch | ||||
| extra/0026-target-i386-Fix-C-flag-for-BLSI-BLSMSK-BLSR.patch | ||||
| extra/0027-target-i386-fix-ADOX-followed-by-ADCX.patch | ||||
| extra/0028-target-i386-Fix-BZHI-instruction.patch | ||||
| extra/0002-memory-prevent-dma-reentracy-issues.patch | ||||
| extra/0003-scsi-megasas-Internal-cdbs-have-16-byte-length.patch | ||||
| extra/0004-ide-avoid-potential-deadlock-when-draining-during-tr.patch | ||||
| extra/0005-memory-Allow-disabling-re-entrancy-checking-per-MR.patch | ||||
| extra/0006-lsi53c895a-disable-reentrancy-detection-for-script-R.patch | ||||
| bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch | ||||
| bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch | ||||
| bitmap-mirror/0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch | ||||
| @ -94,3 +72,8 @@ pve/0059-vma-create-support-64KiB-unaligned-input-images.patch | ||||
| pve/0060-vma-create-avoid-triggering-assertion-in-error-case.patch | ||||
| pve/0061-block-alloc-track-avoid-premature-break.patch | ||||
| pve/0062-PVE-Backup-allow-passing-max-workers-performance-set.patch | ||||
| pve/0063-alloc-track-fix-deadlock-during-drop.patch | ||||
| pve/0064-savevm-async-optimize-querying-pending.patch | ||||
| pve/0065-savevm-async-also-initialize-compression-counters.patch | ||||
| pve/0066-migration-for-snapshots-hold-the-BQL-during-setup-ca.patch | ||||
| pve/0067-savevm-async-don-t-hold-BQL-during-setup.patch | ||||
|  | ||||
							
								
								
									
										2
									
								
								qemu
									
									
									
									
									
								
							
							
								
								
								
								
								
								
							
						
						
									
										2
									
								
								qemu
									
									
									
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit b67b00e6b4c7831a3f5bc684bc0df7a9bfd1bd56 | ||||
| Subproject commit c1eb2ddf0f8075faddc5f7c3d39feae3e8e9d6b4 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Fiona Ebner
						Fiona Ebner