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,48 @@ 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
+ }
24
52
}
25
53
26
54
struct Tables < T : Type + ?Sized > ( T ) ;
27
55
impl < T : Type + ?Sized > Tables < T > {
28
56
const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
29
57
free : Some ( Self :: free_callback) ,
30
- parse_param : None ,
58
+ parse_param : Some ( Self :: parse_param_callback ) ,
31
59
get_tree : Some ( Self :: get_tree_callback) ,
32
60
reconfigure : Some ( Self :: reconfigure_callback) ,
33
- parse_monolithic : None ,
61
+ parse_monolithic : if <T :: Context as Context < T > >:: HAS_PARSE_MONOLITHIC {
62
+ Some ( Self :: parse_monolithic_callback)
63
+ } else {
64
+ None
65
+ } ,
34
66
dup : None ,
35
67
} ;
36
68
@@ -44,6 +76,55 @@ impl<T: Type + ?Sized> Tables<T> {
44
76
}
45
77
}
46
78
79
+ unsafe extern "C" fn parse_param_callback (
80
+ fc : * mut bindings:: fs_context ,
81
+ param : * mut bindings:: fs_parameter ,
82
+ ) -> core:: ffi:: c_int {
83
+ from_kernel_result ! {
84
+ // SAFETY: The callback contract guarantees that `fc` is valid.
85
+ let ptr = unsafe { ( * fc) . fs_private } ;
86
+
87
+ // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
88
+ // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
89
+ // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
90
+ // the callback contract guarantees that callbacks are serialised, so it is ok to
91
+ // mutably reference it.
92
+ let mut data =
93
+ unsafe { <<T :: Context as Context <T >>:: Data as PointerWrapper >:: borrow_mut( ptr) } ;
94
+ let mut result = bindings:: fs_parse_result:: default ( ) ;
95
+ // SAFETY: All parameters are valid at least for the duration of the call.
96
+ let opt =
97
+ unsafe { bindings:: fs_parse( fc, T :: Context :: PARAMS . first, param, & mut result) } ;
98
+
99
+ // SAFETY: The callback contract guarantees that `param` is valid for the duration of
100
+ // the callback.
101
+ let param = unsafe { & * param } ;
102
+ if opt >= 0 {
103
+ let opt = opt as usize ;
104
+ if opt >= T :: Context :: PARAMS . handlers. len( ) {
105
+ return Err ( EINVAL ) ;
106
+ }
107
+ T :: Context :: PARAMS . handlers[ opt] . handle_param( & mut data, param, & result) ?;
108
+ return Ok ( 0 ) ;
109
+ }
110
+
111
+ if opt != ENOPARAM . to_kernel_errno( ) {
112
+ return Err ( Error :: from_kernel_errno( opt) ) ;
113
+ }
114
+
115
+ if !T :: Context :: HAS_PARSE_UNKNOWN_PARAM {
116
+ return Err ( ENOPARAM ) ;
117
+ }
118
+
119
+ let val = param:: Value :: from_fs_parameter( param) ;
120
+ // SAFETY: The callback contract guarantees the parameter key to be valid and last at
121
+ // least the duration of the callback.
122
+ T :: Context :: parse_unknown_param(
123
+ & mut data, unsafe { CStr :: from_char_ptr( param. key) } , val) ?;
124
+ Ok ( 0 )
125
+ }
126
+ }
127
+
47
128
unsafe extern "C" fn fill_super_callback (
48
129
sb_ptr : * mut bindings:: super_block ,
49
130
_fc : * mut bindings:: fs_context ,
@@ -64,6 +145,8 @@ impl<T: Type + ?Sized> Tables<T> {
64
145
sb. s_time_gran = 1 ;
65
146
66
147
// Create and initialise the root inode.
148
+
149
+ // SAFETY: `sb` was just created initialised, so it is safe pass it to `new_inode`.
67
150
let inode = unsafe { bindings:: new_inode( sb) } ;
68
151
if inode. is_null( ) {
69
152
return Err ( ENOMEM ) ;
@@ -117,6 +200,40 @@ impl<T: Type + ?Sized> Tables<T> {
117
200
EINVAL . to_kernel_errno ( )
118
201
}
119
202
203
+ unsafe extern "C" fn parse_monolithic_callback (
204
+ fc : * mut bindings:: fs_context ,
205
+ buf : * mut core:: ffi:: c_void ,
206
+ ) -> core:: ffi:: c_int {
207
+ from_kernel_result ! {
208
+ // SAFETY: The callback contract guarantees that `fc` is valid.
209
+ let ptr = unsafe { ( * fc) . fs_private } ;
210
+
211
+ // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
212
+ // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
213
+ // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
214
+ // the callback contract guarantees that callbacks are serialised, so it is ok to
215
+ // mutably reference it.
216
+ let mut data =
217
+ unsafe { <<T :: Context as Context <T >>:: Data as PointerWrapper >:: borrow_mut( ptr) } ;
218
+ let page = if buf. is_null( ) {
219
+ None
220
+ } else {
221
+ // SAFETY: This callback is called to handle the `mount` syscall, which takes a
222
+ // page-sized buffer as data.
223
+ Some ( unsafe { & mut * ptr:: slice_from_raw_parts_mut( buf. cast( ) , crate :: PAGE_SIZE ) } )
224
+ } ;
225
+ let regular = T :: Context :: parse_monolithic( & mut data, page) ?;
226
+ if let Some ( buf) = regular {
227
+ // SAFETY: Both `fc` and `buf` are guaranteed to be valid; the former because the
228
+ // callback is still ongoing and the latter because its lifefime is tied to that of
229
+ // `page`, which is also valid for the duration of the callback.
230
+ to_result(
231
+ unsafe { bindings:: generic_parse_monolithic( fc, buf. as_mut_ptr( ) . cast( ) ) } ) ?;
232
+ }
233
+ Ok ( 0 )
234
+ }
235
+ }
236
+
120
237
const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
121
238
alloc_inode : None ,
122
239
destroy_inode : None ,
@@ -240,6 +357,7 @@ impl Registration {
240
357
fs. owner = module. 0 ;
241
358
fs. name = T :: NAME . as_char_ptr ( ) ;
242
359
fs. fs_flags = T :: FLAGS ;
360
+ fs. parameters = T :: Context :: PARAMS . first ;
243
361
fs. init_fs_context = Some ( Self :: init_fs_context_callback :: < T > ) ;
244
362
fs. kill_sb = Some ( Self :: kill_sb_callback :: < T > ) ;
245
363
@@ -372,3 +490,21 @@ unsafe impl AlwaysRefCounted for DEntry {
372
490
unsafe { bindings:: dput ( obj. cast ( ) . as_ptr ( ) ) }
373
491
}
374
492
}
493
+
494
+ /// Wraps the kernel's `struct filename`.
495
+ #[ repr( transparent) ]
496
+ pub struct Filename ( pub ( crate ) UnsafeCell < bindings:: filename > ) ;
497
+
498
+ impl Filename {
499
+ /// Creates a reference to a [`Filename`] from a valid pointer.
500
+ ///
501
+ /// # Safety
502
+ ///
503
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
504
+ /// returned [`Filename`] instance.
505
+ pub ( crate ) unsafe fn from_ptr < ' a > ( ptr : * const bindings:: filename ) -> & ' a Filename {
506
+ // SAFETY: The safety requirements guarantee the validity of the dereference, while the
507
+ // `Filename` type being transparent makes the cast ok.
508
+ unsafe { & * ptr. cast ( ) }
509
+ }
510
+ }
0 commit comments