44//!
55//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h)
66
7- use crate :: { bindings, error:: code:: * , str:: CStr , to_result, AlwaysRefCounted , Result , ThisModule } ;
7+ use crate :: {
8+ bindings, error:: code:: * , error:: from_kernel_result, str:: CStr , to_result,
9+ types:: PointerWrapper , AlwaysRefCounted , Result , ScopeGuard , ThisModule ,
10+ } ;
811use core:: { cell:: UnsafeCell , marker:: PhantomPinned , pin:: Pin , ptr} ;
12+ use macros:: vtable;
13+
14+ /// A file system context.
15+ ///
16+ /// It is used to gather configuration to then mount or reconfigure a file system.
17+ #[ vtable]
18+ pub trait Context < T : Type + ?Sized > {
19+ /// Type of the data associated with the context.
20+ type Data : PointerWrapper + Send + Sync + ' static ;
21+
22+ /// Creates a new context.
23+ fn try_new ( ) -> Result < Self :: Data > ;
24+ }
25+
26+ struct Tables < T : Type + ?Sized > ( T ) ;
27+ impl < T : Type + ?Sized > Tables < T > {
28+ const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
29+ free : Some ( Self :: free_callback) ,
30+ parse_param : None ,
31+ get_tree : Some ( Self :: get_tree_callback) ,
32+ reconfigure : Some ( Self :: reconfigure_callback) ,
33+ parse_monolithic : None ,
34+ dup : None ,
35+ } ;
36+
37+ unsafe extern "C" fn free_callback ( fc : * mut bindings:: fs_context ) {
38+ // SAFETY: The callback contract guarantees that `fc` is valid.
39+ let ptr = unsafe { ( * fc) . fs_private } ;
40+ if !ptr. is_null ( ) {
41+ // SAFETY: `fs_private` was initialised with the result of a `to_pointer` call in
42+ // `init_fs_context_callback`, so it's ok to call `from_pointer` here.
43+ unsafe { <T :: Context as Context < T > >:: Data :: from_pointer ( ptr) } ;
44+ }
45+ }
46+
47+ unsafe extern "C" fn fill_super_callback (
48+ sb_ptr : * mut bindings:: super_block ,
49+ _fc : * mut bindings:: fs_context ,
50+ ) -> core:: ffi:: c_int {
51+ from_kernel_result ! {
52+ // The following is temporary code to create the root inode and dentry. It will be
53+ // replaced with calls to Rust code.
54+
55+ // SAFETY: The callback contract guarantees that `sb_ptr` is the only pointer to a
56+ // newly-allocated superblock, so it is safe to mutably reference it.
57+ let sb = unsafe { & mut * sb_ptr } ;
58+
59+ sb. s_maxbytes = bindings:: MAX_LFS_FILESIZE ;
60+ sb. s_blocksize = crate :: PAGE_SIZE as _;
61+ sb. s_blocksize_bits = bindings:: PAGE_SHIFT as _;
62+ sb. s_magic = T :: MAGIC as _;
63+ sb. s_op = & Tables :: <T >:: SUPER_BLOCK ;
64+ sb. s_time_gran = 1 ;
65+
66+ // Create and initialise the root inode.
67+ let inode = unsafe { bindings:: new_inode( sb) } ;
68+ if inode. is_null( ) {
69+ return Err ( ENOMEM ) ;
70+ }
71+
72+ {
73+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
74+ // safe to mutably dereference it.
75+ let inode = unsafe { & mut * inode } ;
76+
77+ // SAFETY: `current_time` requires that `inode.sb` be valid, which is the case here
78+ // since we allocated the inode through the superblock.
79+ let time = unsafe { bindings:: current_time( inode) } ;
80+ inode. i_ino = 1 ;
81+ inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _;
82+ inode. i_mtime = time;
83+ inode. i_atime = time;
84+ inode. i_ctime = time;
85+
86+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
87+ inode. __bindgen_anon_3. i_fop = unsafe { & bindings:: simple_dir_operations } ;
88+
89+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
90+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
91+
92+ // SAFETY: `inode` is valid for write.
93+ unsafe { bindings:: set_nlink( inode, 2 ) } ;
94+ }
95+
96+ // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
97+ // case for this call.
98+ //
99+ // It takes over the inode, even on failure, so we don't need to clean it up.
100+ let dentry = unsafe { bindings:: d_make_root( inode) } ;
101+ if dentry. is_null( ) {
102+ return Err ( ENOMEM ) ;
103+ }
104+
105+ sb. s_root = dentry;
106+ Ok ( 0 )
107+ }
108+ }
109+
110+ unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
111+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has the
112+ // right type and is a valid callback.
113+ unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
114+ }
115+
116+ unsafe extern "C" fn reconfigure_callback ( _fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
117+ EINVAL . to_kernel_errno ( )
118+ }
119+
120+ const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
121+ alloc_inode : None ,
122+ destroy_inode : None ,
123+ free_inode : None ,
124+ dirty_inode : None ,
125+ write_inode : None ,
126+ drop_inode : None ,
127+ evict_inode : None ,
128+ put_super : None ,
129+ sync_fs : None ,
130+ freeze_super : None ,
131+ freeze_fs : None ,
132+ thaw_super : None ,
133+ unfreeze_fs : None ,
134+ statfs : None ,
135+ remount_fs : None ,
136+ umount_begin : None ,
137+ show_options : None ,
138+ show_devname : None ,
139+ show_path : None ,
140+ show_stats : None ,
141+ #[ cfg( CONFIG_QUOTA ) ]
142+ quota_read : None ,
143+ #[ cfg( CONFIG_QUOTA ) ]
144+ quota_write : None ,
145+ #[ cfg( CONFIG_QUOTA ) ]
146+ get_dquots : None ,
147+ nr_cached_objects : None ,
148+ free_cached_objects : None ,
149+ } ;
150+ }
9151
10152/// A file system type.
11153pub trait Type {
154+ /// The context used to build fs configuration before it is mounted or reconfigured.
155+ type Context : Context < Self > + ?Sized ;
156+
12157 /// The name of the file system type.
13158 const NAME : & ' static CStr ;
14159
160+ /// The magic number associated with the file system.
161+ ///
162+ /// This is normally one of the values in `include/uapi/linux/magic.h`.
163+ const MAGIC : u32 ;
164+
15165 /// The flags of this file system type.
16166 ///
17167 /// It is a combination of the flags in the [`flags`] module.
@@ -78,7 +228,7 @@ impl Registration {
78228 /// The file system is described by the [`Type`] argument.
79229 ///
80230 /// It is automatically unregistered when the registration is dropped.
81- pub fn register < T : Type > ( self : Pin < & mut Self > , module : & ' static ThisModule ) -> Result {
231+ pub fn register < T : Type + ? Sized > ( self : Pin < & mut Self > , module : & ' static ThisModule ) -> Result {
82232 // SAFETY: We never move out of `this`.
83233 let this = unsafe { self . get_unchecked_mut ( ) } ;
84234
@@ -92,20 +242,81 @@ impl Registration {
92242 fs. fs_flags = T :: FLAGS ;
93243 fs. init_fs_context = Some ( Self :: init_fs_context_callback :: < T > ) ;
94244 fs. kill_sb = Some ( Self :: kill_sb_callback :: < T > ) ;
245+
246+ // SAFETY: This block registers all fs type keys with lockdep. We just need the memory
247+ // locations to be owned by the caller, which is the case.
248+ unsafe {
249+ bindings:: lockdep_register_key ( & mut fs. s_lock_key ) ;
250+ bindings:: lockdep_register_key ( & mut fs. s_umount_key ) ;
251+ bindings:: lockdep_register_key ( & mut fs. s_vfs_rename_key ) ;
252+ bindings:: lockdep_register_key ( & mut fs. i_lock_key ) ;
253+ bindings:: lockdep_register_key ( & mut fs. i_mutex_key ) ;
254+ bindings:: lockdep_register_key ( & mut fs. invalidate_lock_key ) ;
255+ bindings:: lockdep_register_key ( & mut fs. i_mutex_dir_key ) ;
256+ for key in & mut fs. s_writers_key {
257+ bindings:: lockdep_register_key ( key) ;
258+ }
259+ }
260+
261+ let ptr = this. fs . get ( ) ;
262+
263+ // SAFETY: `ptr` as valid as it points to the `self.fs`.
264+ let key_guard = ScopeGuard :: new ( || unsafe { Self :: unregister_keys ( ptr) } ) ;
265+
95266 // SAFETY: Pointers stored in `fs` are either static so will live for as long as the
96267 // registration is active (it is undone in `drop`).
97- to_result ( unsafe { bindings:: register_filesystem ( this. fs . get ( ) ) } ) ?;
268+ to_result ( unsafe { bindings:: register_filesystem ( ptr) } ) ?;
269+ key_guard. dismiss ( ) ;
98270 this. is_registered = true ;
99271 Ok ( ( ) )
100272 }
101273
102- unsafe extern "C" fn init_fs_context_callback < T : Type > (
103- _fc_ptr : * mut bindings:: fs_context ,
274+ /// Unregisters the lockdep keys in the file system type.
275+ ///
276+ /// # Safety
277+ ///
278+ /// `fs` must be non-null and valid.
279+ unsafe fn unregister_keys ( fs : * mut bindings:: file_system_type ) {
280+ // SAFETY: This block unregisters all fs type keys from lockdep. They must have been
281+ // registered before.
282+ unsafe {
283+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . s_lock_key) ) ;
284+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . s_umount_key) ) ;
285+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . s_vfs_rename_key) ) ;
286+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . i_lock_key) ) ;
287+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . i_mutex_key) ) ;
288+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . invalidate_lock_key) ) ;
289+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . i_mutex_dir_key) ) ;
290+ for i in 0 ..( * fs) . s_writers_key . len ( ) {
291+ bindings:: lockdep_unregister_key ( ptr:: addr_of_mut!( ( * fs) . s_writers_key[ i] ) ) ;
292+ }
293+ }
294+ }
295+
296+ unsafe extern "C" fn init_fs_context_callback < T : Type + ?Sized > (
297+ fc_ptr : * mut bindings:: fs_context ,
104298 ) -> core:: ffi:: c_int {
105- EINVAL . to_kernel_errno ( )
299+ from_kernel_result ! {
300+ let data = T :: Context :: try_new( ) ?;
301+ // SAFETY: The callback contract guarantees that `fc_ptr` is the only pointer to a
302+ // newly-allocated fs context, so it is safe to mutably reference it.
303+ let fc = unsafe { & mut * fc_ptr } ;
304+ fc. fs_private = data. into_pointer( ) as _;
305+ fc. ops = & Tables :: <T >:: CONTEXT ;
306+ Ok ( 0 )
307+ }
106308 }
107309
108- unsafe extern "C" fn kill_sb_callback < T : Type > ( _sb_ptr : * mut bindings:: super_block ) { }
310+ unsafe extern "C" fn kill_sb_callback < T : Type + ?Sized > ( sb_ptr : * mut bindings:: super_block ) {
311+ // SAFETY: We always call `get_tree_nodev` from `get_tree_callback`, so we never have a
312+ // device, so it is ok to call the function below. Additionally, the callback contract
313+ // guarantees that `sb_ptr` is valid.
314+ unsafe { bindings:: kill_anon_super ( sb_ptr) }
315+
316+ // SAFETY: The callback contract guarantees that `sb_ptr` is valid, and the `kill_sb`
317+ // callback being called implies that the `s_type` is also valid.
318+ unsafe { Self :: unregister_keys ( ( * sb_ptr) . s_type ) } ;
319+ }
109320}
110321
111322impl Drop for Registration {
0 commit comments