@@ -9,34 +9,81 @@ use std::fmt::{Debug, Formatter};
9
9
use std:: fs:: File ;
10
10
use std:: io;
11
11
use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
12
- use std:: ptr;
13
12
use std:: sync:: { RwLock , RwLockReadGuard , RwLockWriteGuard } ;
14
13
14
+ use vmm_sys_util:: {
15
+ fam:: { FamStruct , FamStructWrapper } ,
16
+ generate_fam_struct_impl,
17
+ } ;
18
+
15
19
use crate :: passthrough:: PassthroughFs ;
16
20
17
21
/// An arbitrary maximum size for CFileHandle::f_handle.
18
22
///
19
23
/// According to Linux ABI, struct file_handle has a flexible array member 'f_handle', but it's
20
24
/// 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
+ }
22
49
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 ) ]
24
60
#[ 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 ) ]
25
79
struct 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 ,
32
81
}
33
82
34
83
impl CFileHandle {
35
- fn new ( ) -> Self {
84
+ fn new ( size : usize ) -> Self {
36
85
CFileHandle {
37
- handle_bytes : 0 ,
38
- handle_type : 0 ,
39
- f_handle : ptr:: null_mut ( ) ,
86
+ wrapper : CFileHandleWrapper :: new ( size) . unwrap ( ) ,
40
87
}
41
88
}
42
89
}
@@ -47,14 +94,24 @@ unsafe impl Sync for CFileHandle {}
47
94
48
95
impl Ord for CFileHandle {
49
96
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 ) ;
52
101
}
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
+ }
55
113
}
56
114
57
- // f_handle is left to be compared by FileHandle's buf.
58
115
Ordering :: Equal
59
116
}
60
117
}
@@ -75,10 +132,11 @@ impl Eq for CFileHandle {}
75
132
76
133
impl Debug for CFileHandle {
77
134
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
135
+ let fh = self . wrapper . as_fam_struct_ref ( ) ;
78
136
write ! (
79
137
f,
80
138
"File handle: type {}, len {}" ,
81
- self . handle_type, self . handle_bytes
139
+ fh . handle_type, fh . handle_bytes
82
140
)
83
141
}
84
142
}
@@ -88,15 +146,13 @@ impl Debug for CFileHandle {
88
146
pub struct FileHandle {
89
147
pub ( crate ) mnt_id : u64 ,
90
148
handle : CFileHandle ,
91
- // internal buffer for handle.f_handle
92
- buf : Vec < libc:: c_char > ,
93
149
}
94
150
95
151
extern "C" {
96
152
fn name_to_handle_at (
97
153
dirfd : libc:: c_int ,
98
154
pathname : * const libc:: c_char ,
99
- file_handle : * mut CFileHandle ,
155
+ file_handle : * mut CFileHandleInner ,
100
156
mount_id : * mut libc:: c_int ,
101
157
flags : libc:: c_int ,
102
158
) -> libc:: c_int ;
@@ -105,7 +161,7 @@ extern "C" {
105
161
// not to change it, so we can declare it `const`.
106
162
fn open_by_handle_at (
107
163
mount_fd : libc:: c_int ,
108
- file_handle : * const CFileHandle ,
164
+ file_handle : * const CFileHandleInner ,
109
165
flags : libc:: c_int ,
110
166
) -> libc:: c_int ;
111
167
}
@@ -114,7 +170,7 @@ impl FileHandle {
114
170
/// Create a file handle for the given file.
115
171
pub fn from_name_at ( dir_fd : RawFd , path : & CStr ) -> io:: Result < Self > {
116
172
let mut mount_id: libc:: c_int = 0 ;
117
- let mut c_fh = CFileHandle :: new ( ) ;
173
+ let mut c_fh = CFileHandle :: new ( 0 ) ;
118
174
119
175
// Per name_to_handle_at(2), the caller can discover the required size
120
176
// for the file_handle structure by making a call in which
@@ -126,7 +182,7 @@ impl FileHandle {
126
182
name_to_handle_at (
127
183
dir_fd,
128
184
path. as_ptr ( ) ,
129
- & mut c_fh,
185
+ c_fh. wrapper . as_mut_fam_struct_ptr ( ) ,
130
186
& mut mount_id,
131
187
libc:: AT_EMPTY_PATH ,
132
188
)
@@ -141,18 +197,14 @@ impl FileHandle {
141
197
return Err ( io:: Error :: from ( io:: ErrorKind :: InvalidData ) ) ;
142
198
}
143
199
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) ;
150
202
151
203
let ret = unsafe {
152
204
name_to_handle_at (
153
205
dir_fd,
154
206
path. as_ptr ( ) ,
155
- & mut c_fh,
207
+ c_fh. wrapper . as_mut_fam_struct_ptr ( ) ,
156
208
& mut mount_id,
157
209
libc:: AT_EMPTY_PATH ,
158
210
)
@@ -161,7 +213,6 @@ impl FileHandle {
161
213
Ok ( FileHandle {
162
214
mnt_id : mount_id as u64 ,
163
215
handle : c_fh,
164
- buf,
165
216
} )
166
217
} else {
167
218
let e = io:: Error :: last_os_error ( ) ;
@@ -200,7 +251,13 @@ impl FileHandle {
200
251
/// `mount_fd` must be an open non-`O_PATH` file descriptor for an inode on the same mount as
201
252
/// the file to be opened, i.e. the mount given by `self.mnt_id`.
202
253
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
+ } ;
204
261
if ret >= 0 {
205
262
// Safe because `open_by_handle_at()` guarantees this is a valid fd
206
263
let file = unsafe { File :: from_raw_fd ( ret) } ;
@@ -330,82 +387,92 @@ impl MountFds {
330
387
mod tests {
331
388
use super :: * ;
332
389
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
+
333
407
#[ test]
334
408
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 ] ) ;
341
410
let mut fh1 = FileHandle {
342
411
mnt_id : 0 ,
343
412
handle : h1,
344
- buf : buf1,
345
413
} ;
346
414
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 ] ) ;
353
416
let fh2 = FileHandle {
354
417
mnt_id : 0 ,
355
418
handle : h2,
356
- buf : buf2,
357
419
} ;
358
420
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 ] ) ;
365
422
let fh3 = FileHandle {
366
423
mnt_id : 0 ,
367
424
handle : h3,
368
- buf : buf3,
369
425
} ;
370
426
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 ] ) ;
377
428
let fh4 = FileHandle {
378
429
mnt_id : 0 ,
379
430
handle : h4,
380
- buf : buf4,
381
431
} ;
382
432
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 ] ) ;
389
434
let mut fh5 = FileHandle {
390
435
mnt_id : 0 ,
391
436
handle : h5,
392
- buf : buf5,
393
437
} ;
394
438
395
- assert ! ( fh1 < fh2) ;
439
+ assert ! ( fh1 > fh2) ;
396
440
assert ! ( fh1 != fh2) ;
397
441
assert ! ( fh1 < fh3) ;
398
442
assert ! ( fh1 != fh3) ;
399
443
assert ! ( fh1 < fh4) ;
400
444
assert ! ( fh1 != fh4) ;
401
-
402
445
assert ! ( fh1 == fh5) ;
403
- fh1. buf [ 0 ] = 1 ;
404
- fh1. handle . f_handle = fh1. buf . as_mut_ptr ( ) ;
405
- assert ! ( fh1 > fh5) ;
406
446
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
+ }
409
462
assert ! ( fh1 == fh5) ;
410
463
}
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
+ }
411
478
}
0 commit comments