Reformat comments

Test: presubmit
Change-Id: I39c261d9985989873b698213c5d8b653fc13757b
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5299850
Auto-Submit: Kaiyi Li <kaiyili@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Kaiyi Li 2024-02-15 11:00:41 -08:00 committed by crosvm LUCI
parent 9c0d3e16e7
commit c28067d1d9
170 changed files with 835 additions and 749 deletions

View file

@ -2067,7 +2067,7 @@ mod tests {
0x03, /* 3 name parts */ 0x03, /* 3 name parts */
0x5F, 0x53, 0x42, 0x5F, /* _SB_ */ 0x5F, 0x53, 0x42, 0x5F, /* _SB_ */
0x50, 0x43, 0x49, 0x30, /* PCI0 */ 0x50, 0x43, 0x49, 0x30, /* PCI0 */
0x5F, 0x55, 0x49, 0x44, /* _UID */ 0x5F, 0x55, 0x49, 0x44, /* _UID */
0x0b, /* WordPrefix */ 0x0b, /* WordPrefix */
0x34, 0x12 0x34, 0x12
] ]

View file

@ -453,8 +453,8 @@ pub trait LinuxArch {
/// # Arguments /// # Arguments
/// ///
/// * `components` - Parts to use to build the VM. /// * `components` - Parts to use to build the VM.
/// * `vm_evt_wrtube` - Tube used by sub-devices to request that crosvm exit because guest /// * `vm_evt_wrtube` - Tube used by sub-devices to request that crosvm exit because guest wants
/// wants to stop/shut down or requested reset. /// to stop/shut down or requested reset.
/// * `system_allocator` - Allocator created by this trait's implementation of /// * `system_allocator` - Allocator created by this trait's implementation of
/// `get_system_allocator_config`. /// `get_system_allocator_config`.
/// * `serial_parameters` - Definitions for how the serial devices should be configured. /// * `serial_parameters` - Definitions for how the serial devices should be configured.
@ -1288,8 +1288,8 @@ where
/// * `image` - The file containing the image to be loaded. /// * `image` - The file containing the image to be loaded.
/// * `min_guest_addr` - The minimum address of the start of the image. /// * `min_guest_addr` - The minimum address of the start of the image.
/// * `max_guest_addr` - The address to load the last byte of the image. /// * `max_guest_addr` - The address to load the last byte of the image.
/// * `align` - The minimum alignment of the start address of the image in bytes /// * `align` - The minimum alignment of the start address of the image in bytes (must be a power of
/// (must be a power of two). /// two).
/// ///
/// The guest address and size in bytes of the loaded image are returned. /// The guest address and size in bytes of the loaded image are returned.
pub fn load_image_high<F>( pub fn load_image_high<F>(

View file

@ -94,8 +94,8 @@ pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
/// * `com_evt_1_3` - event for com1 and com3 /// * `com_evt_1_3` - event for com1 and com3
/// * `com_evt_1_4` - event for com2 and com4 /// * `com_evt_1_4` - event for com2 and com4
/// * `serial_parameters` - definitions of serial parameter configurations. /// * `serial_parameters` - definitions of serial parameter configurations.
/// * `serial_jail` - minijail object cloned for use with each serial device. /// * `serial_jail` - minijail object cloned for use with each serial device. All four of the
/// All four of the traditional PC-style serial ports (COM1-COM4) must be specified. /// traditional PC-style serial ports (COM1-COM4) must be specified.
pub fn add_serial_devices( pub fn add_serial_devices(
protection_type: ProtectionType, protection_type: ProtectionType,
io_bus: &Bus, io_bus: &Bus,

View file

@ -179,7 +179,8 @@ mod tests {
let layout = Layout::from_size_align(size_of::<u32>() * 15, align_of::<u32>()).unwrap(); let layout = Layout::from_size_align(size_of::<u32>() * 15, align_of::<u32>()).unwrap();
let allocation = LayoutAllocation::zeroed(layout); let allocation = LayoutAllocation::zeroed(layout);
// SAFETY: // SAFETY:
// Slice less than the allocation size, which will return a slice of only the requested length. // Slice less than the allocation size, which will return a slice of only the requested
// length.
let slice: &[u32] = unsafe { allocation.as_slice(15) }; let slice: &[u32] = unsafe { allocation.as_slice(15) };
assert_eq!(slice.len(), 15); assert_eq!(slice.len(), 15);
assert_eq!(slice[0], 0); assert_eq!(slice[0], 0);
@ -192,7 +193,8 @@ mod tests {
let allocation = LayoutAllocation::zeroed(layout); let allocation = LayoutAllocation::zeroed(layout);
// SAFETY: // SAFETY:
// Slice less than the allocation size, which will return a slice of only the requested length. // Slice less than the allocation size, which will return a slice of only the requested
// length.
let slice: &[u32] = unsafe { allocation.as_slice(5) }; let slice: &[u32] = unsafe { allocation.as_slice(5) };
assert_eq!(slice.len(), 5); assert_eq!(slice.len(), 5);
} }
@ -203,7 +205,8 @@ mod tests {
let allocation = LayoutAllocation::zeroed(layout); let allocation = LayoutAllocation::zeroed(layout);
// SAFETY: // SAFETY:
// Slice more than the allocation size, which will clamp the returned slice len to the limit. // Slice more than the allocation size, which will clamp the returned slice len to the
// limit.
let slice: &[u32] = unsafe { allocation.as_slice(100) }; let slice: &[u32] = unsafe { allocation.as_slice(100) };
assert_eq!(slice.len(), 15); assert_eq!(slice.len(), 15);
} }

View file

@ -27,8 +27,8 @@ use crate::Result;
/// - Uses eventfd on Linux. /// - Uses eventfd on Linux.
/// - Uses synchapi event objects on Windows. /// - Uses synchapi event objects on Windows.
/// - The `Event` and `WaitContext` APIs together cannot easily be implemented with the same /// - The `Event` and `WaitContext` APIs together cannot easily be implemented with the same
/// semantics on all platforms. In particular, it is difficult to support multiple readers, so only /// semantics on all platforms. In particular, it is difficult to support multiple readers, so
/// a single reader is allowed for now. Multiple readers will result in undefined behavior. /// only a single reader is allowed for now. Multiple readers will result in undefined behavior.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
pub struct Event(pub(crate) PlatformEvent); pub struct Event(pub(crate) PlatformEvent);

View file

@ -172,7 +172,8 @@ pub trait FileReadWriteAtVolatile {
/// method must behave as a single call to `read_at_volatile` with the buffers concatenated /// method must behave as a single call to `read_at_volatile` with the buffers concatenated
/// would. The default implementation calls `read_at_volatile` with either the first nonempty /// would. The default implementation calls `read_at_volatile` with either the first nonempty
/// buffer provided, or returns `Ok(0)` if none exists. /// buffer provided, or returns `Ok(0)` if none exists.
/// On Windows file pointer will update with the read, but on Linux the file pointer will not change. /// On Windows file pointer will update with the read, but on Linux the file pointer will not
/// change.
fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
if let Some(&slice) = bufs.first() { if let Some(&slice) = bufs.first() {
self.read_at_volatile(slice, offset) self.read_at_volatile(slice, offset)
@ -182,8 +183,8 @@ pub trait FileReadWriteAtVolatile {
} }
/// Reads bytes from this file at `offset` into the given slice until all bytes in the slice are /// Reads bytes from this file at `offset` into the given slice until all bytes in the slice are
/// read, or an error is returned. On Windows file pointer will update with the read, but on Linux the /// read, or an error is returned. On Windows file pointer will update with the read, but on
/// file pointer will not change. /// Linux the file pointer will not change.
fn read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> { fn read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
while slice.size() > 0 { while slice.size() > 0 {
match self.read_at_volatile(slice, offset) { match self.read_at_volatile(slice, offset) {
@ -209,7 +210,8 @@ pub trait FileReadWriteAtVolatile {
/// consumed. This method must behave as a call to `write_at_volatile` with the buffers /// consumed. This method must behave as a call to `write_at_volatile` with the buffers
/// concatenated would. The default implementation calls `write_at_volatile` with either the /// concatenated would. The default implementation calls `write_at_volatile` with either the
/// first nonempty buffer provided, or returns `Ok(0)` if none exists. /// first nonempty buffer provided, or returns `Ok(0)` if none exists.
/// On Windows file pointer will update with the write, but on Linux the file pointer will not change. /// On Windows file pointer will update with the write, but on Linux the file pointer will not
/// change.
fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
if let Some(&slice) = bufs.first() { if let Some(&slice) = bufs.first() {
self.write_at_volatile(slice, offset) self.write_at_volatile(slice, offset)

View file

@ -64,8 +64,8 @@ impl PlatformEvent {
} }
Ok(PlatformEvent { Ok(PlatformEvent {
// SAFETY: // SAFETY:
// This is safe because we checked ret for success and know the kernel gave us an fd that we // This is safe because we checked ret for success and know the kernel gave us an fd
// own. // that we own.
event_handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) }, event_handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
}) })
} }

View file

@ -575,7 +575,6 @@ pub fn max_open_files() -> Result<u64> {
} }
/// Moves the requested PID/TID to a particular cgroup /// Moves the requested PID/TID to a particular cgroup
///
pub fn move_to_cgroup(cgroup_path: PathBuf, id_to_write: Pid, cgroup_file: &str) -> Result<()> { pub fn move_to_cgroup(cgroup_path: PathBuf, id_to_write: Pid, cgroup_file: &str) -> Result<()> {
use std::io::Write; use std::io::Write;

View file

@ -83,8 +83,8 @@ pub(in crate::sys) fn sockaddr_un<P: AsRef<Path>>(
// Check if the input path is valid. Since // Check if the input path is valid. Since
// * The pathname in sun_path should be null-terminated. // * The pathname in sun_path should be null-terminated.
// * The length of the pathname, including the terminating null byte, // * The length of the pathname, including the terminating null byte, should not exceed the size
// should not exceed the size of sun_path. // of sun_path.
// //
// and our input is a `Path`, we only need to check // and our input is a `Path`, we only need to check
// * If the string size of `Path` should less than sizeof(sun_path) // * If the string size of `Path` should less than sizeof(sun_path)

View file

@ -366,9 +366,14 @@ fn parse_ctrl_group_name_and_id(
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `nl_attr_area` - Nested attributes area (CTRL_ATTR_MCAST_GROUPS data), where nl_attr's /// * `nl_attr_area`
/// corresponding to specific groups are embed ///
/// * `group_name` - String with group_name for which we are looking group_id /// Nested attributes area (CTRL_ATTR_MCAST_GROUPS data), where nl_attr's corresponding to
/// specific groups are embed
///
/// * `group_name`
///
/// String with group_name for which we are looking group_id
/// ///
/// the CTRL_ATTR_MCAST_GROUPS data has nested attributes. Each of nested attribute is per /// the CTRL_ATTR_MCAST_GROUPS data has nested attributes. Each of nested attribute is per
/// multicast group attributes, which have another nested attributes: CTRL_ATTR_MCAST_GRP_NAME and /// multicast group attributes, which have another nested attributes: CTRL_ATTR_MCAST_GRP_NAME and
@ -473,7 +478,6 @@ impl NetlinkGenericRead {
/// ... /// ...
/// } /// }
/// } /// }
///
pub fn get_multicast_group_id(&self, group_name: String) -> Option<u32> { pub fn get_multicast_group_id(&self, group_name: String) -> Option<u32> {
for netlink_msg in self.iter() { for netlink_msg in self.iter() {
debug_pr!( debug_pr!(

View file

@ -132,8 +132,8 @@ pub(in crate::sys) fn sockaddr_un<P: AsRef<Path>>(
// Check if the input path is valid. Since // Check if the input path is valid. Since
// * The pathname in sun_path should be null-terminated. // * The pathname in sun_path should be null-terminated.
// * The length of the pathname, including the terminating null byte, // * The length of the pathname, including the terminating null byte, should not exceed the size
// should not exceed the size of sun_path. // of sun_path.
// //
// and our input is a `Path`, we only need to check // and our input is a `Path`, we only need to check
// * If the string size of `Path` should less than sizeof(sun_path) // * If the string size of `Path` should less than sizeof(sun_path)

View file

@ -13,8 +13,8 @@ use std::os::unix::net::UnixStream;
use crate::FileReadWriteAtVolatile; use crate::FileReadWriteAtVolatile;
use crate::FileReadWriteVolatile; use crate::FileReadWriteVolatile;
// This module allows the below macros to refer to $crate::unix::file_traits::lib::X and ensures other // This module allows the below macros to refer to $crate::unix::file_traits::lib::X and ensures
// crates don't need to add additional crates to their Cargo.toml. // other crates don't need to add additional crates to their Cargo.toml.
pub mod lib { pub mod lib {
pub use libc::c_int; pub use libc::c_int;
pub use libc::c_void; pub use libc::c_void;

View file

@ -33,8 +33,10 @@ impl<T> InterruptibleResult for io::Result<T> {
/// ///
/// The given expression `$x` can return /// The given expression `$x` can return
/// ///
/// * `crate::linux::Result` in which case the expression is retried if the `Error::errno()` is `EINTR`. /// * `crate::linux::Result` in which case the expression is retried if the `Error::errno()` is
/// * `std::io::Result` in which case the expression is retried if the `ErrorKind` is `ErrorKind::Interrupted`. /// `EINTR`.
/// * `std::io::Result` in which case the expression is retried if the `ErrorKind` is
/// `ErrorKind::Interrupted`.
/// ///
/// Note that if expression returns i32 (i.e. either -1 or error code), then handle_eintr_errno() /// Note that if expression returns i32 (i.e. either -1 or error code), then handle_eintr_errno()
/// or handle_eintr_rc() should be used instead. /// or handle_eintr_rc() should be used instead.

View file

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
//! The mmap module provides a safe interface to map memory and ensures UnmapViewOfFile is called when the //! The mmap module provides a safe interface to map memory and ensures UnmapViewOfFile is called
//! mmap object leaves scope. //! when the mmap object leaves scope.
use libc::c_void; use libc::c_void;
use win_util::get_high_order; use win_util::get_high_order;

View file

@ -68,14 +68,14 @@ use crate::WaitContext;
/// ///
/// The general rule is this should be *at least* as big as the largest message, otherwise /// The general rule is this should be *at least* as big as the largest message, otherwise
/// unexpected blocking behavior can result; for example, if too small, this can interact badly with /// unexpected blocking behavior can result; for example, if too small, this can interact badly with
/// crate::windows::StreamChannel, which expects to be able to make a complete write before releasing /// crate::windows::StreamChannel, which expects to be able to make a complete write before
/// a lock that the opposite side needs to complete a read. This means that if the buffer is too /// releasing a lock that the opposite side needs to complete a read. This means that if the buffer
/// small: /// is too small:
/// * The writer can't complete its write and release the lock because the buffer is too small. /// * The writer can't complete its write and release the lock because the buffer is too small.
/// * The reader can't start reading because the lock is held by the writer, so it can't /// * The reader can't start reading because the lock is held by the writer, so it can't relieve
/// relieve buffer pressure. Note that for message pipes, the reader couldn't do anything /// buffer pressure. Note that for message pipes, the reader couldn't do anything to help
/// to help anyway, because a message mode pipe should NOT have a partial read (which is /// anyway, because a message mode pipe should NOT have a partial read (which is what we would
/// what we would need to relieve pressure). /// need to relieve pressure).
/// * Conditions for deadlock are met, and both the reader & writer enter circular waiting. /// * Conditions for deadlock are met, and both the reader & writer enter circular waiting.
pub const DEFAULT_BUFFER_SIZE: usize = 50 * 1024; pub const DEFAULT_BUFFER_SIZE: usize = 50 * 1024;
@ -294,17 +294,15 @@ pub fn pair(
/// # Arguments /// # Arguments
/// ///
/// * `framing_mode` - Whether the system should provide a simple byte stream (Byte) or an /// * `framing_mode` - Whether the system should provide a simple byte stream (Byte) or an
/// automatically framed sequence of messages (Message). In message mode it's an /// automatically framed sequence of messages (Message). In message mode it's an error to read
/// error to read fewer bytes than were sent in a message from the other end of /// fewer bytes than were sent in a message from the other end of the pipe.
/// the pipe.
/// * `blocking_mode` - Whether the system should wait on read() until data is available (Wait) or /// * `blocking_mode` - Whether the system should wait on read() until data is available (Wait) or
/// return immediately if there is nothing available (NoWait). /// return immediately if there is nothing available (NoWait).
/// * `timeout` - A timeout to apply for socket operations, in milliseconds. /// * `timeout` - A timeout to apply for socket operations, in milliseconds. Setting this to
/// Setting this to zero will create sockets with the system /// zero will create sockets with the system default timeout.
/// default timeout.
/// * `buffer_size` - The default buffer size for the named pipe. The system should expand the /// * `buffer_size` - The default buffer size for the named pipe. The system should expand the
/// buffer automatically as needed, except in the case of NOWAIT pipes, where /// buffer automatically as needed, except in the case of NOWAIT pipes, where it will just fail
/// it will just fail writes that don't fit in the buffer. /// writes that don't fit in the buffer.
/// # Return value /// # Return value
/// ///
/// Returns a pair of pipes, of the form (server, client). Note that for some winapis, such as /// Returns a pair of pipes, of the form (server, client). Note that for some winapis, such as
@ -354,19 +352,17 @@ pub fn pair_with_buffer_size(
/// # Arguments /// # Arguments
/// ///
/// * `pipe_name` - The path of the named pipe to create. Should be in the form /// * `pipe_name` - The path of the named pipe to create. Should be in the form
/// `\\.\pipe\<some-name>`. /// `\\.\pipe\<some-name>`.
/// * `framing_mode` - Whether the system should provide a simple byte stream (Byte) or an /// * `framing_mode` - Whether the system should provide a simple byte stream (Byte) or an
/// automatically framed sequence of messages (Message). In message mode it's an /// automatically framed sequence of messages (Message). In message mode it's an error to read
/// error to read fewer bytes than were sent in a message from the other end of /// fewer bytes than were sent in a message from the other end of the pipe.
/// the pipe.
/// * `blocking_mode` - Whether the system should wait on read() until data is available (Wait) or /// * `blocking_mode` - Whether the system should wait on read() until data is available (Wait) or
/// return immediately if there is nothing available (NoWait). /// return immediately if there is nothing available (NoWait).
/// * `timeout` - A timeout to apply for socket operations, in milliseconds. /// * `timeout` - A timeout to apply for socket operations, in milliseconds. Setting this to
/// Setting this to zero will create sockets with the system /// zero will create sockets with the system default timeout.
/// default timeout.
/// * `buffer_size` - The default buffer size for the named pipe. The system should expand the /// * `buffer_size` - The default buffer size for the named pipe. The system should expand the
/// buffer automatically as needed, except in the case of NOWAIT pipes, where /// buffer automatically as needed, except in the case of NOWAIT pipes, where it will just fail
/// it will just fail writes that don't fit in the buffer. /// writes that don't fit in the buffer.
/// * `overlapped` - Sets whether overlapped mode is set on the pipe. /// * `overlapped` - Sets whether overlapped mode is set on the pipe.
pub fn create_server_pipe( pub fn create_server_pipe(
pipe_name: &str, pipe_name: &str,
@ -433,13 +429,12 @@ pub fn create_server_pipe(
/// # Arguments /// # Arguments
/// ///
/// * `pipe_name` - The path of the named pipe to create. Should be in the form /// * `pipe_name` - The path of the named pipe to create. Should be in the form
/// `\\.\pipe\<some-name>`. /// `\\.\pipe\<some-name>`.
/// * `framing_mode` - Whether the system should provide a simple byte stream (Byte) or an /// * `framing_mode` - Whether the system should provide a simple byte stream (Byte) or an
/// automatically framed sequence of messages (Message). In message mode it's an /// automatically framed sequence of messages (Message). In message mode it's an error to read
/// error to read fewer bytes than were sent in a message from the other end of /// fewer bytes than were sent in a message from the other end of the pipe.
/// the pipe.
/// * `blocking_mode` - Whether the system should wait on read() until data is available (Wait) or /// * `blocking_mode` - Whether the system should wait on read() until data is available (Wait) or
/// return immediately if there is nothing available (NoWait). /// return immediately if there is nothing available (NoWait).
/// * `overlapped` - Sets whether the pipe is opened in overlapped mode. /// * `overlapped` - Sets whether the pipe is opened in overlapped mode.
pub fn create_client_pipe( pub fn create_client_pipe(
pipe_name: &str, pipe_name: &str,
@ -711,9 +706,9 @@ impl PipeConnection {
/// (can be created with `OverlappedWrapper::new`) will be passed into /// (can be created with `OverlappedWrapper::new`) will be passed into
/// `WriteFile`. That event will be triggered when the write operation is complete. /// `WriteFile`. That event will be triggered when the write operation is complete.
/// ///
/// In order to get how many bytes were written, call `get_overlapped_result`. That function will /// In order to get how many bytes were written, call `get_overlapped_result`. That function
/// also help with waiting until the write operation is complete. The pipe must be opened in /// will also help with waiting until the write operation is complete. The pipe must be
/// overlapped otherwise there may be unexpected behavior. /// opened in overlapped otherwise there may be unexpected behavior.
/// ///
/// # Safety /// # Safety
/// * buf & overlapped_wrapper MUST live until the overlapped operation is complete. /// * buf & overlapped_wrapper MUST live until the overlapped operation is complete.
@ -1070,8 +1065,8 @@ pub struct NamedPipeInfo {
/// we ensure that the variable size message is written/read right after writing/reading /// we ensure that the variable size message is written/read right after writing/reading
/// fixed size header. For example it avoid sending or receiving in messages in order like /// fixed size header. For example it avoid sending or receiving in messages in order like
/// H1, H2, M1, M2 /// H1, H2, M1, M2
/// - where header H1 and its message M1 are sent by one event loop and H2 and its /// - where header H1 and its message M1 are sent by one event loop and H2 and its message M2 are
/// message M2 are sent by another event loop. /// sent by another event loop.
/// ///
/// Do not expose direct access to reader or writer pipes. /// Do not expose direct access to reader or writer pipes.
/// ///

View file

@ -156,10 +156,12 @@ pub fn set_time_period(res: Duration, begin: bool) -> Result<()> {
} }
let ret = if begin { let ret = if begin {
// SAFETY: Trivially safe. Note that the casts are safe because we know res is within u32's range. // SAFETY: Trivially safe. Note that the casts are safe because we know res is within u32's
// range.
unsafe { timeBeginPeriod(res.as_millis() as u32) } unsafe { timeBeginPeriod(res.as_millis() as u32) }
} else { } else {
// SAFETY: Trivially safe. Note that the casts are safe because we know res is within u32's range. // SAFETY: Trivially safe. Note that the casts are safe because we know res is within u32's
// range.
unsafe { timeEndPeriod(res.as_millis() as u32) } unsafe { timeEndPeriod(res.as_millis() as u32) }
}; };
if ret != TIMERR_NOERROR { if ret != TIMERR_NOERROR {

View file

@ -21,7 +21,8 @@ pub fn set_audio_thread_priority() -> Result<SafeMultimediaHandle> {
let multimedia_handle = unsafe { let multimedia_handle = unsafe {
let mut task_index: u32 = 0; let mut task_index: u32 = 0;
// "Pro Audio" is defined in: // "Pro Audio" is defined in:
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks\Pro Audio // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
// NT\CurrentVersion\Multimedia\SystemProfile\Tasks\Pro Audio
let pro_audio = std::ffi::CString::new("Pro Audio").unwrap(); let pro_audio = std::ffi::CString::new("Pro Audio").unwrap();
AvSetMmThreadCharacteristicsA(pro_audio.as_ptr(), &mut task_index) AvSetMmThreadCharacteristicsA(pro_audio.as_ptr(), &mut task_index)
}; };
@ -58,8 +59,8 @@ impl Drop for SafeMultimediaHandle {
fn drop(&mut self) { fn drop(&mut self) {
// SAFETY: // SAFETY:
// Safe because we `multimedia_handle` is defined in the same thread and is created in the // Safe because we `multimedia_handle` is defined in the same thread and is created in the
// function above. `multimedia_handle` needs be created from `AvSetMmThreadCharacteristicsA`. // function above. `multimedia_handle` needs be created from
// This will also drop the `mulitmedia_handle`. // `AvSetMmThreadCharacteristicsA`. This will also drop the `mulitmedia_handle`.
if unsafe { AvRevertMmThreadCharacteristics(self.multimedia_handle) } == FALSE { if unsafe { AvRevertMmThreadCharacteristics(self.multimedia_handle) } == FALSE {
warn!( warn!(
"Failed to revert audio thread. Error: {}", "Failed to revert audio thread. Error: {}",

View file

@ -219,8 +219,8 @@ impl StreamChannel {
// the notifier though, then we have to be sure, so we'll proceed to the next section. // the notifier though, then we have to be sure, so we'll proceed to the next section.
let byte_count = self.get_readable_byte_count()?; let byte_count = self.get_readable_byte_count()?;
if byte_count > 0 { if byte_count > 0 {
// It's always safe to set the read notifier here because we know there is data in the // It's always safe to set the read notifier here because we know there is data in
// pipe, and no one else could read it out from under us. // the pipe, and no one else could read it out from under us.
self.read_notify.signal().map_err(|e| { self.read_notify.signal().map_err(|e| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,

View file

@ -45,7 +45,8 @@ pub unsafe trait Terminal {
& !(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); & !(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
// SAFETY: // SAFETY:
// Safe because the syscall will only read the extent of mode and we check the return result. // Safe because the syscall will only read the extent of mode and we check the return
// result.
if unsafe { SetConsoleMode(descriptor, new_mode) } == 0 { if unsafe { SetConsoleMode(descriptor, new_mode) } == 0 {
return Err(Error::last()); return Err(Error::last());
} }
@ -56,7 +57,8 @@ pub unsafe trait Terminal {
/// Set this terminal's mode to a previous state returned by `set_raw_mode()`. /// Set this terminal's mode to a previous state returned by `set_raw_mode()`.
fn restore_mode(&self, mode: DWORD) -> Result<()> { fn restore_mode(&self, mode: DWORD) -> Result<()> {
// SAFETY: // SAFETY:
// Safe because the syscall will only read the extent of mode and we check the return result. // Safe because the syscall will only read the extent of mode and we check the return
// result.
if unsafe { SetConsoleMode(self.terminal_descriptor(), mode) } == 0 { if unsafe { SetConsoleMode(self.terminal_descriptor(), mode) } == 0 {
Err(Error::last()) Err(Error::last())
} else { } else {

View file

@ -275,9 +275,9 @@ fn duplicate_handle(desc: RawHandle, target_pid: Option<u32>) -> Result<RawHandl
} }
/// Reads a part of a Tube packet asserting that it was correctly read. This means: /// Reads a part of a Tube packet asserting that it was correctly read. This means:
/// * Treats partial "message" (transport framing) reads are Ok, as long as we filled our buffer. /// * Treats partial "message" (transport framing) reads are Ok, as long as we filled our buffer. We
/// We use this to ignore errors when reading the message header, which has the lengths we need /// use this to ignore errors when reading the message header, which has the lengths we need to
/// to allocate our buffers for the remainder of the message. /// allocate our buffers for the remainder of the message.
/// * We filled the supplied buffer. /// * We filled the supplied buffer.
fn perform_read<F: FnMut(&mut [u8]) -> io::Result<usize>>( fn perform_read<F: FnMut(&mut [u8]) -> io::Result<usize>>(
read_fn: &mut F, read_fn: &mut F,

View file

@ -215,24 +215,26 @@ impl<T: EventToken> EventContext<T> {
WAIT_OBJECT_0..=MAXIMUM_WAIT_OBJECTS_U32 => { WAIT_OBJECT_0..=MAXIMUM_WAIT_OBJECTS_U32 => {
let mut event_index = (result - WAIT_OBJECT_0) as usize; let mut event_index = (result - WAIT_OBJECT_0) as usize;
if event_index >= handles_len { if event_index >= handles_len {
// This is not a valid index and should return an error. This case should not be possible // This is not a valid index and should return an error. This case should not be
// and will likely not return a meaningful system error code, but is still an invalid case. // possible and will likely not return a meaningful system
// error code, but is still an invalid case.
error!("Wait returned index out of range"); error!("Wait returned index out of range");
return errno_result(); return errno_result();
} }
if event_index == 0 { if event_index == 0 {
// The handles list has been modified and triggered the wait, try again with the updated // The handles list has been modified and triggered the wait, try again with the
// handles list. Note it is possible the list was modified again after the wait which will // updated handles list. Note it is possible the list was
// trigger the handles_modified_event again, but that will only err towards the safe side // modified again after the wait which will trigger the
// handles_modified_event again, but that will only err towards the safe side
// of recursing an extra time. // of recursing an extra time.
let _ = self.handles_modified_event.wait(); let _ = self.handles_modified_event.wait();
return self.wait_timeout(timeout); return self.wait_timeout(timeout);
} }
let mut events_to_return = SmallVec::<[TriggeredEvent<T>; 16]>::new(); let mut events_to_return = SmallVec::<[TriggeredEvent<T>; 16]>::new();
// Multiple events may be triggered at once, but WaitForMultipleObjects will only return one. // Multiple events may be triggered at once, but WaitForMultipleObjects will only
// Once it returns, loop through the remaining triggers checking each to ensure they haven't // return one. Once it returns, loop through the remaining triggers
// also been triggered. // checking each to ensure they haven't also been triggered.
let mut handles_offset: usize = 0; let mut handles_offset: usize = 0;
loop { loop {
let event_to_return = raw_handles_list[event_index + handles_offset]; let event_to_return = raw_handles_list[event_index + handles_offset];
@ -270,8 +272,9 @@ impl<T: EventToken> EventContext<T> {
) as usize; ) as usize;
if event_index >= (handles_len - handles_offset) { if event_index >= (handles_len - handles_offset) {
// This indicates a failure condition, as return values greater than the length // This indicates a failure condition, as return values greater than the
// of the provided array are reserved for failures. // length of the provided array are reserved for
// failures.
break; break;
} }
} }

View file

@ -42,8 +42,6 @@
//! //!
//! init_with(cfg).unwrap(); //! init_with(cfg).unwrap();
//! error!("something went horribly wrong: {}", "out of RAMs"); //! error!("something went horribly wrong: {}", "out of RAMs");
//!
//!
//! ``` //! ```
//! //!
//! //!
@ -372,7 +370,7 @@ pub fn init() -> Result<(), Error> {
/// ///
/// Arguments: /// Arguments:
/// * filter: See <https://docs.rs/env_logger/0.9/env_logger/index.html> for example filter /// * filter: See <https://docs.rs/env_logger/0.9/env_logger/index.html> for example filter
/// specifications /// specifications
/// * stderr: If set will output to stderr (in addition) /// * stderr: If set will output to stderr (in addition)
/// * file: If set will output to this file (in addition) /// * file: If set will output to this file (in addition)
/// * proc_name: proc name for Syslog implementation /// * proc_name: proc name for Syslog implementation

View file

@ -116,7 +116,6 @@
//! self.0 << 4 //! self.0 << 4
//! } //! }
//! } //! }
//!
//! ``` //! ```
//! //!
//! Finally, fields may be of user-defined enum types. The enum must satisfy one of the following //! Finally, fields may be of user-defined enum types. The enum must satisfy one of the following

View file

@ -183,8 +183,8 @@ pub trait ShmStreamSource<E: std::error::Error>: Send {
/// Creates a new [`ShmStream`](ShmStream) /// Creates a new [`ShmStream`](ShmStream)
/// ///
/// Creates a new `ShmStream` object, which allows: /// Creates a new `ShmStream` object, which allows:
/// * Waiting until the server has communicated that data is ready or /// * Waiting until the server has communicated that data is ready or requested that we make
/// requested that we make more data available. /// more data available.
/// * Setting the location and length of buffers for reading/writing audio data. /// * Setting the location and length of buffers for reading/writing audio data.
/// ///
/// # Arguments /// # Arguments
@ -193,15 +193,13 @@ pub trait ShmStreamSource<E: std::error::Error>: Send {
/// * `num_channels` - The number of audio channels for the stream. /// * `num_channels` - The number of audio channels for the stream.
/// * `format` - The audio format to use for audio samples. /// * `format` - The audio format to use for audio samples.
/// * `frame_rate` - The stream's frame rate in Hz. /// * `frame_rate` - The stream's frame rate in Hz.
/// * `buffer_size` - The maximum size of an audio buffer. This will be the /// * `buffer_size` - The maximum size of an audio buffer. This will be the size used for
/// size used for transfers of audio data between client /// transfers of audio data between client and server.
/// and server.
/// * `effects` - Audio effects to use for the stream, such as echo-cancellation. /// * `effects` - Audio effects to use for the stream, such as echo-cancellation.
/// * `client_shm` - The shared memory area that will contain samples. /// * `client_shm` - The shared memory area that will contain samples.
/// * `buffer_offsets` - The two initial values to use as buffer offsets /// * `buffer_offsets` - The two initial values to use as buffer offsets for streams. This way,
/// for streams. This way, the server will not write /// the server will not write audio data to an arbitrary offset in `client_shm` if the client
/// audio data to an arbitrary offset in `client_shm` /// fails to update offsets in time.
/// if the client fails to update offsets in time.
/// ///
/// # Errors /// # Errors
/// ///

View file

@ -10,16 +10,15 @@
//! return a PoisonError. This API codifies our error handling strategy around //! return a PoisonError. This API codifies our error handling strategy around
//! poisoned mutexes in crosvm. //! poisoned mutexes in crosvm.
//! //!
//! - Crosvm releases are built with panic=abort so poisoning never occurs. A //! - Crosvm releases are built with panic=abort so poisoning never occurs. A panic while a mutex is
//! panic while a mutex is held (or ever) takes down the entire process. Thus //! held (or ever) takes down the entire process. Thus we would like for code not to have to
//! we would like for code not to have to consider the possibility of poison. //! consider the possibility of poison.
//! //!
//! - We could ask developers to always write `.lock().unwrap()` on a standard //! - We could ask developers to always write `.lock().unwrap()` on a standard library mutex.
//! library mutex. However, we would like to stigmatize the use of unwrap. It //! However, we would like to stigmatize the use of unwrap. It is confusing to permit unwrap but
//! is confusing to permit unwrap but only on mutex lock results. During code //! only on mutex lock results. During code review it may not always be obvious whether a
//! review it may not always be obvious whether a particular unwrap is //! particular unwrap is unwrapping a mutex lock result or a different error that should be
//! unwrapping a mutex lock result or a different error that should be handled //! handled in a more principled way.
//! in a more principled way.
//! //!
//! Developers should feel free to use sync::Mutex anywhere in crosvm that they //! Developers should feel free to use sync::Mutex anywhere in crosvm that they
//! would otherwise be using std::sync::Mutex. //! would otherwise be using std::sync::Mutex.

View file

@ -22,8 +22,7 @@ use crate::BlockingPool;
/// This is convenient, though not preferred. Pros/cons: /// This is convenient, though not preferred. Pros/cons:
/// + It avoids passing executor all the way to each call sites. /// + It avoids passing executor all the way to each call sites.
/// + The call site can assume that executor will never shutdown. /// + The call site can assume that executor will never shutdown.
/// + Provides similar functionality as async_task with a few improvements /// + Provides similar functionality as async_task with a few improvements around ability to cancel.
/// around ability to cancel.
/// - Globals are harder to reason about. /// - Globals are harder to reason about.
static EXECUTOR: Lazy<CancellableBlockingPool> = static EXECUTOR: Lazy<CancellableBlockingPool> =
Lazy::new(|| CancellableBlockingPool::new(256, Duration::from_secs(10))); Lazy::new(|| CancellableBlockingPool::new(256, Duration::from_secs(10)));
@ -279,7 +278,6 @@ impl CancellableBlockingPool {
/// This will block until all work that has been started by the worker threads is finished. Any /// This will block until all work that has been started by the worker threads is finished. Any
/// work that was added to the `CancellableBlockingPool` but not yet picked up by a worker /// work that was added to the `CancellableBlockingPool` but not yet picked up by a worker
/// thread will not complete and `await`ing on the `Task` for that work will panic. /// thread will not complete and `await`ing on the `Task` for that work will panic.
///
pub fn shutdown(&self) -> Result<(), Error> { pub fn shutdown(&self) -> Result<(), Error> {
self.shutdown_with_timeout(DEFAULT_SHUTDOWN_TIMEOUT) self.shutdown_with_timeout(DEFAULT_SHUTDOWN_TIMEOUT)
} }

View file

@ -370,8 +370,8 @@ impl Condvar {
let set_on_release = if waiters.is_empty() { let set_on_release = if waiters.is_empty() {
// SAFETY: // SAFETY:
// Clear the rwlock associated with this Condvar since there are no longer any waiters. Safe // Clear the rwlock associated with this Condvar since there are no longer any waiters.
// because we the spin lock guarantees exclusive access. // Safe because we the spin lock guarantees exclusive access.
unsafe { *self.mu.get() = 0 }; unsafe { *self.mu.get() = 0 };
0 0

View file

@ -102,8 +102,8 @@ enum OpStatus {
WakeEvent, WakeEvent,
} }
// An IO source previously registered with an EpollReactor. Used to initiate asynchronous IO with the // An IO source previously registered with an EpollReactor. Used to initiate asynchronous IO with
// associated executor. // the associated executor.
pub struct RegisteredSource<F> { pub struct RegisteredSource<F> {
pub(crate) source: F, pub(crate) source: F,
ex: Weak<RawExecutor<EpollReactor>>, ex: Weak<RawExecutor<EpollReactor>>,

View file

@ -159,8 +159,9 @@ impl<F: AsRawDescriptor> PollSource<F> {
loop { loop {
let res = if let Some(offset) = file_offset { let res = if let Some(offset) = file_offset {
// SAFETY: // SAFETY:
// Safe because we trust the kernel not to write path the length given and the length is // Safe because we trust the kernel not to write path the length given and the
// guaranteed to be valid from the pointer by io_slice_mut. // length is guaranteed to be valid from the pointer by
// io_slice_mut.
unsafe { unsafe {
libc::preadv64( libc::preadv64(
self.registered_source.duped_fd.as_raw_fd(), self.registered_source.duped_fd.as_raw_fd(),
@ -171,8 +172,9 @@ impl<F: AsRawDescriptor> PollSource<F> {
} }
} else { } else {
// SAFETY: // SAFETY:
// Safe because we trust the kernel not to write path the length given and the length is // Safe because we trust the kernel not to write path the length given and the
// guaranteed to be valid from the pointer by io_slice_mut. // length is guaranteed to be valid from the pointer by
// io_slice_mut.
unsafe { unsafe {
libc::readv( libc::readv(
self.registered_source.duped_fd.as_raw_fd(), self.registered_source.duped_fd.as_raw_fd(),
@ -272,8 +274,9 @@ impl<F: AsRawDescriptor> PollSource<F> {
loop { loop {
let res = if let Some(offset) = file_offset { let res = if let Some(offset) = file_offset {
// SAFETY: // SAFETY:
// Safe because we trust the kernel not to write path the length given and the length is // Safe because we trust the kernel not to write path the length given and the
// guaranteed to be valid from the pointer by io_slice_mut. // length is guaranteed to be valid from the pointer by
// io_slice_mut.
unsafe { unsafe {
libc::pwritev64( libc::pwritev64(
self.registered_source.duped_fd.as_raw_fd(), self.registered_source.duped_fd.as_raw_fd(),
@ -284,8 +287,9 @@ impl<F: AsRawDescriptor> PollSource<F> {
} }
} else { } else {
// SAFETY: // SAFETY:
// Safe because we trust the kernel not to write path the length given and the length is // Safe because we trust the kernel not to write path the length given and the
// guaranteed to be valid from the pointer by io_slice_mut. // length is guaranteed to be valid from the pointer by
// io_slice_mut.
unsafe { unsafe {
libc::writev( libc::writev(
self.registered_source.duped_fd.as_raw_fd(), self.registered_source.duped_fd.as_raw_fd(),

View file

@ -30,8 +30,8 @@
//! What if the kernel's reference to the buffer outlives the buffer itself? This could happen if a //! What if the kernel's reference to the buffer outlives the buffer itself? This could happen if a
//! read operation was submitted, then the memory is dropped. To solve this, the executor takes an //! read operation was submitted, then the memory is dropped. To solve this, the executor takes an
//! Arc to the backing memory. Vecs being read to are also wrapped in an Arc before being passed to //! Arc to the backing memory. Vecs being read to are also wrapped in an Arc before being passed to
//! the executor. The executor holds the Arc and ensures all operations are complete before dropping //! the executor. The executor holds the Arc and ensures all operations are complete before
//! it, that guarantees the memory is valid for the duration. //! dropping it, that guarantees the memory is valid for the duration.
//! //!
//! The buffers _have_ to be on the heap. Because we don't have a way to cancel a future if it is //! The buffers _have_ to be on the heap. Because we don't have a way to cancel a future if it is
//! dropped(can't rely on drop running), there is no way to ensure the kernel's buffer remains valid //! dropped(can't rely on drop running), there is no way to ensure the kernel's buffer remains valid
@ -936,8 +936,8 @@ mod tests {
.register_source(&ex, &rx) .register_source(&ex, &rx)
.expect("register source failed"); .expect("register source failed");
// Submit the op to the kernel. Next, test that the source keeps its Arc open for the duration // Submit the op to the kernel. Next, test that the source keeps its Arc open for the
// of the op. // duration of the op.
let pending_op = registered_source let pending_op = registered_source
.start_read_to_mem(None, Arc::clone(&bm), [MemRegion { offset: 0, len: 8 }]) .start_read_to_mem(None, Arc::clone(&bm), [MemRegion { offset: 0, len: 8 }])
.expect("failed to start read to mem"); .expect("failed to start read to mem");
@ -983,8 +983,8 @@ mod tests {
.register_source(&ex, &tx) .register_source(&ex, &tx)
.expect("register source failed"); .expect("register source failed");
// Submit the op to the kernel. Next, test that the source keeps its Arc open for the duration // Submit the op to the kernel. Next, test that the source keeps its Arc open for the
// of the op. // duration of the op.
let pending_op = registered_source let pending_op = registered_source
.start_write_from_mem(None, Arc::clone(&bm), [MemRegion { offset: 0, len: 8 }]) .start_write_from_mem(None, Arc::clone(&bm), [MemRegion { offset: 0, len: 8 }])
.expect("failed to start write to mem"); .expect("failed to start write to mem");

View file

@ -39,11 +39,12 @@ impl EventAsync {
Self::new_without_reset( Self::new_without_reset(
// SAFETY: // SAFETY:
// Safe because: // Safe because:
// a) the underlying Event should be validated by the caller. // * the underlying Event should be validated by the caller.
// b) we do NOT take ownership of the underlying Event. If we did that would cause an early // * we do NOT take ownership of the underlying Event. If we did that would cause an
// free (and later a double free @ the end of this scope). This is why we have to wrap // early free (and later a double free @ the end of this scope). This is why we have
// it in ManuallyDrop. // to wrap it in ManuallyDrop.
// c) we own the clone that is produced exclusively, so it is safe to take ownership of it. // * we own the clone that is produced exclusively, so it is safe to take ownership of
// it.
unsafe { unsafe {
ManuallyDrop::new(Event::from_raw_descriptor(descriptor.as_raw_descriptor())) ManuallyDrop::new(Event::from_raw_descriptor(descriptor.as_raw_descriptor()))
} }

View file

@ -259,8 +259,8 @@ impl WeakWake for HandleReactor {
/// 1. The reactor in use is a HandleReactor. /// 1. The reactor in use is a HandleReactor.
/// 2. Immediately after the IO syscall, this future MUST be awaited. We rely on the fact that /// 2. Immediately after the IO syscall, this future MUST be awaited. We rely on the fact that
/// the executor cannot poll the IOCP before this future is polled for the first time to /// the executor cannot poll the IOCP before this future is polled for the first time to
/// ensure the waker has been registered. (If the executor polls the IOCP before the waker /// ensure the waker has been registered. (If the executor polls the IOCP before the waker is
/// is registered, the future will stall.) /// registered, the future will stall.)
pub(crate) struct OverlappedOperation { pub(crate) struct OverlappedOperation {
overlapped: BoxedOverlapped, overlapped: BoxedOverlapped,
ex: Weak<RawExecutor<HandleReactor>>, ex: Weak<RawExecutor<HandleReactor>>,

View file

@ -331,8 +331,8 @@ impl<F: AsRawDescriptor> HandleSource<F> {
.spawn( .spawn(
move || { move || {
let mut file = get_thread_file(descriptors); let mut file = get_thread_file(descriptors);
// ZeroRange calls `punch_hole` which doesn't extend the File size if it needs to. // ZeroRange calls `punch_hole` which doesn't extend the File size if it needs
// Will fix if it becomes a problem. // to. Will fix if it becomes a problem.
file.write_zeroes_at(file_offset, len as usize) file.write_zeroes_at(file_offset, len as usize)
.map_err(Error::IoWriteZeroesError)?; .map_err(Error::IoWriteZeroesError)?;
Ok(()) Ok(())

View file

@ -203,7 +203,8 @@ impl<F: AsRawDescriptor> OverlappedSource<F> {
.map_err(Error::BackingMemoryVolatileSliceFetchFailed)?; .map_err(Error::BackingMemoryVolatileSliceFetchFailed)?;
// SAFETY: // SAFETY:
// Safe because we're passing a volatile slice (valid ptr), and the size of the memory region it refers to. // Safe because we're passing a volatile slice (valid ptr), and the size of the memory
// region it refers to.
unsafe { unsafe {
read( read(
self.source.as_raw_descriptor(), self.source.as_raw_descriptor(),
@ -291,7 +292,8 @@ impl<F: AsRawDescriptor> OverlappedSource<F> {
.map_err(Error::BackingMemoryVolatileSliceFetchFailed)?; .map_err(Error::BackingMemoryVolatileSliceFetchFailed)?;
// SAFETY: // SAFETY:
// Safe because we're passing a volatile slice (valid ptr), and the size of the memory region it refers to. // Safe because we're passing a volatile slice (valid ptr), and the size of the memory
// region it refers to.
unsafe { unsafe {
write( write(
self.source.as_raw_descriptor(), self.source.as_raw_descriptor(),

View file

@ -168,9 +168,10 @@ where
// Safe because self.descriptor is valid in any state except New or Finished. // Safe because self.descriptor is valid in any state except New or Finished.
// //
// Note: this method call is critical for supplying the safety guarantee relied upon by // Note: this method call is critical for supplying the safety guarantee relied upon by
// wait_for_handle_waker. Upon return, it ensures that wait_for_handle_waker is not running // wait_for_handle_waker. Upon return, it ensures that wait_for_handle_waker is not
// and won't be scheduled again, which makes it safe to drop self.inner_for_callback // running and won't be scheduled again, which makes it safe to drop
// (wait_for_handle_waker has a non owning pointer to self.inner_for_callback). // self.inner_for_callback (wait_for_handle_waker has a non owning pointer
// to self.inner_for_callback).
unsafe { unregister_wait(wait_object) } unsafe { unregister_wait(wait_object) }
} }
} }

View file

@ -96,7 +96,6 @@ pub fn push_descriptors_internal(keep_rds: &mut Vec<RawDescriptor>) {
/// Categories that are enabled will have their events traced at runtime via /// Categories that are enabled will have their events traced at runtime via
/// `trace_event_begin!()`, `trace_event_end!()`, or `trace_event!()` scoped tracing. /// `trace_event_begin!()`, `trace_event_end!()`, or `trace_event!()` scoped tracing.
/// The categories that are marked as false will have their events skipped. /// The categories that are marked as false will have their events skipped.
///
macro_rules! setup_trace_marker { macro_rules! setup_trace_marker {
($(($cat:ident, $enabled:literal)),+) => { ($(($cat:ident, $enabled:literal)),+) => {
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
@ -159,7 +158,6 @@ macro_rules! setup_trace_marker {
/// - `$uid: Exit: exec` /// - `$uid: Exit: exec`
/// ///
/// where `$uid` will be the same unique value across those two events. /// where `$uid` will be the same unique value across those two events.
///
macro_rules! trace_event { macro_rules! trace_event {
($category:ident, $name:literal, $($arg:expr),+) => {{ ($category:ident, $name:literal, $($arg:expr),+) => {{
if($crate::ENABLED_CATEGORIES[$crate::TracedCategories::$category as usize].load(std::sync::atomic::Ordering::Relaxed)) { if($crate::ENABLED_CATEGORIES[$crate::TracedCategories::$category as usize].load(std::sync::atomic::Ordering::Relaxed)) {

View file

@ -427,10 +427,10 @@ use bitmasks::*;
/// ///
/// This function packs bits in NTSTATUS results (generally what a Windows exit code should be). /// This function packs bits in NTSTATUS results (generally what a Windows exit code should be).
/// There are three primary cases it deals with: /// There are three primary cases it deals with:
/// 1. Vendor specific exits. These are error codes we generate explicitly in crosvm. We will /// 1. Vendor specific exits. These are error codes we generate explicitly in crosvm. We will pack
/// pack these codes with the lower 6 "facility" bits ([21, 16]) set so they can't collide /// these codes with the lower 6 "facility" bits ([21, 16]) set so they can't collide with the
/// with the other cases (this makes our facility value > FACILITY_MAXIMUM_VALUE). The top /// other cases (this makes our facility value > FACILITY_MAXIMUM_VALUE). The top 6 bits of the
/// 6 bits of the facility field ([27, 22]) will be clear at this point. /// facility field ([27, 22]) will be clear at this point.
/// ///
/// 2. Non vendor NTSTATUS exits. These are error codes which come from Windows. We flip the /// 2. Non vendor NTSTATUS exits. These are error codes which come from Windows. We flip the
/// vendor bit on these because we're going to pack the facility field, and leaving it unset /// vendor bit on these because we're going to pack the facility field, and leaving it unset
@ -440,9 +440,8 @@ use bitmasks::*;
/// however, if for some reason we see a non vendor code with any of those bits set, we will /// however, if for some reason we see a non vendor code with any of those bits set, we will
/// fall through to case #3. /// fall through to case #3.
/// ///
/// 3. Non NTSTATUS errors. We detect these with two heuristics: /// 3. Non NTSTATUS errors. We detect these with two heuristics: a) Reserved field is set. b) The
/// a) Reserved field is set. /// facility field has exceeded the bottom six bits ([21, 16]).
/// b) The facility field has exceeded the bottom six bits ([21, 16]).
/// ///
/// For such cases, we pack as much of the error as we can into the lower 6 bits of the /// For such cases, we pack as much of the error as we can into the lower 6 bits of the
/// facility field, and code field (2 bytes). In this case, the most significant bit of the /// facility field, and code field (2 bytes). In this case, the most significant bit of the

View file

@ -368,14 +368,15 @@ pub extern "C" fn crosvm_client_max_usb_devices() -> usize {
USB_CONTROL_MAX_PORTS USB_CONTROL_MAX_PORTS
} }
/// Returns all USB devices passed through the crosvm instance whose control socket is listening on `socket_path`. /// Returns all USB devices passed through the crosvm instance whose control socket is listening on
/// `socket_path`.
/// ///
/// The function returns the amount of entries written. /// The function returns the amount of entries written.
/// # Arguments /// # Arguments
/// ///
/// * `socket_path` - Path to the crosvm control socket /// * `socket_path` - Path to the crosvm control socket
/// * `entries` - Pointer to an array of `UsbDeviceEntry` where the details about the attached /// * `entries` - Pointer to an array of `UsbDeviceEntry` where the details about the attached
/// devices will be written to /// devices will be written to
/// * `entries_length` - Amount of entries in the array specified by `entries` /// * `entries_length` - Amount of entries in the array specified by `entries`
/// ///
/// Use the value returned by [`crosvm_client_max_usb_devices()`] to determine the size of the input /// Use the value returned by [`crosvm_client_max_usb_devices()`] to determine the size of the input
@ -863,7 +864,8 @@ pub struct BalloonWSRConfigFfi {
report_threshold: u64, report_threshold: u64,
} }
/// Returns balloon working set of the crosvm instance whose control socket is listening on socket_path. /// Returns balloon working set of the crosvm instance whose control socket is listening on
/// socket_path.
/// ///
/// The function returns true on success or false if an error occurred. /// The function returns true on success or false if an error occurred.
/// ///

View file

@ -312,10 +312,10 @@ impl GoldfishBattery {
/// Create GoldfishBattery device model /// Create GoldfishBattery device model
/// ///
/// * `mmio_base` - The 32-bit mmio base address. /// * `mmio_base` - The 32-bit mmio base address.
/// * `irq_num` - The corresponding interrupt number of the irq_evt /// * `irq_num` - The corresponding interrupt number of the irq_evt which will be put into the
/// which will be put into the ACPI DSDT. /// ACPI DSDT.
/// * `irq_evt` - The interrupt event used to notify driver about /// * `irq_evt` - The interrupt event used to notify driver about the battery properties
/// the battery properties changing. /// changing.
/// * `socket` - Battery control socket /// * `socket` - Battery control socket
pub fn new( pub fn new(
mmio_base: u64, mmio_base: u64,

View file

@ -670,7 +670,8 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
// Attempt to add a file to an fw_cfg device w/ no fileslots and assert that nothing gets inserted // Attempt to add a file to an fw_cfg device w/ no fileslots and assert that nothing gets
// inserted
fn write_file_one_slot_expect_nop() { fn write_file_one_slot_expect_nop() {
let mut fw_cfg = FwCfgDevice::new(0, default_params()).unwrap(); let mut fw_cfg = FwCfgDevice::new(0, default_params()).unwrap();
let data = vec![MAGIC_BYTE]; let data = vec![MAGIC_BYTE];
@ -681,7 +682,8 @@ mod tests {
#[test] #[test]
#[should_panic] #[should_panic]
// Attempt to add two files to an fw_cfg w/ only one fileslot and assert only first insert succeeds. // Attempt to add two files to an fw_cfg w/ only one fileslot and assert only first insert
// succeeds.
fn write_two_files_no_slots_expect_nop_on_second() { fn write_two_files_no_slots_expect_nop_on_second() {
let mut fw_cfg = FwCfgDevice::new(1, default_params()).unwrap(); let mut fw_cfg = FwCfgDevice::new(1, default_params()).unwrap();
let data = vec![MAGIC_BYTE]; let data = vec![MAGIC_BYTE];
@ -706,8 +708,8 @@ mod tests {
fn read_fw_cfg_signature() { fn read_fw_cfg_signature() {
let mut data: Vec<u8> = vec![0]; let mut data: Vec<u8> = vec![0];
let (mut device, bai) = setup_read(&FILENAMES, &get_contents(), FW_CFG_SIGNATURE_SELECTOR); let (mut device, bai) = setup_read(&FILENAMES, &get_contents(), FW_CFG_SIGNATURE_SELECTOR);
// To logically compare the revison vector to FW_CFG_REVISION byte-by-byte, we must use to_be_bytes() // To logically compare the revison vector to FW_CFG_REVISION byte-by-byte, we must use
// since we are comparing byte arrays, not integers. // to_be_bytes() since we are comparing byte arrays, not integers.
let signature = read_u32(&mut device, bai, &mut data[..]).to_be_bytes(); let signature = read_u32(&mut device, bai, &mut data[..]).to_be_bytes();
assert_eq!(signature, FW_CFG_SIGNATURE); assert_eq!(signature, FW_CFG_SIGNATURE);
} }
@ -717,8 +719,8 @@ mod tests {
fn read_fw_cfg_revision() { fn read_fw_cfg_revision() {
let mut data: Vec<u8> = vec![0]; let mut data: Vec<u8> = vec![0];
let (mut device, bai) = setup_read(&FILENAMES, &get_contents(), FW_CFG_REVISION_SELECTOR); let (mut device, bai) = setup_read(&FILENAMES, &get_contents(), FW_CFG_REVISION_SELECTOR);
// To logically compare the revison vector to FW_CFG_REVISION byte-by-byte, we must use to_be_bytes() // To logically compare the revison vector to FW_CFG_REVISION byte-by-byte, we must use
// since we are comparing byte arrays, not integers. // to_be_bytes() since we are comparing byte arrays, not integers.
let revision = read_u32(&mut device, bai, &mut data[..]).to_be_bytes(); let revision = read_u32(&mut device, bai, &mut data[..]).to_be_bytes();
assert_eq!(revision, FW_CFG_REVISION); assert_eq!(revision, FW_CFG_REVISION);
} }

View file

@ -52,8 +52,9 @@ pub struct IrqLevelEvent {
/// An event used by the device backend to signal hypervisor/VM about data or new unit /// An event used by the device backend to signal hypervisor/VM about data or new unit
/// of work being available. /// of work being available.
trigger_evt: Event, trigger_evt: Event,
/// An event used by the hypervisor to signal device backend that it completed processing a unit /// An event used by the hypervisor to signal device backend that it completed processing a
/// of work and that device should re-raise `trigger_evt` if additional work needs to be done. /// unit of work and that device should re-raise `trigger_evt` if additional work needs to
/// be done.
resample_evt: Event, resample_evt: Event,
} }

View file

@ -82,8 +82,9 @@ pub struct Apic {
/// Base duration for the APIC timer. A timer set with initial count = 1 and timer frequency /// Base duration for the APIC timer. A timer set with initial count = 1 and timer frequency
/// divide = 1 runs for this long. /// divide = 1 runs for this long.
cycle_length: Duration, cycle_length: Duration,
// Register state bytes. Each register is 16-byte aligned, but only its first 4 bytes are used. // Register state bytes. Each register is 16-byte aligned, but only its first 4 bytes are
// The register MMIO space is 4 KiB, but only the first 1 KiB (64 registers * 16 bytes) is used. // used. The register MMIO space is 4 KiB, but only the first 1 KiB (64 registers * 16
// bytes) is used.
regs: [u8; APIC_MEM_LENGTH_BYTES as usize], regs: [u8; APIC_MEM_LENGTH_BYTES as usize],
// Multiprocessing initialization state: running, waiting for SIPI, etc. // Multiprocessing initialization state: running, waiting for SIPI, etc.
mp_state: MPState, mp_state: MPState,
@ -96,14 +97,15 @@ pub struct Apic {
// When the timer started or last ticked. For one-shot timers, this is the Instant when the // When the timer started or last ticked. For one-shot timers, this is the Instant when the
// timer started. For periodic timers, it's the Instant when it started or last expired. // timer started. For periodic timers, it's the Instant when it started or last expired.
last_tick: Instant, last_tick: Instant,
// Pending startup interrupt vector. There can only be one pending startup interrupt at a time. // Pending startup interrupt vector. There can only be one pending startup interrupt at a
// time.
sipi: Option<Vector>, sipi: Option<Vector>,
// True if there's a pending INIT interrupt to send to the CPU. // True if there's a pending INIT interrupt to send to the CPU.
init: bool, init: bool,
// The number of pending non-maskable interrupts to be injected into the CPU. The architecture // The number of pending non-maskable interrupts to be injected into the CPU. The architecture
// specifies that multiple NMIs can be sent concurrently and will be processed in order. Unlike // specifies that multiple NMIs can be sent concurrently and will be processed in order.
// fixed interrupts there's no architecturally defined place where the NMIs are queued or // Unlike fixed interrupts there's no architecturally defined place where the NMIs are
// stored, we need to store them separately. // queued or stored, we need to store them separately.
nmis: u32, nmis: u32,
} }
@ -728,11 +730,11 @@ pub struct InterruptDestination {
/// The APIC ID that sent this interrupt. /// The APIC ID that sent this interrupt.
pub source_id: u8, pub source_id: u8,
/// In physical destination mode, used to specify the APIC ID of the destination processor. /// In physical destination mode, used to specify the APIC ID of the destination processor.
/// In logical destination mode, used to specify a message destination address (MDA) that can be /// In logical destination mode, used to specify a message destination address (MDA) that can
/// used to select specific processors in clusters. Only used if shorthand is None. /// be used to select specific processors in clusters. Only used if shorthand is None.
pub dest_id: u8, pub dest_id: u8,
/// Specifies a quick destination of all processors, all excluding self, or self. If None, then /// Specifies a quick destination of all processors, all excluding self, or self. If None,
/// dest_id and mode are used to find the destinations. /// then dest_id and mode are used to find the destinations.
pub shorthand: DestinationShorthand, pub shorthand: DestinationShorthand,
/// Specifies if physical or logical addressing is used for matching dest_id. /// Specifies if physical or logical addressing is used for matching dest_id.
pub mode: DestinationMode, pub mode: DestinationMode,
@ -747,7 +749,8 @@ pub struct InterruptData {
pub delivery: DeliveryMode, pub delivery: DeliveryMode,
/// Edge- or level-triggered. /// Edge- or level-triggered.
pub trigger: TriggerMode, pub trigger: TriggerMode,
/// For level-triggered interrupts, specifies whether the line should be asserted or deasserted. /// For level-triggered interrupts, specifies whether the line should be asserted or
/// deasserted.
pub level: Level, pub level: Level,
} }
@ -883,14 +886,14 @@ impl Reg {
#[repr(usize)] #[repr(usize)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum VectorReg { enum VectorReg {
/// In-service register. A bit is set for each interrupt vector currently being serviced by the /// In-service register. A bit is set for each interrupt vector currently being serviced by
/// processor. /// the processor.
Isr = Reg::ISR, Isr = Reg::ISR,
/// Trigger mode register. Records whether interrupts are edge-triggered (bit is clear) or /// Trigger mode register. Records whether interrupts are edge-triggered (bit is clear) or
/// level-triggered (bit is set). /// level-triggered (bit is set).
Tmr = Reg::TMR, Tmr = Reg::TMR,
/// Interrupt request register. A bit is set for each interrupt vector received by the APIC but /// Interrupt request register. A bit is set for each interrupt vector received by the APIC
/// not yet serviced by the processor. /// but not yet serviced by the processor.
Irr = Reg::IRR, Irr = Reg::IRR,
} }
@ -1439,7 +1442,7 @@ mod tests {
level: Level::Assert, level: Level::Assert,
}); });
// Non-fixed irqs should be injected even if vcpu_ready is false. */ // Non-fixed irqs should be injected even if vcpu_ready is false. */
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ false); let irqs = a.get_pending_irqs(/* vcpu_ready= */ false);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1460,7 +1463,7 @@ mod tests {
trigger: TriggerMode::Edge, trigger: TriggerMode::Edge,
level: Level::Assert, level: Level::Assert,
}); });
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1470,7 +1473,7 @@ mod tests {
); );
assert_eq!(a.nmis, 0); assert_eq!(a.nmis, 0);
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1491,7 +1494,7 @@ mod tests {
trigger: TriggerMode::Level, trigger: TriggerMode::Level,
level: Level::Assert, level: Level::Assert,
}); });
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ false); let irqs = a.get_pending_irqs(/* vcpu_ready= */ false);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1502,7 +1505,7 @@ mod tests {
); );
assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x10)); assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x10));
assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), None); assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), None);
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1527,7 +1530,7 @@ mod tests {
trigger: TriggerMode::Level, trigger: TriggerMode::Level,
level: Level::Assert, level: Level::Assert,
}); });
let _ = a.get_pending_irqs(/*vcpu_ready=*/ true); let _ = a.get_pending_irqs(/* vcpu_ready= */ true);
// An interrupt in a higher priority class should be injected immediately if the window is // An interrupt in a higher priority class should be injected immediately if the window is
// open. // open.
@ -1537,7 +1540,7 @@ mod tests {
trigger: TriggerMode::Level, trigger: TriggerMode::Level,
level: Level::Assert, level: Level::Assert,
}); });
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ false); let irqs = a.get_pending_irqs(/* vcpu_ready= */ false);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1548,7 +1551,7 @@ mod tests {
); );
assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x20)); assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x20));
assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(0x10)); assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(0x10));
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1573,7 +1576,7 @@ mod tests {
trigger: TriggerMode::Level, trigger: TriggerMode::Level,
level: Level::Assert, level: Level::Assert,
}); });
let _ = a.get_pending_irqs(/*vcpu_ready=*/ true); let _ = a.get_pending_irqs(/* vcpu_ready= */ true);
// An interrupt in the same or lower priority class should be deferred. // An interrupt in the same or lower priority class should be deferred.
a.accept_irq(&InterruptData { a.accept_irq(&InterruptData {
@ -1582,12 +1585,13 @@ mod tests {
trigger: TriggerMode::Level, trigger: TriggerMode::Level,
level: Level::Assert, level: Level::Assert,
}); });
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
fixed: None, fixed: None,
needs_window: false, // Not injectable due to higher priority ISRV, so no window needed. // Not injectable due to higher priority ISRV, so no window needed.
needs_window: false,
..Default::default() ..Default::default()
} }
); );
@ -1597,7 +1601,7 @@ mod tests {
// EOI lets it be injected. // EOI lets it be injected.
let msg = a.write(Reg::EOI as u64, &[0; 4]).unwrap(); let msg = a.write(Reg::EOI as u64, &[0; 4]).unwrap();
assert_eq!(msg, ApicBusMsg::Eoi(0x10)); assert_eq!(msg, ApicBusMsg::Eoi(0x10));
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1621,7 +1625,7 @@ mod tests {
level: Level::Assert, level: Level::Assert,
}); });
a.set_reg(Reg::TPR, 0x20); a.set_reg(Reg::TPR, 0x20);
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {
@ -1631,7 +1635,7 @@ mod tests {
} }
); );
a.set_reg(Reg::TPR, 0x19); a.set_reg(Reg::TPR, 0x19);
let irqs = a.get_pending_irqs(/*vcpu_ready=*/ true); let irqs = a.get_pending_irqs(/* vcpu_ready= */ true);
assert_eq!( assert_eq!(
irqs, irqs,
PendingInterrupts { PendingInterrupts {

View file

@ -214,8 +214,8 @@ impl IrqChip for GeniezoneKernelIrqChip {
/// Return a vector of all registered irq numbers and their associated events and event /// Return a vector of all registered irq numbers and their associated events and event
/// indices. These should be used by the main thread to wait for irq events. /// indices. These should be used by the main thread to wait for irq events.
/// For the GeniezoneKernelIrqChip, the kernel handles listening to irq events being triggered by /// For the GeniezoneKernelIrqChip, the kernel handles listening to irq events being triggered
/// devices, so this function always returns an empty Vec. /// by devices, so this function always returns an empty Vec.
fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> { fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> {
Ok(Vec::new()) Ok(Vec::new())
} }

View file

@ -96,10 +96,10 @@ struct OutEventSnapshot {
} }
/// Snapshot of [Ioapic] state. Some fields were intentionally excluded: /// Snapshot of [Ioapic] state. Some fields were intentionally excluded:
/// * [Ioapic::resample_events]: these will get re-registered when the VM is /// * [Ioapic::resample_events]: these will get re-registered when the VM is created (e.g. prior to
/// created (e.g. prior to restoring a snapshot). /// restoring a snapshot).
/// * [Ioapic::out_events]: this isn't serializable as it contains Events. /// * [Ioapic::out_events]: this isn't serializable as it contains Events. Replaced by
/// Replaced by [IoapicSnapshot::out_event_snapshots]. /// [IoapicSnapshot::out_event_snapshots].
/// * [Ioapic::irq_tube]: will be set up as part of creating the VM. /// * [Ioapic::irq_tube]: will be set up as part of creating the VM.
/// ///
/// See [Ioapic] for descriptions of fields by the same names. /// See [Ioapic] for descriptions of fields by the same names.
@ -131,8 +131,8 @@ pub struct Ioapic {
ioregsel: u8, ioregsel: u8,
/// ioapicid register. Bits 24 - 27 contain the APIC ID for this device. /// ioapicid register. Bits 24 - 27 contain the APIC ID for this device.
ioapicid: u32, ioapicid: u32,
/// Remote IRR for Edge Triggered Real Time Clock interrupts, which allows the CMOS to know when /// Remote IRR for Edge Triggered Real Time Clock interrupts, which allows the CMOS to know
/// one of its interrupts is being coalesced. /// when one of its interrupts is being coalesced.
rtc_remote_irr: bool, rtc_remote_irr: bool,
/// Outgoing irq events that are used to inject MSI interrupts. /// Outgoing irq events that are used to inject MSI interrupts.
/// Also contains the serializable form used for snapshotting. /// Also contains the serializable form used for snapshotting.

View file

@ -170,8 +170,8 @@ impl AiaDescriptor {
addr: raw_aplic_addr as u64, addr: raw_aplic_addr as u64,
flags: 0, flags: 0,
}; };
// Safe because we allocated the struct that's being passed in, and raw_aplic_addr is pointing // Safe because we allocated the struct that's being passed in, and raw_aplic_addr is
// to a uniquely owned local, mutable variable. // pointing to a uniquely owned local, mutable variable.
let ret = unsafe { ioctl_with_ref(self, KVM_SET_DEVICE_ATTR(), &kvm_attr) }; let ret = unsafe { ioctl_with_ref(self, KVM_SET_DEVICE_ATTR(), &kvm_attr) };
if ret != 0 { if ret != 0 {
return errno_result(); return errno_result();

View file

@ -611,8 +611,8 @@ impl IrqChip for KvmSplitIrqChip {
vcpu.interrupt(vector)?; vcpu.interrupt(vector)?;
} }
// The second interrupt request should be handled immediately, so ask vCPU to exit as soon as // The second interrupt request should be handled immediately, so ask vCPU to exit as soon
// possible. // as possible.
if self.interrupt_requested(vcpu_id) { if self.interrupt_requested(vcpu_id) {
vcpu.set_interrupt_window_requested(true); vcpu.set_interrupt_window_requested(true);
} }

View file

@ -161,7 +161,8 @@ pub trait IrqChip: Send {
/// Add a vcpu to the irq chip. /// Add a vcpu to the irq chip.
fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>; fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>;
/// Register an event with edge-trigger semantic that can trigger an interrupt for a particular GSI. /// Register an event with edge-trigger semantic that can trigger an interrupt for a particular
/// GSI.
fn register_edge_irq_event( fn register_edge_irq_event(
&mut self, &mut self,
irq: u32, irq: u32,
@ -172,7 +173,8 @@ pub trait IrqChip: Send {
/// Unregister an event with edge-trigger semantic for a particular GSI. /// Unregister an event with edge-trigger semantic for a particular GSI.
fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>; fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>;
/// Register an event with level-trigger semantic that can trigger an interrupt for a particular GSI. /// Register an event with level-trigger semantic that can trigger an interrupt for a particular
/// GSI.
fn register_level_irq_event( fn register_level_irq_event(
&mut self, &mut self,
irq: u32, irq: u32,

View file

@ -801,7 +801,7 @@ mod tests {
icw_init_both(&mut data.pic); icw_init_both(&mut data.pic);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 12, /*level=*/ true); data.pic.service_irq(/* irq= */ 12, /* level= */ true);
// Check that IRQ is requesting acknowledgment. // Check that IRQ is requesting acknowledgment.
assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, (1 << 4)); assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, (1 << 4));
@ -830,12 +830,12 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 12, /*level=*/ true); data.pic.service_irq(/* irq= */ 12, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4)); assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
// Request higher-priority IRQ on secondary. // Request higher-priority IRQ on secondary.
data.pic.service_irq(/*irq=*/ 8, /*level=*/ true); data.pic.service_irq(/* irq= */ 8, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 0)); assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 0));
// Check that IRQ is ack'd and EOI is automatically done. // Check that IRQ is ack'd and EOI is automatically done.
@ -859,10 +859,10 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, 0x01); icw_init_both_with_icw4(&mut data.pic, 0x01);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 12, /*level=*/ true); data.pic.service_irq(/* irq= */ 12, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4)); assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
data.pic.service_irq(/*irq=*/ 8, /*level=*/ true); data.pic.service_irq(/* irq= */ 8, /* level= */ true);
// Primary cannot get any IRQ, so this should not provide any interrupt. // Primary cannot get any IRQ, so this should not provide any interrupt.
assert_eq!(data.pic.get_external_interrupt(), None); assert_eq!(data.pic.get_external_interrupt(), None);
@ -899,7 +899,7 @@ mod tests {
// OCW2: Mask IRQ line 6 on secondary (IRQ 14). // OCW2: Mask IRQ line 6 on secondary (IRQ 14).
data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x40]); data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x40]);
data.pic.service_irq(/*irq=*/ 14, /*level=*/ true); data.pic.service_irq(/* irq= */ 14, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), None); assert_eq!(data.pic.get_external_interrupt(), None);
assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 6); assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 6);
@ -932,9 +932,9 @@ mod tests {
data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0xff]); data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0xff]);
data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0xff]); data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0xff]);
data.pic.service_irq(/*irq=*/ 14, /*level=*/ true); data.pic.service_irq(/* irq= */ 14, /* level= */ true);
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
data.pic.service_irq(/*irq=*/ 12, /*level=*/ true); data.pic.service_irq(/* irq= */ 12, /* level= */ true);
// Primary cannot get any IRQs since they're all masked. // Primary cannot get any IRQs since they're all masked.
assert_eq!(data.pic.get_external_interrupt(), None); assert_eq!(data.pic.get_external_interrupt(), None);
@ -968,8 +968,8 @@ mod tests {
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
// Poplate some data on irr/isr. IRQ4 will be in isr and IRQ5 in irr. // Poplate some data on irr/isr. IRQ4 will be in isr and IRQ5 in irr.
data.pic.service_irq(/*irq=*/ 5, /*level=*/ true); data.pic.service_irq(/* irq= */ 5, /* level= */ true);
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
// Read primary IRR. // Read primary IRR.
@ -1010,7 +1010,7 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 2, /*level=*/ true); data.pic.service_irq(/* irq= */ 2, /* level= */ true);
// 0x70 is secondary IRQ base, 7 is for a spurious IRQ. // 0x70 is secondary IRQ base, 7 is for a spurious IRQ.
assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 7)); assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 7));
} }
@ -1022,11 +1022,11 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
// get_external_interrupt clears the irr so it is possible to request the same IRQ again. // get_external_interrupt clears the irr so it is possible to request the same IRQ again.
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
// In edge triggered mode, there should be no IRQ after this EOI. // In edge triggered mode, there should be no IRQ after this EOI.
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
@ -1044,11 +1044,11 @@ mod tests {
data.pic.write(pic_bus_address(PIC_PRIMARY_ELCR), &[0x10]); data.pic.write(pic_bus_address(PIC_PRIMARY_ELCR), &[0x10]);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
// get_external_interrupt clears the irr so it is possible to request the same IRQ again. // get_external_interrupt clears the irr so it is possible to request the same IRQ again.
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
// In level-triggered mode, there should be another IRQ request after this EOI. // In level-triggered mode, there should be another IRQ request after this EOI.
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
@ -1063,7 +1063,7 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true); data.pic.service_irq(/* irq= */ 4, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
// Specific EOI command on IRQ3. Primary PIC's ISR should be unaffected since it's targeted // Specific EOI command on IRQ3. Primary PIC's ISR should be unaffected since it's targeted
@ -1089,9 +1089,9 @@ mod tests {
.write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x00]); .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x00]);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 5, /*level=*/ true); data.pic.service_irq(/* irq= */ 5, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
data.pic.service_irq(/*irq=*/ 5, /*level=*/ false); data.pic.service_irq(/* irq= */ 5, /* level= */ false);
// EOI automatically happened. Now priority should not be rotated. // EOI automatically happened. Now priority should not be rotated.
assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0); assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
@ -1104,9 +1104,9 @@ mod tests {
.write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x80]); .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x80]);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 5, /*level*/ true); data.pic.service_irq(/* irq= */ 5, /* level */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
data.pic.service_irq(/*irq=*/ 5, /*level=*/ false); data.pic.service_irq(/* irq= */ 5, /* level= */ false);
// EOI automatically happened, and the priority *should* be rotated. // EOI automatically happened, and the priority *should* be rotated.
assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0); assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
@ -1120,9 +1120,9 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 5, /*level=*/ true); data.pic.service_irq(/* irq= */ 5, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
data.pic.service_irq(/*irq=*/ 5, /*level=*/ false); data.pic.service_irq(/* irq= */ 5, /* level= */ false);
// Rotate on specific EOI IRQ4. Since this is a different IRQ number, Should not have an // Rotate on specific EOI IRQ4. Since this is a different IRQ number, Should not have an
// effect on isr. // effect on isr.
@ -1146,9 +1146,9 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 5, /*level=*/ true); data.pic.service_irq(/* irq= */ 5, /* level= */ true);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5)); assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
data.pic.service_irq(/*irq=*/ 5, /*level=*/ false); data.pic.service_irq(/* irq= */ 5, /* level= */ false);
// Rotate on non-specific EOI. // Rotate on non-specific EOI.
data.pic data.pic
@ -1166,7 +1166,7 @@ mod tests {
icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI); icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
// TODO(mutexlox): Verify APIC interaction when it is implemented. // TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 12, /*level=*/ true); data.pic.service_irq(/* irq= */ 12, /* level= */ true);
assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 1 << 2); assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 1 << 2);
assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 4); assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 4);

View file

@ -673,7 +673,7 @@ impl<V: VcpuX86_64 + 'static> IrqChip for UserspaceIrqChip<V> {
/// `wait_until_runnable` calls go back to waiting for runnability normally. /// `wait_until_runnable` calls go back to waiting for runnability normally.
fn kick_halted_vcpus(&self) { fn kick_halted_vcpus(&self) {
for waiter in self.waiters.iter() { for waiter in self.waiters.iter() {
waiter.set_and_notify(/*interrupted=*/ true); waiter.set_and_notify(/* interrupted= */ true);
} }
} }

View file

@ -389,8 +389,8 @@ impl IrqChip for WhpxSplitIrqChip {
vcpu.interrupt(vector as u32)?; vcpu.interrupt(vector as u32)?;
} }
// The second interrupt request should be handled immediately, so ask vCPU to exit as soon as // The second interrupt request should be handled immediately, so ask vCPU to exit as soon
// possible. // as possible.
if self.interrupt_requested(vcpu_id) { if self.interrupt_requested(vcpu_id) {
vcpu.set_interrupt_window_requested(true); vcpu.set_interrupt_window_requested(true);
} }

View file

@ -395,8 +395,8 @@ pub trait PciDevice: Send + Suspendable {
Ok(()) Ok(())
} }
/// Gets a reference to the API client for sending VmMemoryRequest. Any devices that uses ioevents /// Gets a reference to the API client for sending VmMemoryRequest. Any devices that uses
/// must provide this. /// ioevents must provide this.
fn get_vm_memory_client(&self) -> Option<&VmMemoryClient> { fn get_vm_memory_client(&self) -> Option<&VmMemoryClient> {
None None
} }

View file

@ -684,12 +684,12 @@ impl PitCounter {
speaker.set_output(self.get_output().into()); speaker.set_output(self.get_output().into());
speaker.set_iochk_nmi(0); speaker.set_iochk_nmi(0);
speaker.set_serr_nmi(0); speaker.set_serr_nmi(0);
speaker.get(/*offset=*/ 0, /*width=*/ 8) as u8 speaker.get(/* offset= */ 0, /* width= */ 8) as u8
} }
fn write_speaker(&mut self, datum: u8) { fn write_speaker(&mut self, datum: u8) {
let mut speaker = SpeakerPortFields::new(); let mut speaker = SpeakerPortFields::new();
speaker.set(/*offset=*/ 0, /*width=*/ 8, datum.into()); speaker.set(/* offset= */ 0, /* width= */ 8, datum.into());
let new_gate = speaker.get_gate() != 0; let new_gate = speaker.get_gate() != 0;
match self.get_command_mode() { match self.get_command_mode() {
Some(CommandMode::CommandInterrupt) | Some(CommandMode::CommandSWStrobe) => (), Some(CommandMode::CommandInterrupt) | Some(CommandMode::CommandSWStrobe) => (),

View file

@ -282,7 +282,8 @@ impl VfioPlatformDevice {
let host = mmap.as_ptr() as u64; let host = mmap.as_ptr() as u64;
// SAFETY: // SAFETY:
// Safe because the given guest_map_start is valid guest bar address. and // Safe because the given guest_map_start is valid guest bar address. and
// the host pointer is correct and valid guaranteed by MemoryMapping interface. // the host pointer is correct and valid guaranteed by MemoryMapping
// interface.
match unsafe { match unsafe {
self.device self.device
.vfio_dma_map(guest_map_start, mmap_size, host, true) .vfio_dma_map(guest_map_start, mmap_size, host, true)

View file

@ -218,9 +218,10 @@ impl Serial {
for event in events.iter() { for event in events.iter() {
match event.token { match event.token {
Token::Kill => { Token::Kill => {
// Ignore the kill event until there are no other events to process so that // Ignore the kill event until there are no other events to process
// we drain `rx` as much as possible. The next `wait_ctx.wait()` call will // so that we drain `rx` as much as possible. The next
// immediately re-entry this case since we don't call `kill_evt.wait()`. // `wait_ctx.wait()` call will immediately re-entry this case since
// we don't call `kill_evt.wait()`.
if events.iter().all(|e| matches!(e.token, Token::Kill)) { if events.iter().all(|e| matches!(e.token, Token::Kill)) {
return rx; return rx;
} }
@ -262,7 +263,8 @@ impl Serial {
} }
} }
Err(e) => { Err(e) => {
// Being interrupted is not an error, but everything else is. // Being interrupted is not an error, but everything else
// is.
if e.kind() != io::ErrorKind::Interrupted { if e.kind() != io::ErrorKind::Interrupted {
error!( error!(
"failed to read for bytes to queue into serial device: {}", "failed to read for bytes to queue into serial device: {}",

View file

@ -175,7 +175,7 @@ impl SerialParameters {
/// # Arguments /// # Arguments
/// * `evt` - event used for interrupt events /// * `evt` - event used for interrupt events
/// * `keep_rds` - Vector of FDs required by this device if it were sandboxed in a child /// * `keep_rds` - Vector of FDs required by this device if it were sandboxed in a child
/// process. `evt` will always be added to this vector by this function. /// process. `evt` will always be added to this vector by this function.
pub fn create_serial_device<T: SerialDevice>( pub fn create_serial_device<T: SerialDevice>(
&self, &self,
protection_type: ProtectionType, protection_type: ProtectionType,

View file

@ -118,8 +118,8 @@ fn tsc_sync_mitigations_inner(
let host_tsc_now = rdtsc(); let host_tsc_now = rdtsc();
for i in 0..num_vcpus { for i in 0..num_vcpus {
// This handles the case where num_vcpus > num_cores, even though we try to avoid that in // This handles the case where num_vcpus > num_cores, even though we try to avoid that
// practice. // in practice.
let pinned_core = i % num_cores; let pinned_core = i % num_cores;
mitigations.affinities[i] = Some(vec![pinned_core]); mitigations.affinities[i] = Some(vec![pinned_core]);

View file

@ -660,8 +660,8 @@ impl BackendDeviceType {
) -> Result<()> { ) -> Result<()> {
let transfer_status = { let transfer_status = {
// We need to hold the lock to avoid race condition. // We need to hold the lock to avoid race condition.
// While we are trying to submit the transfer, another thread might want to cancel the same // While we are trying to submit the transfer, another thread might want to cancel the
// transfer. Holding the lock here makes sure one of them is cancelled. // same transfer. Holding the lock here makes sure one of them is cancelled.
let mut state = xhci_transfer.state().lock(); let mut state = xhci_transfer.state().lock();
match mem::replace(&mut *state, XhciTransferState::Cancelled) { match mem::replace(&mut *state, XhciTransferState::Cancelled) {
XhciTransferState::Created => { XhciTransferState::Created => {

View file

@ -385,7 +385,7 @@ pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
guest_write_1_to_clear_mask: 0,); guest_write_1_to_clear_mask: 0,);
mmio.add_register_array(&doorbells); mmio.add_register_array(&doorbells);
/*Runtime Registers */ /* Runtime Registers */
mmio.add_register( mmio.add_register(
// mfindex // mfindex

View file

@ -172,8 +172,8 @@ impl EventLoop {
.map_err(Error::WaitContextAddDescriptor) .map_err(Error::WaitContextAddDescriptor)
} }
/// Removes event for this `descriptor`. This function is safe to call even when the `descriptor` /// Removes event for this `descriptor`. This function is safe to call even when the
/// is not actively being polled because it's been paused. /// `descriptor` is not actively being polled because it's been paused.
/// ///
/// EventLoop does not guarantee all events for `descriptor` is handled. /// EventLoop does not guarantee all events for `descriptor` is handled.
pub fn remove_event_for_descriptor(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> { pub fn remove_event_for_descriptor(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {

View file

@ -757,8 +757,8 @@ impl VfioGroup {
let container_raw_descriptor = container.as_raw_descriptor(); let container_raw_descriptor = container.as_raw_descriptor();
// SAFETY: // SAFETY:
// Safe as we are the owner of group_file and container_raw_descriptor which are valid value, // Safe as we are the owner of group_file and container_raw_descriptor which are valid
// and we verify the ret value // value, and we verify the ret value
ret = unsafe { ret = unsafe {
ioctl_with_ref( ioctl_with_ref(
&group_file, &group_file,
@ -1355,10 +1355,10 @@ impl VfioDevice {
} }
/// Enable vfio device's irq and associate Irqfd Event with device. /// Enable vfio device's irq and associate Irqfd Event with device.
/// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to subindex + /// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to
/// descriptors length will be assigned with irqfd in the descriptors array. /// subindex + descriptors length will be assigned with irqfd in the descriptors array.
/// when index = VFIO_PCI_REQ_IRQ_INDEX, kernel vfio will trigger this event when physical device /// when index = VFIO_PCI_REQ_IRQ_INDEX, kernel vfio will trigger this event when physical
/// is removed. /// device is removed.
/// If descriptor is None, -1 is assigned to the irq. A value of -1 is used to either de-assign /// If descriptor is None, -1 is assigned to the irq. A value of -1 is used to either de-assign
/// interrupts if already assigned or skip un-assigned interrupts. /// interrupts if already assigned or skip un-assigned interrupts.
pub fn irq_enable( pub fn irq_enable(

View file

@ -108,8 +108,8 @@ pub struct DiskOption {
)] )]
pub io_concurrency: NonZeroU32, pub io_concurrency: NonZeroU32,
#[serde(default)] #[serde(default)]
/// Experimental option to run multiple worker threads in parallel. If false, only single thread /// Experimental option to run multiple worker threads in parallel. If false, only single
/// runs by default. Note this option is not effective for vhost-user blk device. /// thread runs by default. Note this option is not effective for vhost-user blk device.
pub multiple_workers: bool, pub multiple_workers: bool,
#[serde(default, alias = "async_executor")] #[serde(default, alias = "async_executor")]
/// The async executor kind to simulate the block device with. This option takes /// The async executor kind to simulate the block device with. This option takes

View file

@ -436,9 +436,9 @@ impl VirtioDevice for Console {
match queues_state { match queues_state {
None => Ok(()), None => Ok(()),
Some((mem, interrupt, queues)) => { Some((mem, interrupt, queues)) => {
// TODO(khei): activate is just what we want at the moment, but we should probably move // TODO(khei): activate is just what we want at the moment, but we should probably
// it into a "start workers" function to make it obvious that it isn't strictly // move it into a "start workers" function to make it obvious that
// used for activate events. // it isn't strictly used for activate events.
self.activate(mem, interrupt, queues)?; self.activate(mem, interrupt, queues)?;
Ok(()) Ok(())
} }

View file

@ -22,15 +22,15 @@ pub enum CachePolicy {
/// the FUSE client (i.e., the file system does not have exclusive access to the directory). /// the FUSE client (i.e., the file system does not have exclusive access to the directory).
Never, Never,
/// The client is free to choose when and how to cache file data. This is the default policy and /// The client is free to choose when and how to cache file data. This is the default policy
/// uses close-to-open consistency as described in the enum documentation. /// and uses close-to-open consistency as described in the enum documentation.
#[default] #[default]
Auto, Auto,
/// The client should always cache file data. This means that the FUSE client will not /// The client should always cache file data. This means that the FUSE client will not
/// invalidate any cached data that was returned by the file system the last time the file was /// invalidate any cached data that was returned by the file system the last time the file was
/// opened. This policy should only be selected when the file system has exclusive access to the /// opened. This policy should only be selected when the file system has exclusive access to
/// directory. /// the directory.
Always, Always,
} }
@ -108,17 +108,17 @@ pub struct Config {
#[serde(default, alias = "cache")] #[serde(default, alias = "cache")]
pub cache_policy: CachePolicy, pub cache_policy: CachePolicy,
/// Whether the file system should enabled writeback caching. This can improve performance as it /// Whether the file system should enabled writeback caching. This can improve performance as
/// allows the FUSE client to cache and coalesce multiple writes before sending them to the file /// it allows the FUSE client to cache and coalesce multiple writes before sending them to
/// system. However, enabling this option can increase the risk of data corruption if the file /// the file system. However, enabling this option can increase the risk of data corruption
/// contents can change without the knowledge of the FUSE client (i.e., the server does **NOT** /// if the file contents can change without the knowledge of the FUSE client (i.e., the
/// have exclusive access). Additionally, the file system should have read access to all files /// server does **NOT** have exclusive access). Additionally, the file system should have
/// in the directory it is serving as the FUSE client may send read requests even for files /// read access to all files in the directory it is serving as the FUSE client may send
/// opened with `O_WRONLY`. /// read requests even for files opened with `O_WRONLY`.
/// ///
/// Therefore callers should only enable this option when they can guarantee that: 1) the file /// Therefore callers should only enable this option when they can guarantee that: 1) the file
/// system has exclusive access to the directory and 2) the file system has read permissions for /// system has exclusive access to the directory and 2) the file system has read permissions
/// all files in that directory. /// for all files in that directory.
/// ///
/// The default value for this option is `false`. /// The default value for this option is `false`.
#[serde(default)] #[serde(default)]
@ -127,8 +127,8 @@ pub struct Config {
/// Controls whether security.* xattrs (except for security.selinux) are re-written. When this /// Controls whether security.* xattrs (except for security.selinux) are re-written. When this
/// is set to true, the server will add a "user.virtiofs" prefix to xattrs in the security /// is set to true, the server will add a "user.virtiofs" prefix to xattrs in the security
/// namespace. Setting these xattrs requires CAP_SYS_ADMIN in the namespace where the file /// namespace. Setting these xattrs requires CAP_SYS_ADMIN in the namespace where the file
/// system was mounted and since the server usually runs in an unprivileged user namespace, it's /// system was mounted and since the server usually runs in an unprivileged user namespace,
/// unlikely to have that capability. /// it's unlikely to have that capability.
/// ///
/// The default value for this option is `false`. /// The default value for this option is `false`.
#[serde(default, alias = "rewrite-security-xattrs")] #[serde(default, alias = "rewrite-security-xattrs")]
@ -140,21 +140,21 @@ pub struct Config {
#[serde(default)] #[serde(default)]
pub ascii_casefold: bool, pub ascii_casefold: bool,
// UIDs which are privileged to perform quota-related operations. We cannot perform a CAP_FOWNER // UIDs which are privileged to perform quota-related operations. We cannot perform a
// check so we consult this list when the VM tries to set the project quota and the process uid // CAP_FOWNER check so we consult this list when the VM tries to set the project quota and
// doesn't match the owner uid. In that case, all uids in this list are treated as if they have // the process uid doesn't match the owner uid. In that case, all uids in this list are
// CAP_FOWNER. // treated as if they have CAP_FOWNER.
#[cfg(feature = "arc_quota")] #[cfg(feature = "arc_quota")]
#[serde(default, deserialize_with = "deserialize_privileged_quota_uids")] #[serde(default, deserialize_with = "deserialize_privileged_quota_uids")]
pub privileged_quota_uids: Vec<libc::uid_t>, pub privileged_quota_uids: Vec<libc::uid_t>,
/// Use DAX for shared files. /// Use DAX for shared files.
/// ///
/// Enabling DAX can improve performance for frequently accessed files by mapping regions of the /// Enabling DAX can improve performance for frequently accessed files by mapping regions of
/// file directly into the VM's memory region, allowing direct access with the cost of slightly /// the file directly into the VM's memory region, allowing direct access with the cost of
/// increased latency the first time the file is accessed. Additionally, since the mapping is /// slightly increased latency the first time the file is accessed. Additionally, since the
/// shared directly from the host kernel's file cache, enabling DAX can improve performance even /// mapping is shared directly from the host kernel's file cache, enabling DAX can improve
/// when the cache policy is `Never`. /// performance even when the cache policy is `Never`.
/// ///
/// The default value for this option is `false`. /// The default value for this option is `false`.
#[serde(default, alias = "dax")] #[serde(default, alias = "dax")]

View file

@ -162,10 +162,10 @@ ioctl_iowr_nr!(FS_IOC_GET_ENCRYPTION_POLICY_EX, 'f' as u32, 22, [u8; 9]);
#[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)] #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)]
struct fsxattr { struct fsxattr {
fsx_xflags: u32, /* xflags field value (get/set) */ fsx_xflags: u32, /* xflags field value (get/set) */
fsx_extsize: u32, /* extsize field value (get/set)*/ fsx_extsize: u32, /* extsize field value (get/set) */
fsx_nextents: u32, /* nextents field value (get) */ fsx_nextents: u32, /* nextents field value (get) */
fsx_projid: u32, /* project identifier (get/set) */ fsx_projid: u32, /* project identifier (get/set) */
fsx_cowextsize: u32, /* CoW extsize field value (get/set)*/ fsx_cowextsize: u32, /* CoW extsize field value (get/set) */
fsx_pad: [u8; 8], fsx_pad: [u8; 8],
} }
@ -1506,9 +1506,10 @@ impl PassthroughFs {
let data = self.find_handle(handle, inode)?; let data = self.find_handle(handle, inode)?;
{ {
// We can't enable verity while holding a writable fd. We don't know whether the file // We can't enable verity while holding a writable fd. We don't know whether the
// was opened for writing so check it here. We don't expect this to be a frequent // file was opened for writing so check it here. We don't expect
// operation so the extra latency should be fine. // this to be a frequent operation so the extra latency should be
// fine.
let mut file = data.file.lock(); let mut file = data.file.lock();
let flags = FileFlags::from_file(&*file).map_err(io::Error::from)?; let flags = FileFlags::from_file(&*file).map_err(io::Error::from)?;
match flags { match flags {
@ -3712,7 +3713,8 @@ mod tests {
); );
} }
// atomic_open with flag O_RDWR | O_CREATE | O_EXCL, should return positive dentry and file handler // atomic_open with flag O_RDWR | O_CREATE | O_EXCL, should return positive dentry and file
// handler
let res = atomic_open( let res = atomic_open(
&fs, &fs,
&temp_dir.path().join("dir/c.txt"), &temp_dir.path().join("dir/c.txt"),

View file

@ -1182,9 +1182,9 @@ pub struct Gpu {
udmabuf: bool, udmabuf: bool,
rutabaga_server_descriptor: Option<SafeDescriptor>, rutabaga_server_descriptor: Option<SafeDescriptor>,
#[cfg(windows)] #[cfg(windows)]
/// Because the Windows GpuDisplay can't expose an epollfd, it has to inform the GPU worker which /// Because the Windows GpuDisplay can't expose an epollfd, it has to inform the GPU worker
/// descriptors to add to its wait context. That's what this Tube is used for (it is provided /// which descriptors to add to its wait context. That's what this Tube is used for (it is
/// to each display backend. /// provided to each display backend.
gpu_display_wait_descriptor_ctrl_wr: SendTube, gpu_display_wait_descriptor_ctrl_wr: SendTube,
#[cfg(windows)] #[cfg(windows)]
/// The GPU worker uses this Tube to receive the descriptors that should be added to its wait /// The GPU worker uses this Tube to receive the descriptors that should be added to its wait

View file

@ -548,7 +548,8 @@ impl VirtioGpu {
&self.display &self.display
} }
/// Gets the list of supported display resolutions as a slice of `(width, height, enabled)` tuples. /// Gets the list of supported display resolutions as a slice of `(width, height, enabled)`
/// tuples.
pub fn display_info(&self) -> Vec<(u32, u32, bool)> { pub fn display_info(&self) -> Vec<(u32, u32, bool)> {
(0..VIRTIO_GPU_MAX_SCANOUTS) (0..VIRTIO_GPU_MAX_SCANOUTS)
.map(|scanout_id| scanout_id as u32) .map(|scanout_id| scanout_id as u32)

View file

@ -64,7 +64,8 @@ pub fn new_keyboard_config(idx: u32) -> VirtioInputConfig {
) )
} }
/// Instantiates a VirtioInputConfig object with the default configuration for a collection of switches. /// Instantiates a VirtioInputConfig object with the default configuration for a collection of
/// switches.
pub fn new_switches_config(idx: u32) -> VirtioInputConfig { pub fn new_switches_config(idx: u32) -> VirtioInputConfig {
VirtioInputConfig::new( VirtioInputConfig::new(
virtio_input_device_ids::new(0, 0, 0, 0), virtio_input_device_ids::new(0, 0, 0, 0),
@ -76,7 +77,8 @@ pub fn new_switches_config(idx: u32) -> VirtioInputConfig {
) )
} }
/// Instantiates a VirtioInputConfig object with the default configuration for a collection of rotary. /// Instantiates a VirtioInputConfig object with the default configuration for a collection of
/// rotary.
pub fn new_rotary_config(idx: u32) -> VirtioInputConfig { pub fn new_rotary_config(idx: u32) -> VirtioInputConfig {
VirtioInputConfig::new( VirtioInputConfig::new(
virtio_input_device_ids::new(0, 0, 0, 0), virtio_input_device_ids::new(0, 0, 0, 0),

View file

@ -238,8 +238,8 @@ pub fn abs_info<T: AsRawDescriptor>(descriptor: &T) -> BTreeMap<u16, virtio_inpu
} }
/// Grabs an event device (see EVIOCGGRAB ioctl for details). After this function succeeds the given /// Grabs an event device (see EVIOCGGRAB ioctl for details). After this function succeeds the given
/// descriptor has exclusive access to the device, effectively making it unusable for any other process in /// descriptor has exclusive access to the device, effectively making it unusable for any other
/// the host. /// process in the host.
pub fn grab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> { pub fn grab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
let val: u32 = 1; let val: u32 = 1;
let ret = { let ret = {

View file

@ -214,9 +214,9 @@ impl virtio_input_bitmap {
if byte_pos < ret.len() { if byte_pos < ret.len() {
ret.bitmap[byte_pos] |= bit_byte; ret.bitmap[byte_pos] |= bit_byte;
} else { } else {
// This would only happen if new event codes (or types, or ABS_*, etc) are defined to be // This would only happen if new event codes (or types, or ABS_*, etc) are defined
// larger than or equal to 1024, in which case a new version of the virtio input // to be larger than or equal to 1024, in which case a new version
// protocol needs to be defined. // of the virtio input protocol needs to be defined.
// There is nothing we can do about this error except log it. // There is nothing we can do about this error except log it.
error!("Attempted to set an out of bounds bit: {}", idx); error!("Attempted to set an out of bounds bit: {}", idx);
} }

View file

@ -411,7 +411,8 @@ impl State {
let vfio_map_result = match dmabuf_map { let vfio_map_result = match dmabuf_map {
// SAFETY: // SAFETY:
// Safe because [dmabuf_map, dmabuf_map + size) refers to an external mmap'ed region. // Safe because [dmabuf_map, dmabuf_map + size) refers to an external mmap'ed
// region.
Some(dmabuf_map) => unsafe { Some(dmabuf_map) => unsafe {
mapper mapper
.1 .1

View file

@ -169,9 +169,8 @@ pub struct CreateIpcMapperRet {
/// # Arguments /// # Arguments
/// ///
/// * `endpoint_id` - For the remote iommu to identify the device/ipc mapper. /// * `endpoint_id` - For the remote iommu to identify the device/ipc mapper.
/// * `request_tx` - A tube to send `TranslateRequest` to a remote iommu. This /// * `request_tx` - A tube to send `TranslateRequest` to a remote iommu. This should be cloned and
/// should be cloned and shared between different ipc mappers /// shared between different ipc mappers with different `endpoint_id`s.
/// with different `endpoint_id`s.
pub fn create_ipc_mapper(endpoint_id: u32, request_tx: Tube) -> CreateIpcMapperRet { pub fn create_ipc_mapper(endpoint_id: u32, request_tx: Tube) -> CreateIpcMapperRet {
let (response_tx, response_rx) = Tube::pair().expect("failed to create tube pair"); let (response_tx, response_rx) = Tube::pair().expect("failed to create tube pair");
CreateIpcMapperRet { CreateIpcMapperRet {

View file

@ -155,26 +155,24 @@ pub enum AddMapResult {
/// the virtio request that triggered the fault. /// the virtio request that triggered the fault.
/// ///
/// As such, the flow of a fault is: /// As such, the flow of a fault is:
/// 1) The guest sends an virtio-iommu message that triggers a fault. Faults can /// 1) The guest sends an virtio-iommu message that triggers a fault. Faults can be triggered by
/// be triggered by unmap or detach messages, or by attach messages if such /// unmap or detach messages, or by attach messages if such messages are re-attaching an
/// messages are re-attaching an endpoint to a new domain. One example of /// endpoint to a new domain. One example of a guest event that can trigger such a message is a
/// a guest event that can trigger such a message is a userspace VVU device /// userspace VVU device process crashing and triggering the guest kernel to re-attach the VVU
/// process crashing and triggering the guest kernel to re-attach the VVU
/// device to the null endpoint. /// device to the null endpoint.
/// 2) The viommu device removes an exported mapping from the mapper. /// 2) The viommu device removes an exported mapping from the mapper.
/// 3) The mapper signals the IOMMU fault eventfd and returns the fault /// 3) The mapper signals the IOMMU fault eventfd and returns the fault resolution event to the
/// resolution event to the viommu device. /// viommu device.
/// 4) The viommu device starts waiting on the fault resolution event. Note that /// 4) The viommu device starts waiting on the fault resolution event. Note that although the
/// although the viommu device and mapper are both running on the same /// viommu device and mapper are both running on the same executor, this wait is async. This
/// executor, this wait is async. This means that although further processing /// means that although further processing of virtio-iommu requests is paused, the mapper
/// of virtio-iommu requests is paused, the mapper continues to run. /// continues to run.
/// 5) The client receives the IOMMU fault. /// 5) The client receives the IOMMU fault.
/// 6) The client releases all exported regions. /// 6) The client releases all exported regions.
/// 7) Once the mapper receives the final release message from the client, /// 7) Once the mapper receives the final release message from the client, it signals the fault
/// it signals the fault resolution event that the viommu device is /// resolution event that the viommu device is waiting on.
/// waiting on. /// 8) The viommu device finishes processing the original virtio iommu request and sends a reply to
/// 8) The viommu device finishes processing the original virtio iommu /// the guest.
/// request and sends a reply to the guest.
pub trait MemoryMapper: Send { pub trait MemoryMapper: Send {
/// Creates a new mapping. If the mapping overlaps with an existing /// Creates a new mapping. If the mapping overlaps with an existing
/// mapping, return Ok(false). /// mapping, return Ok(false).

View file

@ -118,10 +118,10 @@ impl MemoryMapper for VfioWrapper {
fn supports_detach(&self) -> bool { fn supports_detach(&self) -> bool {
// A few reasons why we don't support detach: // A few reasons why we don't support detach:
// //
// 1. Seems it's not possible to dynamically attach and detach a IOMMU domain if the // 1. Seems it's not possible to dynamically attach and detach a IOMMU domain if the virtio
// virtio IOMMU device is running on top of VFIO // IOMMU device is running on top of VFIO
// 2. Even if VIRTIO_IOMMU_T_DETACH is implemented in front-end driver, it could violate // 2. Even if VIRTIO_IOMMU_T_DETACH is implemented in front-end driver, it could violate the
// the following virtio IOMMU spec: Detach an endpoint from a domain. when this request // following virtio IOMMU spec: Detach an endpoint from a domain. when this request
// completes, the endpoint cannot access any mapping from that domain anymore. // completes, the endpoint cannot access any mapping from that domain anymore.
// //
// This is because VFIO doesn't support detaching a single device. When the virtio-iommu // This is because VFIO doesn't support detaching a single device. When the virtio-iommu

View file

@ -452,8 +452,8 @@ impl PvClockWorker {
( (
Self::get_suspended_duration(&suspend_time), Self::get_suspended_duration(&suspend_time),
// SAFETY: // SAFETY:
// Safe because _rdtsc takes no arguments, and we trust _rdtsc to not modify any // Safe because _rdtsc takes no arguments, and we trust _rdtsc to not modify
// other memory. // any other memory.
unsafe { _rdtsc() } - suspend_time.tsc_value, unsafe { _rdtsc() } - suspend_time.tsc_value,
) )
} else { } else {

View file

@ -49,8 +49,8 @@ pub struct QueueConfig {
max_size: u16, max_size: u16,
/// The queue size in elements the driver selected. This is always guaranteed to be a power of /// The queue size in elements the driver selected. This is always guaranteed to be a power of
/// two less than or equal to `max_size`, as required for split virtqueues. These invariants are /// two less than or equal to `max_size`, as required for split virtqueues. These invariants
/// enforced by `set_size()`. /// are enforced by `set_size()`.
size: u16, size: u16,
/// Indicates if the queue is finished with configuration /// Indicates if the queue is finished with configuration
@ -59,7 +59,8 @@ pub struct QueueConfig {
/// MSI-X vector for the queue. Don't care for INTx /// MSI-X vector for the queue. Don't care for INTx
vector: u16, vector: u16,
/// Ring features (e.g. `VIRTIO_RING_F_EVENT_IDX`, `VIRTIO_F_RING_PACKED`) offered by the device /// Ring features (e.g. `VIRTIO_RING_F_EVENT_IDX`, `VIRTIO_F_RING_PACKED`) offered by the
/// device
features: u64, features: u64,
// Device feature bits accepted by the driver // Device feature bits accepted by the driver
@ -267,7 +268,8 @@ impl QueueConfig {
if self.activated { if self.activated {
bail!("queue is already activated"); bail!("queue is already activated");
} }
// If VIRTIO_F_RING_PACKED feature bit is set, create a packed queue, otherwise create a split queue // If VIRTIO_F_RING_PACKED feature bit is set, create a packed queue, otherwise create a
// split queue
let queue: Queue = if ((self.acked_features >> VIRTIO_F_RING_PACKED) & 1) != 0 { let queue: Queue = if ((self.acked_features >> VIRTIO_F_RING_PACKED) & 1) != 0 {
let pq = let pq =
PackedQueue::new(self, mem, event).context("Failed to create a packed queue.")?; PackedQueue::new(self, mem, event).context("Failed to create a packed queue.")?;
@ -335,13 +337,15 @@ impl QueueConfig {
} }
} }
/// Usage: define_queue_method!(method_name, return_type[, mut][, arg1: arg1_type, arg2: arg2_type, ...]) /// Usage: define_queue_method!(method_name, return_type[, mut][, arg1: arg1_type, arg2: arg2_type,
/// ...])
/// ///
/// - `method_name`: The name of the method to be defined (as an identifier). /// - `method_name`: The name of the method to be defined (as an identifier).
/// - `return_type`: The return type of the method. /// - `return_type`: The return type of the method.
/// - `mut` (optional): Include this keyword if the method requires a mutable reference to `self` (`&mut self`). /// - `mut` (optional): Include this keyword if the method requires a mutable reference to `self`
/// - `arg1: arg1_type, arg2: arg2_type, ...` (optional): Include method parameters as a comma-separated list /// (`&mut self`).
/// of `name: type` pairs, if the method takes any arguments. /// - `arg1: arg1_type, arg2: arg2_type, ...` (optional): Include method parameters as a
/// comma-separated list of `name: type` pairs, if the method takes any arguments.
macro_rules! define_queue_method { macro_rules! define_queue_method {
( (
$(#[$doc:meta])* $(#[$doc:meta])*

View file

@ -212,8 +212,8 @@ impl PackedQueue {
/// Set the device event suppression /// Set the device event suppression
/// ///
// This field is used to specify the timing of when the driver notifies the /// This field is used to specify the timing of when the driver notifies the
// device that the descriptor table is ready to be processed. /// device that the descriptor table is ready to be processed.
fn set_avail_event(&mut self, event: PackedDescEvent) { fn set_avail_event(&mut self, event: PackedDescEvent) {
fence(Ordering::SeqCst); fence(Ordering::SeqCst);
self.mem self.mem

View file

@ -345,11 +345,11 @@ impl SplitQueue {
/// (similar to how DC circuits are analyzed). /// (similar to how DC circuits are analyzed).
/// ///
/// The two distances are as follows: /// The two distances are as follows:
/// * `A` is the distance between the driver's requested notification /// * `A` is the distance between the driver's requested notification point, and the current
/// point, and the current position in the ring. /// position in the ring.
/// ///
/// * `B` is the distance between the last time we notified the guest, /// * `B` is the distance between the last time we notified the guest, and the current position
/// and the current position in the ring. /// in the ring.
/// ///
/// If we graph these distances for the situation where we want to notify /// If we graph these distances for the situation where we want to notify
/// the guest, and when we don't want to notify the guest, we see that /// the guest, and when we don't want to notify the guest, we see that
@ -389,15 +389,13 @@ impl SplitQueue {
/// anymore. (Notifications will never be sent.) But why is that? The algebra /// anymore. (Notifications will never be sent.) But why is that? The algebra
/// here *appears* to work out, but all semantic meaning is lost. There are /// here *appears* to work out, but all semantic meaning is lost. There are
/// two explanations for why this happens: /// two explanations for why this happens:
/// * The intuitive one: the terms in the inequality are not actually /// * The intuitive one: the terms in the inequality are not actually separable; in other words,
/// separable; in other words, (next_used - last_used) is an inseparable /// (next_used - last_used) is an inseparable term, so subtracting next_used from both sides
/// term, so subtracting next_used from both sides of the original /// of the original inequality and zeroing them out is semantically invalid. But why aren't
/// inequality and zeroing them out is semantically invalid. But why aren't
/// they separable? See below. /// they separable? See below.
/// * The theoretical one: canceling like terms relies a vector space law: /// * The theoretical one: canceling like terms relies a vector space law: a + x = b + x => a =
/// a + x = b + x => a = b (cancellation law). For congruences / equality /// b (cancellation law). For congruences / equality under modulo, this law is satisfied, but
/// under modulo, this law is satisfied, but for inequalities under mod, it /// for inequalities under mod, it is not; therefore, we cannot cancel like terms.
/// is not; therefore, we cannot cancel like terms.
/// ///
/// ```text /// ```text
/// ┌──────────────────────────────────┐ /// ┌──────────────────────────────────┐

View file

@ -374,7 +374,8 @@ impl Inquiry {
0xb2 => { 0xb2 => {
// Page length // Page length
outbuf[3] = 4; outbuf[3] = 4;
// skip outbuf[4]: crosvm does not support logical block provisioning threshold sets. // skip outbuf[4]: crosvm does not support logical block provisioning threshold
// sets.
const UNMAP: u8 = 1 << 7; const UNMAP: u8 = 1 << 7;
const WRITE_SAME_16: u8 = 1 << 6; const WRITE_SAME_16: u8 = 1 << 6;
const WRITE_SAME_10: u8 = 1 << 5; const WRITE_SAME_10: u8 = 1 << 5;

View file

@ -727,11 +727,12 @@ async fn notify_reset_signal(reset_signal: &(AsyncRwLock<bool>, Condvar)) {
/// Runs all workers once and exit if any worker exit. /// Runs all workers once and exit if any worker exit.
/// ///
/// Returns [`LoopState::Break`] if the worker `f_kill` or `f_resample` exit, or something went wrong /// Returns [`LoopState::Break`] if the worker `f_kill` or `f_resample` exit, or something went
/// on shutdown process. The caller should not run the worker again and should exit the main loop. /// wrong on shutdown process. The caller should not run the worker again and should exit the main
/// loop.
/// ///
/// If this function returns [`LoopState::Continue`], the caller can continue the main loop by resetting /// If this function returns [`LoopState::Continue`], the caller can continue the main loop by
/// the streams and run the worker again. /// resetting the streams and run the worker again.
fn run_worker_once( fn run_worker_once(
ex: &Executor, ex: &Executor,
streams: &Rc<AsyncRwLock<Vec<AsyncRwLock<StreamInfo>>>>, streams: &Rc<AsyncRwLock<Vec<AsyncRwLock<StreamInfo>>>>,

View file

@ -56,7 +56,8 @@ pub struct StreamInfoBuilder {
impl StreamInfoBuilder { impl StreamInfoBuilder {
/// Creates a StreamInfoBuilder with minimal required fields: /// Creates a StreamInfoBuilder with minimal required fields:
/// ///
/// * `stream_source_generator`: Generator which generates stream source in [`StreamInfo::prepare()`]. /// * `stream_source_generator`: Generator which generates stream source in
/// [`StreamInfo::prepare()`].
pub fn new(stream_source_generator: Arc<SysAudioStreamSourceGenerator>) -> Self { pub fn new(stream_source_generator: Arc<SysAudioStreamSourceGenerator>) -> Self {
StreamInfoBuilder { StreamInfoBuilder {
stream_source_generator, stream_source_generator,
@ -64,8 +65,8 @@ impl StreamInfoBuilder {
} }
} }
/// Set the [`StreamEffect`]s to use when creating a stream from the stream source in [`StreamInfo::prepare()`]. /// Set the [`StreamEffect`]s to use when creating a stream from the stream source in
/// The default value is no effects. /// [`StreamInfo::prepare()`]. The default value is no effects.
pub fn effects(mut self, effects: Vec<StreamEffect>) -> Self { pub fn effects(mut self, effects: Vec<StreamEffect>) -> Self {
self.effects = effects; self.effects = effects;
self self
@ -392,7 +393,8 @@ impl StreamInfo {
buffer_bytes: self.buffer_bytes, buffer_bytes: self.buffer_bytes,
period_bytes: self.period_bytes, period_bytes: self.period_bytes,
direction: self.direction, // VIRTIO_SND_D_* direction: self.direction, // VIRTIO_SND_D_*
state: self.state, // VIRTIO_SND_R_PCM_SET_PARAMS -> VIRTIO_SND_R_PCM_STOP, or 0 (uninitialized) // VIRTIO_SND_R_PCM_SET_PARAMS -> VIRTIO_SND_R_PCM_STOP, or 0 (uninitialized)
state: self.state,
effects: self.effects.clone(), effects: self.effects.clone(),
just_reset: self.just_reset, just_reset: self.just_reset,
} }

View file

@ -38,7 +38,8 @@ pub enum Error {
/// Failed to parse parameters. /// Failed to parse parameters.
#[error("Invalid snd parameter: {0}")] #[error("Invalid snd parameter: {0}")]
UnknownParameter(String), UnknownParameter(String),
/// Invalid PCM device config index. Happens when the length of PCM device config is less than the number of PCM devices. /// Invalid PCM device config index. Happens when the length of PCM device config is less than
/// the number of PCM devices.
#[error("Invalid PCM device config index: {0}")] #[error("Invalid PCM device config index: {0}")]
InvalidPCMDeviceConfigIndex(usize), InvalidPCMDeviceConfigIndex(usize),
/// Invalid PCM info direction (VIRTIO_SND_D_OUTPUT = 0, VIRTIO_SND_D_INPUT = 1) /// Invalid PCM info direction (VIRTIO_SND_D_OUTPUT = 0, VIRTIO_SND_D_INPUT = 1)

View file

@ -115,9 +115,10 @@ impl StreamInfo {
self.channels as usize, self.channels as usize,
self.format, self.format,
self.frame_rate as usize, self.frame_rate as usize,
// `buffer_size` in `audio_streams` API indicates the buffer size in bytes that the stream // `buffer_size` in `audio_streams` API indicates the buffer size in bytes that the
// consumes (or transmits) each time (next_playback/capture_buffer). // stream consumes (or transmits) each time
// `period_bytes` in virtio-snd device (or ALSA) indicates the device transmits (or // (next_playback/capture_buffer). `period_bytes` in virtio-snd
// device (or ALSA) indicates the device transmits (or
// consumes) for each PCM message. // consumes) for each PCM message.
// Therefore, `buffer_size` in `audio_streams` == `period_bytes` in virtio-snd. // Therefore, `buffer_size` in `audio_streams` == `period_bytes` in virtio-snd.
self.period_bytes / frame_size, self.period_bytes / frame_size,

View file

@ -344,8 +344,8 @@ impl Stream {
impl Drop for Stream { impl Drop for Stream {
fn drop(&mut self) { fn drop(&mut self) {
// Try to stop and release the stream in case it was playing, these operations will fail if the // Try to stop and release the stream in case it was playing, these operations will fail if
// stream is already released, just ignore that failure // the stream is already released, just ignore that failure
let _ = self.vios_client.lock().stop_stream(self.stream_id); let _ = self.vios_client.lock().stop_stream(self.stream_id);
let _ = self.vios_client.lock().release_stream(self.stream_id); let _ = self.vios_client.lock().release_stream(self.stream_id);

View file

@ -252,7 +252,8 @@ impl Worker {
} else { } else {
( (
VIRTIO_SND_S_OK, VIRTIO_SND_S_OK,
// Safe to unwrap because we just ensured all the ids are valid // Safe to unwrap because we just ensured all the ids are
// valid
(start_id..end_id) (start_id..end_id)
.map(|id| { .map(|id| {
self.vios_client.lock().jack_info(id).unwrap() self.vios_client.lock().jack_info(id).unwrap()
@ -319,7 +320,8 @@ impl Worker {
} else { } else {
( (
VIRTIO_SND_S_OK, VIRTIO_SND_S_OK,
// Safe to unwrap because we just ensured all the ids are valid // Safe to unwrap because we just ensured all the ids are
// valid
(start_id..end_id) (start_id..end_id)
.map(|id| { .map(|id| {
self.vios_client.lock().chmap_info(id).unwrap() self.vios_client.lock().chmap_info(id).unwrap()
@ -348,7 +350,8 @@ impl Worker {
} else { } else {
( (
VIRTIO_SND_S_OK, VIRTIO_SND_S_OK,
// Safe to unwrap because we just ensured all the ids are valid // Safe to unwrap because we just ensured all the ids are
// valid
(start_id..end_id) (start_id..end_id)
.map(|id| { .map(|id| {
self.vios_client.lock().stream_info(id).unwrap() self.vios_client.lock().stream_info(id).unwrap()

View file

@ -231,7 +231,8 @@ fn create_vu_multi_port_device(
let port = x let port = x
.create_serial_device::<ConsolePort>( .create_serial_device::<ConsolePort>(
ProtectionType::Unprotected, ProtectionType::Unprotected,
// We need to pass an event as per Serial Device API but we don't really use it anyway. // We need to pass an event as per Serial Device API but we don't really use it
// anyway.
&Event::new()?, &Event::new()?,
keep_rds, keep_rds,
) )

View file

@ -281,13 +281,13 @@ pub fn run_gpu_device(opts: Options) -> anyhow::Result<()> {
let gpu = Rc::new(RefCell::new(Gpu::new( let gpu = Rc::new(RefCell::new(Gpu::new(
config.exit_evt_wrtube, config.exit_evt_wrtube,
config.gpu_control_device_tube, config.gpu_control_device_tube,
/*resource_bridges=*/ Vec::new(), /* resource_bridges= */ Vec::new(),
display_backends, display_backends,
&gpu_params, &gpu_params,
/*render_server_descriptor*/ None, /* render_server_descriptor */ None,
input_event_backend_config.event_devices, input_event_backend_config.event_devices,
base_features, base_features,
/*channels=*/ &Default::default(), /* channels= */ &Default::default(),
wndproc_thread, wndproc_thread,
))); )));

View file

@ -35,7 +35,6 @@
//! Ok(()) //! Ok(())
//! } //! }
//! ``` //! ```
//!
// Implementation note: // Implementation note:
// This code lets us take advantage of the vmm_vhost low level implementation of the vhost user // This code lets us take advantage of the vmm_vhost low level implementation of the vhost user
// protocol. DeviceRequestHandler implements the VhostUserSlaveReqHandler trait from vmm_vhost, // protocol. DeviceRequestHandler implements the VhostUserSlaveReqHandler trait from vmm_vhost,

View file

@ -33,7 +33,8 @@ pub fn read_from_tube_transporter(
let tube_transporter = TubeTransporterReader::create_tube_transporter_reader( let tube_transporter = TubeTransporterReader::create_tube_transporter_reader(
// SAFETY: // SAFETY:
// Safe because we know that raw_transport_tube is valid (passed by inheritance), and that // Safe because we know that raw_transport_tube is valid (passed by inheritance), and that
// the blocking & framing modes are accurate because we create them ourselves in the broker. // the blocking & framing modes are accurate because we create them ourselves in the
// broker.
unsafe { unsafe {
PipeConnection::from_raw_descriptor( PipeConnection::from_raw_descriptor(
raw_transport_tube, raw_transport_tube,

View file

@ -74,7 +74,8 @@ pub trait VhostUserDevice {
ex: &Executor, ex: &Executor,
) -> anyhow::Result<Box<dyn VhostUserSlaveReqHandler>>; ) -> anyhow::Result<Box<dyn VhostUserSlaveReqHandler>>;
/// The preferred ExecutorKind of an Executor to accept by [`VhostUserDevice::into_req_handler()`]. /// The preferred ExecutorKind of an Executor to accept by
/// [`VhostUserDevice::into_req_handler()`].
fn executor_kind(&self) -> Option<ExecutorKind> { fn executor_kind(&self) -> Option<ExecutorKind> {
None None
} }

View file

@ -55,8 +55,8 @@ struct InputBuffer {
mapping: MemoryMappingArena, mapping: MemoryMappingArena,
/// Resource ID that we will signal using `NotifyEndOfBitstreamBuffer` upon destruction. /// Resource ID that we will signal using `NotifyEndOfBitstreamBuffer` upon destruction.
resource_id: u32, resource_id: u32,
/// Pointer to the event queue to send the `NotifyEndOfBitstreamBuffer` event to. The event will /// Pointer to the event queue to send the `NotifyEndOfBitstreamBuffer` event to. The event
/// not be sent if the pointer becomes invalid. /// will not be sent if the pointer becomes invalid.
event_queue: Weak<SyncEventQueue<DecoderEvent>>, event_queue: Weak<SyncEventQueue<DecoderEvent>>,
} }

View file

@ -32,6 +32,7 @@ pub enum Token {
} }
/// A tag for commands being processed asynchronously in the back-end device. /// A tag for commands being processed asynchronously in the back-end device.
///
/// TODO(b/149720783): Remove this enum by using async primitives. /// TODO(b/149720783): Remove this enum by using async primitives.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum AsyncCmdTag { pub enum AsyncCmdTag {
@ -102,11 +103,13 @@ pub enum VideoEvtResponseType {
pub trait Device { pub trait Device {
/// Processes a virtio-video command. /// Processes a virtio-video command.
/// If the command expects a synchronous response, it returns a response as `VideoCmdResponseType::Sync`. /// If the command expects a synchronous response, it returns a response as
/// Otherwise, it returns a name of the descriptor chain that will be used when a response is prepared. /// `VideoCmdResponseType::Sync`. Otherwise, it returns a name of the descriptor chain that
/// Implementations of this method is passed a WaitContext object which can be used to add or remove /// will be used when a response is prepared. Implementations of this method is passed a
/// descriptors to wait on. It is expected that only Token::Event items would be added. When a Token::Event /// WaitContext object which can be used to add or remove descriptors to wait on. It is
/// event arrives, process_event() will be invoked. /// expected that only Token::Event items would be added. When a Token::Event event arrives,
/// process_event() will be invoked.
///
/// TODO(b/149720783): Make this an async function. /// TODO(b/149720783): Make this an async function.
fn process_cmd( fn process_cmd(
&mut self, &mut self,
@ -119,8 +122,10 @@ pub trait Device {
/// Processes an available `Token::Event` event and returns a list of `VideoEvtResponseType` /// Processes an available `Token::Event` event and returns a list of `VideoEvtResponseType`
/// responses. It returns None if an invalid event comes. /// responses. It returns None if an invalid event comes.
/// For responses to be sent via command queue, the return type is `VideoEvtResponseType::AsyncCmd`. /// For responses to be sent via command queue, the return type is
/// For responses to be sent via event queue, the return type is `VideoEvtResponseType::Event`. /// `VideoEvtResponseType::AsyncCmd`. For responses to be sent via event queue, the return
/// type is `VideoEvtResponseType::Event`.
///
/// TODO(b/149720783): Make this an async function. /// TODO(b/149720783): Make this an async function.
fn process_event( fn process_event(
&mut self, &mut self,

View file

@ -105,9 +105,9 @@ pub struct FfmpegEncoderSession {
output_queue: VecDeque<(OutputBufferId, MemoryMappingArena)>, output_queue: VecDeque<(OutputBufferId, MemoryMappingArena)>,
/// `true` if a flush is pending. While a pending flush exist, input buffers are temporarily /// `true` if a flush is pending. While a pending flush exist, input buffers are temporarily
/// held on and not sent to the encoder. An actual flush call will be issued when we run out of /// held on and not sent to the encoder. An actual flush call will be issued when we run out of
/// output buffers (to defend against FFmpeg bugs), and we'll try to receive outputs again until /// output buffers (to defend against FFmpeg bugs), and we'll try to receive outputs again
/// we receive another code indicating the flush has completed, at which point this flag will /// until we receive another code indicating the flush has completed, at which point this
/// be reset. /// flag will be reset.
is_flushing: bool, is_flushing: bool,
/// The libav context for this session. /// The libav context for this session.

View file

@ -121,7 +121,8 @@ impl LibvdaEncoder {
let mut parsed_formats: BTreeMap<Format, ParsedFormat> = BTreeMap::new(); let mut parsed_formats: BTreeMap<Format, ParsedFormat> = BTreeMap::new();
for output_format in output_formats.iter() { for output_format in output_formats.iter() {
// TODO(alexlau): Consider using `max_framerate_numerator` and `max_framerate_denominator`. // TODO(alexlau): Consider using `max_framerate_numerator` and
// `max_framerate_denominator`.
let libvda::encode::OutputProfile { let libvda::encode::OutputProfile {
profile: libvda_profile, profile: libvda_profile,
max_width, max_width,

View file

@ -671,8 +671,8 @@ impl<T: Encoder> EncoderDevice<T> {
GuestResource::from_virtio_object_entry( GuestResource::from_virtio_object_entry(
// SAFETY: // SAFETY:
// Safe because we confirmed the correct type for the resource. // Safe because we confirmed the correct type for the resource.
// unwrap() is also safe here because we just tested above that `entries` had // unwrap() is also safe here because we just tested above that
// exactly one element. // `entries` had exactly one element.
unsafe { entries.get(0).unwrap().object }, unsafe { entries.get(0).unwrap().object },
&self.resource_bridge, &self.resource_bridge,
&stream.src_params, &stream.src_params,
@ -721,8 +721,8 @@ impl<T: Encoder> EncoderDevice<T> {
GuestResource::from_virtio_object_entry( GuestResource::from_virtio_object_entry(
// SAFETY: // SAFETY:
// Safe because we confirmed the correct type for the resource. // Safe because we confirmed the correct type for the resource.
// unwrap() is also safe here because we just tested above that `entries` had // unwrap() is also safe here because we just tested above that
// exactly one element. // `entries` had exactly one element.
unsafe { entries.get(0).unwrap().object }, unsafe { entries.get(0).unwrap().object },
&self.resource_bridge, &self.resource_bridge,
&stream.dst_params, &stream.dst_params,
@ -866,9 +866,9 @@ impl<T: Encoder> EncoderDevice<T> {
let buffer_size = dst_resource.resource.planes[0].size as u32; let buffer_size = dst_resource.resource.planes[0].size as u32;
// Stores an output buffer to notify EOS. // Stores an output buffer to notify EOS.
// This is necessary because libvda is unable to indicate EOS along with returned buffers. // This is necessary because libvda is unable to indicate EOS along with returned
// For now, when a `Flush()` completes, this saved resource will be returned as a zero-sized // buffers. For now, when a `Flush()` completes, this saved resource
// buffer with the EOS flag. // will be returned as a zero-sized buffer with the EOS flag.
if stream.eos_manager.try_reserve_eos_buffer(resource_id) { if stream.eos_manager.try_reserve_eos_buffer(resource_id) {
return Ok(VideoCmdResponseType::Async(AsyncCmdTag::Queue { return Ok(VideoCmdResponseType::Async(AsyncCmdTag::Queue {
stream_id, stream_id,

View file

@ -186,8 +186,8 @@ impl PlaneFormat {
}, },
// UV plane, 1 sample per group of 4 pixels for U and V. // UV plane, 1 sample per group of 4 pixels for U and V.
PlaneFormat { PlaneFormat {
// Add one vertical line so odd resolutions result in an extra UV line to cover all the // Add one vertical line so odd resolutions result in an extra UV line to cover
// Y samples. // all the Y samples.
plane_size: width * half_height, plane_size: width * half_height,
stride: width, stride: width,
}, },

View file

@ -21,8 +21,8 @@
//! * Derive implementations of AsBytes and FromBytes for each struct as needed. //! * Derive implementations of AsBytes and FromBytes for each struct as needed.
//! * Added GET_PARAMS_EXT and SET_PARAMS_EXT to allow querying and changing the resource type //! * Added GET_PARAMS_EXT and SET_PARAMS_EXT to allow querying and changing the resource type
//! dynamically. //! dynamically.
//! * Moved some definitions such as virtio_video_config to device_constants to make them visible //! * Moved some definitions such as virtio_video_config to device_constants to make them visible to
//! to vhost-user modules, and also pub-use them. //! vhost-user modules, and also pub-use them.
#![allow(dead_code, non_snake_case, non_camel_case_types)] #![allow(dead_code, non_snake_case, non_camel_case_types)]

View file

@ -181,8 +181,8 @@ impl Worker {
/// # Arguments /// # Arguments
/// ///
/// * `device` - Instance of backend device /// * `device` - Instance of backend device
/// * `wait_ctx` - `device` may register a new `Token::Event` for a new stream session /// * `wait_ctx` - `device` may register a new `Token::Event` for a new stream session to
/// to `wait_ctx` /// `wait_ctx`
/// * `desc` - `DescriptorChain` to handle /// * `desc` - `DescriptorChain` to handle
fn handle_command_desc( fn handle_command_desc(
&mut self, &mut self,
@ -266,8 +266,8 @@ impl Worker {
/// # Arguments /// # Arguments
/// ///
/// * `device` - Instance of backend device /// * `device` - Instance of backend device
/// * `wait_ctx` - `device` may register a new `Token::Event` for a new stream session /// * `wait_ctx` - `device` may register a new `Token::Event` for a new stream session to
/// to `wait_ctx` /// `wait_ctx`
fn handle_command_queue( fn handle_command_queue(
&mut self, &mut self,
device: &mut dyn Device, device: &mut dyn Device,
@ -286,8 +286,8 @@ impl Worker {
/// ///
/// * `device` - Instance of backend device /// * `device` - Instance of backend device
/// * `stream_id` - Stream session ID of the event /// * `stream_id` - Stream session ID of the event
/// * `wait_ctx` - `device` may register a new `Token::Buffer` for a new stream session /// * `wait_ctx` - `device` may register a new `Token::Buffer` for a new stream session to
/// to `wait_ctx` /// `wait_ctx`
fn handle_event( fn handle_event(
&mut self, &mut self,
device: &mut dyn Device, device: &mut dyn Device,

View file

@ -398,9 +398,9 @@ struct VsockConnection {
prev_recv_cnt: usize, prev_recv_cnt: usize,
// Total auxiliary buffer space available to receive packets from the driver, not including // Total auxiliary buffer space available to receive packets from the driver, not including
// the virtqueue itself. For us, this is tx buffer on the named pipe into which we drain packets // the virtqueue itself. For us, this is tx buffer on the named pipe into which we drain
// for the connection. Note that if the named pipe has a grow on demand TX buffer, we use // packets for the connection. Note that if the named pipe has a grow on demand TX buffer,
// DEFAULT_BUF_ALLOC instead. // we use DEFAULT_BUF_ALLOC instead.
buf_alloc: usize, buf_alloc: usize,
// Peer (driver) total free-running count of received bytes. // Peer (driver) total free-running count of received bytes.
@ -1155,7 +1155,8 @@ impl Worker {
fwd_cnt: 0.into(), fwd_cnt: 0.into(),
..Default::default() ..Default::default()
}; };
// Safe because virtio_vsock_hdr is a simple data struct and converts cleanly to bytes // Safe because virtio_vsock_hdr is a simple data struct and converts cleanly to
// bytes
self.write_bytes_to_queue( self.write_bytes_to_queue(
&mut *send_queue.lock().await, &mut *send_queue.lock().await,
rx_queue_evt, rx_queue_evt,

View file

@ -59,17 +59,17 @@ const MAJOR_VERSION: u16 = 1;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug, AsBytes, FromZeroes, FromBytes)] #[derive(Clone, Copy, Debug, AsBytes, FromZeroes, FromBytes)]
struct SparseHeader { struct SparseHeader {
magic: Le32, /* SPARSE_HEADER_MAGIC */ magic: Le32, // SPARSE_HEADER_MAGIC
major_version: Le16, /* (0x1) - reject images with higher major versions */ major_version: Le16, // (0x1) - reject images with higher major versions
minor_version: Le16, /* (0x0) - allow images with higer minor versions */ minor_version: Le16, // (0x0) - allow images with higer minor versions
file_hdr_sz: Le16, /* 28 bytes for first revision of the file format */ file_hdr_sz: Le16, // 28 bytes for first revision of the file format
chunk_hdr_size: Le16, /* 12 bytes for first revision of the file format */ chunk_hdr_size: Le16, // 12 bytes for first revision of the file format
blk_sz: Le32, /* block size in bytes, must be a multiple of 4 (4096) */ blk_sz: Le32, // block size in bytes, must be a multiple of 4 (4096)
total_blks: Le32, /* total blocks in the non-sparse output image */ total_blks: Le32, // total blocks in the non-sparse output image
total_chunks: Le32, /* total chunks in the sparse input image */ total_chunks: Le32, // total chunks in the sparse input image
image_checksum: Le32, /* CRC32 checksum of the original data, counting "don't care" */ // CRC32 checksum of the original data, counting "don't care" as 0. Standard 802.3 polynomial,
/* as 0. Standard 802.3 polynomial, use a Public Domain */ // use a Public Domain table implementation
/* table implementation */ image_checksum: Le32,
} }
const CHUNK_TYPE_RAW: u16 = 0xCAC1; const CHUNK_TYPE_RAW: u16 = 0xCAC1;

View file

@ -219,7 +219,8 @@ impl CompositeDiskFile {
}; };
let comp_file = open_file_or_duplicate( let comp_file = open_file_or_duplicate(
&path, &path,
OpenOptions::new().read(true).write(writable), // TODO(b/190435784): add support for O_DIRECT. OpenOptions::new().read(true).write(writable), /* TODO(b/190435784): add
* support for O_DIRECT. */
) )
.map_err(|e| Error::OpenFile(e.into(), disk.file_path.to_string()))?; .map_err(|e| Error::OpenFile(e.into(), disk.file_path.to_string()))?;
@ -1302,8 +1303,8 @@ mod tests {
// Write to the RW part so that some fsync operation will occur. // Write to the RW part so that some fsync operation will occur.
composite.write_zeroes_at(0, 20).await.unwrap(); composite.write_zeroes_at(0, 20).await.unwrap();
// This is the test's assert. fsyncing should NOT touch a read-only disk part. On Windows, // This is the test's assert. fsyncing should NOT touch a read-only disk part. On
// this would be an error. // Windows, this would be an error.
composite.fsync().await.expect( composite.fsync().await.expect(
"Failed to fsync composite disk. \ "Failed to fsync composite disk. \
This can happen if the disk writable state is wrong.", This can happen if the disk writable state is wrong.",

Some files were not shown because too many files have changed in this diff Show more