7
7
//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
8
8
9
9
use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
10
- use crate :: types:: { AlwaysRefCounted , Opaque } ;
11
- use crate :: { bindings, init:: PinInit , str:: CStr , try_pin_init, ThisModule } ;
12
- use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
10
+ use crate :: types:: { ARef , AlwaysRefCounted , Either , Opaque } ;
11
+ use crate :: { bindings, init:: PinInit , str:: CStr , time :: Timespec , try_pin_init, ThisModule } ;
12
+ use core:: { marker:: PhantomData , marker:: PhantomPinned , mem :: ManuallyDrop , pin:: Pin , ptr} ;
13
13
use macros:: { pin_data, pinned_drop} ;
14
14
15
15
/// Maximum size of an inode.
@@ -22,6 +22,12 @@ pub trait FileSystem {
22
22
23
23
/// Returns the parameters to initialise a super block.
24
24
fn super_params ( sb : & NewSuperBlock < Self > ) -> Result < SuperParams > ;
25
+
26
+ /// Initialises and returns the root inode of the given superblock.
27
+ ///
28
+ /// This is called during initialisation of a superblock after [`FileSystem::super_params`] has
29
+ /// completed successfully.
30
+ fn init_root ( sb : & SuperBlock < Self > ) -> Result < ARef < INode < Self > > > ;
25
31
}
26
32
27
33
/// A registration of a file system.
@@ -143,12 +149,136 @@ unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for INode<T> {
143
149
}
144
150
}
145
151
152
+ /// An inode that is locked and hasn't been initialised yet.
153
+ #[ repr( transparent) ]
154
+ pub struct NewINode < T : FileSystem + ?Sized > ( ARef < INode < T > > ) ;
155
+
156
+ impl < T : FileSystem + ?Sized > NewINode < T > {
157
+ /// Initialises the new inode with the given parameters.
158
+ pub fn init ( self , params : INodeParams ) -> Result < ARef < INode < T > > > {
159
+ // SAFETY: This is a new inode, so it's safe to manipulate it mutably.
160
+ let inode = unsafe { & mut * self . 0 . 0 . get ( ) } ;
161
+
162
+ let mode = match params. typ {
163
+ INodeType :: Dir => {
164
+ // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
165
+ inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
166
+
167
+ // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
168
+ inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
169
+ bindings:: S_IFDIR
170
+ }
171
+ } ;
172
+
173
+ inode. i_mode = ( params. mode & 0o777 ) | u16:: try_from ( mode) ?;
174
+ inode. i_size = params. size ;
175
+ inode. i_blocks = params. blocks ;
176
+
177
+ inode. __i_ctime = params. ctime . into ( ) ;
178
+ inode. i_mtime = params. mtime . into ( ) ;
179
+ inode. i_atime = params. atime . into ( ) ;
180
+
181
+ // SAFETY: inode is a new inode, so it is valid for write.
182
+ unsafe {
183
+ bindings:: set_nlink ( inode, params. nlink ) ;
184
+ bindings:: i_uid_write ( inode, params. uid ) ;
185
+ bindings:: i_gid_write ( inode, params. gid ) ;
186
+ bindings:: unlock_new_inode ( inode) ;
187
+ }
188
+
189
+ // SAFETY: We are manually destructuring `self` and preventing `drop` from being called.
190
+ Ok ( unsafe { ( & ManuallyDrop :: new ( self ) . 0 as * const ARef < INode < T > > ) . read ( ) } )
191
+ }
192
+ }
193
+
194
+ impl < T : FileSystem + ?Sized > Drop for NewINode < T > {
195
+ fn drop ( & mut self ) {
196
+ // SAFETY: The new inode failed to be turned into an initialised inode, so it's safe (and
197
+ // in fact required) to call `iget_failed` on it.
198
+ unsafe { bindings:: iget_failed ( self . 0 . 0 . get ( ) ) } ;
199
+ }
200
+ }
201
+
202
+ /// The type of the inode.
203
+ #[ derive( Copy , Clone ) ]
204
+ pub enum INodeType {
205
+ /// Directory type.
206
+ Dir ,
207
+ }
208
+
209
+ /// Required inode parameters.
210
+ ///
211
+ /// This is used when creating new inodes.
212
+ pub struct INodeParams {
213
+ /// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
214
+ /// everyone, the owner group, and the owner.
215
+ pub mode : u16 ,
216
+
217
+ /// Type of inode.
218
+ ///
219
+ /// Also carries additional per-type data.
220
+ pub typ : INodeType ,
221
+
222
+ /// Size of the contents of the inode.
223
+ ///
224
+ /// Its maximum value is [`MAX_LFS_FILESIZE`].
225
+ pub size : i64 ,
226
+
227
+ /// Number of blocks.
228
+ pub blocks : u64 ,
229
+
230
+ /// Number of links to the inode.
231
+ pub nlink : u32 ,
232
+
233
+ /// User id.
234
+ pub uid : u32 ,
235
+
236
+ /// Group id.
237
+ pub gid : u32 ,
238
+
239
+ /// Creation time.
240
+ pub ctime : Timespec ,
241
+
242
+ /// Last modification time.
243
+ pub mtime : Timespec ,
244
+
245
+ /// Last access time.
246
+ pub atime : Timespec ,
247
+ }
248
+
146
249
/// A file system super block.
147
250
///
148
251
/// Wraps the kernel's `struct super_block`.
149
252
#[ repr( transparent) ]
150
253
pub struct SuperBlock < T : FileSystem + ?Sized > ( Opaque < bindings:: super_block > , PhantomData < T > ) ;
151
254
255
+ impl < T : FileSystem + ?Sized > SuperBlock < T > {
256
+ /// Tries to get an existing inode or create a new one if it doesn't exist yet.
257
+ pub fn get_or_create_inode ( & self , ino : Ino ) -> Result < Either < ARef < INode < T > > , NewINode < T > > > {
258
+ // SAFETY: The only initialisation missing from the superblock is the root, and this
259
+ // function is needed to create the root, so it's safe to call it.
260
+ let inode =
261
+ ptr:: NonNull :: new ( unsafe { bindings:: iget_locked ( self . 0 . get ( ) , ino) } ) . ok_or ( ENOMEM ) ?;
262
+
263
+ // SAFETY: `inode` is valid for read, but there could be concurrent writers (e.g., if it's
264
+ // an already-initialised inode), so we use `read_volatile` to read its current state.
265
+ let state = unsafe { ptr:: read_volatile ( ptr:: addr_of!( ( * inode. as_ptr( ) ) . i_state) ) } ;
266
+ if state & u64:: from ( bindings:: I_NEW ) == 0 {
267
+ // The inode is cached. Just return it.
268
+ //
269
+ // SAFETY: `inode` had its refcount incremented by `iget_locked`; this increment is now
270
+ // owned by `ARef`.
271
+ Ok ( Either :: Left ( unsafe { ARef :: from_raw ( inode. cast ( ) ) } ) )
272
+ } else {
273
+ // SAFETY: The new inode is valid but not fully initialised yet, so it's ok to create a
274
+ // `NewINode`.
275
+ Ok ( Either :: Right ( NewINode ( unsafe {
276
+ ARef :: from_raw ( inode. cast ( ) )
277
+ } ) ) )
278
+ }
279
+ }
280
+ }
281
+
152
282
/// Required superblock parameters.
153
283
///
154
284
/// This is returned by implementations of [`FileSystem::super_params`].
@@ -215,41 +345,28 @@ impl<T: FileSystem + ?Sized> Tables<T> {
215
345
sb. 0 . s_blocksize = 1 << sb. 0 . s_blocksize_bits ;
216
346
sb. 0 . s_flags |= bindings:: SB_RDONLY ;
217
347
218
- // The following is scaffolding code that will be removed in a subsequent patch. It is
219
- // needed to build a root dentry, otherwise core code will BUG().
220
- // SAFETY: `sb` is the superblock being initialised, it is valid for read and write.
221
- let inode = unsafe { bindings:: new_inode ( & mut sb. 0 ) } ;
222
- if inode. is_null ( ) {
223
- return Err ( ENOMEM ) ;
224
- }
225
-
226
- // SAFETY: `inode` is valid for write.
227
- unsafe { bindings:: set_nlink ( inode, 2 ) } ;
228
-
229
- {
230
- // SAFETY: This is a newly-created inode. No other references to it exist, so it is
231
- // safe to mutably dereference it.
232
- let inode = unsafe { & mut * inode } ;
233
- inode. i_ino = 1 ;
234
- inode. i_mode = ( bindings:: S_IFDIR | 0o755 ) as _ ;
235
-
236
- // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
237
- inode. __bindgen_anon_3 . i_fop = unsafe { & bindings:: simple_dir_operations } ;
348
+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
349
+ // newly-created (and initialised above) superblock.
350
+ let sb = unsafe { & mut * sb_ptr. cast ( ) } ;
351
+ let root = T :: init_root ( sb) ?;
238
352
239
- // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
240
- inode. i_op = unsafe { & bindings:: simple_dir_inode_operations } ;
353
+ // Reject root inode if it belongs to a different superblock.
354
+ if !ptr:: eq ( root. super_block ( ) , sb) {
355
+ return Err ( EINVAL ) ;
241
356
}
242
357
243
358
// SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
244
359
// case for this call.
245
360
//
246
361
// It takes over the inode, even on failure, so we don't need to clean it up.
247
- let dentry = unsafe { bindings:: d_make_root ( inode ) } ;
362
+ let dentry = unsafe { bindings:: d_make_root ( ManuallyDrop :: new ( root ) . 0 . get ( ) ) } ;
248
363
if dentry. is_null ( ) {
249
364
return Err ( ENOMEM ) ;
250
365
}
251
366
252
- sb. 0 . s_root = dentry;
367
+ // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
368
+ // newly-created (and initialised above) superblock.
369
+ unsafe { ( * sb_ptr) . s_root = dentry } ;
253
370
254
371
Ok ( 0 )
255
372
} )
@@ -314,9 +431,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
314
431
///
315
432
/// ```
316
433
/// # mod module_fs_sample {
317
- /// use kernel::fs::{NewSuperBlock, SuperParams};
434
+ /// use kernel::fs::{INode, NewSuperBlock, SuperBlock , SuperParams};
318
435
/// use kernel::prelude::*;
319
- /// use kernel::{c_str, fs};
436
+ /// use kernel::{c_str, fs, types::ARef };
320
437
///
321
438
/// kernel::module_fs! {
322
439
/// type: MyFs,
@@ -332,6 +449,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
332
449
/// fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams> {
333
450
/// todo!()
334
451
/// }
452
+ /// fn init_root(_sb: &SuperBlock<Self>) -> Result<ARef<INode<Self>>> {
453
+ /// todo!()
454
+ /// }
335
455
/// }
336
456
/// # }
337
457
/// ```
0 commit comments