From bffbb430ee045c616dfe13ad4fd44823f18e6b21 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 23 Jun 2025 15:34:36 +0800 Subject: rust/qemu-api: Fix binding path in source directory The build.rs had supported placing bindings.inc.rs in rust/qemu-api/src, but this "not encouraged" feature is broken. Considering that manually copying bindings.inc.rs to the development directory is also useful, fix the bindings.inc.rs path generation to give this feature another chance. Fixes: commit 1ae4ca0463d7 ("rust: move rust.bindgen to qemu-api crate") Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250623073436.1833357-1-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/qemu-api/build.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'rust/qemu-api') diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs index 7849486..29d0945 100644 --- a/rust/qemu-api/build.rs +++ b/rust/qemu-api/build.rs @@ -9,12 +9,14 @@ use std::os::windows::fs::symlink_file; use std::{env, fs::remove_file, io::Result, path::Path}; fn main() -> Result<()> { - // Placing bindings.inc.rs in the source directory is supported - // but not documented or encouraged. - let path = env::var("MESON_BUILD_ROOT") - .unwrap_or_else(|_| format!("{}/src", env!("CARGO_MANIFEST_DIR"))); + let file = if let Ok(root) = env::var("MESON_BUILD_ROOT") { + format!("{root}/rust/qemu-api/bindings.inc.rs") + } else { + // Placing bindings.inc.rs in the source directory is supported + // but not documented or encouraged. + format!("{}/src/bindings.inc.rs", env!("CARGO_MANIFEST_DIR")) + }; - let file = format!("{path}/rust/qemu-api/bindings.inc.rs"); let file = Path::new(&file); if !Path::new(&file).exists() { panic!(concat!( -- cgit v1.1 From dab63b8a710c2c489276d60d51e21e82b91a92f5 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 3 Jul 2025 17:20:22 +0300 Subject: rust/bindings: allow unnecessary_transmutes (1.88) This is a new lint introduced in Rust 1.88. It does not affect compilation when using a previous version or our MSRV, 1.77. But with 1.88 compilation fails because we deny all warnings: error: unnecessary transmute --> rust/qemu-api/libqemu_api.rlib.p/structured/bindings.inc.rs:729:18 | 729 | unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 24u8) as u32) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(self._bitfield_1.get(0usize, 24u8) as u32)` | = note: `-D unnecessary-transmutes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(unnecessary_transmutes)]` Allow this lint, which even though it does not exist in previous versions, it works because we allow for `unknown_lints` in rust/Cargo.toml. Signed-off-by: Manos Pitsidianakis Link: https://lore.kernel.org/r/20250703-rust_bindings_allow_unnecessary_transmutes-v1-1-692ca210d331@linaro.org Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/bindings.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'rust/qemu-api') diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 057de4b..3cdad0f 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -6,6 +6,7 @@ non_camel_case_types, non_snake_case, non_upper_case_globals, + unnecessary_transmutes, unsafe_op_in_unsafe_fn, clippy::pedantic, clippy::restriction, -- cgit v1.1 From ed7f6da282e263403badb507b2532f51f8ed31cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 Jun 2025 10:16:10 +0200 Subject: rust/qemu-api: log: implement io::Write This makes it possible to lock the log file; it also makes log_mask_ln! not allocate memory when logging a constant string. Reviewed-by: Zhao Liu Reviewed-by: Manos Pitsidianakis Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/log.rs | 92 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 8 deletions(-) (limited to 'rust/qemu-api') diff --git a/rust/qemu-api/src/log.rs b/rust/qemu-api/src/log.rs index d6c3d6c..a441b8c 100644 --- a/rust/qemu-api/src/log.rs +++ b/rust/qemu-api/src/log.rs @@ -3,6 +3,13 @@ //! Bindings for QEMU's logging infrastructure +use std::{ + io::{self, Write}, + ptr::NonNull, +}; + +use crate::{bindings, errno}; + #[repr(u32)] /// Represents specific error categories within QEMU's logging system. /// @@ -11,11 +18,82 @@ pub enum Log { /// Log invalid access caused by the guest. /// Corresponds to `LOG_GUEST_ERROR` in the C implementation. - GuestError = crate::bindings::LOG_GUEST_ERROR, + GuestError = bindings::LOG_GUEST_ERROR, /// Log guest access of unimplemented functionality. /// Corresponds to `LOG_UNIMP` in the C implementation. - Unimp = crate::bindings::LOG_UNIMP, + Unimp = bindings::LOG_UNIMP, +} + +/// A RAII guard for QEMU's logging infrastructure. Creating the guard +/// locks the log file, and dropping it (letting it go out of scope) unlocks +/// the file. +/// +/// As long as the guard lives, it can be written to using [`std::io::Write`]. +/// +/// The locking is recursive, therefore owning a guard does not prevent +/// using [`log_mask_ln!()`](crate::log_mask_ln). +pub struct LogGuard(NonNull); + +impl LogGuard { + /// Return a RAII guard that writes to QEMU's logging infrastructure. + /// The log file is locked while the guard exists, ensuring that there + /// is no tearing of the messages. + /// + /// Return `None` if the log file is closed and could not be opened. + /// Do *not* use `unwrap()` on the result; failure can be handled simply + /// by not logging anything. + /// + /// # Examples + /// + /// ``` + /// # use qemu_api::log::LogGuard; + /// # use std::io::Write; + /// if let Some(mut log) = LogGuard::new() { + /// writeln!(log, "test"); + /// } + /// ``` + pub fn new() -> Option { + let f = unsafe { bindings::qemu_log_trylock() }.cast(); + NonNull::new(f).map(Self) + } + + /// Writes a formatted string into the log, returning any error encountered. + /// + /// This method is primarily used by the + /// [`log_mask_ln!()`](crate::log_mask_ln) macro, and it is rare for it + /// to be called explicitly. It is public because it is the only way to + /// examine the error, which `log_mask_ln!()` ignores + /// + /// Unlike `log_mask_ln!()`, it does *not* append a newline at the end. + pub fn log_fmt(args: std::fmt::Arguments) -> io::Result<()> { + if let Some(mut log) = Self::new() { + log.write_fmt(args)?; + } + Ok(()) + } +} + +impl Write for LogGuard { + fn write(&mut self, bytes: &[u8]) -> io::Result { + let ret = unsafe { + bindings::rust_fwrite(bytes.as_ptr().cast(), 1, bytes.len(), self.0.as_ptr()) + }; + errno::into_io_result(ret) + } + + fn flush(&mut self) -> io::Result<()> { + // Do nothing, dropping the guard takes care of flushing + Ok(()) + } +} + +impl Drop for LogGuard { + fn drop(&mut self) { + unsafe { + bindings::qemu_log_unlock(self.0.as_ptr()); + } + } } /// A macro to log messages conditionally based on a provided mask. @@ -24,6 +102,8 @@ pub enum Log { /// log level and, if so, formats and logs the message. It is the Rust /// counterpart of the `qemu_log_mask()` macro in the C implementation. /// +/// Errors from writing to the log are ignored. +/// /// # Parameters /// /// - `$mask`: A log level mask. This should be a variant of the `Log` enum. @@ -62,12 +142,8 @@ macro_rules! log_mask_ln { if unsafe { (::qemu_api::bindings::qemu_loglevel & ($mask as std::os::raw::c_int)) != 0 } { - let formatted_string = format!("{}\n", format_args!($fmt $($args)*)); - let c_string = std::ffi::CString::new(formatted_string).unwrap(); - - unsafe { - ::qemu_api::bindings::qemu_log(c_string.as_ptr()); - } + _ = ::qemu_api::log::LogGuard::log_fmt( + format_args!("{}\n", format_args!($fmt $($args)*))); } }}; } -- cgit v1.1