From patchwork Tue Feb 11 21:43:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970737 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EC12BC021A2 for ; Tue, 11 Feb 2025 21:45:04 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy3L-0007wy-2k; Tue, 11 Feb 2025 16:44:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3H-0007wA-9J for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:19 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3E-00057M-99 for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310255; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7fpWi6Lp+0idjuJpbly0bAmMnHVPZli1daAYI9ZCRM4=; b=ZD12PBkxpM6vhZFGNDWFOI04NZuhjsYLOZU3fg1Vfjq0AQAV0hn34PxU608LIWknX7WP0S uksPbaqgPrhJDVrnUaWtL5rtZaRA/Cl1HPPX0P5nwdCasi0y8EDlWcTeRDHyo0WXsCMoCQ 2FiwkH87J6SNia0lOkvEkIAAjd4AriY= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-582-oju8D7GoNEipsrnBma2jOg-1; Tue, 11 Feb 2025 16:44:11 -0500 X-MC-Unique: oju8D7GoNEipsrnBma2jOg-1 X-Mimecast-MFC-AGG-ID: oju8D7GoNEipsrnBma2jOg Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 97EF7180087F; Tue, 11 Feb 2025 21:44:08 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1F015195608D; Tue, 11 Feb 2025 21:44:05 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 01/11] rust: Build separate qemu_api_tools and qemu_api_system Date: Tue, 11 Feb 2025 22:43:18 +0100 Message-ID: <20250211214328.640374-2-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The existing qemu_api library can't be linked into tools because it contains a few bindings for things that only exist in the system emulator. This adds a new "system" feature to the qemu_api crate that enables the system emulator parts in it, and build the crate twice: qemu_api_tools is the core library that can be linked into tools, and qemu_api_system is the full one for the system emulator. Unfortunately, since library names have to be unique in meson, this means that every user of the library now needs to specify a rust_dependency_map to make either qemu_api_tools or qemu_api_system show up as the qemu_api crate in Rust. Signed-off-by: Kevin Wolf --- rust/wrapper-system.h | 44 +++++++++++++++++++++ rust/wrapper.h | 9 ----- meson.build | 11 +++++- rust/hw/char/pl011/meson.build | 3 +- rust/meson.build | 11 +++--- rust/qemu-api/Cargo.toml | 1 + rust/qemu-api/build.rs | 10 ++++- rust/qemu-api/meson.build | 70 ++++++++++++++++++++++------------ rust/qemu-api/src/bindings.rs | 16 ++++++-- rust/qemu-api/src/lib.rs | 4 ++ rust/qemu-api/src/prelude.rs | 2 + rust/qemu-api/src/zeroable.rs | 10 +++++ 12 files changed, 143 insertions(+), 48 deletions(-) create mode 100644 rust/wrapper-system.h diff --git a/rust/wrapper-system.h b/rust/wrapper-system.h new file mode 100644 index 0000000000..fc6c571e6d --- /dev/null +++ b/rust/wrapper-system.h @@ -0,0 +1,44 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2024 Linaro Ltd. + * + * Authors: Manos Pitsidianakis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +/* + * This header file is meant to be used as input to the `bindgen` application + * in order to generate C FFI compatible Rust bindings. + */ + +/* The system emulator has all of the bindings tools have */ +#include "wrapper.h" + +#include "system/system.h" +#include "hw/sysbus.h" +#include "exec/memory.h" +#include "hw/clock.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/irq.h" +#include "migration/vmstate.h" diff --git a/rust/wrapper.h b/rust/wrapper.h index a9bc67af0d..41be87adcf 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -50,15 +50,6 @@ typedef enum memory_order { #include "qemu/osdep.h" #include "qemu/module.h" #include "qemu-io.h" -#include "system/system.h" -#include "hw/sysbus.h" -#include "exec/memory.h" #include "chardev/char-fe.h" -#include "hw/clock.h" -#include "hw/qdev-clock.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "hw/irq.h" #include "qapi/error.h" -#include "migration/vmstate.h" #include "chardev/char-serial.h" diff --git a/meson.build b/meson.build index 18cf9e2913..1f26801b69 100644 --- a/meson.build +++ b/meson.build @@ -4094,10 +4094,17 @@ if have_rust # this case you must pass the path to `clang` and `libclang` to your build # command invocation using the environment variables CLANG_PATH and # LIBCLANG_PATH - bindings_rs = rust.bindgen( + bindings_rs_tools = rust.bindgen( input: 'rust/wrapper.h', + output: 'bindings_tools.inc.rs', + include_directories: include_directories('.', 'include'), + bindgen_version: ['>=0.60.0'], + args: bindgen_args, + ) + bindings_rs_system = rust.bindgen( + input: 'rust/wrapper-system.h', dependencies: common_ss.all_dependencies(), - output: 'bindings.inc.rs', + output: 'bindings_system.inc.rs', include_directories: include_directories('.', 'include'), bindgen_version: ['>=0.60.0'], args: bindgen_args, diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build index 547cca5a96..d2cfede5dc 100644 --- a/rust/hw/char/pl011/meson.build +++ b/rust/hw/char/pl011/meson.build @@ -12,9 +12,10 @@ _libpl011_rs = static_library( dependencies: [ bilge_dep, bilge_impl_dep, - qemu_api, + qemu_api_system, qemu_api_macros, ], + rust_dependency_map: {'qemu_api_system': 'qemu_api'}, ) rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency( diff --git a/rust/meson.build b/rust/meson.build index 91e52b8fb8..50eb23b072 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -9,18 +9,19 @@ if cargo.found() run_target('clippy', command: [config_host['MESON'], 'devenv', '--workdir', '@CURRENT_SOURCE_DIR@', - cargo, 'clippy', '--tests'], - depends: bindings_rs) + cargo, 'clippy', '--tests', '--features', 'system'], + depends: bindings_rs_system) run_target('rustfmt', command: [config_host['MESON'], 'devenv', '--workdir', '@CURRENT_SOURCE_DIR@', cargo, 'fmt'], - depends: bindings_rs) + depends: bindings_rs_system) run_target('rustdoc', command: [config_host['MESON'], 'devenv', '--workdir', '@CURRENT_SOURCE_DIR@', - cargo, 'doc', '--no-deps', '--document-private-items'], - depends: bindings_rs) + cargo, 'doc', '--no-deps', '--document-private-items', + '--features', 'system'], + depends: bindings_rs_system) endif diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml index a51dd14285..ed7b60bc80 100644 --- a/rust/qemu-api/Cargo.toml +++ b/rust/qemu-api/Cargo.toml @@ -24,6 +24,7 @@ version_check = "~0.9" default = ["debug_cell"] allocator = [] debug_cell = [] +system= [] [lints] workspace = true diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs index 471e6c633d..b14f9d4e4a 100644 --- a/rust/qemu-api/build.rs +++ b/rust/qemu-api/build.rs @@ -16,7 +16,13 @@ fn main() -> Result<()> { let path = env::var("MESON_BUILD_ROOT") .unwrap_or_else(|_| format!("{}/src", env!("CARGO_MANIFEST_DIR"))); - let file = format!("{}/bindings.inc.rs", path); + let basename = if cfg!(feature = "system") { + "bindings_system.inc.rs" + } else { + "bindings_tools.inc.rs" + }; + + let file = format!("{}/{}", path, basename); let file = Path::new(&file); if !Path::new(&file).exists() { panic!(concat!( @@ -31,7 +37,7 @@ fn main() -> Result<()> { } let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = format!("{}/bindings.inc.rs", out_dir); + let dest_path = format!("{}/{}", out_dir, basename); let dest_path = Path::new(&dest_path); if dest_path.symlink_metadata().is_ok() { remove_file(dest_path)?; diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index 60944a657d..acac384936 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -10,39 +10,58 @@ if get_option('debug_mutex') _qemu_api_cfg += ['--cfg', 'feature="debug_cell"'] endif -_qemu_api_rs = static_library( - 'qemu_api', +sources_core = [ + 'src/lib.rs', + 'src/assertions.rs', + 'src/bindings.rs', + 'src/bitops.rs', + 'src/callbacks.rs', + 'src/cell.rs', + 'src/c_str.rs', + 'src/module.rs', + 'src/offset_of.rs', + 'src/prelude.rs', + 'src/qom.rs', + 'src/zeroable.rs', +] +sources_system = sources_core + [ + 'src/irq.rs', + 'src/qdev.rs', + 'src/sysbus.rs', + 'src/vmstate.rs', +] + + +_qemu_api_tools_rs = static_library( + 'qemu_api_tools', structured_sources( - [ - 'src/lib.rs', - 'src/assertions.rs', - 'src/bindings.rs', - 'src/bitops.rs', - 'src/callbacks.rs', - 'src/cell.rs', - 'src/c_str.rs', - 'src/irq.rs', - 'src/module.rs', - 'src/offset_of.rs', - 'src/prelude.rs', - 'src/qdev.rs', - 'src/qom.rs', - 'src/sysbus.rs', - 'src/vmstate.rs', - 'src/zeroable.rs', - ], - {'.' : bindings_rs}, + sources_core, + {'.' : bindings_rs_tools}, ), override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', rust_args: _qemu_api_cfg, ) +_qemu_api_system_rs = static_library( + 'qemu_api_system', + structured_sources( + sources_system, + {'.' : bindings_rs_system}, + ), + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + rust_args: _qemu_api_cfg + ['--cfg', 'feature="system"'], +) -rust.test('rust-qemu-api-tests', _qemu_api_rs, +rust.test('rust-qemu-api-tests', _qemu_api_system_rs, suite: ['unit', 'rust']) -qemu_api = declare_dependency( - link_with: _qemu_api_rs, +qemu_api_tools = declare_dependency( + link_with: _qemu_api_tools_rs, + dependencies: qemu_api_macros, +) +qemu_api_system = declare_dependency( + link_with: _qemu_api_system_rs, dependencies: qemu_api_macros, ) @@ -59,7 +78,8 @@ test('rust-qemu-api-integration', override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_args: ['--test'], install: false, - dependencies: [qemu_api, qemu_api_macros], + dependencies: [qemu_api_system, qemu_api_macros], + rust_dependency_map: {'qemu_api_system': 'qemu_api'}, link_whole: [rust_qemu_api_objs, libqemuutil]), args: [ '--test', '--test-threads', '1', diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 8a9b821bb9..2bf6c13a32 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -15,15 +15,23 @@ clippy::missing_safety_doc )] -#[cfg(MESON)] -include!("bindings.inc.rs"); +#[cfg(all(MESON, not(feature="system")))] +include!("bindings_tools.inc.rs"); +#[cfg(all(MESON, feature="system"))] +include!("bindings_system.inc.rs"); -#[cfg(not(MESON))] -include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs")); +#[cfg(all(not(MESON), not(feature="system")))] +include!(concat!(env!("OUT_DIR"), "/bindings_tools.inc.rs")); +#[cfg(all(not(MESON), feature="system"))] +include!(concat!(env!("OUT_DIR"), "/bindings_system.inc.rs")); unsafe impl Send for Property {} unsafe impl Sync for Property {} unsafe impl Sync for TypeInfo {} + +#[cfg(feature="system")] unsafe impl Sync for VMStateDescription {} +#[cfg(feature="system")] unsafe impl Sync for VMStateField {} +#[cfg(feature="system")] unsafe impl Sync for VMStateInfo {} diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 3cf9371cff..3c6c154f3d 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -18,12 +18,16 @@ pub mod c_str; pub mod callbacks; pub mod cell; +#[cfg(feature = "system")] pub mod irq; pub mod module; pub mod offset_of; +#[cfg(feature = "system")] pub mod qdev; pub mod qom; +#[cfg(feature = "system")] pub mod sysbus; +#[cfg(feature = "system")] pub mod vmstate; pub mod zeroable; diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 2dc86e19b2..1b8d7d319e 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -17,6 +17,8 @@ pub use crate::qom_isa; +#[cfg(feature="system")] pub use crate::sysbus::SysBusDeviceMethods; +#[cfg(feature="system")] pub use crate::vmstate::VMState; diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs index 7b04947cb6..b454e9e05e 100644 --- a/rust/qemu-api/src/zeroable.rs +++ b/rust/qemu-api/src/zeroable.rs @@ -56,6 +56,7 @@ pub unsafe trait Zeroable: Default { /// ## Differences with `core::mem::zeroed` /// /// `const_zero` zeroes padding bits, while `core::mem::zeroed` doesn't +#[allow(unused)] macro_rules! const_zero { // This macro to produce a type-generic zero constant is taken from the // const_zero crate (v0.1.1): @@ -77,6 +78,7 @@ union TypeAsBytes { } /// A wrapper to implement the `Zeroable` trait through the `const_zero` macro. +#[allow(unused)] macro_rules! impl_zeroable { ($type:ty) => { unsafe impl Zeroable for $type { @@ -86,6 +88,7 @@ unsafe impl Zeroable for $type { } // bindgen does not derive Default here +#[cfg(feature = "system")] #[allow(clippy::derivable_impls)] impl Default for crate::bindings::VMStateFlags { fn default() -> Self { @@ -93,10 +96,17 @@ fn default() -> Self { } } +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::Property__bindgen_ty_1); +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::Property); +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::VMStateFlags); +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::VMStateField); +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::VMStateDescription); +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1); +#[cfg(feature = "system")] impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2); From patchwork Tue Feb 11 21:43:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970736 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7B71BC021A0 for ; Tue, 11 Feb 2025 21:45:03 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy3K-0007wj-8B; Tue, 11 Feb 2025 16:44:22 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3G-0007vf-GD for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:18 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3E-00057S-Mt for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310255; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=49QZIYrrAS5aS5cSfm2FbcETY+HU9KApwMSA1aqo0yM=; b=iXUnaY+xs5ul72ygFEQ2Cdet1X+k40O+qMETXd6g1rVN6w46TuMT20fB/H83B8f8Na+ElE d/R8+tuOsNJiSG3W3VcyUMFgcjdjKPqAkFPRhwFIBnUktCseievl2pke0fZYuoWnQFcMXf zOtM8f6cCCI2kwbsYHX0mo6FHxMWQR8= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-625-QhrwrscUOe2keRJ8VeJEzg-1; Tue, 11 Feb 2025 16:44:12 -0500 X-MC-Unique: QhrwrscUOe2keRJ8VeJEzg-1 X-Mimecast-MFC-AGG-ID: QhrwrscUOe2keRJ8VeJEzg Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6F0F81955DD0; Tue, 11 Feb 2025 21:44:11 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1C6AD1956048; Tue, 11 Feb 2025 21:44:08 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 02/11] meson: Add rust_block_ss and link tools with it Date: Tue, 11 Feb 2025 22:43:19 +0100 Message-ID: <20250211214328.640374-3-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Kevin Wolf --- meson.build | 36 ++++++++++++++++++++++++++++++++---- storage-daemon/meson.build | 2 +- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 1f26801b69..30aae6b3c3 100644 --- a/meson.build +++ b/meson.build @@ -3640,6 +3640,7 @@ qom_ss = ss.source_set() system_ss = ss.source_set() specific_fuzz_ss = ss.source_set() specific_ss = ss.source_set() +rust_block_ss = ss.source_set() rust_devices_ss = ss.source_set() stub_ss = ss.source_set() trace_ss = ss.source_set() @@ -4209,7 +4210,11 @@ foreach target : target_dirs arch_deps += target_specific.dependencies() if have_rust and target_type == 'system' - target_rust = rust_devices_ss.apply(config_target, strict: false) + target_rust_ss = ss.source_set() + target_rust_ss.add_all(rust_block_ss) + target_rust_ss.add_all(rust_devices_ss) + + target_rust = target_rust_ss.apply(config_target, strict: false) crates = [] foreach dep : target_rust.dependencies() crates += dep.get_variable('crate') @@ -4349,15 +4354,38 @@ if xkbcommon.found() endif if have_tools + tools_deps = [] + if have_rust + tools_rust = rust_block_ss.apply({}) + crates = [] + foreach dep : tools_rust.dependencies() + crates += dep.get_variable('crate') + endforeach + if crates.length() > 0 + rlib_rs = custom_target('rust_tools.rs', + output: 'rust_tools.rs', + command: [rust_root_crate, crates], + capture: true, + build_by_default: true, + build_always_stale: true) + rlib = static_library('rust_tools', + rlib_rs, + dependencies: tools_rust.dependencies(), + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'c') + tools_deps += declare_dependency(link_whole: [rlib]) + endif + endif + qemu_img = executable('qemu-img', [files('qemu-img.c'), hxdep], link_args: '@block.syms', link_depends: block_syms, - dependencies: [authz, block, crypto, io, qom, qemuutil], install: true) + dependencies: tools_deps + [authz, block, crypto, io, qom, qemuutil], install: true) qemu_io = executable('qemu-io', files('qemu-io.c'), link_args: '@block.syms', link_depends: block_syms, - dependencies: [block, qemuutil], install: true) + dependencies: tools_deps + [block, qemuutil], install: true) qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'), link_args: '@block.syms', link_depends: block_syms, - dependencies: [blockdev, qemuutil, selinux], + dependencies: tools_deps + [blockdev, qemuutil, selinux], install: true) subdir('storage-daemon') diff --git a/storage-daemon/meson.build b/storage-daemon/meson.build index 5e61a9d1bd..92bc2e0cba 100644 --- a/storage-daemon/meson.build +++ b/storage-daemon/meson.build @@ -9,6 +9,6 @@ if have_tools qsd = executable('qemu-storage-daemon', qsd_ss.sources(), link_args: '@block.syms', link_depends: block_syms, - dependencies: qsd_ss.dependencies(), + dependencies: tools_deps + qsd_ss.dependencies(), install: true) endif From patchwork Tue Feb 11 21:43:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970739 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7AC37C0219B for ; Tue, 11 Feb 2025 21:46:18 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy4X-0000E4-KN; Tue, 11 Feb 2025 16:45:40 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3N-0007xl-4J for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:28 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3K-0005CK-5Q for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310260; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XSzSFAT3rgdThuIc6FzbUhbBWhXyBUS0hMTEzRpzB2k=; b=NEGuWR2FPbOpfxFvBmFeujzMsCRRRZlkgVEmMBcSHSjp6wNSykj3CVa47N68xTKldrZfib 7xRHRUqmQweZhOk9S3Q4Cymj9JOhJQqQNX/ExZ+1pTS+p1FgvAr6z4iabPIZ/VPDkgULVz t2ECGN0MdwWculZMSUXX1ljMNq3kmyo= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-590-e6x9UmKPO-qPmCxSyi2fmg-1; Tue, 11 Feb 2025 16:44:16 -0500 X-MC-Unique: e6x9UmKPO-qPmCxSyi2fmg-1 X-Mimecast-MFC-AGG-ID: e6x9UmKPO-qPmCxSyi2fmg Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 236EA1955DD0; Tue, 11 Feb 2025 21:44:15 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E87B0195608D; Tue, 11 Feb 2025 21:44:11 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 03/11] rust: Add some block layer bindings Date: Tue, 11 Feb 2025 22:43:20 +0100 Message-ID: <20250211214328.640374-4-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Kevin Wolf --- rust/wrapper.h | 4 ++++ meson.build | 1 + rust/qemu-api/src/zeroable.rs | 5 +++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rust/wrapper.h b/rust/wrapper.h index 41be87adcf..c3e1e6f9cf 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -53,3 +53,7 @@ typedef enum memory_order { #include "chardev/char-fe.h" #include "qapi/error.h" #include "chardev/char-serial.h" +#include "block/block.h" +#include "block/block_int.h" +#include "block/qdict.h" +#include "qapi/qapi-visit-block-core.h" diff --git a/meson.build b/meson.build index 30aae6b3c3..154195bc80 100644 --- a/meson.build +++ b/meson.build @@ -4045,6 +4045,7 @@ if have_rust '--with-derive-default', '--no-layout-tests', '--no-prepend-enum-name', + '--allowlist-item', 'EINVAL|EIO', '--allowlist-file', meson.project_source_root() + '/include/.*', '--allowlist-file', meson.project_source_root() + '/.*', '--allowlist-file', meson.project_build_root() + '/.*' diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs index b454e9e05e..60af681293 100644 --- a/rust/qemu-api/src/zeroable.rs +++ b/rust/qemu-api/src/zeroable.rs @@ -56,7 +56,6 @@ pub unsafe trait Zeroable: Default { /// ## Differences with `core::mem::zeroed` /// /// `const_zero` zeroes padding bits, while `core::mem::zeroed` doesn't -#[allow(unused)] macro_rules! const_zero { // This macro to produce a type-generic zero constant is taken from the // const_zero crate (v0.1.1): @@ -78,7 +77,6 @@ union TypeAsBytes { } /// A wrapper to implement the `Zeroable` trait through the `const_zero` macro. -#[allow(unused)] macro_rules! impl_zeroable { ($type:ty) => { unsafe impl Zeroable for $type { @@ -110,3 +108,6 @@ fn default() -> Self { impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1); #[cfg(feature = "system")] impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2); + +impl_zeroable!(crate::bindings::BlockDriver); +impl_zeroable!(crate::bindings::BlockDriver__bindgen_ty_1); From patchwork Tue Feb 11 21:43:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970742 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5CB33C021A0 for ; Tue, 11 Feb 2025 21:47:20 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy5u-0001WB-EX; Tue, 11 Feb 2025 16:47:03 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3P-00080w-BS for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:36 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3K-0005DR-8r for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310261; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Gt9MtMPak5dCFIyItE8PxiGLTKybUmN/3gmNvVFg0uM=; b=boNZgKu8LA4H/zJVCtIkUz240W9E6caW+GCP8uwdFl8FkpzMfTK7UBgv0pANWMYWyAOQVU 9pp56iVSW52StpA4j9x1xz+AOLUUsSRu8HQJjjr5aOJgIKxnGSwfuezOuj5TO5lRzucVpI Tzsbk5YkOklAFBIvmrZpUUEoTdd1+Jg= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-114-uypDdlaqP2KLKHc8pFHSAA-1; Tue, 11 Feb 2025 16:44:19 -0500 X-MC-Unique: uypDdlaqP2KLKHc8pFHSAA-1 X-Mimecast-MFC-AGG-ID: uypDdlaqP2KLKHc8pFHSAA_1739310258 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F08A51800874; Tue, 11 Feb 2025 21:44:17 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9A93F195608D; Tue, 11 Feb 2025 21:44:15 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 04/11] rust/qemu-api: Add wrappers to run futures in QEMU Date: Tue, 11 Feb 2025 22:43:21 +0100 Message-ID: <20250211214328.640374-5-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This adds helper functions that allow running Rust futures to completion using QEMU's event loops. Signed-off-by: Kevin Wolf --- include/qemu/coroutine-rust.h | 24 +++++++++++ rust/wrapper.h | 1 + util/qemu-co-rust-async.c | 55 ++++++++++++++++++++++++ rust/qemu-api/meson.build | 1 + rust/qemu-api/src/futures.rs | 78 +++++++++++++++++++++++++++++++++++ rust/qemu-api/src/lib.rs | 1 + util/meson.build | 3 ++ 7 files changed, 163 insertions(+) create mode 100644 include/qemu/coroutine-rust.h create mode 100644 util/qemu-co-rust-async.c create mode 100644 rust/qemu-api/src/futures.rs diff --git a/include/qemu/coroutine-rust.h b/include/qemu/coroutine-rust.h new file mode 100644 index 0000000000..0c5cf42a6b --- /dev/null +++ b/include/qemu/coroutine-rust.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Helpers to run Rust futures using QEMU coroutines + * + * Copyright Red Hat + * + * Author: + * Kevin Wolf + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef QEMU_COROUTINE_RUST_H +#define QEMU_COROUTINE_RUST_H + +typedef struct RustBoxedFuture RustBoxedFuture; +typedef void coroutine_fn RunFuture(RustBoxedFuture *future, void *opaque); + +void no_coroutine_fn rust_run_future(RustBoxedFuture *future, + RunFuture *entry, + void *opaque); + +#endif diff --git a/rust/wrapper.h b/rust/wrapper.h index c3e1e6f9cf..61afac0494 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -57,3 +57,4 @@ typedef enum memory_order { #include "block/block_int.h" #include "block/qdict.h" #include "qapi/qapi-visit-block-core.h" +#include "qemu/coroutine-rust.h" diff --git a/util/qemu-co-rust-async.c b/util/qemu-co-rust-async.c new file mode 100644 index 0000000000..d893dfb7bd --- /dev/null +++ b/util/qemu-co-rust-async.c @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Helpers to run Rust futures using QEMU coroutines + * + * Copyright Red Hat + * + * Author: + * Kevin Wolf + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "block/aio-wait.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine-rust.h" +#include "qemu/main-loop.h" + +typedef struct FutureCo { + RustBoxedFuture *future; + RunFuture *entry; + void *opaque; + bool done; +} FutureCo; + +static void coroutine_fn rust_co_run_future_entry(void *opaque) +{ + FutureCo *data = opaque; + + data->entry(data->future, data->opaque); + data->done = true; + aio_wait_kick(); +} + +void no_coroutine_fn rust_run_future(RustBoxedFuture *future, + RunFuture *entry, + void *opaque) +{ + AioContext *ctx = qemu_get_current_aio_context(); + Coroutine *co; + FutureCo data = { + .future = future, + .entry = entry, + .opaque = opaque, + .done = false, + }; + + GLOBAL_STATE_CODE(); + + co = qemu_coroutine_create(rust_co_run_future_entry, &data); + aio_co_enter(ctx, co); + AIO_WAIT_WHILE(ctx, !data.done); +} diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index acac384936..713812bc2f 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -18,6 +18,7 @@ sources_core = [ 'src/callbacks.rs', 'src/cell.rs', 'src/c_str.rs', + 'src/futures.rs', 'src/module.rs', 'src/offset_of.rs', 'src/prelude.rs', diff --git a/rust/qemu-api/src/futures.rs b/rust/qemu-api/src/futures.rs new file mode 100644 index 0000000000..485041fd98 --- /dev/null +++ b/rust/qemu-api/src/futures.rs @@ -0,0 +1,78 @@ +use crate::bindings; +use std::ffi::c_void; +use std::future::Future; +use std::mem::MaybeUninit; +use std::sync::Arc; +use std::task::{Context, Poll, Wake}; + +struct RunFutureWaker { + co: *mut bindings::Coroutine, +} +unsafe impl Send for RunFutureWaker {} +unsafe impl Sync for RunFutureWaker {} + +impl Wake for RunFutureWaker { + fn wake(self: Arc) { + unsafe { + bindings::aio_co_wake(self.co); + } + } +} + +/// Use QEMU's event loops to run a Rust [`Future`] to completion and return its result. +/// +/// This function must be called in coroutine context. If the future isn't ready yet, it yields. +pub fn qemu_co_run_future(future: F) -> F::Output { + let waker = Arc::new(RunFutureWaker { + co: unsafe { bindings::qemu_coroutine_self() }, + }) + .into(); + let mut cx = Context::from_waker(&waker); + + let mut pinned_future = std::pin::pin!(future); + loop { + match pinned_future.as_mut().poll(&mut cx) { + Poll::Ready(res) => return res, + Poll::Pending => unsafe { + bindings::qemu_coroutine_yield(); + }, + } + } +} + +/// Wrapper around [`qemu_co_run_future`] that can be called from C. +/// +/// # Safety +/// +/// `future` must be a valid pointer to an owned `F` (it will be freed in this function). `output` +/// must be a valid pointer representing a mutable reference to an `F::Output` where the result can +/// be stored. +unsafe extern "C" fn rust_co_run_future( + future: *mut bindings::RustBoxedFuture, + output: *mut c_void, +) { + let future = unsafe { Box::from_raw(future.cast::()) }; + let output = output.cast::(); + let ret = qemu_co_run_future(*future); + unsafe { + *output = ret; + } +} + +/// Use QEMU's event loops to run a Rust [`Future`] to completion and return its result. +/// +/// This function must be called outside of coroutine context to avoid deadlocks. It blocks and +/// runs a nested even loop until the future is ready and returns a result. +pub fn qemu_run_future(future: F) -> F::Output { + let future_ptr = Box::into_raw(Box::new(future)); + let mut output = MaybeUninit::::uninit(); + unsafe { + bindings::rust_run_future( + future_ptr.cast::(), + #[allow(clippy::as_underscore)] + Some(rust_co_run_future:: as _), + output.as_mut_ptr().cast::(), + ); + output.assume_init() + } +} diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 3c6c154f3d..9b8f5fa4f1 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -18,6 +18,7 @@ pub mod c_str; pub mod callbacks; pub mod cell; +pub mod futures; #[cfg(feature = "system")] pub mod irq; pub mod module; diff --git a/util/meson.build b/util/meson.build index 780b5977a8..14a2ae17fd 100644 --- a/util/meson.build +++ b/util/meson.build @@ -101,6 +101,9 @@ if have_block util_ss.add(files('qemu-coroutine-sleep.c')) util_ss.add(files('qemu-co-shared-resource.c')) util_ss.add(files('qemu-co-timeout.c')) + if have_rust + util_ss.add(files('qemu-co-rust-async.c')) + endif util_ss.add(files('readline.c')) util_ss.add(files('throttle.c')) util_ss.add(files('timed-average.c')) From patchwork Tue Feb 11 21:43:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970743 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6A82AC0219B for ; Tue, 11 Feb 2025 21:47:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy5c-0001AI-UD; Tue, 11 Feb 2025 16:46:48 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3Q-000818-RJ for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:36 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3P-0005Gr-3W for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:28 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310265; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=51SymC/HU+zgawyXNtMurq2f2giRy+7dnTCif234KJc=; b=cppTBfq+0GZTSxZ5tWE8MfYQ2jvLIW3vV9g3JJ7SmbB9G2QsI9cG6WDKGUrErI5dO0UZUl rTwyZVYFZ7Y+9dTtMiVKB61Qsx9jz0Ido6vgIDQXBCE0xZBLBWVlXGUeYcZakcFDMwqpEG PQsY9840qbzxDgB3BXvbEtvGt2/pReI= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-141-KFfcg90-NtaxrhZ6VhsdyQ-1; Tue, 11 Feb 2025 16:44:21 -0500 X-MC-Unique: KFfcg90-NtaxrhZ6VhsdyQ-1 X-Mimecast-MFC-AGG-ID: KFfcg90-NtaxrhZ6VhsdyQ_1739310260 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C53E31800873; Tue, 11 Feb 2025 21:44:20 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 72B8B195608D; Tue, 11 Feb 2025 21:44:18 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 05/11] rust/block: Add empty crate Date: Tue, 11 Feb 2025 22:43:22 +0100 Message-ID: <20250211214328.640374-6-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Kevin Wolf --- rust/Cargo.lock | 7 +++++++ rust/Cargo.toml | 1 + rust/block/Cargo.toml | 15 +++++++++++++++ rust/block/README.md | 3 +++ rust/block/meson.build | 19 +++++++++++++++++++ rust/block/src/lib.rs | 1 + rust/meson.build | 1 + 7 files changed, 47 insertions(+) create mode 100644 rust/block/Cargo.toml create mode 100644 rust/block/README.md create mode 100644 rust/block/meson.build create mode 100644 rust/block/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c0c6069247..b6af988a03 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -31,6 +31,13 @@ dependencies = [ "syn", ] +[[package]] +name = "block" +version = "0.1.0" +dependencies = [ + "qemu_api", +] + [[package]] name = "either" version = "1.12.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 5b0cb55928..777a2e9157 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "qemu-api-macros", "qemu-api", + "block", "hw/char/pl011", ] diff --git a/rust/block/Cargo.toml b/rust/block/Cargo.toml new file mode 100644 index 0000000000..70ee02f429 --- /dev/null +++ b/rust/block/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "block" +version = "0.1.0" +edition = "2021" +authors = ["Kevin Wolf "] +license = "GPL-2.0-or-later" +readme = "README.md" +description = "Block backends for QEMU" +repository = "https://gitlab.com/qemu-project/qemu/" +publish = false +keywords = [] +categories = [] + +[dependencies] +qemu_api = { path = "../qemu-api" } diff --git a/rust/block/README.md b/rust/block/README.md new file mode 100644 index 0000000000..debcc9d815 --- /dev/null +++ b/rust/block/README.md @@ -0,0 +1,3 @@ +# QEMU block backends + +This library implements block drivers for QEMU. diff --git a/rust/block/meson.build b/rust/block/meson.build new file mode 100644 index 0000000000..b13c037b2f --- /dev/null +++ b/rust/block/meson.build @@ -0,0 +1,19 @@ +_block_rs = static_library( + 'block', + files('src/lib.rs'), + override_options: ['rust_std=2021', 'build.rust_std=2021'], + rust_abi: 'rust', + dependencies: [ + qemu_api_tools, + qemu_api_macros, + ], + rust_dependency_map: {'qemu_api_tools': 'qemu_api'}, +) + +rust_block_ss.add(if_true: [declare_dependency( + link_whole: [_block_rs], + # Putting proc macro crates in `dependencies` is necessary for Meson to find + # them when compiling the root per-target static rust lib. + dependencies: [qemu_api_macros], + variables: {'crate': 'block'}, +)]) diff --git a/rust/block/src/lib.rs b/rust/block/src/lib.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/rust/block/src/lib.rs @@ -0,0 +1 @@ + diff --git a/rust/meson.build b/rust/meson.build index 50eb23b072..d959809fda 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -1,6 +1,7 @@ subdir('qemu-api-macros') subdir('qemu-api') +subdir('block') subdir('hw') cargo = find_program('cargo', required: false) From patchwork Tue Feb 11 21:43:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970738 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 33987C0219B for ; Tue, 11 Feb 2025 21:46:03 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy4K-0008G2-Ow; Tue, 11 Feb 2025 16:45:33 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3V-00081X-K8 for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:38 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3S-0005OW-Uf for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310270; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/OWHn8YVudrVjD30pFiw9gzLSOJXgZ2dezAHaj9jIKU=; b=KMoRRxexdvw6dlOIXUyuWJ4GLcUo1QkOMiHnvwOE+tnyDgHFmAF8JIIXfcGlvuhuujbfHc kLIEcxbM2hUjCf4oiAAs4csoHNLyZvrmqxGeJu2DCd5HlhkPk4eND4WTxR2rvPMUxqPtSA VQYlV7Wc4AarvZVTCzakuV/rC29c7f4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-232-I6KzDElLPP2cB1iufbH_UQ-1; Tue, 11 Feb 2025 16:44:25 -0500 X-MC-Unique: I6KzDElLPP2cB1iufbH_UQ-1 X-Mimecast-MFC-AGG-ID: I6KzDElLPP2cB1iufbH_UQ Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C24E8195609F; Tue, 11 Feb 2025 21:44:23 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 47125195608D; Tue, 11 Feb 2025 21:44:21 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 06/11] rust/block: Add I/O buffer traits Date: Tue, 11 Feb 2025 22:43:23 +0100 Message-ID: <20250211214328.640374-7-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Types that implement IoBuffer can be used with safe I/O functions. Signed-off-by: Kevin Wolf --- rust/block/src/iobuffer.rs | 94 ++++++++++++++++++++++++++++++++++++++ rust/block/src/lib.rs | 2 + 2 files changed, 96 insertions(+) create mode 100644 rust/block/src/iobuffer.rs diff --git a/rust/block/src/iobuffer.rs b/rust/block/src/iobuffer.rs new file mode 100644 index 0000000000..d61370c961 --- /dev/null +++ b/rust/block/src/iobuffer.rs @@ -0,0 +1,94 @@ +// Copyright Red Hat Inc. +// Author(s): Kevin Wolf +// SPDX-License-Identifier: GPL-2.0-or-later + +use std::mem::MaybeUninit; + +/// Types that implement IoBuffer can be used with safe I/O functions. +/// +/// # Safety +/// +/// `buffer_ptr()` and `buffer_mut_ptr()` must return pointers to the address of the same I/O +/// buffer with the size returned by `buffer_len()` which remain valid for the lifetime of the +/// object. It must be safe for the I/O buffer to contain any byte patterns. +pub unsafe trait IoBuffer { + /// Returns a const pointer to be used as a raw I/O buffer + fn buffer_ptr(&self) -> *const u8; + + /// Returns a mutable pointer to be used as a raw I/O buffer + fn buffer_mut_ptr(&mut self) -> *mut u8; + + /// Returns the length in bytes for the raw I/O buffer returned by [`buffer_ptr`] and + /// [`buffer_mut_ptr`] + /// + /// [`buffer_ptr`]: IoBuffer::buffer_ptr + /// [`buffer_mut_ptr`]: IoBuffer::buffer_mut_ptr + fn buffer_len(&self) -> usize; +} + +/// Implementing `SizedIoBuffer` provides an implementation for [`IoBuffer`] without having to +/// implement any functions manually. +/// +/// # Safety +/// +/// Types implementing `SizedIoBuffer` guarantee that the whole object can be accessed as an I/O +/// buffer that is safe to contain any byte patterns. +pub unsafe trait SizedIoBuffer: Sized { + /// Safely converts a byte slice into a shared reference to the type implementing + /// `SizedIoBuffer` + fn from_byte_slice(buf: &[u8]) -> Option<&Self> { + if buf.len() < std::mem::size_of::() { + return None; + } + + let ptr = buf.as_ptr() as *const Self; + + // TODO Use ptr.is_aligned() when MSRV is updated to at least 1.79.0 + if (ptr as usize) % std::mem::align_of::() != 0 { + return None; + } + + // SAFETY: This function checked that the byte slice is large enough and aligned. + // Implementing SizedIoBuffer promises that any byte pattern is valid for the type. + Some(unsafe { &*ptr }) + } +} + +unsafe impl IoBuffer for T { + fn buffer_ptr(&self) -> *const u8 { + self as *const Self as *const u8 + } + + fn buffer_mut_ptr(&mut self) -> *mut u8 { + self as *mut Self as *mut u8 + } + + fn buffer_len(&self) -> usize { + std::mem::size_of::() + } +} + +unsafe impl IoBuffer for [T] { + fn buffer_ptr(&self) -> *const u8 { + self.as_ptr() as *const u8 + } + + fn buffer_mut_ptr(&mut self) -> *mut u8 { + self.as_mut_ptr() as *mut u8 + } + + fn buffer_len(&self) -> usize { + std::mem::size_of_val(self) + } +} + +unsafe impl SizedIoBuffer for MaybeUninit {} + +unsafe impl SizedIoBuffer for u8 {} +unsafe impl SizedIoBuffer for u16 {} +unsafe impl SizedIoBuffer for u32 {} +unsafe impl SizedIoBuffer for u64 {} +unsafe impl SizedIoBuffer for i8 {} +unsafe impl SizedIoBuffer for i16 {} +unsafe impl SizedIoBuffer for i32 {} +unsafe impl SizedIoBuffer for i64 {} diff --git a/rust/block/src/lib.rs b/rust/block/src/lib.rs index 8b13789179..1c03549821 100644 --- a/rust/block/src/lib.rs +++ b/rust/block/src/lib.rs @@ -1 +1,3 @@ +mod iobuffer; +pub use iobuffer::{IoBuffer, SizedIoBuffer}; From patchwork Tue Feb 11 21:43:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970741 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 96C32C0219B for ; Tue, 11 Feb 2025 21:47:20 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy66-0001lk-JE; Tue, 11 Feb 2025 16:47:15 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3U-00081V-U3 for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:38 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3S-0005O9-4D for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=T/99BXNFXp53Ja3vDa+y7xf/RyDUHMK3ysaFIpdmW2Y=; b=Pc4vl4w0zQ+bB8eZHwBeQNQXZA6PZS+d6g4ncS0xmyUUgHrpdesrDv5SJagkntsO73oNbX XcoFhjH/ndFWwoF9a3KeWs+jsKrX2qDhDki6IwVdLVJasM0O7GLnnudIkWulCY2J4ezBMl e2Dr4GMH25lP0G5QuY8FYaytFjENwMk= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-128-Z_JfnwRAOeKi-ByY-vDg0Q-1; Tue, 11 Feb 2025 16:44:28 -0500 X-MC-Unique: Z_JfnwRAOeKi-ByY-vDg0Q-1 X-Mimecast-MFC-AGG-ID: Z_JfnwRAOeKi-ByY-vDg0Q_1739310267 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 193E01956089; Tue, 11 Feb 2025 21:44:27 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 45127195608D; Tue, 11 Feb 2025 21:44:24 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 07/11] block: Add bdrv_open_blockdev_ref_file() Date: Tue, 11 Feb 2025 22:43:24 +0100 Message-ID: <20250211214328.640374-8-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This is the equivalent of bdrv_open_file_child() to be used in cases where the caller is QAPI based and has a BlockdevRef rather than a filename and an options QDict. Signed-off-by: Kevin Wolf --- include/block/block-global-state.h | 4 ++++ block.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 9be34b3c99..861e19cfe6 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -100,6 +100,10 @@ bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); BlockDriverState * coroutine_fn no_co_wrapper bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp); +BlockDriverState * no_coroutine_fn +bdrv_open_blockdev_ref_file(BlockdevRef *ref, BlockDriverState *parent, + Error **errp); + int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, Error **errp); int GRAPH_WRLOCK diff --git a/block.c b/block.c index 0ece805e41..6315be79d8 100644 --- a/block.c +++ b/block.c @@ -3847,7 +3847,11 @@ int bdrv_open_file_child(const char *filename, * TODO Future callers may need to specify parent/child_class in order for * option inheritance to work. Existing callers use it for the root node. */ -BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) +static BlockDriverState * no_coroutine_fn +bdrv_open_blockdev_ref_common(BlockdevRef *ref, BlockDriverState *parent, + const BdrvChildClass *child_class, + BdrvChildRole child_role, bool parse_filename, + Error **errp) { BlockDriverState *bs = NULL; QObject *obj = NULL; @@ -3880,14 +3884,34 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) } - bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false, - errp); + bs = bdrv_open_inherit(NULL, reference, qdict, 0, parent, child_class, + child_role, parse_filename, errp); obj = NULL; qobject_unref(obj); visit_free(v); return bs; } +BlockDriverState *bdrv_open_blockdev_ref_file(BlockdevRef *ref, + BlockDriverState *parent, + Error **errp) +{ + BdrvChildRole role; + + /* commit_top and mirror_top don't use this function */ + assert(!parent->drv->filtered_child_is_backing); + role = parent->drv->is_filter ? + (BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY) : BDRV_CHILD_IMAGE; + + return bdrv_open_blockdev_ref_common(ref, parent, &child_of_bds, role, + true, errp); +} + +BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) +{ + return bdrv_open_blockdev_ref_common(ref, NULL, NULL, 0, false, errp); +} + static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, QDict *snapshot_options, From patchwork Tue Feb 11 21:43:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970740 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CC020C0219B for ; Tue, 11 Feb 2025 21:46:36 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy56-0000iO-Hs; Tue, 11 Feb 2025 16:46:23 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3b-00082c-Vi for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:42 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3Z-0005PF-F1 for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310274; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fv2Uo09WYcGphLTGQEV2WMtzqcDmBt/d8fau8kl6t7w=; b=CrDYeDvwhgt2pfv65Arpz6ilh9xquom7B0kON32ZtMhihH/uMPPGa1VhXGkNepMqhWYdpy xhlw9zKjP2X0i0A90pgP1zDcFWB4TmoHfenXnbSI+Q/rV9Q4zr6b3RmBVH/wYcZHVwv22Y ifzuOMzSIGH0P79Oa7swSu1n6deUMdY= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-386-Ig6yLRrxN2yyTbjmMdhOoQ-1; Tue, 11 Feb 2025 16:44:31 -0500 X-MC-Unique: Ig6yLRrxN2yyTbjmMdhOoQ-1 X-Mimecast-MFC-AGG-ID: Ig6yLRrxN2yyTbjmMdhOoQ Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E6CEC195609D; Tue, 11 Feb 2025 21:44:29 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 93274195608D; Tue, 11 Feb 2025 21:44:27 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 08/11] rust/block: Add driver module Date: Tue, 11 Feb 2025 22:43:25 +0100 Message-ID: <20250211214328.640374-9-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This adds a barebones module for a block driver interface. Because there is no native QAPI support for Rust yet, opening images takes a few unsafe functions to call into C visitor functions. This should be cleaned up later. Signed-off-by: Kevin Wolf --- rust/block/src/driver.rs | 190 +++++++++++++++++++++++++++++++++++++++ rust/block/src/lib.rs | 1 + 2 files changed, 191 insertions(+) create mode 100644 rust/block/src/driver.rs diff --git a/rust/block/src/driver.rs b/rust/block/src/driver.rs new file mode 100644 index 0000000000..5c7c46bfa0 --- /dev/null +++ b/rust/block/src/driver.rs @@ -0,0 +1,190 @@ +// Copyright Red Hat Inc. +// Author(s): Kevin Wolf +// SPDX-License-Identifier: GPL-2.0-or-later + +// All of this is unused until the first block driver is added +#![allow(dead_code)] +#![allow(unused_macros)] +#![allow(unused_imports)] + +use crate::{IoBuffer, SizedIoBuffer}; +use qemu_api::bindings; +use std::ffi::c_void; +use std::io::{self, Error, ErrorKind}; +use std::mem::MaybeUninit; +use std::ptr; + +/// A trait for writing block drivers. +/// +/// Types that implement this trait can be registered as QEMU block drivers using the +/// [`block_driver`] macro. +pub trait BlockDriver { + /// The type that contains the block driver specific options for opening an image + type Options; + + // TODO Native support for QAPI types and deserialization + unsafe fn parse_options( + v: &mut bindings::Visitor, + opts: &mut *mut Self::Options, + errp: *mut *mut bindings::Error, + ); + unsafe fn free_options(opts: *mut Self::Options); + unsafe fn open( + bs: *mut bindings::BlockDriverState, + opts: &Self::Options, + errp: *mut *mut bindings::Error, + ) -> std::os::raw::c_int; + + /// Returns the size of the image in bytes + fn size(&self) -> u64; +} + +/// Represents the connection between a parent and its child node. +/// +/// This is a wrapper around the `BdrvChild` type in C. +pub struct BdrvChild { + child: *mut bindings::BdrvChild, +} + +impl BdrvChild { + /// Creates a new child reference from a `BlockdevRef`. + pub unsafe fn new( + parent: *mut bindings::BlockDriverState, + bref: *mut bindings::BlockdevRef, + errp: *mut *mut bindings::Error, + ) -> Option { + unsafe { + let child_bs = bindings::bdrv_open_blockdev_ref_file(bref, parent, errp); + if child_bs.is_null() { + return None; + } + + bindings::bdrv_graph_wrlock(); + let child = bindings::bdrv_attach_child( + parent, + child_bs, + c"file".as_ptr(), + &bindings::child_of_bds as *const _, + bindings::BDRV_CHILD_IMAGE, + errp, + ); + bindings::bdrv_graph_wrunlock(); + + if child.is_null() { + None + } else { + Some(BdrvChild { child }) + } + } + } + + /// Reads data from the child node into a linear byte buffer. + /// + /// # Safety + /// + /// `buf` must be a valid I/O buffer that can store at least `bytes` bytes. + pub async unsafe fn read_raw(&self, offset: u64, bytes: usize, buf: *mut u8) -> io::Result<()> { + let offset: i64 = offset + .try_into() + .map_err(|e| Error::new(ErrorKind::InvalidInput, e))?; + let bytes: i64 = bytes + .try_into() + .map_err(|e| Error::new(ErrorKind::InvalidInput, e))?; + + let ret = unsafe { bindings::bdrv_pread(self.child, offset, bytes, buf as *mut c_void, 0) }; + if ret < 0 { + Err(Error::from_raw_os_error(ret)) + } else { + Ok(()) + } + } + + /// Reads data from the child node into a linear typed buffer. + pub async fn read(&self, offset: u64, buf: &mut T) -> io::Result<()> { + unsafe { + self.read_raw(offset, buf.buffer_len(), buf.buffer_mut_ptr()) + .await + } + } + + /// Reads data from the child node into a linear, potentially uninitialised typed buffer. + pub async fn read_uninit( + &self, + offset: u64, + mut buf: MaybeUninit, + ) -> io::Result { + unsafe { + self.read_raw(offset, buf.buffer_len(), buf.buffer_mut_ptr()) + .await?; + Ok(buf.assume_init()) + } + } +} + +#[doc(hidden)] +pub unsafe extern "C" fn bdrv_open( + bs: *mut bindings::BlockDriverState, + options: *mut bindings::QDict, + _flags: std::os::raw::c_int, + errp: *mut *mut bindings::Error, +) -> std::os::raw::c_int { + unsafe { + let v = match bindings::qobject_input_visitor_new_flat_confused(options, errp).as_mut() { + None => return -(bindings::EINVAL as std::os::raw::c_int), + Some(v) => v, + }; + + let mut opts: *mut D::Options = ptr::null_mut(); + D::parse_options(v, &mut opts, errp); + bindings::visit_free(v); + + let opts = match opts.as_mut() { + None => return -(bindings::EINVAL as std::os::raw::c_int), + Some(opts) => opts, + }; + + while let Some(e) = bindings::qdict_first(options).as_ref() { + bindings::qdict_del(options, e.key); + } + + let ret = D::open(bs, opts, errp); + D::free_options(opts); + ret + } +} + +#[doc(hidden)] +pub unsafe extern "C" fn bdrv_close(bs: *mut bindings::BlockDriverState) { + unsafe { + let state = (*bs).opaque as *mut D; + ptr::drop_in_place(state); + } +} + +/// Declare a format block driver. This macro is meant to be used at the top level. +/// +/// `typ` is a type implementing the [`BlockDriver`] trait to handle the image format with the +/// user-visible name `fmtname`. +macro_rules! block_driver { + ($fmtname:expr, $typ:ty) => { + const _: () = { + static mut BLOCK_DRIVER: ::qemu_api::bindings::BlockDriver = + ::qemu_api::bindings::BlockDriver { + format_name: ::qemu_api::c_str!($fmtname).as_ptr(), + instance_size: ::std::mem::size_of::<$typ>() as i32, + bdrv_open: Some($crate::driver::bdrv_open::<$typ>), + bdrv_close: Some($crate::driver::bdrv_close::<$typ>), + bdrv_child_perm: Some(::qemu_api::bindings::bdrv_default_perms), + is_format: true, + ..::qemu_api::zeroable::Zeroable::ZERO + }; + + qemu_api::module_init! { + MODULE_INIT_BLOCK => unsafe { + ::qemu_api::bindings::bdrv_register(std::ptr::addr_of_mut!(BLOCK_DRIVER)); + } + } + }; + }; +} +pub(crate) use block_driver; diff --git a/rust/block/src/lib.rs b/rust/block/src/lib.rs index 1c03549821..54ebd480ec 100644 --- a/rust/block/src/lib.rs +++ b/rust/block/src/lib.rs @@ -1,3 +1,4 @@ +mod driver; mod iobuffer; pub use iobuffer::{IoBuffer, SizedIoBuffer}; From patchwork Tue Feb 11 21:43:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970756 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 70366C0219B for ; Tue, 11 Feb 2025 21:49:30 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy7k-00055P-0I; Tue, 11 Feb 2025 16:48:56 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3d-00082q-3F for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:44 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3b-0005SX-8S for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310278; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=haheJ5bpjRBjbwxH7eaaz7CF0vcGhATS04334Z3InTo=; b=N180bO5TvpogyNy0fNL27rpGyWKa8Kc2qEA08bTxvNGT9MYND7py8CDV1QrDzAKtdbAi33 qkhHm6f/IA1bazpBDqcgSug4bKMw3Awnw2DIkTWQkZUZMVbLbcYe0GFDXdn3qPZYnCsqZW Av1N1xiJ+tW5zBpBKI7eqCrB6NGc+hQ= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-231-kYVvKMFWPDibMpEgJQxqQA-1; Tue, 11 Feb 2025 16:44:34 -0500 X-MC-Unique: kYVvKMFWPDibMpEgJQxqQA-1 X-Mimecast-MFC-AGG-ID: kYVvKMFWPDibMpEgJQxqQA Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BAEA31800874; Tue, 11 Feb 2025 21:44:32 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6A6D7195608D; Tue, 11 Feb 2025 21:44:30 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 09/11] rust/block: Add read support for block drivers Date: Tue, 11 Feb 2025 22:43:26 +0100 Message-ID: <20250211214328.640374-10-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This adds a map() function to the BlockDriver trait and makes use of it to implement reading from an image. Signed-off-by: Kevin Wolf --- rust/block/src/driver.rs | 100 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/rust/block/src/driver.rs b/rust/block/src/driver.rs index 5c7c46bfa0..2849ef6949 100644 --- a/rust/block/src/driver.rs +++ b/rust/block/src/driver.rs @@ -9,11 +9,46 @@ use crate::{IoBuffer, SizedIoBuffer}; use qemu_api::bindings; +use qemu_api::futures::qemu_co_run_future; +use std::cmp::min; use std::ffi::c_void; use std::io::{self, Error, ErrorKind}; use std::mem::MaybeUninit; use std::ptr; +/// A request to a block driver +pub enum Request { + Read { offset: u64, len: u64 }, +} + +/// The target for a number of guest blocks, e.g. a location in a child node or the information +/// that the described blocks are unmapped. +// FIXME Actually use node +#[allow(dead_code)] +pub enum MappingTarget { + /// The described blocks are unallocated. Reading from them yields zeros. + Unmapped, + + /// The described blocks are stored in a child node. + Data { + /// Child node in which the data is stored + node: (), + + /// Offset in the child node at which the data is stored + offset: u64, + }, +} + +/// A mapping for a number of contiguous guest blocks +pub struct Mapping { + /// Offset of the mapped blocks from the perspective of the guest + pub offset: u64, + /// Length of the mapping in bytes + pub len: u64, + /// Where the data for the described blocks is stored + pub target: MappingTarget, +} + /// A trait for writing block drivers. /// /// Types that implement this trait can be registered as QEMU block drivers using the @@ -37,6 +72,11 @@ unsafe fn open( /// Returns the size of the image in bytes fn size(&self) -> u64; + + /// Returns the mapping for the first part of `req`. If the returned mapping is shorter than + /// the request, the function can be called again with a shortened request to get the mapping + /// for the remaining part. + async fn map(&self, req: &Request) -> io::Result; } /// Represents the connection between a parent and its child node. @@ -161,6 +201,65 @@ pub async fn read_uninit( } } +#[doc(hidden)] +pub unsafe extern "C" fn bdrv_co_preadv_part( + bs: *mut bindings::BlockDriverState, + offset: i64, + bytes: i64, + qiov: *mut bindings::QEMUIOVector, + mut qiov_offset: usize, + flags: bindings::BdrvRequestFlags, +) -> std::os::raw::c_int { + let s = unsafe { &mut *((*bs).opaque as *mut D) }; + + let mut offset = offset as u64; + let mut bytes = bytes as u64; + + while bytes > 0 { + let req = Request::Read { offset, len: bytes }; + let mapping = match qemu_co_run_future(s.map(&req)) { + Ok(mapping) => mapping, + Err(e) => { + return e + .raw_os_error() + .unwrap_or(-(bindings::EIO as std::os::raw::c_int)) + } + }; + + let mapping_offset = offset - mapping.offset; + let cur_bytes = min(bytes, mapping.len - mapping_offset); + + match mapping.target { + MappingTarget::Unmapped => unsafe { + bindings::qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes.try_into().unwrap()); + }, + MappingTarget::Data { + node: _, + offset: target_offset, + } => unsafe { + // TODO Support using child nodes other than bs->file + let ret = bindings::bdrv_co_preadv_part( + (*bs).file, + (target_offset + mapping_offset) as i64, + cur_bytes as i64, + qiov, + qiov_offset, + flags, + ); + if ret < 0 { + return ret; + } + }, + } + + offset += cur_bytes; + qiov_offset += cur_bytes as usize; + bytes -= cur_bytes; + } + + 0 +} + /// Declare a format block driver. This macro is meant to be used at the top level. /// /// `typ` is a type implementing the [`BlockDriver`] trait to handle the image format with the @@ -174,6 +273,7 @@ macro_rules! block_driver { instance_size: ::std::mem::size_of::<$typ>() as i32, bdrv_open: Some($crate::driver::bdrv_open::<$typ>), bdrv_close: Some($crate::driver::bdrv_close::<$typ>), + bdrv_co_preadv_part: Some($crate::driver::bdrv_co_preadv_part::<$typ>), bdrv_child_perm: Some(::qemu_api::bindings::bdrv_default_perms), is_format: true, ..::qemu_api::zeroable::Zeroable::ZERO From patchwork Tue Feb 11 21:43:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970757 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2F2B1C0219B for ; Tue, 11 Feb 2025 21:49:39 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy7n-0005PY-5d; Tue, 11 Feb 2025 16:48:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3k-00089C-3I for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:48 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3g-0005aS-Vy for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310282; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jeMPrbZ7HrrR2ej85bCz6ZMBw4eoh4NTs56QCravtpw=; b=AQBXVFelHr344kwYN5NDcTXU6OhFpjSGo2kNMU+x9fCFdDuA1ozbDDzblRXhEyVgMDL/BK e2DJaqxzQ3vo2Qfc+qdPe1L9DpL6hnahY2MCLNM40qQJTS8wQOBq2cGJj4dRf4DnBv9KBQ y60bvF0eSQvCBe5PC5HjzjpwLsmtefY= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-298-395Fcx2jMIqgB1Yhvo9Ehg-1; Tue, 11 Feb 2025 16:44:36 -0500 X-MC-Unique: 395Fcx2jMIqgB1Yhvo9Ehg-1 X-Mimecast-MFC-AGG-ID: 395Fcx2jMIqgB1Yhvo9Ehg Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A29A719560B6; Tue, 11 Feb 2025 21:44:35 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3D460195608D; Tue, 11 Feb 2025 21:44:32 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 10/11] bochs-rs: Add bochs block driver reimplementation in Rust Date: Tue, 11 Feb 2025 22:43:27 +0100 Message-ID: <20250211214328.640374-11-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This adds a separate block driver for the bochs image format called 'bochs-rs' so that for the moment both the C implementation and the Rust implementation can be present in the same build. The intention is to remove the C implementation eventually and rename this one into 'bochs'. This can only happen once Rust can be a hard build dependency for QEMU. Signed-off-by: Kevin Wolf --- rust/block/Cargo.toml | 2 +- rust/block/src/bochs.rs | 296 +++++++++++++++++++++++++++++++++++++++ rust/block/src/driver.rs | 5 - rust/block/src/lib.rs | 1 + 4 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 rust/block/src/bochs.rs diff --git a/rust/block/Cargo.toml b/rust/block/Cargo.toml index 70ee02f429..1c06f3a00c 100644 --- a/rust/block/Cargo.toml +++ b/rust/block/Cargo.toml @@ -3,7 +3,7 @@ name = "block" version = "0.1.0" edition = "2021" authors = ["Kevin Wolf "] -license = "GPL-2.0-or-later" +license = "GPL-2.0-or-later AND MIT" readme = "README.md" description = "Block backends for QEMU" repository = "https://gitlab.com/qemu-project/qemu/" diff --git a/rust/block/src/bochs.rs b/rust/block/src/bochs.rs new file mode 100644 index 0000000000..388ac5ef03 --- /dev/null +++ b/rust/block/src/bochs.rs @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: MIT +/* + * Block driver for the various disk image formats used by Bochs + * Currently only for "growing" type in read-only mode + * + * Copyright (c) 2005 Alex Beregszaszi + * Copyright (c) 2024 Red Hat + * + * Authors: + * Alex Beregszaszi + * Kevin Wolf + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +use crate::driver::{block_driver, BdrvChild, BlockDriver, Mapping, MappingTarget, Request}; +use crate::SizedIoBuffer; +use qemu_api::bindings; +use qemu_api::futures::qemu_run_future; +use std::cmp::min; +use std::io::{self, Error, ErrorKind}; +use std::mem::MaybeUninit; +use std::ptr; + +const BDRV_SECTOR_SIZE: u64 = 512; + +const HEADER_MAGIC: [u8; 32] = *b"Bochs Virtual HD Image\0\0\0\0\0\0\0\0\0\0"; +const HEADER_VERSION: u32 = 0x00020000; +const HEADER_V1: u32 = 0x00010000; +const HEADER_SIZE: usize = 512; + +const HEADER_TYPE_REDOLOG: [u8; 16] = *b"Redolog\0\0\0\0\0\0\0\0\0"; +const HEADER_SUBTYPE_GROWING: [u8; 16] = *b"Growing\0\0\0\0\0\0\0\0\0"; + +// TODO Use u64.div_ceil() when MSRV is updated to at least 1.73.0 +fn div_ceil(a: u64, b: u64) -> u64 { + (a + b - 1) / b +} + +// TODO Use little endian enforcing type for integers + +#[repr(C, packed)] +struct BochsHeader { + pub magic: [u8; 32], + pub imgtype: [u8; 16], + pub subtype: [u8; 16], + pub version: u32, + pub header_size: u32, + pub catalog_entries: u32, + pub bitmap_size: u32, + pub extent_size: u32, + pub extra: BochsHeaderExtra, +} +unsafe impl SizedIoBuffer for BochsHeader {} + +#[repr(C, packed)] +union BochsHeaderExtra { + v2: BochsHeaderExtraRedolog, + v1: BochsHeaderExtraRedologV1, + padding: [u8; HEADER_SIZE - 84], +} + +#[repr(C, packed)] +#[derive(Clone, Copy)] +struct BochsHeaderExtraRedolog { + pub timestamp: u32, + pub disk_size: u64, +} + +#[repr(C, packed)] +#[derive(Clone, Copy)] +struct BochsHeaderExtraRedologV1 { + pub disk_size: u64, +} + +pub struct BochsImage { + file: BdrvChild, + size: u64, + data_offset: u64, + bitmap_blocks: u64, + extent_size: u64, + extent_blocks: u64, + catalog_bitmap: Vec, // TODO Rename +} + +impl BochsImage { + pub async fn new(file: BdrvChild) -> io::Result { + let header = file + .read_uninit(0, MaybeUninit::::uninit()) + .await?; + + if header.magic != HEADER_MAGIC + || header.imgtype != HEADER_TYPE_REDOLOG + || header.subtype != HEADER_SUBTYPE_GROWING + { + return Err(Error::new( + ErrorKind::InvalidInput, + "Image not in Bochs format", + )); + } + + let size = match u32::from_le(header.version) { + HEADER_VERSION => unsafe { header.extra.v2.disk_size.to_le() }, + HEADER_V1 => unsafe { header.extra.v1.disk_size.to_le() }, + _ => return Err(Error::new(ErrorKind::InvalidInput, "Version not supported")), + }; + + let header_size: u64 = header.header_size.to_le().into(); + let extent_size: u64 = header.extent_size.to_le().into(); + + if extent_size < BDRV_SECTOR_SIZE { + // bximage actually never creates extents smaller than 4k + return Err(Error::new( + ErrorKind::InvalidInput, + "Extent size must be at least 512", + )); + } else if !extent_size.is_power_of_two() { + return Err(Error::new( + ErrorKind::InvalidInput, + format!("Extent size {extent_size} is not a power of two"), + )); + } else if extent_size > 0x800000 { + return Err(Error::new( + ErrorKind::InvalidInput, + format!("Extent size {extent_size} is too large"), + )); + } + + // Limit to 1M entries to avoid unbounded allocation. This is what is + // needed for the largest image that bximage can create (~8 TB). + let catalog_entries: usize = header + .catalog_entries + .to_le() + .try_into() + .map_err(|e| Error::new(ErrorKind::InvalidInput, e))?; + if catalog_entries > 0x100000 { + return Err(Error::new(ErrorKind::Other, "Catalog size is too large")); + } else if (catalog_entries as u64) < div_ceil(size, extent_size) { + return Err(Error::new( + ErrorKind::InvalidInput, + "Catalog size is too small for this disk size", + )); + } + + // FIXME This was g_try_malloc() in C + let mut catalog_bitmap = vec![0u32; catalog_entries]; + file.read(header_size, catalog_bitmap.as_mut_slice()) + .await?; + + for entry in &mut catalog_bitmap { + *entry = entry.to_le(); + } + + let data_offset = header_size + (catalog_entries as u64 * 4); + let bitmap_blocks = (1 + (header.bitmap_size.to_le() - 1) / 512).into(); + let extent_blocks = 1 + (extent_size - 1) / 512; + + Ok(Self { + file, + size, + data_offset, + bitmap_blocks, + extent_size, + extent_blocks, + catalog_bitmap, + }) + } +} + +impl BlockDriver for BochsImage { + type Options = bindings::BlockdevOptionsGenericFormat; + + unsafe fn parse_options( + v: &mut bindings::Visitor, + opts: &mut *mut Self::Options, + errp: *mut *mut bindings::Error, + ) { + unsafe { + bindings::visit_type_BlockdevOptionsGenericFormat(v, ptr::null(), opts as *mut _, errp); + } + } + + unsafe fn free_options(opts: *mut Self::Options) { + unsafe { + bindings::qapi_free_BlockdevOptionsGenericFormat(opts); + } + } + + unsafe fn open( + bs: *mut bindings::BlockDriverState, + opts: &Self::Options, + errp: *mut *mut bindings::Error, + ) -> std::os::raw::c_int { + let file_child; + unsafe { + /* No write support yet */ + bindings::bdrv_graph_rdlock_main_loop(); + let ret = bindings::bdrv_apply_auto_read_only(bs, ptr::null(), errp); + bindings::bdrv_graph_rdunlock_main_loop(); + if ret < 0 { + return ret; + } + + file_child = match BdrvChild::new(bs, opts.file, errp) { + Some(c) => c, + None => return -(bindings::EINVAL as std::os::raw::c_int), + }; + } + + qemu_run_future(async { + match BochsImage::new(file_child).await { + Ok(bdrv) => unsafe { + (*bs).total_sectors = + div_ceil(bdrv.size(), BDRV_SECTOR_SIZE).try_into().unwrap(); + let state = (*bs).opaque as *mut BochsImage; + *state = bdrv; + 0 + }, + // FIXME This is not a good default error code + Err(e) => e.raw_os_error().unwrap_or(-1), + } + }) + } + + fn size(&self) -> u64 { + self.size + } + + async fn map(&self, req: &Request) -> io::Result { + let (offset, len) = match *req { + Request::Read { offset, len } => (offset, len), + }; + + let extent_index: usize = (offset / self.extent_size).try_into().unwrap(); + let extent_offset = (offset % self.extent_size) / 512; + + if self.catalog_bitmap[extent_index] == 0xffffffff { + return Ok(Mapping { + offset: (extent_index as u64) * self.extent_size, + len: self.extent_size, + target: MappingTarget::Unmapped, + }); + } + + let bitmap_offset = self.data_offset + + (512 + * (self.catalog_bitmap[extent_index] as u64) + * (self.extent_blocks + self.bitmap_blocks)); + + // Read in bitmap for current extent + // TODO This should be cached + let mut bitmap_entry = 0x8; + self.file + .read(bitmap_offset + (extent_offset / 8), &mut bitmap_entry) + .await?; + + // We checked only a single sector + let offset = offset & !511; + let len = min(len, 512); + + if (bitmap_entry >> (extent_offset % 8)) & 1 == 0 { + return Ok(Mapping { + offset, + len, + target: MappingTarget::Unmapped, + }); + } + + Ok(Mapping { + offset, + len, + target: MappingTarget::Data { + node: (), + offset: bitmap_offset + (512 * (self.bitmap_blocks + extent_offset)), + }, + }) + } +} + +block_driver!("bochs-rs", BochsImage); diff --git a/rust/block/src/driver.rs b/rust/block/src/driver.rs index 2849ef6949..740e9266aa 100644 --- a/rust/block/src/driver.rs +++ b/rust/block/src/driver.rs @@ -2,11 +2,6 @@ // Author(s): Kevin Wolf // SPDX-License-Identifier: GPL-2.0-or-later -// All of this is unused until the first block driver is added -#![allow(dead_code)] -#![allow(unused_macros)] -#![allow(unused_imports)] - use crate::{IoBuffer, SizedIoBuffer}; use qemu_api::bindings; use qemu_api::futures::qemu_co_run_future; diff --git a/rust/block/src/lib.rs b/rust/block/src/lib.rs index 54ebd480ec..ff528609bc 100644 --- a/rust/block/src/lib.rs +++ b/rust/block/src/lib.rs @@ -1,3 +1,4 @@ +mod bochs; mod driver; mod iobuffer; From patchwork Tue Feb 11 21:43:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 13970755 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 30118C0219B for ; Tue, 11 Feb 2025 21:48:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thy6N-0002jT-I2; Tue, 11 Feb 2025 16:47:31 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3k-00089E-Fe for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:48 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thy3g-0005aB-WB for qemu-devel@nongnu.org; Tue, 11 Feb 2025 16:44:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1739310282; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EQGiwTCHjvG0hJog8XC9+JXJepkNrNsdabgIXvuqv1g=; b=PvLOIBdLWjoDHdM5okSlkNVlwZW05oHMRXaTZf4ihkzul+hpizJoZlayIPcW3ZW0KozDN9 qG570BBZDl77ccCm/ocOv5GDgfBPVFbQ9XAA42W1ujZNlk7FKsswNoyoh4mYH3EVOcjBRl CZPKsjE7YacJSmlOnX2ZiTB1QqyqJv8= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-591-vZ7AGSsxMHCCLTBQoS_rVw-1; Tue, 11 Feb 2025 16:44:39 -0500 X-MC-Unique: vZ7AGSsxMHCCLTBQoS_rVw-1 X-Mimecast-MFC-AGG-ID: vZ7AGSsxMHCCLTBQoS_rVw Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5A80A19560A7; Tue, 11 Feb 2025 21:44:38 +0000 (UTC) Received: from merkur.redhat.com (unknown [10.44.32.210]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0B89E195608D; Tue, 11 Feb 2025 21:44:35 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com, manos.pitsidianakis@linaro.org, qemu-devel@nongnu.org, qemu-rust@nongnu.org Subject: [PATCH 11/11] rust/block: Add format probing Date: Tue, 11 Feb 2025 22:43:28 +0100 Message-ID: <20250211214328.640374-12-kwolf@redhat.com> In-Reply-To: <20250211214328.640374-1-kwolf@redhat.com> References: <20250211214328.640374-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Received-SPF: pass client-ip=170.10.129.124; envelope-from=kwolf@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -35 X-Spam_score: -3.6 X-Spam_bar: --- X-Spam_report: (-3.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.54, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This adds format probing both to the BlockDriver trait and the bochs-rs block driver. With this, bochs-rs achieves feature parity with its C counterpart. Its probe function returns a higher priority so that it is preferred when both drivers are available. Signed-off-by: Kevin Wolf --- rust/block/src/bochs.rs | 20 ++++++++++++++++++++ rust/block/src/driver.rs | 26 +++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/rust/block/src/bochs.rs b/rust/block/src/bochs.rs index 388ac5ef03..bccc55ead9 100644 --- a/rust/block/src/bochs.rs +++ b/rust/block/src/bochs.rs @@ -186,6 +186,26 @@ pub async fn new(file: BdrvChild) -> io::Result { impl BlockDriver for BochsImage { type Options = bindings::BlockdevOptionsGenericFormat; + fn probe(buf: &[u8], _filename: &str) -> u16 { + let header = match BochsHeader::from_byte_slice(buf) { + Some(header) => header, + None => return 0, + }; + + if header.magic != HEADER_MAGIC + || header.imgtype != HEADER_TYPE_REDOLOG + || header.subtype != HEADER_SUBTYPE_GROWING + { + return 0; + } + + // This driver is better than the C one which returns 100, give it priority + match header.version { + HEADER_VERSION | HEADER_V1 => 200, + _ => 0, + } + } + unsafe fn parse_options( v: &mut bindings::Visitor, opts: &mut *mut Self::Options, diff --git a/rust/block/src/driver.rs b/rust/block/src/driver.rs index 740e9266aa..727d13b751 100644 --- a/rust/block/src/driver.rs +++ b/rust/block/src/driver.rs @@ -6,7 +6,7 @@ use qemu_api::bindings; use qemu_api::futures::qemu_co_run_future; use std::cmp::min; -use std::ffi::c_void; +use std::ffi::{c_void, CStr}; use std::io::{self, Error, ErrorKind}; use std::mem::MaybeUninit; use std::ptr; @@ -65,6 +65,16 @@ unsafe fn open( errp: *mut *mut bindings::Error, ) -> std::os::raw::c_int; + /// Returns the image format probing priority of this block driver for disk images starting + /// with the byte sequence in `buf`. Probing selects the driver that returns the highest + /// number. + /// + /// If the driver doesn't support images starting with `buf`, 0 is returned. + fn probe(buf: &[u8], filename: &str) -> u16 { + let _ = (buf, filename); + 0 + } + /// Returns the size of the image in bytes fn size(&self) -> u64; @@ -156,6 +166,19 @@ pub async fn read_uninit( } } +#[doc(hidden)] +pub unsafe extern "C" fn bdrv_probe( + buf: *const u8, + buf_size: std::os::raw::c_int, + filename: *const std::os::raw::c_char, +) -> std::os::raw::c_int { + let buf = unsafe { std::slice::from_raw_parts(buf, buf_size as usize) }; + match unsafe { CStr::from_ptr(filename) }.to_str() { + Ok(filename) => D::probe(buf, filename).into(), + Err(_) => 0, + } +} + #[doc(hidden)] pub unsafe extern "C" fn bdrv_open( bs: *mut bindings::BlockDriverState, @@ -266,6 +289,7 @@ macro_rules! block_driver { ::qemu_api::bindings::BlockDriver { format_name: ::qemu_api::c_str!($fmtname).as_ptr(), instance_size: ::std::mem::size_of::<$typ>() as i32, + bdrv_probe: Some($crate::driver::bdrv_probe::<$typ>), bdrv_open: Some($crate::driver::bdrv_open::<$typ>), bdrv_close: Some($crate::driver::bdrv_close::<$typ>), bdrv_co_preadv_part: Some($crate::driver::bdrv_co_preadv_part::<$typ>),