Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ categories = ["api-bindings", "os::linux-apis"]
repository = "https://github.com/mripard/dma-buf/"

[dependencies]
rustix = { version = "1.0.5", features = ["fs", "mm", "param"] }
thiserror = "2.0.3"
rustix = { version = "1.0.5", default-features = false, features = [
"fs",
"mm",
"param",
"std",
] }
tracing = { version = "0.1.41", default-features = false, features = ["std"] }

[features]
Expand Down Expand Up @@ -41,7 +45,7 @@ single_use_lifetimes = "warn"
trivial_casts = "warn"
trivial_numeric_casts = "warn"
unreachable_pub = "warn"
# unsafe_code = "deny"
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "warn"
unused_crate_dependencies = "warn"
unused_import_braces = "warn"
Expand All @@ -68,6 +72,7 @@ as_pointer_underscore = "warn"
assertions_on_result_states = "warn"
dbg_macro = "warn"
decimal_literal_representation = "warn"
empty_enum_variants_with_brackets = "warn"
empty_drop = "warn"
empty_structs_with_brackets = "warn"
error_impl_error = "warn"
Expand Down
94 changes: 43 additions & 51 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
// Licensed under the MIT License
// See the LICENSE file or <http://opensource.org/licenses/MIT>

#![allow(unsafe_code)]
#![cfg_attr(
feature = "nightly",
feature(
type_privacy_lints,

Check warning on line 9 in src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

the feature `type_privacy_lints` has been stable since 1.79.0 and no longer requires an attribute to enable

warning: the feature `type_privacy_lints` has been stable since 1.79.0 and no longer requires an attribute to enable --> src/lib.rs:9:9 | 9 | type_privacy_lints, | ^^^^^^^^^^^^^^^^^^ | = note: `#[warn(stable_features)]` on by default
non_exhaustive_omitted_patterns_lint,
strict_provenance

Check warning on line 11 in src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

the feature `strict_provenance` has been stable since 1.84.0 and no longer requires an attribute to enable

warning: the feature `strict_provenance` has been stable since 1.84.0 and no longer requires an attribute to enable --> src/lib.rs:11:9 | 11 | strict_provenance | ^^^^^^^^^^^^^^^^^
)
)]
#![cfg_attr(
feature = "nightly",
warn(
fuzzy_provenance_casts,

Check warning on line 17 in src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

unknown lint: `fuzzy_provenance_casts`

warning: unknown lint: `fuzzy_provenance_casts` --> src/lib.rs:17:9 | 17 | fuzzy_provenance_casts, | ^^^^^^^^^^^^^^^^^^^^^^ | = note: the `fuzzy_provenance_casts` lint is unstable = note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information = help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable = note: this compiler was built on 2025-05-25; consider upgrading it if it is out of date = note: `#[warn(unknown_lints)]` on by default
lossy_provenance_casts,

Check warning on line 18 in src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy

unknown lint: `lossy_provenance_casts`

warning: unknown lint: `lossy_provenance_casts` --> src/lib.rs:18:9 | 18 | lossy_provenance_casts, | ^^^^^^^^^^^^^^^^^^^^^^ | = note: the `lossy_provenance_casts` lint is unstable = note: see issue #130351 <https://github.com/rust-lang/rust/issues/130351> for more information = help: add `#![feature(strict_provenance_lints)]` to the crate attributes to enable = note: this compiler was built on 2025-05-25; consider upgrading it if it is out of date
unnameable_types,
non_exhaustive_omitted_patterns,
clippy::empty_enum_variants_with_brackets
Expand All @@ -22,8 +23,11 @@
)]
#![doc = include_str!("../README.md")]

use core::{ffi::c_void, fmt, num::TryFromIntError, ptr, slice};
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
use core::{error, ffi::c_void, fmt, ptr, slice};
use std::{
io,
os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
};

use rustix::{
fs::fstat,
Expand All @@ -39,35 +43,6 @@
dma_buf_end_cpu_write_access,
};

