From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, hreitz@redhat.com, pbonzini@redhat.com,
manos.pitsidianakis@linaro.org, philmd@linaro.org,
qemu-devel@nongnu.org, qemu-rust@nongnu.org
Subject: [PATCH v2 08/11] rust/block: Add driver module
Date: Tue, 18 Feb 2025 19:20:16 +0100 [thread overview]
Message-ID: <20250218182019.111467-9-kwolf@redhat.com> (raw)
In-Reply-To: <20250218182019.111467-1-kwolf@redhat.com>
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 <kwolf@redhat.com>
---
rust/block/src/driver.rs | 195 +++++++++++++++++++++++++++++++++++++++
rust/block/src/lib.rs | 1 +
2 files changed, 196 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..fe19f4b88f
--- /dev/null
+++ b/rust/block/src/driver.rs
@@ -0,0 +1,195 @@
+// Copyright Red Hat Inc.
+// Author(s): Kevin Wolf <kwolf@redhat.com>
+// 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,
+}
+
+// TODO Represent the graph lock and let the compiler verify it's held when accessing child
+unsafe impl Send for BdrvChild {}
+unsafe impl Sync for 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<Self> {
+ 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<T: IoBuffer + ?Sized>(&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<T: SizedIoBuffer>(
+ &self,
+ offset: u64,
+ mut buf: Box<MaybeUninit<T>>,
+ ) -> io::Result<Box<T>> {
+ unsafe {
+ self.read_raw(offset, buf.buffer_len(), buf.buffer_mut_ptr())
+ .await?;
+ let ptr = Box::into_raw(buf) as *mut T;
+ Ok(Box::from_raw(ptr))
+ }
+ }
+}
+
+#[doc(hidden)]
+pub unsafe extern "C" fn bdrv_open<D: BlockDriver>(
+ 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 -libc::EINVAL,
+ 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 -libc::EINVAL,
+ 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<D: BlockDriver>(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};
--
2.48.1
next prev parent reply other threads:[~2025-02-18 18:21 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-18 18:20 [PATCH v2 00/11] rust/block: Add minimal block driver bindings Kevin Wolf
2025-02-18 18:20 ` [PATCH v2 01/11] rust: Build separate qemu_api_tools and qemu_api_system Kevin Wolf
2025-02-20 7:10 ` Zhao Liu
2025-02-18 18:20 ` [PATCH v2 02/11] meson: Add rust_block_ss and link tools with it Kevin Wolf
2025-02-18 18:20 ` [PATCH v2 03/11] rust: Add some block layer bindings Kevin Wolf
2025-02-18 18:20 ` [PATCH v2 04/11] rust/qemu-api: Add wrappers to run futures in QEMU Kevin Wolf
2025-02-20 6:35 ` Zhao Liu
2025-02-20 14:58 ` Kevin Wolf
2025-03-05 2:15 ` Stefan Hajnoczi
2025-02-18 18:20 ` [PATCH v2 05/11] rust/block: Add empty crate Kevin Wolf
2025-02-19 6:46 ` Zhao Liu
2025-02-18 18:20 ` [PATCH v2 06/11] rust/block: Add I/O buffer traits Kevin Wolf
2025-02-18 18:20 ` [PATCH v2 07/11] block: Add bdrv_open_blockdev_ref_file() Kevin Wolf
2025-02-18 18:20 ` Kevin Wolf [this message]
2025-02-20 6:52 ` [PATCH v2 08/11] rust/block: Add driver module Zhao Liu
2025-03-05 2:43 ` Stefan Hajnoczi
2025-02-18 18:20 ` [PATCH v2 09/11] rust/block: Add read support for block drivers Kevin Wolf
2025-02-19 6:11 ` Paolo Bonzini
2025-02-19 13:02 ` Kevin Wolf
2025-02-19 22:42 ` Paolo Bonzini
2025-03-05 3:04 ` Stefan Hajnoczi
2025-03-05 9:56 ` Stefan Hajnoczi
2025-02-18 18:20 ` [PATCH v2 10/11] bochs-rs: Add bochs block driver reimplementation in Rust Kevin Wolf
2025-02-20 7:02 ` Zhao Liu
2025-03-05 10:21 ` Stefan Hajnoczi
2025-02-18 18:20 ` [PATCH v2 11/11] rust/block: Add format probing Kevin Wolf
2025-03-05 10:23 ` [PATCH v2 00/11] rust/block: Add minimal block driver bindings Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250218182019.111467-9-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=hreitz@redhat.com \
--cc=manos.pitsidianakis@linaro.org \
--cc=pbonzini@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-rust@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.