4
4
//!
5
5
//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h)
6
6
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
+ } ;
8
11
use 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
+ }
9
151
10
152
/// A file system type.
11
153
pub trait Type {
154
+ /// The context used to build fs configuration before it is mounted or reconfigured.
155
+ type Context : Context < Self > + ?Sized ;
156
+
12
157
/// The name of the file system type.
13
158
const NAME : & ' static CStr ;
14
159
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
+
15
165
/// The flags of this file system type.
16
166
///
17
167
/// It is a combination of the flags in the [`flags`] module.
@@ -78,7 +228,7 @@ impl Registration {
78
228
/// The file system is described by the [`Type`] argument.
79
229
///
80
230
/// 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 {
82
232
// SAFETY: We never move out of `this`.
83
233
let this = unsafe { self . get_unchecked_mut ( ) } ;
84
234
@@ -92,20 +242,81 @@ impl Registration {
92
242
fs. fs_flags = T :: FLAGS ;
93
243
fs. init_fs_context = Some ( Self :: init_fs_context_callback :: < T > ) ;
94
244
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
+
95
266
// SAFETY: Pointers stored in `fs` are either static so will live for as long as the
96
267
// 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 ( ) ;
98
270
this. is_registered = true ;
99
271
Ok ( ( ) )
100
272
}
101
273
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 ,
104
298
) -> 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
+ }
106
308
}
107
309
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
+ }
109
320
}
110
321
111
322
impl Drop for Registration {
0 commit comments