1- use  crate :: runtime:: driver:: op:: { CancelData ,  Cancellable ,  Completable ,  CqeResult ,  Op } ; 
1+ use  crate :: { 
2+     runtime:: driver:: op:: { CancelData ,  Cancellable ,  Completable ,  CqeResult ,  Op } , 
3+     util:: as_ref:: OwnedBuf , 
4+ } ; 
25use  io_uring:: { opcode,  types} ; 
36use  std:: { 
4-     cmp ,   io, 
5-     os:: fd:: { AsRawFd ,  BorrowedFd } , 
7+     io, 
8+     os:: fd:: { AsRawFd ,  OwnedFd } , 
69} ; 
710
811#[ derive( Debug ) ]  
9- pub ( crate )  struct  Write ; 
12+ pub ( crate )  struct  Write  { 
13+     buf :  OwnedBuf , 
14+     fd :  OwnedFd , 
15+ } 
1016
1117impl  Completable  for  Write  { 
12-     // The number of bytes written. 
13-     type  Output  = u32 ; 
18+     type  Output  = ( u32 ,  OwnedBuf ,  OwnedFd ) ; 
1419    fn  complete ( self ,  cqe :  CqeResult )  -> io:: Result < Self :: Output >  { 
15-         cqe. result 
20+         Ok ( ( cqe. result ? ,   self . buf ,   self . fd ) ) 
1621    } 
1722} 
1823
@@ -23,23 +28,29 @@ impl Cancellable for Write {
2328} 
2429
2530impl  Op < Write >  { 
26-     /// # SAFETY 
27- /// 
28- /// The caller must ensure that `fd` and `buf` remain valid until the 
29- /// operation finishes (or gets cancelled) and the `Op::drop` completes. 
30- /// Otherwise, the kernel could access freed memory, breaking soundness. 
31- pub ( crate )  unsafe  fn  write_at ( fd :  BorrowedFd < ' _ > ,  buf :  & [ u8 ] ,  offset :  u64 )  -> io:: Result < Self >  { 
32-         // There is a cap on how many bytes we can write in a single uring write operation. 
33-         // ref: https://github.com/axboe/liburing/discussions/497 
34-         let  len:  u32  = cmp:: min ( buf. len ( ) ,  u32:: MAX  as  usize )  as  u32 ; 
31+     /// Issue a write that starts at `buf_offset` within `buf` and writes `len` bytes 
32+ /// into `file` at `file_offset`. 
33+ pub ( crate )  fn  write_at ( 
34+         fd :  OwnedFd , 
35+         buf :  OwnedBuf , 
36+         buf_offset :  usize , 
37+         len :  u32 , 
38+         file_offset :  u64 , 
39+     )  -> io:: Result < Self >  { 
40+         // Check if `buf_offset` stays in bounds of the allocation 
41+         debug_assert ! ( buf_offset + len as  usize  <= buf. len( ) ) ; 
3542
36-         let  sqe = opcode:: Write :: new ( types:: Fd ( fd. as_raw_fd ( ) ) ,  buf. as_ptr ( ) ,  len) 
37-             . offset ( offset) 
43+         // SAFETY: 
44+         // - `buf_offset` stays in bounds of the allocation. 
45+         // - `buf` is derived from an actual allocation, and the entire memory 
46+         //    range is in bounds of that allocation. 
47+         let  ptr = unsafe  {  buf. as_ptr ( ) . add ( buf_offset)  } ; 
48+         let  sqe = opcode:: Write :: new ( types:: Fd ( fd. as_raw_fd ( ) ) ,  ptr,  len) 
49+             . offset ( file_offset) 
3850            . build ( ) ; 
3951
40-         // SAFETY: `fd` and `buf` valid until the operation completes or gets cancelled 
41-         // and the `Op::drop` completes. 
42-         let  op = unsafe  {  Op :: new ( sqe,  Write )  } ; 
52+         // SAFETY: parameters of the entry is valid until this operation completes. 
53+         let  op = unsafe  {  Op :: new ( sqe,  Write  {  buf,  fd } )  } ; 
4354        Ok ( op) 
4455    } 
4556} 
0 commit comments