9
9
use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
10
10
use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque } ;
11
11
use crate :: {
12
- bindings, folio:: LockedFolio , init:: PinInit , str :: CStr , time :: Timespec , try_pin_init ,
13
- ThisModule ,
12
+ bindings, container_of , folio:: LockedFolio , init:: PinInit , mem_cache :: MemCache , str :: CStr ,
13
+ time :: Timespec , try_pin_init , ThisModule ,
14
14
} ;
15
- use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
15
+ use core:: mem:: { size_of, ManuallyDrop , MaybeUninit } ;
16
+ use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
16
17
use macros:: { pin_data, pinned_drop} ;
17
18
18
19
#[ cfg( CONFIG_BUFFER_HEAD ) ]
@@ -37,6 +38,9 @@ pub trait FileSystem {
37
38
/// Data associated with each file system instance (super-block).
38
39
type Data : ForeignOwnable + Send + Sync ;
39
40
41
+ /// Type of data associated with each inode.
42
+ type INodeData : Send + Sync ;
43
+
40
44
/// The name of the file system type.
41
45
const NAME : & ' static CStr ;
42
46
@@ -161,6 +165,7 @@ impl core::convert::TryFrom<u32> for DirEntryType {
161
165
pub struct Registration {
162
166
#[ pin]
163
167
fs : Opaque < bindings:: file_system_type > ,
168
+ inode_cache : Option < MemCache > ,
164
169
#[ pin]
165
170
_pin : PhantomPinned ,
166
171
}
@@ -178,6 +183,14 @@ impl Registration {
178
183
pub fn new < T : FileSystem + ?Sized > ( module : & ' static ThisModule ) -> impl PinInit < Self , Error > {
179
184
try_pin_init ! ( Self {
180
185
_pin: PhantomPinned ,
186
+ inode_cache: if size_of:: <T :: INodeData >( ) == 0 {
187
+ None
188
+ } else {
189
+ Some ( MemCache :: try_new:: <INodeWithData <T :: INodeData >>(
190
+ T :: NAME ,
191
+ Some ( Self :: inode_init_once_callback:: <T >) ,
192
+ ) ?)
193
+ } ,
181
194
fs <- Opaque :: try_ffi_init( |fs_ptr| {
182
195
// SAFETY: `try_ffi_init` guarantees that `fs_ptr` is valid for write.
183
196
let fs = unsafe { & mut * fs_ptr } ;
@@ -232,6 +245,16 @@ impl Registration {
232
245
unsafe { T :: Data :: from_foreign ( ptr) } ;
233
246
}
234
247
}
248
+
249
+ unsafe extern "C" fn inode_init_once_callback < T : FileSystem + ?Sized > (
250
+ outer_inode : * mut core:: ffi:: c_void ,
251
+ ) {
252
+ let ptr = outer_inode. cast :: < INodeWithData < T :: INodeData > > ( ) ;
253
+
254
+ // SAFETY: This is only used in `new`, so we know that we have a valid `INodeWithData`
255
+ // instance whose inode part can be initialised.
256
+ unsafe { bindings:: inode_init_once ( ptr:: addr_of_mut!( ( * ptr) . inode) ) } ;
257
+ }
235
258
}
236
259
237
260
#[ pinned_drop]
@@ -270,6 +293,15 @@ impl<T: FileSystem + ?Sized> INode<T> {
270
293
unsafe { & * ( * self . 0 . get ( ) ) . i_sb . cast ( ) }
271
294
}
272
295
296
+ /// Returns the data associated with the inode.
297
+ pub fn data ( & self ) -> & T :: INodeData {
298
+ let outerp = container_of ! ( self . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
299
+ // SAFETY: `self` is guaranteed to be valid by the existence of a shared reference
300
+ // (`&self`) to it. Additionally, we know `T::INodeData` is always initialised in an
301
+ // `INode`.
302
+ unsafe { & * ( * outerp) . data . as_ptr ( ) }
303
+ }
304
+
273
305
/// Returns the size of the inode contents.
274
306
pub fn size ( & self ) -> i64 {
275
307
// SAFETY: `self` is guaranteed to be valid by the existence of a shared reference.
@@ -290,15 +322,29 @@ unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for INode<T> {
290
322
}
291
323
}
292
324
325
+ struct INodeWithData < T > {
326
+ data : MaybeUninit < T > ,
327
+ inode : bindings:: inode ,
328
+ }
329
+
293
330
/// An inode that is locked and hasn't been initialised yet.
294
331
#[ repr( transparent) ]
295
332
pub struct NewINode < T : FileSystem + ?Sized > ( ARef < INode < T > > ) ;
296
333
297
334
impl < T : FileSystem + ?Sized > NewINode < T > {
298
335
/// Initialises the new inode with the given parameters.
299
- pub fn init ( self , params : INodeParams ) -> Result < ARef < INode < T > > > {
300
- // SAFETY: This is a new inode, so it's safe to manipulate it mutably.
301
- let inode = unsafe { & mut * self . 0 . 0 . get ( ) } ;
336
+ pub fn init ( self , params : INodeParams < T :: INodeData > ) -> Result < ARef < INode < T > > > {
337
+ let outerp = container_of ! ( self . 0 . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
338
+
339
+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
340
+ // safe to mutably dereference it.
341
+ let outer = unsafe { & mut * outerp. cast_mut ( ) } ;
342
+
343
+ // N.B. We must always write this to a newly allocated inode because the free callback
344
+ // expects the data to be initialised and drops it.
345
+ outer. data . write ( params. value ) ;
346
+
347
+ let inode = & mut outer. inode ;
302
348
303
349
let mode = match params. typ {
304
350
INodeType :: Dir => {
@@ -414,7 +460,7 @@ pub enum INodeType {
414
460
/// Required inode parameters.
415
461
///
416
462
/// This is used when creating new inodes.
417
- pub struct INodeParams {
463
+ pub struct INodeParams < T > {
418
464
/// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
419
465
/// everyone, the owner group, and the owner.
420
466
pub mode : u16 ,
@@ -449,6 +495,9 @@ pub struct INodeParams {
449
495
450
496
/// Last access time.
451
497
pub atime : Timespec ,
498
+
499
+ /// Value to attach to this node.
500
+ pub value : T ,
452
501
}
453
502
454
503
/// A file system super block.
@@ -745,8 +794,12 @@ impl<T: FileSystem + ?Sized> Tables<T> {
745
794
}
746
795
747
796
const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
748
- alloc_inode : None ,
749
- destroy_inode : None ,
797
+ alloc_inode : if size_of :: < T :: INodeData > ( ) != 0 {
798
+ Some ( Self :: alloc_inode_callback)
799
+ } else {
800
+ None
801
+ } ,
802
+ destroy_inode : Some ( Self :: destroy_inode_callback) ,
750
803
free_inode : None ,
751
804
dirty_inode : None ,
752
805
write_inode : None ,
@@ -776,6 +829,61 @@ impl<T: FileSystem + ?Sized> Tables<T> {
776
829
shutdown : None ,
777
830
} ;
778
831
832
+ unsafe extern "C" fn alloc_inode_callback (
833
+ sb : * mut bindings:: super_block ,
834
+ ) -> * mut bindings:: inode {
835
+ // SAFETY: The callback contract guarantees that `sb` is valid for read.
836
+ let super_type = unsafe { ( * sb) . s_type } ;
837
+
838
+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
839
+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
840
+ // superblock associated to it.
841
+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
842
+
843
+ // SAFETY: `sb` and `cache` are guaranteed to be valid by the callback contract and by
844
+ // the existence of a superblock respectively.
845
+ let ptr = unsafe {
846
+ bindings:: alloc_inode_sb ( sb, MemCache :: ptr ( & reg. inode_cache ) , bindings:: GFP_KERNEL )
847
+ }
848
+ . cast :: < INodeWithData < T :: INodeData > > ( ) ;
849
+ if ptr. is_null ( ) {
850
+ return ptr:: null_mut ( ) ;
851
+ }
852
+ ptr:: addr_of_mut!( ( * ptr) . inode)
853
+ }
854
+
855
+ unsafe extern "C" fn destroy_inode_callback ( inode : * mut bindings:: inode ) {
856
+ // SAFETY: By the C contract, `inode` is a valid pointer.
857
+ let is_bad = unsafe { bindings:: is_bad_inode ( inode) } ;
858
+
859
+ // SAFETY: The inode is guaranteed to be valid by the callback contract. Additionally, the
860
+ // superblock is also guaranteed to still be valid by the inode existence.
861
+ let super_type = unsafe { ( * ( * inode) . i_sb ) . s_type } ;
862
+
863
+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
864
+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
865
+ // superblock associated to it.
866
+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
867
+ let ptr = container_of ! ( inode, INodeWithData <T :: INodeData >, inode) . cast_mut ( ) ;
868
+
869
+ if !is_bad {
870
+ // SAFETY: The code either initialises the data or marks the inode as bad. Since the
871
+ // inode is not bad, the data is initialised, and thus safe to drop.
872
+ unsafe { ptr:: drop_in_place ( ( * ptr) . data . as_mut_ptr ( ) ) } ;
873
+ }
874
+
875
+ if size_of :: < T :: INodeData > ( ) == 0 {
876
+ // SAFETY: When the size of `INodeData` is zero, we don't use a separate mem_cache, so
877
+ // it is allocated from the regular mem_cache, which is what `free_inode_nonrcu` uses
878
+ // to free the inode.
879
+ unsafe { bindings:: free_inode_nonrcu ( inode) } ;
880
+ } else {
881
+ // The callback contract guarantees that the inode was previously allocated via the
882
+ // `alloc_inode_callback` callback, so it is safe to free it back to the cache.
883
+ unsafe { bindings:: kmem_cache_free ( MemCache :: ptr ( & reg. inode_cache ) , ptr. cast ( ) ) } ;
884
+ }
885
+ }
886
+
779
887
unsafe extern "C" fn statfs_callback (
780
888
dentry : * mut bindings:: dentry ,
781
889
buf : * mut bindings:: kstatfs ,
@@ -1119,6 +1227,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
1119
1227
/// struct MyFs;
1120
1228
/// impl fs::FileSystem for MyFs {
1121
1229
/// type Data = ();
1230
+ /// type INodeData =();
1122
1231
/// const NAME: &'static CStr = c_str!("myfs");
1123
1232
/// fn fill_super(_: NewSuperBlock<'_, Self>) -> Result<&SuperBlock<Self>> {
1124
1233
/// todo!()
0 commit comments