11// SPDX-License-Identifier: AGPL-3.0-only
2- #![ allow( unsafe_code) ] // VFIO DMA ioctls + BorrowedFd::borrow_raw(container_fd)
2+ #![ allow( unsafe_code) ] // VFIO DMA map/unmap ioctls require unsafe
33//! DMA buffer management for VFIO NPU backend
44//!
55//! Provides page-aligned, mlock'd, IOMMU-mapped memory buffers for
66//! zero-copy data transfer between host and NPU hardware.
77
88use crate :: error:: { AkidaError , Result } ;
9- use std:: os:: fd:: RawFd ;
9+ use std:: os:: fd:: { AsFd , OwnedFd } ;
1010
1111use toadstool_hw_safe:: LockedMemory ;
12- use toadstool_hw_safe:: vfio_dma:: { VfioDmaMap , VfioDmaUnmap , dma_map_fd , dma_unmap_fd , flags} ;
12+ use toadstool_hw_safe:: vfio_dma:: { VfioDmaMap , VfioDmaUnmap , dma_map , dma_unmap , flags} ;
1313
1414/// DMA buffer for fast host-to-device data transfer.
1515///
@@ -20,7 +20,7 @@ pub struct DmaBuffer {
2020 mem : LockedMemory ,
2121 iova : u64 ,
2222 size : usize ,
23- container_fd : RawFd ,
23+ container_fd : OwnedFd ,
2424}
2525
2626impl DmaBuffer {
@@ -29,7 +29,7 @@ impl DmaBuffer {
2929 /// # Errors
3030 ///
3131 /// Returns an error if allocation, mlock, or IOMMU DMA mapping fails.
32- pub ( crate ) fn new ( container_fd : RawFd , size : usize , iova : u64 ) -> Result < Self > {
32+ pub ( crate ) fn new ( container_fd : OwnedFd , size : usize , iova : u64 ) -> Result < Self > {
3333 if size == 0 {
3434 return Err ( AkidaError :: transfer_failed ( "DMA buffer size must be > 0" ) ) ;
3535 }
@@ -59,9 +59,9 @@ impl DmaBuffer {
5959 dma_map_arg. flags
6060 ) ;
6161
62- // SAFETY: container_fd from VFIO container open (valid and not closed );
62+ // SAFETY: container_fd is the VFIO container (OwnedFd guarantees validity );
6363 // map.vaddr points at mem's allocation for size bytes; IOVA range chosen by caller.
64- if let Err ( e) = unsafe { dma_map_fd ( container_fd, & dma_map_arg) } {
64+ if let Err ( e) = unsafe { dma_map ( container_fd. as_fd ( ) , & dma_map_arg) } {
6565 tracing:: warn!( "DMA map failed: {e}" ) ;
6666 return Err ( AkidaError :: transfer_failed ( format ! (
6767 "Failed to map DMA: {e}"
@@ -115,9 +115,9 @@ impl Drop for DmaBuffer {
115115 size : self . size as u64 ,
116116 } ;
117117
118- // SAFETY: DmaBuffer dropped before VfioBackend (parent), so container_fd is still
119- // valid and open; iova/size match the prior dma_map_fd call.
120- let _ = unsafe { dma_unmap_fd ( self . container_fd , & dma_unmap_arg) } ;
118+ // SAFETY: container_fd is OwnedFd (guaranteed valid until Drop completes);
119+ // iova/size match the prior dma_map call for this buffer .
120+ let _ = unsafe { dma_unmap ( self . container_fd . as_fd ( ) , & dma_unmap_arg) } ;
121121
122122 tracing:: debug!( "Freed DMA buffer at iova={:#x}" , self . iova) ;
123123 }
@@ -128,18 +128,23 @@ mod tests {
128128 use super :: * ;
129129 use toadstool_hw_safe:: vfio_dma:: { VfioDmaMap , VfioDmaUnmap } ;
130130
131+ fn dummy_fd ( ) -> OwnedFd {
132+ use std:: fs:: File ;
133+ let f = File :: open ( "/dev/null" ) . expect ( "/dev/null" ) ;
134+ f. into ( )
135+ }
136+
131137 #[ test]
132138 fn test_dma_buffer_new_size_zero ( ) {
133- let result = DmaBuffer :: new ( - 1 , 0 , 0 ) ;
139+ let result = DmaBuffer :: new ( dummy_fd ( ) , 0 , 0 ) ;
134140 assert ! ( result. is_err( ) ) ;
135141 let err = result. unwrap_err ( ) ;
136142 assert ! ( err. to_string( ) . contains( "size must be > 0" ) ) ;
137143 }
138144
139145 #[ test]
140146 fn test_dma_buffer_iova_size_accessors ( ) {
141- // We can't create a real DmaBuffer without VFIO, but we can test the size zero path
142- let result = DmaBuffer :: new ( 0 , 0 , 0x1000 ) ;
147+ let result = DmaBuffer :: new ( dummy_fd ( ) , 0 , 0x1000 ) ;
143148 assert ! ( result. is_err( ) ) ;
144149 }
145150
0 commit comments