@@ -12,29 +12,34 @@ use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable};
1212use crate :: { str:: CStr , KernelModule , ThisModule } ;
1313use alloc:: boxed:: Box ;
1414use core:: marker:: { PhantomData , PhantomPinned } ;
15- use core:: pin:: Pin ;
15+ use core:: { mem :: MaybeUninit , pin:: Pin } ;
1616
1717/// A registration of a miscellaneous device.
18+ ///
19+ /// # Invariants
20+ ///
21+ /// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
1822pub struct Registration < T : Sync = ( ) > {
1923 registered : bool ,
2024 mdev : bindings:: miscdevice ,
2125 _pin : PhantomPinned ,
2226
2327 /// Context initialised on construction and made available to all file instances on
2428 /// [`FileOpener::open`].
25- pub context : T ,
29+ open_data : MaybeUninit < T > ,
2630}
2731
2832impl < T : Sync > Registration < T > {
2933 /// Creates a new [`Registration`] but does not register it yet.
3034 ///
3135 /// It is allowed to move.
32- pub fn new ( context : T ) -> Self {
36+ pub fn new ( ) -> Self {
37+ // INVARIANT: `registered` is `false` and `open_data` is not initialised.
3338 Self {
3439 registered : false ,
3540 mdev : bindings:: miscdevice:: default ( ) ,
3641 _pin : PhantomPinned ,
37- context ,
42+ open_data : MaybeUninit :: uninit ( ) ,
3843 }
3944 }
4045
@@ -44,10 +49,10 @@ impl<T: Sync> Registration<T> {
4449 pub fn new_pinned < F : FileOpener < T > > (
4550 name : & ' static CStr ,
4651 minor : Option < i32 > ,
47- context : T ,
52+ open_data : T ,
4853 ) -> Result < Pin < Box < Self > > > {
49- let mut r = Pin :: from ( Box :: try_new ( Self :: new ( context ) ) ?) ;
50- r. as_mut ( ) . register :: < F > ( name, minor) ?;
54+ let mut r = Pin :: from ( Box :: try_new ( Self :: new ( ) ) ?) ;
55+ r. as_mut ( ) . register :: < F > ( name, minor, open_data ) ?;
5156 Ok ( r)
5257 }
5358
@@ -59,6 +64,7 @@ impl<T: Sync> Registration<T> {
5964 self : Pin < & mut Self > ,
6065 name : & ' static CStr ,
6166 minor : Option < i32 > ,
67+ open_data : T ,
6268 ) -> Result {
6369 // SAFETY: We must ensure that we never move out of `this`.
6470 let this = unsafe { self . get_unchecked_mut ( ) } ;
@@ -72,31 +78,51 @@ impl<T: Sync> Registration<T> {
7278 this. mdev . name = name. as_char_ptr ( ) ;
7379 this. mdev . minor = minor. unwrap_or ( bindings:: MISC_DYNAMIC_MINOR as i32 ) ;
7480
81+ // We write to `open_data` here because as soon as `misc_register` succeeds, the file can be
82+ // opened, so we need `open_data` configured ahead of time.
83+ //
84+ // INVARIANT: `registered` is set to `true`, but `open_data` is also initialised.
85+ this. registered = true ;
86+ this. open_data . write ( open_data) ;
87+
7588 let ret = unsafe { bindings:: misc_register ( & mut this. mdev ) } ;
7689 if ret < 0 {
90+ // INVARIANT: `registered` is set back to `false` and the `open_data` is destructued.
91+ this. registered = false ;
92+ // SAFETY: `open_data` was initialised a few lines above.
93+ unsafe { this. open_data . assume_init_drop ( ) } ;
7794 return Err ( Error :: from_kernel_errno ( ret) ) ;
7895 }
79- this . registered = true ;
96+
8097 Ok ( ( ) )
8198 }
8299}
83100
101+ impl < T : Sync > Default for Registration < T > {
102+ fn default ( ) -> Self {
103+ Self :: new ( )
104+ }
105+ }
106+
84107impl < T : Sync > FileOpenAdapter for Registration < T > {
85108 type Arg = T ;
86109
87110 unsafe fn convert ( _inode : * mut bindings:: inode , file : * mut bindings:: file ) -> * const Self :: Arg {
88111 // SAFETY: the caller must guarantee that `file` is valid.
89112 let reg = crate :: container_of!( unsafe { ( * file) . private_data } , Self , mdev) ;
90- unsafe { & ( * reg) . context }
113+
114+ // SAFETY: This function is only called while the misc device is still registered, so the
115+ // registration must be valid. Additionally, the type invariants guarantee that while the
116+ // miscdev is registered, `open_data` is initialised.
117+ unsafe { ( * reg) . open_data . as_ptr ( ) }
91118 }
92119}
93120
94121// SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it
95- // is safe to pass `&Registration` to multiple threads because it offers no interior mutability,
96- // except maybe through `Registration::context`, but it is itself `Sync`.
122+ // is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
97123unsafe impl < T : Sync > Sync for Registration < T > { }
98124
99- // SAFETY: All functions work from any thread. So as long as the `Registration::context ` is
125+ // SAFETY: All functions work from any thread. So as long as the `Registration::open_data ` is
100126// `Send`, so is `Registration<T>`. `T` needs to be `Sync` because it's a requirement of
101127// `Registration<T>`.
102128unsafe impl < T : Send + Sync > Send for Registration < T > { }
@@ -105,7 +131,13 @@ impl<T: Sync> Drop for Registration<T> {
105131 /// Removes the registration from the kernel if it has completed successfully before.
106132 fn drop ( & mut self ) {
107133 if self . registered {
108- unsafe { bindings:: misc_deregister ( & mut self . mdev ) }
134+ // SAFETY: `registered` being `true` indicates that a previous call to `misc_register`
135+ // succeeded.
136+ unsafe { bindings:: misc_deregister ( & mut self . mdev ) } ;
137+
138+ // SAFETY: The type invariant guarantees that `open_data` is initialised when
139+ // `registered` is `true`.
140+ unsafe { self . open_data . assume_init_drop ( ) } ;
109141 }
110142 }
111143}
0 commit comments