/// Error type to map a [`DmaBuf`]
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
pub enum MapError {
/// An Error occurred while accessing the buffer file descriptor
#[error("Could not access the buffer file descriptor: {reason}")]
FdAccess {
/// Description of the Error
reason: String,

/// Source of the Error
source: std::io::Error,
},

/// An Error occurred while mapping the buffer file descriptor
#[error("Could not map the buffer file descriptor: {reason}")]
MappingFailed {
/// Description of the Error
reason: String,

/// Source of the Error
source: std::io::Error,
},

/// An Error occurred while converting between Integer types
#[error("Integer Conversion Error")]
IntegerConversionFailed(#[from] TryFromIntError),
}

/// A DMA-Buf buffer
#[derive(Debug)]
pub struct DmaBuf(OwnedFd);
Expand All @@ -83,15 +58,16 @@
///
/// Will return an error if either the Buffer's length can't be retrieved, or if the mmap call
/// fails.
pub fn memory_map(self) -> Result<MappedDmaBuf, MapError> {
#[expect(
clippy::unwrap_in_result,
reason = "The kernel doesn't use the same types between stat and munmap, but it's not something one can recover from."
)]
pub fn memory_map(self) -> io::Result<MappedDmaBuf> {
debug!("Mapping DMA-Buf buffer with File Descriptor {:#?}", self.0);

let stat = fstat(&self.0).map_err(|e| MapError::FdAccess {
reason: e.to_string(),
source: std::io::Error::from(e),
})?;

let len = usize::try_from(stat.st_size)?.next_multiple_of(page_size());
let len = usize::try_from(fstat(&self.0)?.st_size)
.expect("Buffer size can't fit into mmap argument length")
.next_multiple_of(page_size());
trace!("Valid buffer, size {len}");

// SAFETY: It's unclear at this point what the exact safety requirements from mmap are, but
Expand All @@ -106,11 +82,7 @@
0,
)
}
.map(<*mut c_void>::cast::<u8>)
.map_err(|e| MapError::MappingFailed {
reason: e.to_string(),
source: std::io::Error::from(e),
})?;
.map(<*mut c_void>::cast::<u8>)?;

trace!("Memory Mapping Done");

Expand All @@ -130,21 +102,41 @@
}

/// Error type to access a [`MappedDmaBuf`]
#[derive(Debug, thiserror::Error)]
#[derive(Debug)]
pub enum BufferError {
/// An Error occured while accessing the buffer file descriptor
#[error("Could not access the buffer: {reason}")]
FdAccess {
/// Description of the Error
reason: String,

/// Source of the Error
source: std::io::Error,
source: io::Error,
},

/// An Error occured in the closure
#[error("The closure returned an error: {0}")]
Closure(Box<dyn core::error::Error>),
Closure(Box<dyn error::Error>),
}

impl fmt::Display for BufferError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BufferError::FdAccess { reason, .. } => {
f.write_fmt(format_args!("Could not access the buffer: {reason}"))
}
BufferError::Closure(error) => {
f.write_fmt(format_args!("The closure returned an error: {error}"))
}
}
}
}

impl error::Error for BufferError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
BufferError::FdAccess { source, .. } => Some(source),
BufferError::Closure(error) => Some(error.as_ref()),
}
}
}

impl MappedDmaBuf {
Expand Down Expand Up @@ -175,7 +167,7 @@
/// Will return [Error] if the underlying ioctl or the closure fails
pub fn read<A, F, R>(&self, f: F, arg: Option<A>) -> Result<R, BufferError>
where
F: Fn(&[u8], Option<A>) -> Result<R, Box<dyn core::error::Error>>,
F: Fn(&[u8], Option<A>) -> Result<R, Box<dyn error::Error>>,
{
trace_span!("Buffer Read Access").in_scope(|| {
trace_span!("dma-buf begin access ioctl")
Expand Down Expand Up @@ -213,7 +205,7 @@
/// Will return [Error] if the underlying ioctl or the closure fails
pub fn readwrite<A, F, R>(&mut self, f: F, arg: Option<A>) -> Result<R, BufferError>
where
F: Fn(&mut [u8], Option<A>) -> Result<R, Box<dyn core::error::Error>>,
F: Fn(&mut [u8], Option<A>) -> Result<R, Box<dyn error::Error>>,
{
trace_span!("Buffer Read / Write Access").in_scope(|| {
trace_span!("dma-buf begin access ioctl")
Expand Down Expand Up @@ -250,7 +242,7 @@
/// Will return [Error] if the underlying ioctl or the closure fails
pub fn write<A, F>(&mut self, f: F, arg: Option<A>) -> Result<(), BufferError>
where
F: Fn(&mut [u8], Option<A>) -> Result<(), Box<dyn core::error::Error>>,
F: Fn(&mut [u8], Option<A>) -> Result<(), Box<dyn error::Error>>,
{
trace_span!("Buffer Write Access").in_scope(|| {
trace_span!("dma-buf begin access ioctl")
Expand Down
Loading