6
6
//!
7
7
//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
8
8
9
- use crate :: error:: { code:: * , from_result, to_result, Error } ;
9
+ use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
10
10
use crate :: types:: Opaque ;
11
11
use crate :: { bindings, init:: PinInit , str:: CStr , try_pin_init, ThisModule } ;
12
12
use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin } ;
13
13
use macros:: { pin_data, pinned_drop} ;
14
14
15
+ /// Maximum size of an inode.
16
+ pub const MAX_LFS_FILESIZE : i64 = bindings:: MAX_LFS_FILESIZE ;
17
+
15
18
/// A file system type.
16
19
pub trait FileSystem {
17
20
/// The name of the file system type.
18
21
const NAME : & ' static CStr ;
22
+
23
+ /// Returns the parameters to initialise a super block.
24
+ fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams > ;
19
25
}
20
26
21
27
/// A registration of a file system.
@@ -49,7 +55,7 @@ impl Registration {
49
55
let fs = unsafe { & mut * fs_ptr } ;
50
56
fs. owner = module. 0 ;
51
57
fs. name = T :: NAME . as_char_ptr( ) ;
52
- fs. init_fs_context = Some ( Self :: init_fs_context_callback) ;
58
+ fs. init_fs_context = Some ( Self :: init_fs_context_callback:: < T > ) ;
53
59
fs. kill_sb = Some ( Self :: kill_sb_callback) ;
54
60
fs. fs_flags = 0 ;
55
61
@@ -60,13 +66,22 @@ impl Registration {
60
66
} )
61
67
}
62
68
63
- unsafe extern "C" fn init_fs_context_callback (
64
- _fc_ptr : * mut bindings:: fs_context ,
69
+ unsafe extern "C" fn init_fs_context_callback < T : FileSystem + ? Sized > (
70
+ fc_ptr : * mut bindings:: fs_context ,
65
71
) -> core:: ffi:: c_int {
66
- from_result ( || Err ( ENOTSUPP ) )
72
+ from_result ( || {
73
+ // SAFETY: The C callback API guarantees that `fc_ptr` is valid.
74
+ let fc = unsafe { & mut * fc_ptr } ;
75
+ fc. ops = & Tables :: < T > :: CONTEXT ;
76
+ Ok ( 0 )
77
+ } )
67
78
}
68
79
69
- unsafe extern "C" fn kill_sb_callback ( _sb_ptr : * mut bindings:: super_block ) { }
80
+ unsafe extern "C" fn kill_sb_callback ( sb_ptr : * mut bindings:: super_block ) {
81
+ // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
82
+ // the appropriate function to call for cleanup.
83
+ unsafe { bindings:: kill_anon_super ( sb_ptr) } ;
84
+ }
70
85
}
71
86
72
87
#[ pinned_drop]
@@ -79,6 +94,151 @@ impl PinnedDrop for Registration {
79
94
}
80
95
}
81
96
97
+ /// A file system super block.
98
+ ///
99
+ /// Wraps the kernel's `struct super_block`.
100
+ #[ repr( transparent) ]
101
+ pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
102
+
103
+ /// Required superblock parameters.
104
+ ///
105
+ /// This is returned by implementations of [`FileSystem::super_params`].
106
+ pub struct SuperParams {
107
+ /// The magic number of the superblock.
108
+ pub magic : u32 ,
109
+
110
+ /// The size of a block in powers of 2 (i.e., for a value of `n`, the size is `2^n`).
111
+ pub blocksize_bits : u8 ,
112
+
113
+ /// Maximum size of a file.
114
+ ///
115
+ /// The maximum allowed value is [`MAX_LFS_FILESIZE`].
116
+ pub maxbytes : i64 ,
117
+
118
+ /// Granularity of c/m/atime in ns (cannot be worse than a second).
119
+ pub time_gran : u32 ,
120
+ }
121
+
122
+ /// A superblock that is still being initialised.
123
+ ///
124
+ /// # Invariants
125
+ ///
126
+ /// The superblock is a newly-created one and this is the only active pointer to it.
127
+ #[ repr( transparent) ]
128
+ pub struct NewSuperBlock < T : FileSystem + ?Sized > ( bindings:: super_block , PhantomData < T > ) ;
129
+
130
+ struct Tables < T : FileSystem + ?Sized > ( T ) ;
131
+ impl < T : FileSystem + ?Sized > Tables < T > {
132
+ const CONTEXT : bindings:: fs_context_operations = bindings:: fs_context_operations {
133
+ free : None ,
134
+ parse_param : None ,
135
+ get_tree : Some ( Self :: get_tree_callback) ,
136
+ reconfigure : None ,
137
+ parse_monolithic : None ,
138
+ dup : None ,
139
+ } ;
140
+
141
+ unsafe extern "C" fn get_tree_callback ( fc : * mut bindings:: fs_context ) -> core:: ffi:: c_int {
142
+ // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
143
+ // the right type and is a valid callback.
144
+ unsafe { bindings:: get_tree_nodev ( fc, Some ( Self :: fill_super_callback) ) }
145
+ }
146
+
147
+ unsafe extern "C" fn fill_super_callback (
148
+ sb_ptr : * mut bindings:: super_block ,
149
+ _fc : * mut bindings:: fs_context ,
150
+ ) -> core:: ffi:: c_int {
151
+ from_result ( || {
152
+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
153
+ // newly-created superblock.
154
+ let sb = unsafe { & mut * sb_ptr. cast ( ) } ;
155
+ let params = T :: super_params ( sb) ?;
156
+
157
+ sb. 0 . s_magic = params. magic as _ ;
158
+ sb. 0 . s_op = & Tables :: < T > :: SUPER_BLOCK ;
159
+ sb. 0 . s_maxbytes = params. maxbytes ;
160
+ sb. 0 . s_time_gran = params. time_gran ;
161
+ sb. 0 . s_blocksize_bits = params. blocksize_bits ;
162
+ sb. 0 . s_blocksize = 1 ;
163
+ if sb. 0 . s_blocksize . leading_zeros ( ) < params. blocksize_bits . into ( ) {
164
+ return Err ( EINVAL ) ;
165
+ }
166
+ sb. 0 . s_blocksize = 1 << sb. 0 . s_blocksize_bits ;
167
+ sb. 0 . s_flags |= bindings:: SB_RDONLY ;
168
+
169
+ // The following is scaffolding code that will be removed in a subsequent patch. It is
170
+ // needed to build a root dentry, otherwise core code will BUG().
171
+ // SAFETY: `sb` is the superblock being initialised, it is valid for read and write.
172
+ let inode = unsafe { bindings:: new_inode ( & mut sb. 0 ) } ;
173
+ if inode. is_null ( ) {
174
+ return Err ( ENOMEM ) ;
175
+ }
176
+
177
+ // SAFETY: `inode` is valid for write.
178
+ unsafe { bindings:: set_nlink ( inode, 2 ) } ;
179
+
180
+ {
181
+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
182
+ // safe to mutably dereference it.
183
+ let inode = unsafe { & mut * inode } ;
184
+ inode. i_ino = 1 ;
185
+ inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _ ;
186
+
187
+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
188
+ inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
189
+
190
+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
191
+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
192
+ }
193
+
194
+ // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
195
+ // case for this call.
196
+ //
197
+ // It takes over the inode, even on failure, so we don't need to clean it up.
198
+ let dentry = unsafe { bindings:: d_make_root ( inode) } ;
199
+ if dentry. is_null ( ) {
200
+ return Err ( ENOMEM ) ;
201
+ }
202
+
203
+ sb. 0 . s_root = dentry;
204
+
205
+ Ok ( 0 )
206
+ } )
207
+ }
208
+
209
+ const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
210
+ alloc_inode : None ,
211
+ destroy_inode : None ,
212
+ free_inode : None ,
213
+ dirty_inode : None ,
214
+ write_inode : None ,
215
+ drop_inode : None ,
216
+ evict_inode : None ,
217
+ put_super : None ,
218
+ sync_fs : None ,
219
+ freeze_super : None ,
220
+ freeze_fs : None ,
221
+ thaw_super : None ,
222
+ unfreeze_fs : None ,
223
+ statfs : None ,
224
+ remount_fs : None ,
225
+ umount_begin : None ,
226
+ show_options : None ,
227
+ show_devname : None ,
228
+ show_path : None ,
229
+ show_stats : None ,
230
+ #[ cfg( CONFIG_QUOTA ) ]
231
+ quota_read : None ,
232
+ #[ cfg( CONFIG_QUOTA ) ]
233
+ quota_write : None ,
234
+ #[ cfg( CONFIG_QUOTA ) ]
235
+ get_dquots : None ,
236
+ nr_cached_objects : None ,
237
+ free_cached_objects : None ,
238
+ shutdown : None ,
239
+ } ;
240
+ }
241
+
82
242
/// Kernel module that exposes a single file system implemented by `T`.
83
243
#[ pin_data]
84
244
pub struct Module < T : FileSystem + ?Sized > {
@@ -105,6 +265,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
105
265
///
106
266
/// ```
107
267
/// # mod module_fs_sample {
268
+ /// use kernel::fs::{NewSuperBlock, SuperParams};
108
269
/// use kernel::prelude::*;
109
270
/// use kernel::{c_str, fs};
110
271
///
@@ -119,6 +280,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
119
280
/// struct MyFs;
120
281
/// impl fs::FileSystem for MyFs {
121
282
/// const NAME: &'static CStr = c_str!("myfs");
283
+ /// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams> {
284
+ /// todo!()
285
+ /// }
122
286
/// }
123
287
/// # }
124
288
/// ```
0 commit comments