Implement the BinaryWriter trait for CoherentAllocation<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 <[email protected]> --- drivers/gpu/nova-core/gsp.rs | 1 + rust/kernel/dma.rs | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 174feaca0a6b..f7134c75b1f2 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -3,6 +3,7 @@ mod boot; use kernel::{ + debugfs, device, dma::{ CoherentAllocation, diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index acc65b1e0f24..dca16fb5a2fc 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -5,12 +5,14 @@ //! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-mapping.h) use crate::{ - bindings, build_assert, device, + bindings, build_assert, debugfs, device, device::{Bound, Core}, error::{to_result, Result}, + fs::file, prelude::*, sync::aref::ARef, transmute::{AsBytes, FromBytes}, + uaccess::UserSliceWriter, }; use core::ptr::NonNull; @@ -651,6 +653,38 @@ fn drop(&mut self) { // can be sent to another thread. unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {} +// SAFETY: Sharing `&CoherentAllocation` 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: AsBytes + FromBytes + Sync> Sync for CoherentAllocation<T> {} + +impl debugfs::BinaryWriter for CoherentAllocation<u8> { + fn write_to_slice( + &self, + writer: &mut UserSliceWriter, + offset: &mut file::Offset, + ) -> Result<usize> { + if offset.is_negative() { + return Err(EINVAL); + } + + let offset_val: usize = (*offset).try_into().map_err(|_| EINVAL)?; + let len = self.count(); + + if offset_val >= len { + return Ok(0); + } + + let count = (len - 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. /// /// # Examples -- 2.52.0
