@@ -9,34 +9,81 @@ use std::fmt::{Debug, Formatter};
99use std:: fs:: File ;
1010use std:: io;
1111use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
12- use std:: ptr;
1312use std:: sync:: { RwLock , RwLockReadGuard , RwLockWriteGuard } ;
1413
14+ use vmm_sys_util:: {
15+ fam:: { FamStruct , FamStructWrapper } ,
16+ generate_fam_struct_impl,
17+ } ;
18+
1519use crate :: passthrough:: PassthroughFs ;
1620
1721/// An arbitrary maximum size for CFileHandle::f_handle.
1822///
1923/// According to Linux ABI, struct file_handle has a flexible array member 'f_handle', but it's
2024/// hard-coded here for simplicity.
21- //pub const MAX_HANDLE_SZ: usize = 128;
25+ pub const MAX_HANDLE_SIZE : usize = 128 ;
26+
27+ /// Dynamically allocated array.
28+ #[ derive( Default ) ]
29+ #[ repr( C ) ]
30+ pub struct __IncompleteArrayField < T > ( :: std:: marker:: PhantomData < T > , [ T ; 0 ] ) ;
31+ impl < T > __IncompleteArrayField < T > {
32+ #[ inline]
33+ pub unsafe fn as_ptr ( & self ) -> * const T {
34+ self as * const __IncompleteArrayField < T > as * const T
35+ }
36+ #[ inline]
37+ pub unsafe fn as_mut_ptr ( & mut self ) -> * mut T {
38+ self as * mut __IncompleteArrayField < T > as * mut T
39+ }
40+ #[ inline]
41+ pub unsafe fn as_slice ( & self , len : usize ) -> & [ T ] {
42+ :: std:: slice:: from_raw_parts ( self . as_ptr ( ) , len)
43+ }
44+ #[ inline]
45+ pub unsafe fn as_mut_slice ( & mut self , len : usize ) -> & mut [ T ] {
46+ :: std:: slice:: from_raw_parts_mut ( self . as_mut_ptr ( ) , len)
47+ }
48+ }
2249
23- #[ derive( Clone , Copy ) ]
50+ /// The structure to transfer file_handle struct between user space and kernel space.
51+ /// ```c
52+ /// struct file_handle {
53+ /// __u32 handle_bytes;
54+ /// int handle_type;
55+ /// /* file identifier */
56+ /// unsigned char f_handle[];
57+ /// }
58+ /// ```
59+ #[ derive( Default ) ]
2460#[ repr( C ) ]
61+ pub struct CFileHandleInner {
62+ pub handle_bytes : libc:: c_uint ,
63+ pub handle_type : libc:: c_int ,
64+ pub f_handle : __IncompleteArrayField < libc:: c_char > ,
65+ }
66+
67+ generate_fam_struct_impl ! (
68+ CFileHandleInner ,
69+ libc:: c_char,
70+ f_handle,
71+ libc:: c_uint,
72+ handle_bytes,
73+ MAX_HANDLE_SIZE
74+ ) ;
75+
76+ type CFileHandleWrapper = FamStructWrapper < CFileHandleInner > ;
77+
78+ #[ derive( Clone ) ]
2579struct CFileHandle {
26- // Size of f_handle [in, out]
27- handle_bytes : libc:: c_uint ,
28- // Handle type [out]
29- handle_type : libc:: c_int ,
30- // File identifier (sized by caller) [out]
31- f_handle : * mut libc:: c_char ,
80+ pub wrapper : CFileHandleWrapper ,
3281}
3382
3483impl CFileHandle {
35- fn new ( ) -> Self {
84+ fn new ( size : usize ) -> Self {
3685 CFileHandle {
37- handle_bytes : 0 ,
38- handle_type : 0 ,
39- f_handle : ptr:: null_mut ( ) ,
86+ wrapper : CFileHandleWrapper :: new ( size) . unwrap ( ) ,
4087 }
4188 }
4289}
@@ -47,14 +94,24 @@ unsafe impl Sync for CFileHandle {}
4794
4895impl Ord for CFileHandle {
4996 fn cmp ( & self , other : & Self ) -> Ordering {
50- if self . handle_bytes != other. handle_bytes {
51- return self . handle_bytes . cmp ( & other. handle_bytes ) ;
97+ let s_fh = self . wrapper . as_fam_struct_ref ( ) ;
98+ let o_fh = other. wrapper . as_fam_struct_ref ( ) ;
99+ if s_fh. handle_bytes != o_fh. handle_bytes {
100+ return s_fh. handle_bytes . cmp ( & o_fh. handle_bytes ) ;
52101 }
53- if self . handle_type != other. handle_type {
54- return self . handle_type . cmp ( & other. handle_type ) ;
102+ let length = s_fh. handle_bytes as usize ;
103+ if s_fh. handle_type != o_fh. handle_type {
104+ return s_fh. handle_type . cmp ( & o_fh. handle_type ) ;
105+ }
106+ unsafe {
107+ if s_fh. f_handle . as_ptr ( ) != o_fh. f_handle . as_ptr ( ) {
108+ return s_fh
109+ . f_handle
110+ . as_slice ( length)
111+ . cmp ( o_fh. f_handle . as_slice ( length) ) ;
112+ }
55113 }
56114
57- // f_handle is left to be compared by FileHandle's buf.
58115 Ordering :: Equal
59116 }
60117}
@@ -75,10 +132,11 @@ impl Eq for CFileHandle {}
75132
76133impl Debug for CFileHandle {
77134 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
135+ let fh = self . wrapper . as_fam_struct_ref ( ) ;
78136 write ! (
79137 f,
80138 "File handle: type {}, len {}" ,
81- self . handle_type, self . handle_bytes
139+ fh . handle_type, fh . handle_bytes
82140 )
83141 }
84142}
@@ -88,15 +146,13 @@ impl Debug for CFileHandle {
88146pub struct FileHandle {
89147 pub ( crate ) mnt_id : u64 ,
90148 handle : CFileHandle ,
91- // internal buffer for handle.f_handle
92- buf : Vec < libc:: c_char > ,
93149}
94150
95151extern "C" {
96152 fn name_to_handle_at (
97153 dirfd : libc:: c_int ,
98154 pathname : * const libc:: c_char ,
99- file_handle : * mut CFileHandle ,
155+ file_handle : * mut CFileHandleInner ,
100156 mount_id : * mut libc:: c_int ,
101157 flags : libc:: c_int ,
102158 ) -> libc:: c_int ;
@@ -105,7 +161,7 @@ extern "C" {
105161 // not to change it, so we can declare it `const`.
106162 fn open_by_handle_at (
107163 mount_fd : libc:: c_int ,
108- file_handle : * const CFileHandle ,
164+ file_handle : * const CFileHandleInner ,
109165 flags : libc:: c_int ,
110166 ) -> libc:: c_int ;
111167}
@@ -114,7 +170,7 @@ impl FileHandle {
114170 /// Create a file handle for the given file.
115171 pub fn from_name_at ( dir_fd : RawFd , path : & CStr ) -> io:: Result < Self > {
116172 let mut mount_id: libc:: c_int = 0 ;
117- let mut c_fh = CFileHandle :: new ( ) ;
173+ let mut c_fh = CFileHandle :: new ( 0 ) ;
118174
119175 // Per name_to_handle_at(2), the caller can discover the required size
120176 // for the file_handle structure by making a call in which
@@ -126,7 +182,7 @@ impl FileHandle {
126182 name_to_handle_at (
127183 dir_fd,
128184 path. as_ptr ( ) ,
129- & mut c_fh,
185+ c_fh. wrapper . as_mut_fam_struct_ptr ( ) ,
130186 & mut mount_id,
131187 libc:: AT_EMPTY_PATH ,
132188 )
@@ -141,18 +197,14 @@ impl FileHandle {
141197 return Err ( io:: Error :: from ( io:: ErrorKind :: InvalidData ) ) ;
142198 }
143199
144- let needed = c_fh. handle_bytes as usize ;
145- let mut buf = vec ! [ 0 ; needed] ;
146-
147- // get a unsafe pointer, FileHandle takes care of freeing the memory
148- // that 'f_handle' points to.
149- c_fh. f_handle = buf. as_mut_ptr ( ) ;
200+ let needed = c_fh. wrapper . as_fam_struct_ref ( ) . handle_bytes as usize ;
201+ let mut c_fh = CFileHandle :: new ( needed) ;
150202
151203 let ret = unsafe {
152204 name_to_handle_at (
153205 dir_fd,
154206 path. as_ptr ( ) ,
155- & mut c_fh,
207+ c_fh. wrapper . as_mut_fam_struct_ptr ( ) ,
156208 & mut mount_id,
157209 libc:: AT_EMPTY_PATH ,
158210 )
@@ -161,7 +213,6 @@ impl FileHandle {
161213 Ok ( FileHandle {
162214 mnt_id : mount_id as u64 ,
163215 handle : c_fh,
164- buf,
165216 } )
166217 } else {
167218 let e = io:: Error :: last_os_error ( ) ;
@@ -200,7 +251,13 @@ impl FileHandle {
200251 /// `mount_fd` must be an open non-`O_PATH` file descriptor for an inode on the same mount as
201252 /// the file to be opened, i.e. the mount given by `self.mnt_id`.
202253 fn open ( & self , mount_fd : & impl AsRawFd , flags : libc:: c_int ) -> io:: Result < File > {
203- let ret = unsafe { open_by_handle_at ( mount_fd. as_raw_fd ( ) , & self . handle , flags) } ;
254+ let ret = unsafe {
255+ open_by_handle_at (
256+ mount_fd. as_raw_fd ( ) ,
257+ self . handle . wrapper . as_fam_struct_ptr ( ) ,
258+ flags,
259+ )
260+ } ;
204261 if ret >= 0 {
205262 // Safe because `open_by_handle_at()` guarantees this is a valid fd
206263 let file = unsafe { File :: from_raw_fd ( ret) } ;
@@ -330,82 +387,92 @@ impl MountFds {
330387mod tests {
331388 use super :: * ;
332389
390+ fn generate_c_file_handle (
391+ handle_bytes : usize ,
392+ handle_type : libc:: c_int ,
393+ buf : Vec < libc:: c_char > ,
394+ ) -> CFileHandle {
395+ let mut wrapper = CFileHandle :: new ( handle_bytes) ;
396+ let fh = wrapper. wrapper . as_mut_fam_struct ( ) ;
397+ fh. handle_type = handle_type;
398+ unsafe {
399+ fh. f_handle
400+ . as_mut_slice ( handle_bytes)
401+ . copy_from_slice ( buf. as_slice ( ) ) ;
402+ }
403+
404+ wrapper
405+ }
406+
333407 #[ test]
334408 fn test_file_handle_derives ( ) {
335- let mut buf1 = vec ! [ 0 ; 128 ] ;
336- let h1 = CFileHandle {
337- handle_bytes : 128 ,
338- handle_type : 3 ,
339- f_handle : buf1. as_mut_ptr ( ) ,
340- } ;
409+ let h1 = generate_c_file_handle ( 128 , 3 , vec ! [ 0 ; 128 ] ) ;
341410 let mut fh1 = FileHandle {
342411 mnt_id : 0 ,
343412 handle : h1,
344- buf : buf1,
345413 } ;
346414
347- let mut buf2 = vec ! [ 0 ; 129 ] ;
348- let h2 = CFileHandle {
349- handle_bytes : 129 ,
350- handle_type : 3 ,
351- f_handle : buf2. as_mut_ptr ( ) ,
352- } ;
415+ let h2 = generate_c_file_handle ( 127 , 3 , vec ! [ 0 ; 127 ] ) ;
353416 let fh2 = FileHandle {
354417 mnt_id : 0 ,
355418 handle : h2,
356- buf : buf2,
357419 } ;
358420
359- let mut buf3 = vec ! [ 0 ; 128 ] ;
360- let h3 = CFileHandle {
361- handle_bytes : 128 ,
362- handle_type : 4 ,
363- f_handle : buf3. as_mut_ptr ( ) ,
364- } ;
421+ let h3 = generate_c_file_handle ( 128 , 4 , vec ! [ 0 ; 128 ] ) ;
365422 let fh3 = FileHandle {
366423 mnt_id : 0 ,
367424 handle : h3,
368- buf : buf3,
369425 } ;
370426
371- let mut buf4 = vec ! [ 1 ; 128 ] ;
372- let h4 = CFileHandle {
373- handle_bytes : 128 ,
374- handle_type : 3 ,
375- f_handle : buf4. as_mut_ptr ( ) ,
376- } ;
427+ let h4 = generate_c_file_handle ( 128 , 3 , vec ! [ 1 ; 128 ] ) ;
377428 let fh4 = FileHandle {
378429 mnt_id : 0 ,
379430 handle : h4,
380- buf : buf4,
381431 } ;
382432
383- let mut buf5 = vec ! [ 0 ; 128 ] ;
384- let h5 = CFileHandle {
385- handle_bytes : 128 ,
386- handle_type : 3 ,
387- f_handle : buf5. as_mut_ptr ( ) ,
388- } ;
433+ let h5 = generate_c_file_handle ( 128 , 3 , vec ! [ 0 ; 128 ] ) ;
389434 let mut fh5 = FileHandle {
390435 mnt_id : 0 ,
391436 handle : h5,
392- buf : buf5,
393437 } ;
394438
395- assert ! ( fh1 < fh2) ;
439+ assert ! ( fh1 > fh2) ;
396440 assert ! ( fh1 != fh2) ;
397441 assert ! ( fh1 < fh3) ;
398442 assert ! ( fh1 != fh3) ;
399443 assert ! ( fh1 < fh4) ;
400444 assert ! ( fh1 != fh4) ;
401-
402445 assert ! ( fh1 == fh5) ;
403- fh1. buf [ 0 ] = 1 ;
404- fh1. handle . f_handle = fh1. buf . as_mut_ptr ( ) ;
405- assert ! ( fh1 > fh5) ;
406446
407- fh5. buf [ 0 ] = 1 ;
408- fh5. handle . f_handle = fh5. buf . as_mut_ptr ( ) ;
447+ unsafe {
448+ fh1. handle
449+ . wrapper
450+ . as_mut_fam_struct ( )
451+ . f_handle
452+ . as_mut_slice ( 128 ) [ 0 ] = 1 ;
453+ }
454+ assert ! ( fh1 > fh5) ;
455+ unsafe {
456+ fh5. handle
457+ . wrapper
458+ . as_mut_fam_struct ( )
459+ . f_handle
460+ . as_mut_slice ( 128 ) [ 0 ] = 1 ;
461+ }
409462 assert ! ( fh1 == fh5) ;
410463 }
464+
465+ #[ test]
466+ fn test_c_file_handle_wrapper ( ) {
467+ let buf = ( 0 ..=127 ) . collect :: < Vec < libc:: c_char > > ( ) ;
468+ let mut wrapper = generate_c_file_handle ( MAX_HANDLE_SIZE , 3 , buf. clone ( ) ) ;
469+ let fh = wrapper. wrapper . as_mut_fam_struct ( ) ;
470+
471+ assert_eq ! ( fh. handle_bytes as usize , MAX_HANDLE_SIZE ) ;
472+ assert_eq ! ( fh. handle_type, 3 ) ;
473+ assert_eq ! (
474+ unsafe { fh. f_handle. as_slice( MAX_HANDLE_SIZE ) } ,
475+ buf. as_slice( ) ,
476+ ) ;
477+ }
411478}
0 commit comments