-
Notifications
You must be signed in to change notification settings - Fork 1
Vnc264 #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Allow virtio-scsi virtqueues to be assigned to different IOThreads. This makes it possible to take advantage of host multi-queue block layer scalability by assigning virtqueues that have affinity with vCPUs to different IOThreads that have affinity with host CPUs. The same feature was introduced for virtio-blk in the past: https://developers.redhat.com/articles/2024/09/05/scaling-virtio-blk-disk-io-iothread-virtqueue-mapping Here are fio randread 4k iodepth=64 results from a 4 vCPU guest with an Intel P4800X SSD: iothreads IOPS ------------------------------ 1 189576 2 312698 4 346744 Signed-off-by: Stefan Hajnoczi <[email protected]> Message-ID: <[email protected]> Tested-by: Peter Krempa <[email protected]> [kwolf: Updated 051 output, virtio-scsi can now use any iothread] Reviewed-by: Kevin Wolf <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
Previously the ctrl virtqueue was handled in the AioContext where SCSI requests are processed. When IOThread Virtqueue Mapping was added things become more complicated because SCSI requests could run in other AioContexts. Simplify by handling the ctrl virtqueue in the main loop where reset operations can be performed. Note that BHs are still used canceling SCSI requests in their AioContexts but at least the mean loop activity doesn't need BHs anymore. Signed-off-by: Stefan Hajnoczi <[email protected]> Message-ID: <[email protected]> Tested-by: Peter Krempa <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
Peter Krempa and Kevin Wolf observed that iothread-vq-mapping is confusing to use because the control and event virtqueues have a fixed location before the command virtqueues but need to be treated differently. Only expose the command virtqueues via iothread-vq-mapping so that the command-line parameter is intuitive: it controls where SCSI requests are processed. The control virtqueue needs to be hardcoded to the main loop thread for technical reasons anyway. Kevin also pointed out that it's better to place the event virtqueue in the main loop thread since its no poll behavior would prevent polling if assigned to an IOThread. This change is its own commit to avoid squashing the previous commit. Suggested-by: Kevin Wolf <[email protected]> Suggested-by: Peter Krempa <[email protected]> Signed-off-by: Stefan Hajnoczi <[email protected]> Message-ID: <[email protected]> Tested-by: Peter Krempa <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
This tool converts a disk image to qcow2, writing the result directly to stdout. This can be used for example to send the generated file over the network. This is equivalent to using qemu-img to convert a file to qcow2 and then writing the result to stdout, with the difference that this tool does not need to create this temporary qcow2 file and therefore does not need any additional disk space. Implementing this directly in qemu-img is not really an option because it expects the output file to be seekable and it is also meant to be a generic tool that supports all combinations of file formats and image options. Instead, this tool can only produce qcow2 files with the basic options, without compression, encryption or other features. The input file is read twice. The first pass is used to determine which clusters contain non-zero data and that information is used to create the qcow2 header, refcount table and blocks, and L1 and L2 tables. After all that metadata is created then the second pass is used to write the guest data. By default qcow2-to-stdout.py expects the input to be a raw file, but if qemu-storage-daemon is available then it can also be used to read images in other formats. Alternatively the user can also run qemu-nbd or qemu-storage-daemon manually instead. Signed-off-by: Alberto Garcia <[email protected]> Signed-off-by: Madeeha Javed <[email protected]> Message-ID: <[email protected]> Reviewed-by: Kevin Wolf <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
…into staging * Various fixes for functional tests * Fix the name of the "configs" directory in the documentation # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmfSjagRHHRodXRoQHJl # ZGhhdC5jb20ACgkQLtnXdP5wLbWBmA//RhAHuF/fTmQagBsZPETXjU1g8ifw9aqm # WPZcQEXyQFlqYYQZmtV7dk3aTGEw4kBDmm+SKTSQz1yUcBGptMl8xuWaxgdpcOw0 # Bqt+lYNgwGL9/OocCdNolU3+aVbETljr5l+rzbnwsTVIqGk63Qhmtwdupb8h1nfY # 4vCXU+sY3BkvBF8HbV6Wb1aPtqC+iH/Ln8+yoKkC8UePD623dK58SsOVrhUQDfFr # U/HUy4BZlHFCfGGmDVGBjHdEbOzQkLQ9N3ilsNSWcF87RPkWPft+qLs4RjDFW+oT # oksXEFHcr8XQO03fwHBNTyv+NUfnrvDY8V+gl6C9ItQr58SZzse57caZKWrYppZ3 # l5iHoaLMV3juZFDNXNHkWHuveXi05+0V0UbZihzBeC4+zjNRyh3e1GuDoh5VoG8o # XIb55RxU8eBG2/ulHZ71eAYrGpxO+tDdsdnak1coPFsU8HrC9QzRfywiAZe1Wwmx # 5t5AHbZ7RdnxgStU1lWTUT2IDVSini4DKevt/FzhKkv1aD8NbhI/ooGDC0zbS6SU # XK6PP2G5a5OnjQ904oRCQbnhrxFa5qNfryylvvreT2bVgX0BiE4pJ9JXdgQOMYlP # kZERZZQcv3y6VVavAT67yeNKQpyb4HSHdTDQ2irgXP1UwHRpwLpKdqB1UhzNJ8m8 # k0faA8RXir4= # =VtGZ # -----END PGP SIGNATURE----- # gpg: Signature made Thu 13 Mar 2025 15:47:52 HKT # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "[email protected]" # gpg: Good signature from "Thomas Huth <[email protected]>" [full] # gpg: aka "Thomas Huth <[email protected]>" [full] # gpg: aka "Thomas Huth <[email protected]>" [full] # gpg: aka "Thomas Huth <[email protected]>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * tag 'pull-request-2025-03-13' of https://gitlab.com/thuth/qemu: tests/functional: skip vulkan test if missing vulkaninfo tests/functional/asset: Add AssetError exception class tests/functional/asset: Verify downloaded size tests/functional/asset: Fail assert fetch when retries are exceeded docs/system: Fix the information on how to run certain functional tests tests/functional: Bump up arm_replay timeout tests/functional: Require 'user' netdev for ppc64 e500 test docs: Rename default-configs to configs Signed-off-by: Stefan Hajnoczi <[email protected]>
Block layer patches - virtio-scsi: add iothread-vq-mapping parameter - Improve writethrough performance - Fix missing zero init in bdrv_snapshot_goto() - Added scripts/qcow2-to-stdout.py - Code cleanup and iotests fixes # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmfTDysRHGt3b2xmQHJl # ZGhhdC5jb20ACgkQfwmycsiPL9Yz6A//asOl37zjbtf9pYjY/gliH859TQOppPGD # LB9IIr+nTDME0wfUkCOlag+CeEYZwkeo2PF+XeopsyzlJeBOk4tL7AkY57XYe3lZ # M5hlnNrn6l3gb6iioMg60pEKSMrpKprB16vT3nAtyN6aEXsm9TvtPkWPFTCFGVeK # W74VCr7wuXbfdEJcOGd8WhB9ZHIgwoWYnoL41tvCoefW2yNaMA6X0TLn98toXzOi # il50ZnnchTQngns5R+n+1R1Ma995t393D+CArQcYVRzxKGOs5p0y4otz4gCkMhdp # GVL09R7Ge4TteSJ2myxlN/EjYOxmdoMrVDajr4xPdHBw12MKzgk8i82h4/Es/Q5o # 3Npgx74+jDyqlICb/czTVM5KJINpyO80vO3N3WpYUOQGyTCcYgv7pIpy8pB2o6Te # RPlv0W9bHVSSgThFFLQ0Ud8WRGJe1K/ar8bdmiWN08Wez1avENWaYmsv5zGnFL24 # vD6cNXMR4mF7mzyeWda/5hGKv75djVgX+ZfzvWNT3qgizD56JBOA3RdCRwBZJOJb # TvJkfi5RGyaji9BfKVCYBL3/iDELJEVDW8jxvIIUrS0aPcTHpAQ5gTO7VAokreqZ # 5Smll11eeoEgPPvNLw8ikmOGTWOMkJGrmExP2K1ApANq3kSbBSU4jroEr0BG9PZT # 6Y0hUdtFSdU= # =w2Ri # -----END PGP SIGNATURE----- # gpg: Signature made Fri 14 Mar 2025 01:00:27 HKT # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "[email protected]" # gpg: Good signature from "Kevin Wolf <[email protected]>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (23 commits) scripts/qcow2-to-stdout.py: Add script to write qcow2 images to stdout virtio-scsi: only expose cmd vqs via iothread-vq-mapping virtio-scsi: handle ctrl virtqueue in main loop virtio-scsi: add iothread-vq-mapping parameter virtio: extract iothread-vq-mapping.h API virtio-blk: tidy up iothread_vq_mapping functions virtio-blk: extract cleanup_iothread_vq_mapping() function virtio-scsi: perform TMFs in appropriate AioContexts virtio-scsi: protect events_dropped field virtio-scsi: introduce event and ctrl virtqueue locks scsi: introduce requests_lock scsi: track per-SCSIRequest AioContext dma: use current AioContext for dma_blk_io() scsi-disk: drop unused SCSIDiskState->bh field iotests: Limit qsd-migrate to working formats aio-posix: Adjust polling time also for new handlers aio-posix: Separate AioPolledEvent per AioHandler aio-posix: Factor out adjust_polling_time() aio: Create AioPolledEvent block/io: Ignore FUA with cache.no-flush=on ... Signed-off-by: Stefan Hajnoczi <[email protected]>
The description of feature @unstable is three paragraphs. The second and third became part of the description by accident in commit 9fb49da (qapi: Mark unstable QMP parts with feature 'unstable'). The second paragraph describes a defect in terms of the implementation. Fine, but doesn't belong into user-facing documentation. Turn it into a TODO section. Rewrite everything else for clarity and completeness. Signed-off-by: Markus Armbruster <[email protected]> Message-ID: <[email protected]> Acked-by: Alberto Garcia <[email protected]>
When using the annotations feature, type hints do not need to be imported at runtime, only at type check time. Move type-check-only imports into a conditional to reduce the number of imports needed at runtime. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
Currently, only the definition name is stored in the tree metadata; but the node property is confusingly called "fullname". Rectify this by always storing the FQN in the tree metadata. ... While we're here, re-organize the code in preparation for namespace support to make it a bit easier to add additional components of the FQN. With this change, there is now extremely little code left that's taken directly from the Python domain :) Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
This patch adds a namespace component to the "Fully Qualified Name", in the form of "domain:module.name". As there are no namespace directives or options yet, this component will simply be empty as of this patch. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
Akin to the :module: override option, the :namespace: options allows you to forcibly override the contextual namespace associatied with a definition. We don't necessarily actually need this, but I felt compelled to stick close to how the Python domain works that offers context overrides. As of this commit, it is possible to add e.g. ":namespace: QMP" to any QAPI directive to forcibly associate that definition with a given namespace. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
Add a new directive that marks the beginning of a QAPI "namespace", for example; "QMP", "QGA" or "QSD". This directive will associate all subsequent QAPI directives in a document with the specified namespace. This does not change the visual display of any of the definitions or index entries, but does change the "Fully Qualified Name" inside the QAPI domain's object table. This allows for two different "namespaces" to define entities with otherwise identical names -- which will come in handy for documenting both QEMU QMP and the QEMU Storage Daemon. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
Add a :namespace: option to the qapi-doc directive, which inserts a qapi:namespace directive into the start of the generated document. This, in turn, associates all auto-generated definitions by this directive with the specified namespace. The source info for these generated lines are credited to the start of the qapi-doc directive, which isn't precisely correct, but I wasn't sure how to get it more accurate without some re-parsing shenanigans. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
This patch does three things: 1. Record the current namespace context in pending_xrefs so it can be used for link resolution later, 2. Pass that recorded namespace context to find_obj() when resolving a reference, and 3. Wildly and completely rewrite find_obj(). cross-reference support is expanded to tolerate the presence or absence of either namespace or module, and to cope with the presence or absence of contextual information for either. References now work like this: 1. If the explicit reference target is recorded in the domain's object registry, we link to that target and stop looking. We do this lookup regardless of how fully qualified the target is, which allows direct references to modules (which don't have a module component to their names) or direct references to definitions that may or may not belong to a namespace or module. 2. If contextual information is available from qapi:namespace or qapi:module directives, try using those components to find a direct match to the implied target name. 3. If both prior lookups fail, generate a series of regular expressions looking for wildcard matches in order from most to least specific. Any explicitly provided components (namespace, module) *must* match exactly, but both contextual and entirely omitted components are allowed to differ from the search result. Note that if more than one result is found, Sphinx will emit a warning (a build error for QEMU) and list all of the candidate references. The practical upshot is that in the large majority of cases, namespace and module information is not required when creating simple `references` to definitions from within the same context -- even when identical definitions exist in other contexts. Even when using simple `references` from elsewhere in the QEMU documentation manual, explicit namespace info is not required if there is only one definition by that name. Disambiguation *will* be required from outside of the QAPI documentation when referencing e.g. block-core definitions, which are shared between QEMU QMP and the QEMU Storage Daemon. In that case, there are two options: A: References can be made partially or fully explicit, e.g. `QMP:block-dirty-bitmap-add` will link to the QEMU version of the definition, while `QSD:block-dirty-bitmap-add` would link to the QSD version. B: If all of the references in a document are intended to go to the same place, you can insert a "qapi:namespace:: QMP" directive to influence the fuzzy-searching for later references. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> [Commit message typo fixed] Signed-off-by: Markus Armbruster <[email protected]>
Generate an index-per-namespace for the QAPI domain. Due to a limitation with Sphinx's architecture, these indices must be defined during setup time and cannot be dynamically created on-demand when a namespace directive is encountered. Owing to that limitation, add a configuration value to conf.py that specifies which QAPI namespaces we'll generate indices for. Indices will be named after their namespace, e.g. the "QMP" namespace will generate to "qapi-qmp-index.html" and can be referenced using `qapi-qmp-index`. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
This also creates the qapi-qmp-index.html index and cross-reference target. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
Before we enable the QGA and QSD namespaces, we need to disambiguate some of the references that would become ambiguous as a result! Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
This also creates the `qapi-qsd-index` and `qapi-qga-index` QMP indices. Signed-off-by: John Snow <[email protected]> Message-ID: <[email protected]> Acked-by: Markus Armbruster <[email protected]> Signed-off-by: Markus Armbruster <[email protected]>
The A32_BANKED_REG_{GET,SET} macros are only used inside target/arm; move their definitions to cpregs.h. There's no need to have them defined in all the code that includes cpu.h. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
We would like to move arm_el_is_aa64() to internals.h; however, it is used by access_secure_reg(). Make that function not be inline, so that it can stay in cpu.h. access_secure_reg() is used only in two places: * in hflags.c * in the user-mode arm emulators, to decide whether to store the TLS value in the secure or non-secure banked field The second of these is not on a super-hot path that would care about the inlining (and incidentally will always use the NS banked field because our user-mode CPUs never set ARM_FEATURE_EL3); put the definition of access_secure_reg() in hflags.c, near its only use inside target/arm. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
At the top of linux-user/aarch64/cpu_loop.c we define a set of macros for reading and writing data and code words, but we never use these macros. Delete them. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
In linux-user/arm/cpu_loop.c we define a full set of get/put macros for both code and data (since the endianness handling is different between the two). However the only one we actually use is get_user_code_u32(). Remove the rest. We leave a comment noting how data-side accesses should be handled for big-endian, because that's a subtle point and we just removed the macros that were effectively documenting it. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
The arm_cpu_data_is_big_endian() and related functions are now used only in target/arm; they can be moved to internals.h. The motivation here is that we would like to move arm_current_el() to internals.h. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
The functions arm_current_el() and arm_el_is_aa64() are used only in target/arm and in hw/intc/arm_gicv3_cpuif.c. They're functions that query internal state of the CPU. Move them out of cpu.h and into internals.h. This means we need to include internals.h in arm_gicv3_cpuif.c, but this is justifiable because that file is implementing the GICv3 CPU interface, which really is part of the CPU proper; we just ended up implementing it in code in hw/intc/ for historical reasons. The motivation for this move is that we'd like to change arm_el_is_aa64() to add a condition that uses cpu_isar_feature(); but we don't want to include cpu-features.h in cpu.h. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
…AArch32 The definition of SCR_EL3.RW says that its effective value is 1 if: - EL2 is implemented and does not support AArch32, and SCR_EL3.NS is 1 - the effective value of SCR_EL3.{EEL2,NS} is {1,0} (i.e. we are Secure and Secure EL2 is disabled) We implement the second of these in arm_el_is_aa64(), but forgot the first. Provide a new function arm_scr_rw_eff() to return the effective value of SCR_EL3.RW, and use it in arm_el_is_aa64() and the other places that currently look directly at the bit value. (scr_write() enforces that the RW bit is RAO/WI if neither EL1 nor EL2 have AArch32 support, but if EL1 does but EL2 does not then the bit must still be writeable.) This will mean that if code at EL3 attempts to perform an exception return to AArch32 EL2 when EL2 is AArch64-only we will correctly handle this as an illegal exception return: it will be caught by the "return to an EL which is configured for a different register width" check in HELPER(exception_return). We do already have some CPU types which don't implement AArch32 above EL0, so this is technically a bug; it doesn't seem worth backporting to stable because no sensible guest code will be deliberately attempting to set the RW bit to a value corresponding to an unimplemented execution state and then checking that we did the right thing. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
Define the cpr_is_incoming helper, to be used in several cpr fix patches. Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Peter Xu <[email protected]> Reviewed-by: Fabiano Rosas <[email protected]> Message-ID: <[email protected]> Signed-off-by: Fabiano Rosas <[email protected]>
During normal migration, new QEMU creates and initializes memory regions, then loads the preserved contents of the region from vmstate. During CPR, memory regions are preserved in place, then the realize method initializes the regions contents, losing the old contents. To fix, skip the re-init during CPR. Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Fabiano Rosas <[email protected]> Message-ID: <[email protected]> Signed-off-by: Fabiano Rosas <[email protected]>
During normal migration, new QEMU creates and initializes memory regions, then loads the preserved contents of the region from vmstate. During CPR, memory regions are preserved in place, then the realize method initializes the regions contents, losing the old contents. To fix, skip the re-init during CPR. Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Fabiano Rosas <[email protected]> Message-ID: <[email protected]> Signed-off-by: Fabiano Rosas <[email protected]>
During normal migration, new QEMU creates and initializes memory regions, then loads the preserved contents of the region from vmstate. During CPR, memory regions are preserved in place, then the realize method initializes the regions contents, losing the old contents. To fix, skip writes to the qxl memory regions during CPR load. Reported-by: [email protected] Tested-by: [email protected] Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Fabiano Rosas <[email protected]> Message-ID: <[email protected]> Signed-off-by: Fabiano Rosas <[email protected]>
When EL1 doesn't support AArch32, the HCR_EL2.RW bit is supposed to be RAO/WI. Enforce the RAO/WI behaviour. Note that we handle "reset value should honour RES1 bits" in the same way that SCR_EL3 does, via a reset function. We do already have some CPU types which don't implement AArch32 above EL0, so this is technically a bug; it doesn't seem worth backporting to stable because no sensible guest code will be deliberately attempting to set the RW bit to a value corresponding to an unimplemented execution state and then checking that we did the right thing. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
Signed-off-by: Stefan Hajnoczi <[email protected]>
Signed-off-by: Stefan Hajnoczi <[email protected]>
GStreamer is required to implement H264 encoding for VNC. Please note that QEMU already depends on this library when you enable Spice. Signed-off-by: Dietmar Maurer <[email protected]>
This patch implements H264 support for VNC. The RFB protocol extension is defined in: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#open-h-264-encoding Currently the Gstreamer x264enc plugin (software encoder) is used to encode the video stream. The gstreamer pipe is: appsrc -> videoconvert -> x264enc -> appsink Note: videoconvert is required for RGBx to YUV420 conversion. The code still use the VNC server framebuffer change detection, and only encodes and sends video frames if there are changes. Signed-off-by: Dietmar Maurer <[email protected]>
The H264 implementation only sends frames when it detects changes in the server's framebuffer. This leads to artifacts when there are no further changes, as the internal H264 encoder may still contain data. This patch modifies the code to send a few additional frames in such situations to flush the H264 encoder data. Signed-off-by: Dietmar Maurer <[email protected]>
The search list is currently hardcoded to: ["x264enc", "openh264enc"] x264enc: is probably the best available software encoder openh264enc: lower quality, but available on more systems. We restrict encoders to a known list because each encoder requires fine tuning to get reasonable/usable results. Signed-off-by: Dietmar Maurer <[email protected]>
Values can be 'on', 'off', or a space sparated list of allowed gstreamer encoders. - on: automatically select the encoder - off: disbale h264 - encoder-list: select first available encoder from that list. Signed-off-by: Dietmar Maurer <[email protected]>
Signed-off-by: Dietmar Maurer <[email protected]>
Signed-off-by: Dietmar Maurer <[email protected]>
So that we can set --gst- options on the qemu command line. Signed-off-by: Dietmar Maurer <[email protected]>
…ontext Some encoders can hang indefinetly (i.e. nvh264enc) if the pipeline is not stopped before it is destroyed (Observed on Debian bookworm). Signed-off-by: Dietmar Maurer <[email protected]>
Reviewer's Guide by SourceryThis pull request implements the VNC H.264 encoding, enabling the server to stream video using the H.264 codec. It introduces new functions for H.264 initialization, encoding, and cleanup, and integrates with GStreamer for encoding. The changes also include a new VNC option to configure the H.264 encoder and modifications to the refresh logic to accommodate H.264 encoding requirements. No diagrams generated as the changes look simple and do not need a visual representation. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @berrange - I've reviewed your changes - here's some feedback:
Overall Comments:
- Consider adding a configure option to control whether H.264 encoding is enabled at build time.
- It might be worth exploring the use of a circular buffer to avoid allocating memory for each frame.
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟡 Complexity: 2 issues found
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
has_dirty = vnc_refresh_server_surface(vd); | ||
vnc_unlock_display(vd); | ||
|
||
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider extracting the H264-specific logic into a helper function to simplify the vnc_refresh loop and reduce nesting depth, which improves readability and maintainability without altering functionality..
Extract the H264‐specific logic into a helper function. For example, you could create a function that handles the “keep dirty” update and returns the effective client dirty flag. One way to do this is:
#ifdef CONFIG_GSTREAMER
static int h264_handle_dirty(VncState *vs, int client_dirty, bool *global_keep_dirty) {
if (!vs->h264) {
return client_dirty;
}
if (client_dirty) {
vs->h264->keep_dirty = VNC_H264_KEEP_DIRTY;
} else if (vs->h264->keep_dirty > 0) {
client_dirty = 1;
vs->h264->keep_dirty--;
}
if (vs->h264->keep_dirty > 0) {
*global_keep_dirty = true;
}
return client_dirty;
}
#endif
Then, update your loop in vnc_refresh
as follows:
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
int client_dirty = has_dirty;
#ifdef CONFIG_GSTREAMER
client_dirty = h264_handle_dirty(vs, client_dirty, &keep_dirty);
#endif
int count = vnc_update_client(vs, client_dirty);
rects += count;
#ifdef CONFIG_GSTREAMER
if (vs->h264 && !count && vs->h264->keep_dirty) {
VncJob *job = vnc_job_new(vs);
int height = pixman_image_get_height(vd->server);
int width = pixman_image_get_width(vd->server);
vs->job_update = vs->update;
vs->update = VNC_STATE_UPDATE_NONE;
vnc_job_add_rect(job, 0, 0, width, height);
vnc_job_push(job);
}
#endif
}
This refactoring keeps all functionality intact while reducing nesting in the critical loop.
vnc_write_u8(&vs, 0); | ||
saved_offset = vs.output.offset; | ||
vnc_write_u16(&vs, 0); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider extracting the common rectangle update logic into a helper function to avoid code duplication between the H264 and non-H264 encoding paths, and to improve readability and maintainability of the code..
Consider extracting the common update logic into helper functions so that both branches reuse the same code where possible. For example, you can factor the rectangle handling into a small routine and then call it in the non‑H264 branch. One possible refactoring is:
static int process_frame_rectangles(VncState *vs, VncJob *job) {
int n_rectangles = 0;
VncRectEntry *entry, *tmp;
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
int n;
if (job->vs->ioc == NULL) {
vnc_unlock_display(job->vs->vd);
/* Copy persistent encoding data */
vnc_async_encoding_end(job->vs, vs);
return -1; // signal disconnect
}
if (vnc_worker_clamp_rect(vs, job, &entry->rect)) {
n = vnc_send_framebuffer_update(vs,
entry->rect.x,
entry->rect.y,
entry->rect.w,
entry->rect.h);
if (n >= 0) {
n_rectangles += n;
}
}
g_free(entry);
}
return n_rectangles;
}
Then, in your worker thread loop, you can simplify the two branches:
vs.magic = VNC_MAGIC;
n_rectangles = 0;
vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(&vs, 0);
saved_offset = vs.output.offset;
vnc_write_u16(&vs, 0);
vnc_lock_display(job->vs->vd);
if (vs.vnc_encoding == VNC_ENCODING_H264) {
int width = pixman_image_get_width(vs.vd->server);
int height = pixman_image_get_height(vs.vd->server);
int n = vnc_send_framebuffer_update(&vs, 0, 0, width, height);
if (n >= 0)
n_rectangles += n;
/* Free all rectangles since we are using full frame update */
VncRectEntry *entry, *tmp;
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
g_free(entry);
}
} else {
int n = process_frame_rectangles(&vs, job);
if (n < 0)
goto disconnected;
n_rectangles += n;
}
trace_vnc_job_nrects(&vs, job, n_rectangles);
vnc_unlock_display(job->vs->vd);
/* Put n_rectangles at the beginning of the message */
vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
vnc_lock_output(job->vs);
This refactoring reduces duplicated rectangle processing logic while keeping all functionality intact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This suggestion doesn't remove any duplication, as the new funtion is only called in 1 place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand the context of the review comment and the subsequent response. Here's a thoughtful reply:
@berrange You make a fair point. The suggested refactoring might not significantly reduce code duplication if the extracted function is only called in one place.
The primary goal of my original suggestion was to improve code readability and maintainability, but if the proposed helper function doesn't provide clear benefits, it may indeed be unnecessary. In this case, keeping the current implementation might be more straightforward.
If you see opportunities for genuine code simplification or reduction of complexity in this section, I'm open to hearing your perspective. Sometimes, the most effective refactoring comes from the developers most familiar with the specific context and requirements of the code.
Would you be interested in discussing alternative approaches to improving the code structure or readability?
The patches already add a configure option
Nope, this doesn't make sense. Any other comments about correctness of the code ? |
@CodiumAI-Agent /review |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
WalkthroughThis change set introduces optional H.264 video encoding for the VNC server using the GStreamer multimedia framework. The build system is updated to detect and configure GStreamer support, and a new build option is provided for enabling or disabling this feature. Integration with GStreamer is conditionally compiled and initialized at runtime. The VNC implementation is extended with new logic to negotiate, initialize, and utilize H.264 encoding for framebuffer updates, including support for encoder selection and handling of dirty regions. New source files and API declarations are added to support this functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant QEMU
participant GStreamer
participant VNC_Client
User->>QEMU: Start QEMU with VNC + H264 option
QEMU->>GStreamer: gst_init()
QEMU->>VNC_Client: Negotiate encodings (includes H264)
VNC_Client->>QEMU: Requests H264 encoding
QEMU->>GStreamer: Setup encoder pipeline
loop On framebuffer update
QEMU->>GStreamer: Push raw frame data
GStreamer-->>QEMU: Encoded H264 frame
QEMU->>VNC_Client: Send H264 framebuffer update
end
User->>QEMU: Shutdown
QEMU->>GStreamer: Cleanup pipeline
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🔭 Outside diff range comments (1)
ui/vnc-jobs.c (1)
196-209
: 🛠️ Refactor suggestionThread-safety risk: raw pointer to
VncH264
is shared without ownership rules
vnc_async_encoding_start()
/_end()
merely copy the rawVncH264 *
pointer between the I/O thread and the worker thread. While this works today, both threads may concurrently dereference the same GStreamer objects (e.g. if the main thread callsvnc_h264_clear()
while the worker is still running) which is undefined behaviour and will crash inside GStreamer.A low-cost fix is to guard
vs->h264
with the existingoutput_mutex
or hand the ownership exclusively to the worker for the duration of the job./* vnc_async_encoding_start */ - local->h264 = orig->h264; + WITH_QEMU_LOCK_GUARD(&orig->output_mutex) { + local->h264 = orig->h264; + if (local->h264) { + g_atomic_int_inc(&local->h264->refcnt); + } + }…and symmetrically dec-ref in
_end()
.
♻️ Duplicate comments (2)
ui/vnc-enc-h264.c (1)
274-287
:⚠️ Potential issueReturn value breaks contract with header
vnc_h264_encoder_init()
is declared asbool
but returns-1
on error.
Every caller will interpret this as “success”. Returnfalse
instead.- VNC_DEBUG("No H264 encoder available.\n"); - return -1; + VNC_DEBUG("No H264 encoder available.\n"); + return false; ... - return true; + return true; /* unchanged */ui/vnc.c (1)
3243-3256
: Refactor H.264 “keep-dirty” handling into a helper (comment repeated)This block inlines state management for
keep_dirty
, increasing the nesting
and cognitive load insidevnc_refresh()
. A prior review already suggested
extracting it into a helper (see earlier discussion); the advice is still
valid and would make both paths (H.264 vs. non-H.264) easier to follow.
🧹 Nitpick comments (4)
meson.build (1)
1352-1357
: Verify and refine the gstreamer dependency detection logic.The condition
if not get_option('gstreamer').auto() or have_block
will probe for GStreamer whenever block‐device support is enabled, but H.264 encoding is actually tied to VNC, not block I/O. Consider tightening this to only detect GStreamer when the user explicitly requests it (get_option('gstreamer').enabled()
) or when VNC is enabled (get_option('vnc').enabled()
).scripts/meson-buildoptions.sh (1)
232-232
: Reposition the help entry to maintain alphabetical order.The new
gstreamer
entry appears at the end of the list, but help options are grouped alphabetically. To keep the UI consistent, move:-- gstreamer gstreamer support (H264 for VNC)
into the
g
section (e.g., betweenglusterfs
andgnutls
).ui/vnc.h (1)
49-52
: Avoid leaking GStreamer types to public headers
<gst/gst.h>
is included unconditionally wheneverCONFIG_GSTREAMER
is set, propagating heavy GStreamer macros to every translation unit that includesvnc.h
. Wrapping all GStreamer-specific structs in an opaque forward declaration keeps compile times down and removes dependency surprises for downstream code.Also applies to: 191-194, 242-253
ui/vnc-enc-h264.c (1)
357-385
: Defensive coding: replace tightassert()
s with runtime checksThe function aborts the whole QEMU process if the server size ever differs
fromclient_width
/client_height
. A mis-behaving client should not be
able to crash the hypervisor; return-1
and fall back to RAW instead.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
meson.build
(3 hunks)meson_options.txt
(1 hunks)scripts/meson-buildoptions.sh
(2 hunks)system/vl.c
(2 hunks)ui/meson.build
(1 hunks)ui/vnc-enc-h264.c
(1 hunks)ui/vnc-jobs.c
(3 hunks)ui/vnc.c
(7 hunks)ui/vnc.h
(7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
ui/vnc.c (3)
ui/vnc.h (6)
vnc_h264_send_framebuffer_update
(655-655)vs
(72-72)vs
(74-74)vs
(76-80)vnc_h264_clear
(656-656)vnc_h264_encoder_init
(654-654)ui/vnc-enc-h264.c (3)
vnc_h264_send_framebuffer_update
(302-387)vnc_h264_clear
(389-401)vnc_h264_encoder_init
(274-296)ui/vnc-jobs.c (3)
vnc_job_new
(82-92)vnc_job_add_rect
(94-109)vnc_job_push
(111-121)
🪛 Cppcheck (2.10-2)
ui/vnc-enc-h264.c
[error] 48-48: syntax error
(syntaxError)
🔇 Additional comments (7)
meson_options.txt (1)
257-258
: LGTM! The GStreamer option is correctly defined.The new GStreamer option is properly defined as a feature type with an
auto
default value, which is consistent with other VNC-related options. The description clearly indicates its purpose for VNC H.264 encoding.system/vl.c (2)
143-145
: LGTM! Proper conditional inclusion of GStreamer headers.The GStreamer header inclusion is correctly guarded with
CONFIG_GSTREAMER
preprocessor checks, ensuring it's only included when the feature is enabled.
2855-2857
: LGTM! GStreamer initialization is correctly implemented.The GStreamer initialization with
gst_init(&argc, &argv)
is properly guarded withCONFIG_GSTREAMER
and placed early in the initialization sequence, which is important as it allows GStreamer to process any of its own command-line arguments.ui/meson.build (1)
49-49
: LGTM! Conditional addition of the H.264 encoder source.The new source file
vnc-enc-h264.c
is correctly added to the VNC source set, conditionally included only when GStreamer is enabled. This follows the same pattern used for other conditional VNC features like SASL authentication.meson.build (2)
2574-2575
: Record GStreamer found status correctly.Setting
CONFIG_GSTREAMER
togstreamer.found()
aligns with other feature flags. This will make the#ifdef CONFIG_GSTREAMER
guard available in C code.
4848-4849
: Include GStreamer in the configuration summary.Adding
{'gstreamer support': gstreamer}
tosummary_info
follows the existing pattern for optional dependencies (e.g., zstd, qpl). This will print the detected GStreamer package orfalse
if not found.ui/vnc-enc-h264.c (1)
119-147
:destroy_encoder_context()
ignores NULL safety for partial initIf failure happens mid-initialisation some members may still be
NULL
.
gst_clear_object()
already toleratesNULL
, butgst_element_set_state
does not – guard the call:if (h264->pipeline) { ... }
--enable-gstreamer) printf "%s" -Dgstreamer=enabled ;; | ||
--disable-gstreamer) printf "%s" -Dgstreamer=disabled ;; | ||
*) return 1 ;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Regenerate this script instead of manual edits.
This file is auto‐generated by meson-buildoptions.py
(“do not edit!”). Manual additions risk being overwritten. Please update meson-buildoptions.py
(and/or meson_options.txt
) to include gstreamer
, then re-run the generator to produce these --enable-gstreamer
/--disable-gstreamer
entries.
if (vs.vnc_encoding == VNC_ENCODING_H264) { | ||
int width = pixman_image_get_width(vs.vd->server); | ||
int height = pixman_image_get_height(vs.vd->server); | ||
int n = vnc_send_framebuffer_update(&vs, 0, 0, width, height); | ||
if (n >= 0) { | ||
n_rectangles += n; | ||
} | ||
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) { | ||
g_free(entry); | ||
} | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible disconnection race is no longer handled for H.264 path
In the legacy branch we bail out if job->vs->ioc == NULL
to avoid writing to a dead socket, yet the new H.264 branch omits this check. If the client disappears between the first ioc
check (line 262) and this point the encoder may still produce data that will never be sent and leak buffers.
At minimum mirror the early-exit pattern used below:
if (job->vs->ioc == NULL) {
vnc_unlock_display(job->vs->vd);
vnc_async_encoding_end(job->vs, &vs);
goto disconnected;
}
bool vnc_h264_encoder_init(VncState *vs); | ||
int vnc_h264_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); | ||
void vnc_h264_clear(VncState *vs); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public API returns bool
– callers expect false
, not -1
The declaration advertises a boolean result, but the implementation (ui/vnc-enc-h264.c
) returns -1
on failure. In C this is equivalent to true
, so error paths are silently treated as success. Please change the implementation to return false
instead (and keep the success path returning true
).
src_buffer = gst_buffer_new_wrapped_full( | ||
0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL); | ||
|
||
g_signal_emit_by_name( | ||
vs->h264->source, "push-buffer", src_buffer, &flow_ret); | ||
|
||
if (flow_ret != GST_FLOW_OK) { | ||
VNC_DEBUG("gst appsrc push buffer failed\n"); | ||
return -1; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src_buffer
is never unreffed – memory leak per frame
gst_buffer_new_wrapped_full()
adds a reference which must be released
after the push succeeds. Without gst_buffer_unref(src_buffer)
the
reference count is never decremented, leaking one buffer every screen
refresh.
g_signal_emit_by_name(
vs->h264->source, "push-buffer", src_buffer, &flow_ret);
+gst_buffer_unref(src_buffer); /* drop our reference */
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
src_buffer = gst_buffer_new_wrapped_full( | |
0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL); | |
g_signal_emit_by_name( | |
vs->h264->source, "push-buffer", src_buffer, &flow_ret); | |
if (flow_ret != GST_FLOW_OK) { | |
VNC_DEBUG("gst appsrc push buffer failed\n"); | |
return -1; | |
} | |
src_buffer = gst_buffer_new_wrapped_full( | |
0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL); | |
g_signal_emit_by_name( | |
vs->h264->source, "push-buffer", src_buffer, &flow_ret); | |
gst_buffer_unref(src_buffer); /* drop our reference */ | |
if (flow_ret != GST_FLOW_OK) { | |
VNC_DEBUG("gst appsrc push buffer failed\n"); | |
return -1; | |
} |
#ifdef CONFIG_GSTREAMER | ||
case VNC_ENCODING_H264: | ||
if (vs->vd->h264_encoder_list != NULL) { /* if h264 is enabled */ | ||
if (vnc_h264_encoder_init(vs)) { | ||
vnc_set_feature(vs, VNC_FEATURE_H264); | ||
vs->vnc_encoding = enc; | ||
} | ||
} | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vnc_h264_encoder_init()
uses bool but returns -1
→ error paths look like success
vnc_h264_encoder_init()
is declared to return int
/bool
but its
implementation returns -1
on failure and true
on success.
Because C treats every non-zero value as true, callers (like the block
below) treat the failure path as success and enable H.264 anyway.
- if (encoder_name == NULL) {
- VNC_DEBUG("No H264 encoder available.\n");
- return -1;
+ if (!encoder_name) {
+ VNC_DEBUG("No H264 encoder available.\n");
+ return false; /* ← failure */
}
...
- return true;
Update both the implementation and all call-sites (set_encodings()
, etc.) to
treat false
/0
as failure.
This prevents clients from negotiating a non-working H.264 stream.
Committable suggestion skipped: line range outside the PR's diff.
case VNC_ENCODING_H264: | ||
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h); | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard H.264 case with CONFIG_GSTREAMER
to avoid link-time breakage
vnc_h264_send_framebuffer_update()
is only compiled when CONFIG_GSTREAMER
is defined (see ui/vnc-enc-h264.c
).
When QEMU is built without GStreamer, the symbol is absent, and these
un-guarded lines will trigger an undefined-reference linker error.
+#ifdef CONFIG_GSTREAMER
case VNC_ENCODING_H264:
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h);
break;
+#endif
If you still want VNC_ENCODING_H264
numerically accepted when GStreamer is
disabled, fall back to VNC_ENCODING_RAW
(or reject it) inside the #else
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
case VNC_ENCODING_H264: | |
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h); | |
break; | |
#ifdef CONFIG_GSTREAMER | |
case VNC_ENCODING_H264: | |
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h); | |
break; | |
#endif |
const char *h264_opt = qemu_opt_get(opts, "h264"); | ||
if (!strcmp(h264_opt, "off")) { | ||
vd->h264_encoder_list = NULL; /* disable h264 */ | ||
} else if (!strcmp(h264_opt, "on")) { | ||
vd->h264_encoder_list = ""; /* use default encoder list */ | ||
} else { | ||
/* assume this is a list of endiers */ | ||
vd->h264_encoder_list = h264_opt; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strcmp()
on a possible NULL
‑ unchecked access can segfault
qemu_opt_get(opts, "h264")
returns NULL
when the option is omitted, but the
code immediately dereferences the pointer with strcmp()
.
Booting QEMU without an explicit h264=
parameter will therefore crash.
const char *h264_opt = qemu_opt_get(opts, "h264");
/* Default: "on" when option is absent */
-if (!strcmp(h264_opt, "off")) {
+if (!h264_opt || !strcmp(h264_opt, "on")) {
+ vd->h264_encoder_list = ""; /* enable with default list */
+} else if (!strcmp(h264_opt, "off")) {
vd->h264_encoder_list = NULL; /* disable h264 */
-} else if (!strcmp(h264_opt, "on")) {
- vd->h264_encoder_list = ""; /* enable with default list */
} else {
/* assume this is a comma-separated encoder list */
vd->h264_encoder_list = h264_opt;
}
Add a unit/CLI test to ensure bare -vnc ...,h264
(or no parameter) no longer
crashes.
Committable suggestion skipped: line range outside the PR's diff.
ASAN spotted a leaking string in machine_set_loadparm(): Direct leak of 9 byte(s) in 1 object(s) allocated from: #0 0x560ffb5bb379 in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3 #1 0x7f1aca926518 in g_malloc ../glib/gmem.c:106 #2 0x7f1aca94113e in g_strdup ../glib/gstrfuncs.c:364 #3 0x560ffc8afbf9 in qobject_input_type_str ../qapi/qobject-input-visitor.c:542:12 #4 0x560ffc8a80ff in visit_type_str ../qapi/qapi-visit-core.c:349:10 #5 0x560ffbe6053a in machine_set_loadparm ../hw/s390x/s390-virtio-ccw.c:802:10 qemu#6 0x560ffc0c5e52 in object_property_set ../qom/object.c:1450:5 qemu#7 0x560ffc0d4175 in object_property_set_qobject ../qom/qom-qobject.c:28:10 qemu#8 0x560ffc0c6004 in object_property_set_str ../qom/object.c:1458:15 qemu#9 0x560ffbe2ae60 in update_machine_ipl_properties ../hw/s390x/ipl.c:569:9 qemu#10 0x560ffbe2aa65 in s390_ipl_update_diag308 ../hw/s390x/ipl.c:594:5 qemu#11 0x560ffbdee132 in handle_diag_308 ../target/s390x/diag.c:147:9 qemu#12 0x560ffbebb956 in helper_diag ../target/s390x/tcg/misc_helper.c:137:9 qemu#13 0x7f1a3c51c730 (/memfd:tcg-jit (deleted)+0x39730) Cc: [email protected] Signed-off-by: Fabiano Rosas <[email protected]> Message-ID: <[email protected]> Fixes: 1fd396e ("s390x: Register TYPE_S390_CCW_MACHINE properties as class properties") Reviewed-by: Thomas Huth <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Signed-off-by: Thomas Huth <[email protected]>
ASAN spotted a leak of the memory used to hold the tmp_path: Direct leak of 35 byte(s) in 1 object(s) allocated from: #0 0x55e29aa96da9 in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3 #1 0x7fe0cfb26518 in g_malloc ../glib/gmem.c:106 #2 0x7fe0cfb4146e in g_strconcat ../glib/gstrfuncs.c:629 #3 0x7fe0cfb0a78f in g_get_tmp_name ../glib/gfileutils.c:1742 #4 0x7fe0cfb0b00b in g_file_open_tmp ../glib/gfileutils.c:1802 #5 0x55e29ab53961 in test_ast2700_evb ../tests/qtest/ast2700-smc-test.c:20:10 qemu#6 0x55e29ab53803 in main ../tests/qtest/ast2700-smc-test.c:65:5 qemu#7 0x7fe0cf7bd24c in __libc_start_main ../csu/libc-start.c:308 qemu#8 0x55e29a9f7759 in _start ../sysdeps/x86_64/start.S:120 Signed-off-by: Fabiano Rosas <[email protected]> Reviewed-by: Jamin Lin <[email protected]> Message-ID: <[email protected]> Signed-off-by: Cédric Le Goater <[email protected]>
In stm32f250_soc_initfn() we mostly use the standard pattern for child objects of calling object_initialize_child(). However for s->adc_irqs we call object_new() and then later qdev_realize(), and we never unref the object on deinit. This causes a leak, detected by ASAN on the device-introspect-test: Indirect leak of 10 byte(s) in 1 object(s) allocated from: #0 0x5b9fc4789de3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-arm+0x21f1de3) (BuildId: 267a2619a026ed91c78a07b1eb2ef15381538efe) #1 0x740de3f28b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #2 0x740de3f3e4d8 in g_strdup (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x784d8) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #3 0x5b9fc70159e1 in g_strdup_inline /usr/include/glib-2.0/glib/gstrfuncs.h:321:10 #4 0x5b9fc70159e1 in object_property_try_add /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1276:18 #5 0x5b9fc7015f94 in object_property_add /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1294:12 qemu#6 0x5b9fc701b900 in object_add_link_prop /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:2021:10 qemu#7 0x5b9fc701b3fc in object_property_add_link /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:2037:12 qemu#8 0x5b9fc4c299fb in qdev_init_gpio_out_named /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/gpio.c:90:9 qemu#9 0x5b9fc4c29b26 in qdev_init_gpio_out /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/gpio.c:101:5 qemu#10 0x5b9fc4c0f77a in or_irq_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/or-irq.c:70:5 qemu#11 0x5b9fc70257e1 in object_init_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:428:9 qemu#12 0x5b9fc700cd4b in object_initialize_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:570:5 qemu#13 0x5b9fc700e66d in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:774:5 qemu#14 0x5b9fc700e750 in object_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:789:12 qemu#15 0x5b9fc68b2162 in stm32f205_soc_initfn /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/stm32f205_soc.c:69:26 Switch to using object_initialize_child() like all our other child objects for this SoC object. Cc: [email protected] Fixes: b63041c ("STM32F205: Connect the ADC devices") Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-id: [email protected]
The serial-pci-multi device initializes an IRQ with qemu_init_irq() in its instance_init function; however it never calls qemu_free_irq(), so the init/deinit cycle has a memory leak, which ASAN catches in the device-introspect-test: Direct leak of 576 byte(s) in 6 object(s) allocated from: #0 0x626306ddade3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qem u-system-arm+0x21f1de3) (BuildId: 52ece17287eba2d68e5be980e1856cd1f6be932f) #1 0x7756ade79b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1 eb6131419edb83b2178b682829a6913cf682d75) #2 0x7756ade5b45a in g_hash_table_new_full (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4445a ) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #3 0x62630965da37 in object_initialize_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qem u/build/arm-asan/../../qom/object.c:568:23 #4 0x62630965d440 in object_initialize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/ar m-asan/../../qom/object.c:578:5 #5 0x626309653eeb in qemu_init_irq /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-as an/../../hw/core/irq.c:48:5 qemu#6 0x6263072370bb in multi_serial_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/char/serial-pci-multi.c:183:9 Use the new qemu_init_irq_child() function instead, so that the IRQ object is automatically unreffed when the serial-pci device is deinited. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-ID: <[email protected]> [PMD: Use "irq[*]" as child property name] Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
The ICH9 PCI device uses qemu_init_irq() in its instance_init method, but fails to clean it up in its uninit. This results in a leak, detected by ASAN when running the device-introspect-test: Direct leak of 96 byte(s) in 1 object(s) allocated from: #0 0x58f3b53ecde3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qem u-system-arm+0x21f1de3) (BuildId: 8dcd38b1d76bd7bd44f905c38200f4cceafd7ca4) #1 0x72e446dd5b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1 eb6131419edb83b2178b682829a6913cf682d75) #2 0x72e446db745a in g_hash_table_new_full (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4445a ) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #3 0x58f3b7c6fc67 in object_initialize_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qem u/build/arm-asan/../../qom/object.c:568:23 #4 0x58f3b7c6f670 in object_initialize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/ar m-asan/../../qom/object.c:578:5 #5 0x58f3b7c6611b in qemu_init_irq /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/irq.c:48:5 qemu#6 0x58f3b5c6e931 in pci_ich9_ahci_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/ide/ich.c:117:5 We could call qemu_free_irq() in pci_ich9_uninit(), but since we have a method of initializing the IRQ that doesn't need manual freeing, use that instead: qemu_init_irq_child(). Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
In pca9554_set_pin() we have a string property which we parse in order to set some non-string fields in the device state. So we call visit_type_str(), passing it the address of the local variable state_str. visit_type_str() will allocate a new copy of the string; we never free this string, so the result is a memory leak, detected by ASAN during a "make check" run: Direct leak of 5 byte(s) in 1 object(s) allocated from: #0 0x5d605212ede3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-arm+0x21f1de3) ( BuildId: 3d5373c89317f58bfcd191a33988c7347714be14) #1 0x7f7edea57b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b68282 9a6913cf682d75) #2 0x7f7edea6d4d8 in g_strdup (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x784d8) (BuildId: 1eb6131419edb83b2178b68282 9a6913cf682d75) #3 0x5d6055289a91 in g_strdup_inline /usr/include/glib-2.0/glib/gstrfuncs.h:321:10 #4 0x5d6055289a91 in qobject_input_type_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qapi/qo bject-input-visitor.c:542:12 #5 0x5d605528479c in visit_type_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qapi/qapi-visit -core.c:349:10 qemu#6 0x5d60528bdd87 in pca9554_set_pin /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/gpio/pca9554.c:179:10 qemu#7 0x5d60549bcbbb in object_property_set /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1450:5 qemu#8 0x5d60549d2055 in object_property_set_qobject /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/qom-qobject.c:28:10 qemu#9 0x5d60549bcdf1 in object_property_set_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1458:15 qemu#10 0x5d605439d077 in gb200nvl_bmc_i2c_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/aspeed.c:1267:5 qemu#11 0x5d60543a3bbc in aspeed_machine_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/aspeed.c:493:9 Make the state_str g_autofree, so that we will always free it, on both error-exit and success codepaths. Cc: [email protected] Fixes: de0c7d5 ("misc: Add a pca9554 GPIO device model") Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Glenn Miles <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
In the xnlx_dp_init() function we create the s->dpcd and s->edid objects with qdev_new(); then in xlnx_dp_realize() we realize the dpcd with qdev_realize() and the edid with qdev_realize_and_unref(). This is inconsistent, and both ways result in a memory leak for the instance_init -> deinit lifecycle tested by device-introspect-test: Indirect leak of 1968 byte(s) in 1 object(s) allocated from: #0 0x5aded4d54e23 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x24ffe23) (BuildId: 9f1e6c5 3fecd904ba5fc1f521d7da080a0e4103b) #1 0x71fbfac9bb09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #2 0x5aded7b9211c in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:767:15 #3 0x5aded7b92240 in object_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:789:12 #4 0x5aded7b773e4 in qdev_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/qdev.c:149:19 #5 0x5aded54458be in xlnx_dp_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/display/xlnx_dp.c:1272:20 Direct leak of 344 byte(s) in 1 object(s) allocated from: #0 0x5aded4d54e23 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x24ffe23) (BuildId: 9f1e6c53fecd904ba5fc1f521d7da080a0e4103b) #1 0x71fbfac9bb09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #2 0x5aded7b9211c in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:767:15 #3 0x5aded7b92240 in object_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:789:12 #4 0x5aded7b773e4 in qdev_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/qdev.c:149:19 #5 0x5aded5445a56 in xlnx_dp_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/display/xlnx_dp.c:1275:22 Instead, explicitly object_unref() after we have added the objects as child properties of the device. This means they will automatically be freed when this device is deinited. When we do this, qdev_realize() is the correct way to realize them in xlnx_dp_realize(). Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Francisco Iglesias <[email protected]> Reviewed-by: Manos Pitsidianakis <[email protected]> Reviewed-by: Edgar E. Iglesias <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
When running the bios-tables-test under ASAN we see leaks like this: Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x5bc58579b00d in calloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x250400d) (BuildId: 2e27b63dc9ac45f522ced40a17c2a60cc32f1d38) #1 0x7b4ad90337b1 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x637b1) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #2 0x5bc5861826db in qmp_memory_device_list /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/mem/memory-device.c:307:34 #3 0x5bc587a9edb6 in arm_load_dtb /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/boot.c:656:15 Indirect leak of 28 byte(s) in 2 object(s) allocated from: #0 0x5bc58579ae23 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x2503e23) (BuildId: 2e27b63dc9ac45f522ced40a17c2a60cc32f1d38) #1 0x7b4ad6c8f947 in __vasprintf_internal libio/vasprintf.c:116:16 #2 0x7b4ad9080a52 in g_vasprintf (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0xb0a52) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #3 0x7b4ad90515e4 in g_strdup_vprintf (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x815e4) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #4 0x7b4ad9051940 in g_strdup_printf (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x81940) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75) #5 0x5bc5885eb739 in object_get_canonical_path /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:2123:19 qemu#6 0x5bc58618dca8 in pc_dimm_md_fill_device_info /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/mem/pc-dimm.c:268:18 qemu#7 0x5bc586182792 in qmp_memory_device_list /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/mem/memory-device.c:310:9 This happens because we declared the MemoryDeviceInfoList *md_list with g_autofree, which will free the direct memory with g_free() but doesn't free all the other data structures referenced by it. Instead what we want is to declare the pointer with g_autoptr(), which will automatically call the qapi_free_MemoryDeviceInfoList() cleanup function when the variable goes out of scope. Fixes: 36bc78a ("hw/arm: add static NVDIMMs in device tree") Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Manos Pitsidianakis <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
As defined by:
https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#open-h-264-encoding
The noVNC HTML application recently added support for this encoding. There is
also an open pull request to add audio support to noVNC:
novnc/noVNC#1952
With that in place, the web based VNC console is good enough to display
a VM showing a video with reasonable bandwidth.
Possible improvements:
We may also extend the RFB Audio protocol with "opus" encoding, because uncompressed
audio need too much bandwidth.
Summary by Sourcery
Add H.264 video encoding support for VNC using GStreamer, enabling more efficient video streaming over VNC connections
New Features:
Enhancements:
Build:
CI:
Summary by CodeRabbit
New Features
Chores