diff options
| -rw-r--r-- | block/qcow2.c | 4 | ||||
| -rw-r--r-- | docs/devel/qapi-code-gen.rst | 53 | ||||
| -rw-r--r-- | docs/interop/qemu-ga-ref.rst | 3 | ||||
| -rw-r--r-- | docs/interop/qemu-qmp-ref.rst | 2 | ||||
| -rw-r--r-- | docs/interop/qemu-storage-daemon-qmp-ref.rst | 2 | ||||
| -rw-r--r-- | docs/sphinx/qmp_lexer.py | 2 | ||||
| -rw-r--r-- | hw/loongarch/virt.c | 43 | ||||
| -rw-r--r-- | hw/scsi/scsi-disk.c | 39 | ||||
| -rw-r--r-- | include/qemu/job.h | 3 | ||||
| -rw-r--r-- | job.c | 6 | ||||
| -rw-r--r-- | qapi/qapi-schema.json | 31 | ||||
| -rw-r--r-- | qapi/rocker.json | 2 | ||||
| -rw-r--r-- | qemu-img.c | 6 | ||||
| -rw-r--r-- | qga/qapi-schema.json | 20 | ||||
| -rw-r--r-- | storage-daemon/qapi/qapi-schema.json | 22 | ||||
| -rw-r--r-- | target/ppc/cpu_init.c | 23 | ||||
| -rw-r--r-- | target/ppc/misc_helper.c | 9 | ||||
| -rw-r--r-- | tests/qapi-schema/doc-good.json | 2 | ||||
| -rw-r--r-- | tests/qapi-schema/doc-good.out | 2 | ||||
| -rw-r--r-- | tests/qapi-schema/doc-good.txt | 2 | ||||
| -rwxr-xr-x | tests/qemu-iotests/tests/qcow2-encryption | 75 | ||||
| -rw-r--r-- | tests/qemu-iotests/tests/qcow2-encryption.out | 32 | ||||
| -rw-r--r-- | tests/unit/test-bdrv-drain.c | 32 |
23 files changed, 279 insertions, 136 deletions
diff --git a/block/qcow2.c b/block/qcow2.c index dd6bcafbd8..7774e7f090 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1721,7 +1721,7 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, ret = -EINVAL; goto fail; } - } else if (!(flags & BDRV_O_NO_IO)) { + } else { error_setg(errp, "Missing CRYPTO header for crypt method %d", s->crypt_method_header); ret = -EINVAL; @@ -1976,7 +1976,7 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp) { BDRVQcow2State *s = bs->opaque; - if (bs->encrypted) { + if (s->crypto) { /* Encryption works on a sector granularity */ bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto); } diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index f9cfe8721f..231cc0fecf 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -763,8 +763,8 @@ Names beginning with ``x-`` used to signify "experimental". This convention has been replaced by special feature "unstable". Pragmas ``command-name-exceptions`` and ``member-name-exceptions`` let -you violate naming rules. Use for new code is strongly discouraged. See -`Pragma directives`_ for details. +you violate naming rules. Use for new code is strongly discouraged. +See `Pragma directives`_ for details. Downstream extensions @@ -1013,7 +1013,7 @@ like this:: document the success and the error response, respectively. "Errors" sections should be formatted as an rST list, each entry -detailing a relevant error condition. For example:: +detailing a relevant error condition. For example:: # Errors: # - If @device does not exist, DeviceNotFound @@ -1026,31 +1026,28 @@ definition. QMP). In other sections, the text is formatted, and rST markup can be used. -QMP Examples can be added by using the ``.. qmp-example::`` -directive. In its simplest form, this can be used to contain a single -QMP code block which accepts standard JSON syntax with additional server -directionality indicators (``->`` and ``<-``), and elisions (``...``). +QMP Examples can be added by using the ``.. qmp-example::`` directive. +In its simplest form, this can be used to contain a single QMP code +block which accepts standard JSON syntax with additional server +directionality indicators (``->`` and ``<-``), and elisions. An +elision is commonly ``...``, but it can also be or a pair of ``...`` +with text in between. Optionally, a plaintext title may be provided by using the ``:title:`` -directive option. If the title is omitted, the example title will +directive option. If the title is omitted, the example title will default to "Example:". A simple QMP example:: # .. qmp-example:: - # :title: Using query-block # - # -> { "execute": "query-block" } - # <- { ... } + # -> { "execute": "query-name" } + # <- { "return": { "name": "Fred" } } -More complex or multi-step examples where exposition is needed before or -between QMP code blocks can be created by using the ``:annotated:`` -directive option. When using this option, nested QMP code blocks must be -entered explicitly with rST's ``::`` syntax. - -Highlighting in non-QMP languages can be accomplished by using the -``.. code-block:: lang`` directive, and non-highlighted text can be -achieved by omitting the language argument. +More complex or multi-step examples where exposition is needed before +or between QMP code blocks can be created by using the ``:annotated:`` +directive option. When using this option, nested QMP code blocks must +be entered explicitly with rST's ``::`` syntax. For example:: @@ -1061,11 +1058,21 @@ For example:: # This is a more complex example that can use # ``arbitrary rST syntax`` in its exposition:: # - # -> { "execute": "query-block" } - # <- { ... } + # -> { "execute": "query-block" } + # <- { "return": [ + # { + # "device": "ide0-hd0", + # ... + # } + # ... more ... + # ] } # # Above, lengthy output has been omitted for brevity. +Highlighting in non-QMP languages can be accomplished by using the +``.. code-block:: lang`` directive, and non-highlighted text can be +achieved by omitting the language argument. + Examples of complete definition documentation:: @@ -1466,7 +1473,9 @@ As an example, we'll use the following schema, which describes a single complex user-defined type, along with command which takes a list of that type as a parameter, and returns a single element of that type. The user is responsible for writing the implementation of -qmp_my_command(); everything else is produced by the generator. :: +qmp_my_command(); everything else is produced by the generator. + +:: $ cat example-schema.json { 'struct': 'UserDefOne', diff --git a/docs/interop/qemu-ga-ref.rst b/docs/interop/qemu-ga-ref.rst index 19b5c7a549..25f6e24b03 100644 --- a/docs/interop/qemu-ga-ref.rst +++ b/docs/interop/qemu-ga-ref.rst @@ -1,9 +1,6 @@ QEMU Guest Agent Protocol Reference =================================== -.. contents:: - :depth: 3 - .. qapi-doc:: qga/qapi-schema.json :transmogrify: :namespace: QGA diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst index ef8792b53f..3bc1ca12b1 100644 --- a/docs/interop/qemu-qmp-ref.rst +++ b/docs/interop/qemu-qmp-ref.rst @@ -4,7 +4,7 @@ QEMU QMP Reference Manual ========================= .. contents:: - :depth: 3 + :local: .. qapi-doc:: qapi/qapi-schema.json :transmogrify: diff --git a/docs/interop/qemu-storage-daemon-qmp-ref.rst b/docs/interop/qemu-storage-daemon-qmp-ref.rst index d0228d63b8..dc7bde262a 100644 --- a/docs/interop/qemu-storage-daemon-qmp-ref.rst +++ b/docs/interop/qemu-storage-daemon-qmp-ref.rst @@ -2,7 +2,7 @@ QEMU Storage Daemon QMP Reference Manual ======================================== .. contents:: - :depth: 3 + :local: .. qapi-doc:: storage-daemon/qapi/qapi-schema.json :transmogrify: diff --git a/docs/sphinx/qmp_lexer.py b/docs/sphinx/qmp_lexer.py index a59de8a079..7b3b808d12 100644 --- a/docs/sphinx/qmp_lexer.py +++ b/docs/sphinx/qmp_lexer.py @@ -24,7 +24,7 @@ class QMPExampleMarkersLexer(RegexLexer): 'root': [ (r'-> ', token.Generic.Prompt), (r'<- ', token.Generic.Prompt), - (r' ?\.{3} ?', token.Generic.Prompt), + (r'\.{3}( .* \.{3})?', token.Comment.Multiline), ] } diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index e25864214f..65c9027feb 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -936,29 +936,15 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { CPUArchId *cpu_slot; - Error *err = NULL; LoongArchCPU *cpu = LOONGARCH_CPU(dev); LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); /* Notify ipi and extioi irqchip to remove interrupt routing to CPU */ - hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->ipi), dev, &err); - if (err) { - error_propagate(errp, err); - return; - } - - hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->extioi), dev, &err); - if (err) { - error_propagate(errp, err); - return; - } + hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->ipi), dev, &error_abort); + hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort); /* Notify acpi ged CPU removed */ - hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &err); - if (err) { - error_propagate(errp, err); - return; - } + hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &error_abort); cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id); cpu_slot->cpu = NULL; @@ -971,33 +957,22 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, CPUArchId *cpu_slot; LoongArchCPU *cpu = LOONGARCH_CPU(dev); LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(hotplug_dev); - Error *err = NULL; - cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id); - cpu_slot->cpu = CPU(dev); if (lvms->ipi) { - hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), dev, &err); - if (err) { - error_propagate(errp, err); - return; - } + hotplug_handler_plug(HOTPLUG_HANDLER(lvms->ipi), dev, &error_abort); } if (lvms->extioi) { - hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), dev, &err); - if (err) { - error_propagate(errp, err); - return; - } + hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort); } if (lvms->acpi_ged) { - hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &err); - if (err) { - error_propagate(errp, err); - } + hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, + &error_abort); } + cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id); + cpu_slot->cpu = CPU(dev); return; } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 8da1d5a77c..e59632e9b1 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -68,10 +68,9 @@ struct SCSIDiskClass { SCSIDeviceClass parent_class; /* * Callbacks receive ret == 0 for success. Errors are represented either as - * negative errno values, or as positive SAM status codes. - * - * Beware: For errors returned in host_status, the function may directly - * complete the request and never call the callback. + * negative errno values, or as positive SAM status codes. For host_status + * errors, the function passes ret == -ENODEV and sets the host_status field + * of the SCSIRequest. */ DMAIOFunc *dma_readv; DMAIOFunc *dma_writev; @@ -225,11 +224,26 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); SCSISense sense = SENSE_CODE(NO_SENSE); + int16_t host_status; int error; bool req_has_sense = false; BlockErrorAction action; int status; + /* + * host_status should only be set for SG_IO requests that came back with a + * host_status error in scsi_block_sgio_complete(). This error path passes + * -ENODEV as the return value. + * + * Reset host_status in the request because we may still want to complete + * the request successfully with the 'stop' or 'ignore' error policy. + */ + host_status = r->req.host_status; + if (host_status != -1) { + assert(ret == -ENODEV); + r->req.host_status = -1; + } + if (ret < 0) { status = scsi_sense_from_errno(-ret, &sense); error = -ret; @@ -289,6 +303,10 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) if (acct_failed) { block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); } + if (host_status != -1) { + scsi_req_complete_failed(&r->req, host_status); + return true; + } if (req_has_sense) { sdc->update_sense(&r->req); } else if (status == CHECK_CONDITION) { @@ -409,7 +427,6 @@ done: scsi_req_unref(&r->req); } -/* May not be called in all error cases, don't rely on cleanup here */ static void scsi_dma_complete(void *opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; @@ -448,7 +465,6 @@ done: scsi_req_unref(&r->req); } -/* May not be called in all error cases, don't rely on cleanup here */ static void scsi_read_complete(void *opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; @@ -585,7 +601,6 @@ done: scsi_req_unref(&r->req); } -/* May not be called in all error cases, don't rely on cleanup here */ static void scsi_write_complete(void * opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; @@ -2846,14 +2861,10 @@ static void scsi_block_sgio_complete(void *opaque, int ret) sg_io_hdr_t *io_hdr = &req->io_header; if (ret == 0) { - /* FIXME This skips calling req->cb() and any cleanup in it */ if (io_hdr->host_status != SCSI_HOST_OK) { - scsi_req_complete_failed(&r->req, io_hdr->host_status); - scsi_req_unref(&r->req); - return; - } - - if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { + r->req.host_status = io_hdr->host_status; + ret = -ENODEV; + } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { ret = BUSY; } else { ret = io_hdr->status; diff --git a/include/qemu/job.h b/include/qemu/job.h index 2b873f2576..a5a04155ea 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -545,6 +545,9 @@ bool job_is_ready(Job *job); /* Same as job_is_ready(), but called with job lock held. */ bool job_is_ready_locked(Job *job); +/** Returns whether the job is paused. Called with job_mutex *not* held. */ +bool job_is_paused(Job *job); + /** * Request @job to pause at the next pause point. Must be paired with * job_resume(). If the job is supposed to be resumed by user action, call diff --git a/job.c b/job.c index 660ce22c56..0653bc2ba6 100644 --- a/job.c +++ b/job.c @@ -251,6 +251,12 @@ bool job_is_cancelled_locked(Job *job) return job->force_cancel; } +bool job_is_paused(Job *job) +{ + JOB_LOCK_GUARD(); + return job->paused; +} + bool job_is_cancelled(Job *job) { JOB_LOCK_GUARD(); diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index c41c01eb2a..7bc600bb76 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -3,37 +3,24 @@ ## # = Introduction # -# This document describes all commands currently supported by QMP. +# This manual describes the commands and events supported by the QEMU +# Monitor Protocol (QMP). # # For locating a particular item, please see the `qapi-qmp-index`. # -# Most of the time their usage is exactly the same as in the user -# Monitor, this means that any other document which also describe -# commands (the manpage, QEMU's manual, etc) can and should be -# consulted. +# The following notation is used in examples: # -# QMP has two types of commands: regular and query commands. Regular -# commands usually change the Virtual Machine's state someway, while -# query commands just return information. The sections below are -# divided accordingly. +# .. qmp-example:: # -# It's important to observe that all communication examples are -# formatted in a reader-friendly way, so that they're easier to -# understand. However, in real protocol usage, they're emitted as a -# single line. +# -> ... text sent by client (commands) ... +# <- ... text sent by server (command responses and events) ... # -# Also, the following notation is used to denote data flow: -# -# Example: -# -# :: -# -# -> data issued by the Client -# <- Server data response +# Example text is formatted for readability. However, in real +# protocol usage, its commonly emitted as a single line. # # Please refer to the # :doc:`QEMU Machine Protocol Specification </interop/qmp-spec>` -# for detailed information on the Server command and response formats. +# for the general format of commands, responses, and events. ## { 'include': 'pragma.json' } diff --git a/qapi/rocker.json b/qapi/rocker.json index 51aa5b4930..0c7ef1f77c 100644 --- a/qapi/rocker.json +++ b/qapi/rocker.json @@ -254,7 +254,7 @@ # "action": {"goto-tbl": 10}, # "mask": {"in-pport": 4294901760} # }, -# {...}, +# ... # ]} ## { 'command': 'query-rocker-of-dpa-flows', diff --git a/qemu-img.c b/qemu-img.c index 89c93c1eb5..2044c22a4c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4488,7 +4488,11 @@ static void bench_cb(void *opaque, int ret) */ b->in_flight++; b->offset += b->step; - b->offset %= b->image_size; + if (b->image_size == 0) { + b->offset = 0; + } else { + b->offset %= b->image_size; + } if (b->write) { acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b); } else { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 35ec0e7db3..5316bfacbf 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -2,10 +2,24 @@ # vim: filetype=python ## -# = QEMU guest agent protocol commands and structs +# This manual describes the commands supported by the QEMU Guest +# Agent Protocol. # -# For a concise listing of all commands, events, and types in the QEMU -# guest agent, please consult the `qapi-qga-index`. +# For locating a particular item, please see the `qapi-qga-index`. +# +# The following notation is used in examples: +# +# .. qmp-example:: +# +# -> ... text sent by client (commands) ... +# <- ... text sent by server (command responses and events) ... +# +# Example text is formatted for readability. However, in real +# protocol usage, its commonly emitted as a single line. +# +# Please refer to the +# :doc:`QEMU Machine Protocol Specification </interop/qmp-spec>` +# for the general format of commands, responses, and events. ## { 'pragma': { 'doc-required': true } } diff --git a/storage-daemon/qapi/qapi-schema.json b/storage-daemon/qapi/qapi-schema.json index 2a562ee32e..0427594c98 100644 --- a/storage-daemon/qapi/qapi-schema.json +++ b/storage-daemon/qapi/qapi-schema.json @@ -14,10 +14,26 @@ # storage daemon. ## -# = QEMU storage daemon protocol commands and structs +# = Introduction # -# For a concise listing of all commands, events, and types in the QEMU -# storage daemon, please consult the `qapi-qsd-index`. +# This manual describes the commands and events supported by the QEMU +# storage daemon QMP. +# +# For locating a particular item, please see the `qapi-qsd-index`. +# +# The following notation is used in examples: +# +# .. qmp-example:: +# +# -> ... text sent by client (commands) ... +# <- ... text sent by server (command responses and events) ... +# +# Example text is formatted for readability. However, in real +# protocol usage, its commonly emitted as a single line. +# +# Please refer to the +# :doc:`QEMU Machine Protocol Specification </interop/qmp-spec>` +# for the general format of commands, responses, and events. ## diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 7decc09aec..f81cb680fc 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5801,6 +5801,18 @@ static void register_power9_book4_sprs(CPUPPCState *env) &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, 0x00000000); + + /* SPRC/SPRD exist in earlier CPUs but only tested on POWER9/10 */ + spr_register_hv(env, SPR_POWER_SPRC, "SPRC", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_sprc, + 0x00000000); + spr_register_hv(env, SPR_POWER_SPRD, "SPRD", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_sprd, &spr_write_sprd, + 0x00000000); #endif } @@ -5822,17 +5834,6 @@ static void register_power8_book4_sprs(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, KVM_REG_PPC_WORT, 0); - /* SPRC/SPRD exist in earlier CPUs but only tested on POWER9/10 */ - spr_register_hv(env, SPR_POWER_SPRC, "SPRC", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_sprc, - 0x00000000); - spr_register_hv(env, SPR_POWER_SPRD, "SPRD", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_sprd, &spr_write_sprd, - 0x00000000); #endif } diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 2d9512c116..46ae454afd 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -332,6 +332,10 @@ target_ulong helper_load_sprd(CPUPPCState *env) PnvCore *pc = pnv_cpu_state(cpu)->pnv_core; target_ulong sprc = env->spr[SPR_POWER_SPRC]; + if (pc->big_core) { + pc = pnv_chip_find_core(pc->chip, CPU_CORE(pc)->core_id & ~0x1); + } + switch (sprc & 0x3e0) { case 0: /* SCRATCH0-3 */ case 1: /* SCRATCH4-7 */ @@ -368,6 +372,10 @@ void helper_store_sprd(CPUPPCState *env, target_ulong val) PnvCore *pc = pnv_cpu_state(cpu)->pnv_core; int nr; + if (pc->big_core) { + pc = pnv_chip_find_core(pc->chip, CPU_CORE(pc)->core_id & ~0x1); + } + switch (sprc & 0x3e0) { case 0: /* SCRATCH0-3 */ case 1: /* SCRATCH4-7 */ @@ -378,7 +386,6 @@ void helper_store_sprd(CPUPPCState *env, target_ulong val) * information. Could also dump these upon checkstop. */ nr = (sprc >> 3) & 0x7; - qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr); pc->scratch[nr] = val; break; default: diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index 0a4f139f83..14b808f909 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -212,7 +212,7 @@ # # -> "this example" # -# <- "has no title" +# <- ... has no title ... ## { 'command': 'cmd-boxed', 'boxed': true, 'data': 'Object', diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 5773f1dd6d..dc8352eed4 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -217,7 +217,7 @@ another feature -> "this example" - <- "has no title" + <- ... has no title ... doc symbol=EVT_BOXED body= diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt index cb37db606a..17a1d56ef1 100644 --- a/tests/qapi-schema/doc-good.txt +++ b/tests/qapi-schema/doc-good.txt @@ -264,7 +264,7 @@ Example:: -> "this example" - <- "has no title" + <- ... has no title ... "EVT_BOXED" (Event) diff --git a/tests/qemu-iotests/tests/qcow2-encryption b/tests/qemu-iotests/tests/qcow2-encryption new file mode 100755 index 0000000000..95f6195ab8 --- /dev/null +++ b/tests/qemu-iotests/tests/qcow2-encryption @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# group: rw quick +# +# Test case for encryption support in qcow2 +# +# Copyright (C) 2025 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ../common.rc +. ../common.filter + +# This tests qcow2-specific low-level functionality +_supported_fmt qcow2 +_supported_proto file +_require_working_luks + +IMG_SIZE=64M + +echo +echo "=== Create an encrypted image ===" +echo + +_make_test_img --object secret,id=sec0,data=123456 -o encrypt.format=luks,encrypt.key-secret=sec0 $IMG_SIZE +$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts +_img_info +$QEMU_IMG check \ + --object secret,id=sec0,data=123456 \ + --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 \ + | _filter_qemu_img_check + +echo +echo "=== Remove the header extension ===" +echo + +$PYTHON ../qcow2.py "$TEST_IMG" del-header-ext 0x0537be77 +$PYTHON ../qcow2.py "$TEST_IMG" dump-header-exts +_img_info +$QEMU_IMG check \ + --object secret,id=sec0,data=123456 \ + --image-opts file.filename="$TEST_IMG",encrypt.key-secret=sec0 2>&1 \ + | _filter_qemu_img_check \ + | _filter_testdir + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/tests/qcow2-encryption.out b/tests/qemu-iotests/tests/qcow2-encryption.out new file mode 100644 index 0000000000..9b549dc2ab --- /dev/null +++ b/tests/qemu-iotests/tests/qcow2-encryption.out @@ -0,0 +1,32 @@ +QA output created by qcow2-encryption + +=== Create an encrypted image === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Header extension: +magic 0x537be77 (Crypto header) +length 16 +data <binary> + +Header extension: +magic 0x6803f857 (Feature table) +length 384 +data <binary> + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64 MiB (67108864 bytes) +encrypted: yes +cluster_size: 65536 +No errors were found on the image. + +=== Remove the header extension === + +Header extension: +magic 0x6803f857 (Feature table) +length 384 +data <binary> + +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Missing CRYPTO header for crypt method 2 +qemu-img: Could not open 'file.filename=TEST_DIR/t.qcow2,encrypt.key-secret=sec0': Missing CRYPTO header for crypt method 2 +*** done diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index 7410e6f352..290cd2a70e 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -632,6 +632,8 @@ typedef struct TestBlockJob { BlockDriverState *bs; int run_ret; int prepare_ret; + + /* Accessed with atomics */ bool running; bool should_complete; } TestBlockJob; @@ -667,10 +669,10 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) /* We are running the actual job code past the pause point in * job_co_entry(). */ - s->running = true; + qatomic_set(&s->running, true); job_transition_to_ready(&s->common.job); - while (!s->should_complete) { + while (!qatomic_read(&s->should_complete)) { /* Avoid job_sleep_ns() because it marks the job as !busy. We want to * emulate some actual activity (probably some I/O) here so that drain * has to wait for this activity to stop. */ @@ -685,7 +687,7 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) static void test_job_complete(Job *job, Error **errp) { TestBlockJob *s = container_of(job, TestBlockJob, common.job); - s->should_complete = true; + qatomic_set(&s->should_complete, true); } BlockJobDriver test_job_driver = { @@ -791,7 +793,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, /* job_co_entry() is run in the I/O thread, wait for the actual job * code to start (we don't want to catch the job in the pause point in * job_co_entry(). */ - while (!tjob->running) { + while (!qatomic_read(&tjob->running)) { aio_poll(qemu_get_aio_context(), false); } } @@ -799,7 +801,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, WITH_JOB_LOCK_GUARD() { g_assert_cmpint(job->job.pause_count, ==, 0); g_assert_false(job->job.paused); - g_assert_true(tjob->running); + g_assert_true(qatomic_read(&tjob->running)); g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ } @@ -825,7 +827,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, * * paused is reset in the I/O thread, wait for it */ - while (job->job.paused) { + while (job_is_paused(&job->job)) { aio_poll(qemu_get_aio_context(), false); } } @@ -858,7 +860,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type, * * paused is reset in the I/O thread, wait for it */ - while (job->job.paused) { + while (job_is_paused(&job->job)) { aio_poll(qemu_get_aio_context(), false); } } @@ -1411,10 +1413,12 @@ static void test_set_aio_context(void) typedef struct TestDropBackingBlockJob { BlockJob common; - bool should_complete; bool *did_complete; BlockDriverState *detach_also; BlockDriverState *bs; + + /* Accessed with atomics */ + bool should_complete; } TestDropBackingBlockJob; static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp) @@ -1422,7 +1426,7 @@ static int coroutine_fn test_drop_backing_job_run(Job *job, Error **errp) TestDropBackingBlockJob *s = container_of(job, TestDropBackingBlockJob, common.job); - while (!s->should_complete) { + while (!qatomic_read(&s->should_complete)) { job_sleep_ns(job, 0); } @@ -1541,7 +1545,7 @@ static void test_blockjob_commit_by_drained_end(void) job_start(&job->common.job); - job->should_complete = true; + qatomic_set(&job->should_complete, true); bdrv_drained_begin(bs_child); g_assert(!job_has_completed); bdrv_drained_end(bs_child); @@ -1557,15 +1561,17 @@ static void test_blockjob_commit_by_drained_end(void) typedef struct TestSimpleBlockJob { BlockJob common; - bool should_complete; bool *did_complete; + + /* Accessed with atomics */ + bool should_complete; } TestSimpleBlockJob; static int coroutine_fn test_simple_job_run(Job *job, Error **errp) { TestSimpleBlockJob *s = container_of(job, TestSimpleBlockJob, common.job); - while (!s->should_complete) { + while (!qatomic_read(&s->should_complete)) { job_sleep_ns(job, 0); } @@ -1700,7 +1706,7 @@ static void test_drop_intermediate_poll(void) job->did_complete = &job_has_completed; job_start(&job->common.job); - job->should_complete = true; + qatomic_set(&job->should_complete, true); g_assert(!job_has_completed); ret = bdrv_drop_intermediate(chain[1], chain[0], NULL, false); |