66
77use crate :: {
88 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 ,
1010} ;
1111use core:: { cell:: UnsafeCell , marker:: PhantomPinned , pin:: Pin , ptr} ;
1212use macros:: vtable;
1313
14+ pub mod param;
15+
1416/// A file system context.
1517///
1618/// It is used to gather configuration to then mount or reconfigure a file system.
@@ -19,18 +21,48 @@ pub trait Context<T: Type + ?Sized> {
1921 /// Type of the data associated with the context.
2022 type Data : PointerWrapper + Send + Sync + ' static ;
2123
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+
2229 /// Creates a new context.
2330 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+ }
2452}
2553
2654struct Tables < T : Type + ?Sized > ( T ) ;
2755impl < T : Type + ?Sized > Tables < T > {
2856 const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
2957 free : Some ( Self :: free_callback) ,
30- parse_param : None ,
58+ parse_param : Some ( Self :: parse_param_callback ) ,
3159 get_tree : Some ( Self :: get_tree_callback) ,
3260 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+ } ,
3466 dup : None ,
3567 } ;
3668
@@ -44,6 +76,55 @@ impl<T: Type + ?Sized> Tables<T> {
4476 }
4577 }
4678
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+
47128 unsafe extern "C" fn fill_super_callback (
48129 sb_ptr : * mut bindings:: super_block ,
49130 _fc : * mut bindings:: fs_context ,
@@ -64,6 +145,8 @@ impl<T: Type + ?Sized> Tables<T> {
64145 sb. s_time_gran = 1 ;
65146
66147 // Create and initialise the root inode.
148+
149+ // SAFETY: `sb` was just created initialised, so it is safe pass it to `new_inode`.
67150 let inode = unsafe { bindings:: new_inode( sb) } ;
68151 if inode. is_null( ) {
69152 return Err ( ENOMEM ) ;
@@ -117,6 +200,40 @@ impl<T: Type + ?Sized> Tables<T> {
117200 EINVAL . to_kernel_errno ( )
118201 }
119202
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+
120237 const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
121238 alloc_inode : None ,
122239 destroy_inode : None ,
@@ -240,6 +357,7 @@ impl Registration {
240357 fs. owner = module. 0 ;
241358 fs. name = T :: NAME . as_char_ptr ( ) ;
242359 fs. fs_flags = T :: FLAGS ;
360+ fs. parameters = T :: Context :: PARAMS . first ;
243361 fs. init_fs_context = Some ( Self :: init_fs_context_callback :: < T > ) ;
244362 fs. kill_sb = Some ( Self :: kill_sb_callback :: < T > ) ;
245363
@@ -372,3 +490,21 @@ unsafe impl AlwaysRefCounted for DEntry {
372490 unsafe { bindings:: dput ( obj. cast ( ) . as_ptr ( ) ) }
373491 }
374492}
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