6
6
7
7
use crate :: {
8
8
bindings, error:: code:: * , error:: from_kernel_result, str:: CStr , to_result,
9
- types:: PointerWrapper , AlwaysRefCounted , Result , ScopeGuard , ThisModule ,
9
+ types:: PointerWrapper , AlwaysRefCounted , Error , Result , ScopeGuard , ThisModule ,
10
10
} ;
11
11
use core:: { cell:: UnsafeCell , marker:: PhantomPinned , pin:: Pin , ptr} ;
12
12
use macros:: vtable;
13
13
14
+ pub mod param;
15
+
14
16
/// A file system context.
15
17
///
16
18
/// It is used to gather configuration to then mount or reconfigure a file system.
@@ -19,18 +21,65 @@ pub trait Context<T: Type + ?Sized> {
19
21
/// Type of the data associated with the context.
20
22
type Data : PointerWrapper + Send + Sync + ' static ;
21
23
24
+ /// The typed file system parameters.
25
+ ///
26
+ /// Users are encouraged to define it using the [`crate::define_fs_params`] macro.
27
+ const PARAMS : param:: SpecTable < ' static , Self :: Data > = param:: SpecTable :: empty ( ) ;
28
+
22
29
/// Creates a new context.
23
30
fn try_new ( ) -> Result < Self :: Data > ;
31
+
32
+ /// Parses a parameter that wasn't specified in [`Self::PARAMS`].
33
+ fn parse_unknown_param (
34
+ _data : & mut Self :: Data ,
35
+ _name : & CStr ,
36
+ _value : param:: Value < ' _ > ,
37
+ ) -> Result {
38
+ Err ( ENOPARAM )
39
+ }
40
+
41
+ /// Parses the whole parameter block, potentially skipping regular handling for parts of it.
42
+ ///
43
+ /// The return value is the portion of the input buffer for which the regular handling
44
+ /// (involving [`Self::PARAMS`] and [`Self::parse_unknown_param`]) will still be carried out.
45
+ /// If it's `None`, the regular handling is not performed at all.
46
+ fn parse_monolithic < ' a > (
47
+ _data : & mut Self :: Data ,
48
+ _buf : Option < & ' a mut [ u8 ] > ,
49
+ ) -> Result < Option < & ' a mut [ u8 ] > > {
50
+ Ok ( None )
51
+ }
52
+ }
53
+
54
+ /// Borrows a pointer wrapper value mutably.
55
+ ///
56
+ /// # Safety
57
+ ///
58
+ /// Callers must ensure that `ptr` came from a previous call to `PointerWrapper::into_pointer`, and
59
+ /// that no other concurrent users of the pointer run at least until the returned `ScopeGuard` is
60
+ /// dropped.
61
+ unsafe fn borrow_mut < T : PointerWrapper > (
62
+ ptr : * const core:: ffi:: c_void ,
63
+ ) -> ScopeGuard < T , impl FnOnce ( T ) > {
64
+ // SAFETY: The safety requirements ensure that `ptr` came from a previous call to
65
+ // `into_pointer`.
66
+ ScopeGuard :: new_with_data ( unsafe { T :: from_pointer ( ptr) } , |d| {
67
+ d. into_pointer ( ) ;
68
+ } )
24
69
}
25
70
26
71
struct Tables < T : Type + ?Sized > ( T ) ;
27
72
impl < T : Type + ?Sized > Tables < T > {
28
73
const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
29
74
free : Some ( Self :: free_callback) ,
30
- parse_param : None ,
75
+ parse_param : Some ( Self :: parse_param_callback ) ,
31
76
get_tree : Some ( Self :: get_tree_callback) ,
32
77
reconfigure : Some ( Self :: reconfigure_callback) ,
33
- parse_monolithic : None ,
78
+ parse_monolithic : if <T :: Context as Context < T > >:: HAS_PARSE_MONOLITHIC {
79
+ Some ( Self :: parse_monolithic_callback)
80
+ } else {
81
+ None
82
+ } ,
34
83
dup : None ,
35
84
} ;
36
85
@@ -44,6 +93,54 @@ impl<T: Type + ?Sized> Tables<T> {
44
93
}
45
94
}
46
95
96
+ unsafe extern "C" fn parse_param_callback (
97
+ fc : * mut bindings:: fs_context ,
98
+ param : * mut bindings:: fs_parameter ,
99
+ ) -> core:: ffi:: c_int {
100
+ from_kernel_result ! {
101
+ // SAFETY: The callback contract guarantees that `fc` is valid.
102
+ let ptr = unsafe { ( * fc) . fs_private } ;
103
+
104
+ // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
105
+ // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
106
+ // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
107
+ // the callback contract guarantees that callbacks are serialised, so it is ok to
108
+ // mutably reference it.
109
+ let mut data = unsafe { borrow_mut:: <<T :: Context as Context <T >>:: Data >( ptr) } ;
110
+ let mut result = bindings:: fs_parse_result:: default ( ) ;
111
+ // SAFETY: All parameters are valid at least for the duration of the call.
112
+ let opt =
113
+ unsafe { bindings:: fs_parse( fc, T :: Context :: PARAMS . first, param, & mut result) } ;
114
+
115
+ // SAFETY: The callback contract guarantees that `param` is valid for the duration of
116
+ // the callback.
117
+ let param = unsafe { & * param } ;
118
+ if opt >= 0 {
119
+ let opt = opt as usize ;
120
+ if opt >= T :: Context :: PARAMS . handlers. len( ) {
121
+ return Err ( EINVAL ) ;
122
+ }
123
+ T :: Context :: PARAMS . handlers[ opt] . handle_param( & mut data, param, & result) ?;
124
+ return Ok ( 0 ) ;
125
+ }
126
+
127
+ if opt != ENOPARAM . to_kernel_errno( ) {
128
+ return Err ( Error :: from_kernel_errno( opt) ) ;
129
+ }
130
+
131
+ if !T :: Context :: HAS_PARSE_UNKNOWN_PARAM {
132
+ return Err ( ENOPARAM ) ;
133
+ }
134
+
135
+ let val = param:: Value :: from_fs_parameter( param) ;
136
+ // SAFETY: The callback contract guarantees the parameter key to be valid and last at
137
+ // least the duration of the callback.
138
+ T :: Context :: parse_unknown_param(
139
+ & mut data, unsafe { CStr :: from_char_ptr( param. key) } , val) ?;
140
+ Ok ( 0 )
141
+ }
142
+ }
143
+
47
144
unsafe extern "C" fn fill_super_callback (
48
145
sb_ptr : * mut bindings:: super_block ,
49
146
_fc : * mut bindings:: fs_context ,
@@ -64,6 +161,8 @@ impl<T: Type + ?Sized> Tables<T> {
64
161
sb. s_time_gran = 1 ;
65
162
66
163
// Create and initialise the root inode.
164
+
165
+ // SAFETY: `sb` was just created initialised, so it is safe pass it to `new_inode`.
67
166
let inode = unsafe { bindings:: new_inode( sb) } ;
68
167
if inode. is_null( ) {
69
168
return Err ( ENOMEM ) ;
@@ -117,6 +216,39 @@ impl<T: Type + ?Sized> Tables<T> {
117
216
EINVAL . to_kernel_errno ( )
118
217
}
119
218
219
+ unsafe extern "C" fn parse_monolithic_callback (
220
+ fc : * mut bindings:: fs_context ,
221
+ buf : * mut core:: ffi:: c_void ,
222
+ ) -> core:: ffi:: c_int {
223
+ from_kernel_result ! {
224
+ // SAFETY: The callback contract guarantees that `fc` is valid.
225
+ let ptr = unsafe { ( * fc) . fs_private } ;
226
+
227
+ // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
228
+ // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
229
+ // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
230
+ // the callback contract guarantees that callbacks are serialised, so it is ok to
231
+ // mutably reference it.
232
+ let mut data = unsafe { borrow_mut:: <<T :: Context as Context <T >>:: Data >( ptr) } ;
233
+ let page = if buf. is_null( ) {
234
+ None
235
+ } else {
236
+ // SAFETY: This callback is called to handle the `mount` syscall, which takes a
237
+ // page-sized buffer as data.
238
+ Some ( unsafe { & mut * ptr:: slice_from_raw_parts_mut( buf. cast( ) , crate :: PAGE_SIZE ) } )
239
+ } ;
240
+ let regular = T :: Context :: parse_monolithic( & mut data, page) ?;
241
+ if let Some ( buf) = regular {
242
+ // SAFETY: Both `fc` and `buf` are guaranteed to be valid; the former because the
243
+ // callback is still ongoing and the latter because its lifefime is tied to that of
244
+ // `page`, which is also valid for the duration of the callback.
245
+ to_result(
246
+ unsafe { bindings:: generic_parse_monolithic( fc, buf. as_mut_ptr( ) . cast( ) ) } ) ?;
247
+ }
248
+ Ok ( 0 )
249
+ }
250
+ }
251
+
120
252
const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
121
253
alloc_inode : None ,
122
254
destroy_inode : None ,
@@ -240,6 +372,7 @@ impl Registration {
240
372
fs. owner = module. 0 ;
241
373
fs. name = T :: NAME . as_char_ptr ( ) ;
242
374
fs. fs_flags = T :: FLAGS ;
375
+ fs. parameters = T :: Context :: PARAMS . first ;
243
376
fs. init_fs_context = Some ( Self :: init_fs_context_callback :: < T > ) ;
244
377
fs. kill_sb = Some ( Self :: kill_sb_callback :: < T > ) ;
245
378
@@ -372,3 +505,21 @@ unsafe impl AlwaysRefCounted for DEntry {
372
505
unsafe { bindings:: dput ( obj. cast ( ) . as_ptr ( ) ) }
373
506
}
374
507
}
508
+
509
+ /// Wraps the kernel's `struct filename`.
510
+ #[ repr( transparent) ]
511
+ pub struct Filename ( pub ( crate ) UnsafeCell < bindings:: filename > ) ;
512
+
513
+ impl Filename {
514
+ /// Creates a reference to a [`Filename`] from a valid pointer.
515
+ ///
516
+ /// # Safety
517
+ ///
518
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
519
+ /// returned [`Filename`] instance.
520
+ pub ( crate ) unsafe fn from_ptr < ' a > ( ptr : * const bindings:: filename ) -> & ' a Filename {
521
+ // SAFETY: The safety requirements guarantee the validity of the dereference, while the
522
+ // `Filename` type being transparent makes the cast ok.
523
+ unsafe { & * ptr. cast ( ) }
524
+ }
525
+ }
0 commit comments