rust: dma: implement BinaryWriter for Coherent<[u8]>

Implement the BinaryWriter trait for Coherent<[u8]>, enabling DMA
coherent allocations to be exposed as readable binary files.  The
implementation handles offset tracking and bounds checking, copying data
from the coherent allocation to userspace via write_dma().

Signed-off-by: Timur Tabi <ttabi@nvidia.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Tested-by: John Hubbard <jhubbard@nvidia.com>
Tested-by: Eliot Courtney <ecourtney@nvidia.com>
Link: https://patch.msgid.link/20260319212658.2541610-4-ttabi@nvidia.com
[ Rebase onto Coherent<T> changes. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
Timur Tabi 2026-03-19 16:26:55 -05:00 committed by Danilo Krummrich
parent 69bfce0f25
commit 0168185139

View File

@ -6,12 +6,14 @@
use crate::{ use crate::{
bindings, bindings,
debugfs,
device::{ device::{
self, self,
Bound, Bound,
Core, // Core, //
}, },
error::to_result, error::to_result,
fs::file,
prelude::*, prelude::*,
ptr::KnownSize, ptr::KnownSize,
sync::aref::ARef, sync::aref::ARef,
@ -19,6 +21,7 @@
AsBytes, AsBytes,
FromBytes, // FromBytes, //
}, // }, //
uaccess::UserSliceWriter,
}; };
use core::{ use core::{
ops::{ ops::{
@ -876,6 +879,37 @@ fn drop(&mut self) {
// can be sent to another thread. // can be sent to another thread.
unsafe impl<T: KnownSize + Send + ?Sized> Send for Coherent<T> {} unsafe impl<T: KnownSize + Send + ?Sized> Send for Coherent<T> {}
// SAFETY: Sharing `&Coherent` across threads is safe if `T` is `Sync`, because all
// methods that access the buffer contents (`field_read`, `field_write`, `as_slice`,
// `as_slice_mut`) are `unsafe`, and callers are responsible for ensuring no data races occur.
// The safe methods only return metadata or raw pointers whose use requires `unsafe`.
unsafe impl<T: KnownSize + ?Sized + AsBytes + FromBytes + Sync> Sync for Coherent<T> {}
impl debugfs::BinaryWriter for Coherent<[u8]> {
fn write_to_slice(
&self,
writer: &mut UserSliceWriter,
offset: &mut file::Offset,
) -> Result<usize> {
if offset.is_negative() {
return Err(EINVAL);
}
// If the offset is too large for a usize (e.g. on 32-bit platforms),
// then consider that as past EOF and just return 0 bytes.
let Ok(offset_val) = usize::try_from(*offset) else {
return Ok(0);
};
let count = self.size().saturating_sub(offset_val).min(writer.len());
writer.write_dma(self, offset_val, count)?;
*offset += count as i64;
Ok(count)
}
}
/// Reads a field of an item from an allocated region of structs. /// Reads a field of an item from an allocated region of structs.
/// ///
/// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is an expression evaluating /// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is an expression evaluating