@@ -16,10 +16,11 @@ pub mod ro {
16
16
use crate :: error:: { code:: * , from_result, to_result, Error , Result } ;
17
17
use crate :: types:: { ARef , AlwaysRefCounted , Either , ForeignOwnable , Opaque } ;
18
18
use crate :: {
19
- bindings, folio:: LockedFolio , init:: PinInit , str :: CStr , time :: Time , try_pin_init ,
20
- ThisModule ,
19
+ bindings, container_of , folio:: LockedFolio , init:: PinInit , mem_cache :: MemCache , str :: CStr ,
20
+ time :: Time , try_pin_init , ThisModule ,
21
21
} ;
22
- use core:: { marker:: PhantomData , marker:: PhantomPinned , mem:: ManuallyDrop , pin:: Pin , ptr} ;
22
+ use core:: mem:: { size_of, ManuallyDrop , MaybeUninit } ;
23
+ use core:: { marker:: PhantomData , marker:: PhantomPinned , pin:: Pin , ptr} ;
23
24
use macros:: { pin_data, pinned_drop} ;
24
25
25
26
/// Type of superblock keying.
@@ -38,6 +39,9 @@ pub mod ro {
38
39
/// Data associated with each file system instance (super-block).
39
40
type Data : ForeignOwnable + Send + Sync ;
40
41
42
+ /// Type of data associated with each inode.
43
+ type INodeData : Send + Sync ;
44
+
41
45
/// The name of the file system type.
42
46
const NAME : & ' static CStr ;
43
47
@@ -173,6 +177,7 @@ pub mod ro {
173
177
pub struct Registration {
174
178
#[ pin]
175
179
fs : Opaque < bindings:: file_system_type > ,
180
+ inode_cache : Option < MemCache > ,
176
181
#[ pin]
177
182
_pin : PhantomPinned ,
178
183
}
@@ -190,6 +195,14 @@ pub mod ro {
190
195
pub fn new < T : Type + ?Sized > ( module : & ' static ThisModule ) -> impl PinInit < Self , Error > {
191
196
try_pin_init ! ( Self {
192
197
_pin: PhantomPinned ,
198
+ inode_cache: if size_of:: <T :: INodeData >( ) == 0 {
199
+ None
200
+ } else {
201
+ Some ( MemCache :: try_new:: <INodeWithData <T :: INodeData >>(
202
+ T :: NAME ,
203
+ Some ( Self :: inode_init_once_callback:: <T >) ,
204
+ ) ?)
205
+ } ,
193
206
fs <- Opaque :: try_ffi_init( |fs_ptr| {
194
207
// SAFETY: `pin_init_from_closure` guarantees that `fs_ptr` is valid for write.
195
208
let fs = unsafe { & mut * fs_ptr } ;
@@ -244,6 +257,16 @@ pub mod ro {
244
257
unsafe { T :: Data :: from_foreign ( ptr) } ;
245
258
}
246
259
}
260
+
261
+ unsafe extern "C" fn inode_init_once_callback < T : Type + ?Sized > (
262
+ outer_inode : * mut core:: ffi:: c_void ,
263
+ ) {
264
+ let ptr = outer_inode. cast :: < INodeWithData < T :: INodeData > > ( ) ;
265
+
266
+ // SAFETY: This is only used in `new`, so we know that we have a valid `INodeWithData`
267
+ // instance whose inode part can be initialised.
268
+ unsafe { bindings:: inode_init_once ( ptr:: addr_of_mut!( ( * ptr) . inode) ) } ;
269
+ }
247
270
}
248
271
249
272
#[ pinned_drop]
@@ -280,6 +303,15 @@ pub mod ro {
280
303
unsafe { & * ( * self . 0 . get ( ) ) . i_sb . cast ( ) }
281
304
}
282
305
306
+ /// Returns the data associated with the inode.
307
+ pub fn data ( & self ) -> & T :: INodeData {
308
+ let outerp = container_of ! ( self . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
309
+ // SAFETY: `self` is guaranteed to be valid by the existence of a shared reference
310
+ // (`&self`) to it. Additionally, we know `T::INodeData` is always initialised in an
311
+ // `INode`.
312
+ unsafe { & * ( * outerp) . data . as_ptr ( ) }
313
+ }
314
+
283
315
/// Returns the size of the inode contents.
284
316
pub fn size ( & self ) -> i64 {
285
317
// SAFETY: `self` is guaranteed to be valid by the existence of a shared reference.
@@ -300,15 +332,29 @@ pub mod ro {
300
332
}
301
333
}
302
334
335
+ struct INodeWithData < T > {
336
+ data : MaybeUninit < T > ,
337
+ inode : bindings:: inode ,
338
+ }
339
+
303
340
/// An inode that is locked and hasn't been initialised yet.
304
341
#[ repr( transparent) ]
305
342
pub struct NewINode < T : Type + ?Sized > ( ARef < INode < T > > ) ;
306
343
307
344
impl < T : Type + ?Sized > NewINode < T > {
308
345
/// Initialises the new inode with the given parameters.
309
- pub fn init ( self , params : INodeParams ) -> Result < ARef < INode < T > > > {
310
- // SAFETY: This is a new inode, so it's safe to manipulate it mutably.
311
- let inode = unsafe { & mut * self . 0 . 0 . get ( ) } ;
346
+ pub fn init ( self , params : INodeParams < T :: INodeData > ) -> Result < ARef < INode < T > > > {
347
+ let outerp = container_of ! ( self . 0 . 0 . get( ) , INodeWithData <T :: INodeData >, inode) ;
348
+
349
+ // SAFETY: This is a newly-created inode. No other references to it exist, so it is
350
+ // safe to mutably dereference it.
351
+ let outer = unsafe { & mut * outerp. cast_mut ( ) } ;
352
+
353
+ // N.B. We must always write this to a newly allocated inode because the free callback
354
+ // expects the data to be initialised and drops it.
355
+ outer. data . write ( params. value ) ;
356
+
357
+ let inode = & mut outer. inode ;
312
358
313
359
let mode = match params. typ {
314
360
INodeType :: Dir => {
@@ -425,7 +471,7 @@ pub mod ro {
425
471
/// Required inode parameters.
426
472
///
427
473
/// This is used when creating new inodes.
428
- pub struct INodeParams {
474
+ pub struct INodeParams < T > {
429
475
/// The access mode. It's a mask that grants execute (1), write (2) and read (4) access to
430
476
/// everyone, the owner group, and the owner.
431
477
pub mode : u16 ,
@@ -460,6 +506,9 @@ pub mod ro {
460
506
461
507
/// Last access time.
462
508
pub atime : Time ,
509
+
510
+ /// Value to attach to this node.
511
+ pub value : T ,
463
512
}
464
513
465
514
/// A file system super block.
@@ -759,8 +808,12 @@ pub mod ro {
759
808
}
760
809
761
810
const SUPER_BLOCK : bindings:: super_operations = bindings:: super_operations {
762
- alloc_inode : None ,
763
- destroy_inode : None ,
811
+ alloc_inode : if size_of :: < T :: INodeData > ( ) != 0 {
812
+ Some ( Self :: alloc_inode_callback)
813
+ } else {
814
+ None
815
+ } ,
816
+ destroy_inode : Some ( Self :: destroy_inode_callback) ,
764
817
free_inode : None ,
765
818
dirty_inode : None ,
766
819
write_inode : None ,
@@ -790,6 +843,61 @@ pub mod ro {
790
843
shutdown : None ,
791
844
} ;
792
845
846
+ unsafe extern "C" fn alloc_inode_callback (
847
+ sb : * mut bindings:: super_block ,
848
+ ) -> * mut bindings:: inode {
849
+ // SAFETY: The callback contract guarantees that `sb` is valid for read.
850
+ let super_type = unsafe { ( * sb) . s_type } ;
851
+
852
+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
853
+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
854
+ // superblock associated to it.
855
+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
856
+
857
+ // SAFETY: `sb` and `cache` are guaranteed to be valid by the callback contract and by
858
+ // the existence of a superblock respectively.
859
+ let ptr = unsafe {
860
+ bindings:: alloc_inode_sb ( sb, MemCache :: ptr ( & reg. inode_cache ) , bindings:: GFP_KERNEL )
861
+ }
862
+ . cast :: < INodeWithData < T :: INodeData > > ( ) ;
863
+ if ptr. is_null ( ) {
864
+ return ptr:: null_mut ( ) ;
865
+ }
866
+ ptr:: addr_of_mut!( ( * ptr) . inode)
867
+ }
868
+
869
+ unsafe extern "C" fn destroy_inode_callback ( inode : * mut bindings:: inode ) {
870
+ // SAFETY: By the C contrat, inode is a valid pointer.
871
+ let is_bad = unsafe { bindings:: is_bad_inode ( inode) } ;
872
+
873
+ // SAFETY: The inode is guaranteed to be valid by the callback contract. Additionally,
874
+ // the superblock is also guaranteed to still be valid by the inode existence.
875
+ let super_type = unsafe { ( * ( * inode) . i_sb ) . s_type } ;
876
+
877
+ // SAFETY: This callback is only used in `Registration`, so `super_type` is necessarily
878
+ // embedded in a `Registration`, which is guaranteed to be valid because it has a
879
+ // superblock associated to it.
880
+ let reg = unsafe { & * container_of ! ( super_type, Registration , fs) } ;
881
+ let ptr = container_of ! ( inode, INodeWithData <T :: INodeData >, inode) . cast_mut ( ) ;
882
+
883
+ if !is_bad {
884
+ // SAFETY: The code either initialises the data or marks the inode as bad, since
885
+ // it's not bad, it's safey to drop it here.
886
+ unsafe { ptr:: drop_in_place ( ( * ptr) . data . as_mut_ptr ( ) ) } ;
887
+ }
888
+
889
+ if size_of :: < T :: INodeData > ( ) == 0 {
890
+ // SAFETY: When the size of `INodeData` is zero, we don't use a separate
891
+ // mem_cache, so it is allocated from the regular mem_cache, which is what
892
+ // `free_inode_nonrcu` uses to free the inode.
893
+ unsafe { bindings:: free_inode_nonrcu ( inode) } ;
894
+ } else {
895
+ // The callback contract guarantees that the inode was previously allocated via the
896
+ // `alloc_inode_callback` callback, so it is safe to free it back to the cache.
897
+ unsafe { bindings:: kmem_cache_free ( MemCache :: ptr ( & reg. inode_cache ) , ptr. cast ( ) ) } ;
898
+ }
899
+ }
900
+
793
901
unsafe extern "C" fn statfs_callback (
794
902
dentry : * mut bindings:: dentry ,
795
903
buf : * mut bindings:: kstatfs ,
@@ -1089,6 +1197,7 @@ pub mod ro {
1089
1197
/// impl fs::ro::Type for MyFs {
1090
1198
/// // ...
1091
1199
/// # type Data = ();
1200
+ /// # type INodeData = ();
1092
1201
/// # const NAME: &'static CStr = c_str!("myfs");
1093
1202
/// # fn fill_super(
1094
1203
/// # _: fs::ro::NewSuperBlock<'_, Self>
0 commit comments