@@ -12,29 +12,34 @@ use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable};
12
12
use crate :: { str:: CStr , KernelModule , ThisModule } ;
13
13
use alloc:: boxed:: Box ;
14
14
use core:: marker:: { PhantomData , PhantomPinned } ;
15
- use core:: pin:: Pin ;
15
+ use core:: { mem :: MaybeUninit , pin:: Pin } ;
16
16
17
17
/// A registration of a miscellaneous device.
18
+ ///
19
+ /// # Invariants
20
+ ///
21
+ /// `Context` is always initialised when `registered` is `true`, and not initialised otherwise.
18
22
pub struct Registration < T : Sync = ( ) > {
19
23
registered : bool ,
20
24
mdev : bindings:: miscdevice ,
21
25
_pin : PhantomPinned ,
22
26
23
27
/// Context initialised on construction and made available to all file instances on
24
28
/// [`FileOpener::open`].
25
- pub context : T ,
29
+ open_data : MaybeUninit < T > ,
26
30
}
27
31
28
32
impl < T : Sync > Registration < T > {
29
33
/// Creates a new [`Registration`] but does not register it yet.
30
34
///
31
35
/// 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.
33
38
Self {
34
39
registered : false ,
35
40
mdev : bindings:: miscdevice:: default ( ) ,
36
41
_pin : PhantomPinned ,
37
- context ,
42
+ open_data : MaybeUninit :: uninit ( ) ,
38
43
}
39
44
}
40
45
@@ -44,10 +49,10 @@ impl<T: Sync> Registration<T> {
44
49
pub fn new_pinned < F : FileOpener < T > > (
45
50
name : & ' static CStr ,
46
51
minor : Option < i32 > ,
47
- context : T ,
52
+ open_data : T ,
48
53
) -> 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 ) ?;
51
56
Ok ( r)
52
57
}
53
58
@@ -59,6 +64,7 @@ impl<T: Sync> Registration<T> {
59
64
self : Pin < & mut Self > ,
60
65
name : & ' static CStr ,
61
66
minor : Option < i32 > ,
67
+ open_data : T ,
62
68
) -> Result {
63
69
// SAFETY: We must ensure that we never move out of `this`.
64
70
let this = unsafe { self . get_unchecked_mut ( ) } ;
@@ -72,31 +78,51 @@ impl<T: Sync> Registration<T> {
72
78
this. mdev . name = name. as_char_ptr ( ) ;
73
79
this. mdev . minor = minor. unwrap_or ( bindings:: MISC_DYNAMIC_MINOR as i32 ) ;
74
80
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
+
75
88
let ret = unsafe { bindings:: misc_register ( & mut this. mdev ) } ;
76
89
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 ( ) } ;
77
94
return Err ( Error :: from_kernel_errno ( ret) ) ;
78
95
}
79
- this . registered = true ;
96
+
80
97
Ok ( ( ) )
81
98
}
82
99
}
83
100
101
+ impl < T : Sync > Default for Registration < T > {
102
+ fn default ( ) -> Self {
103
+ Self :: new ( )
104
+ }
105
+ }
106
+
84
107
impl < T : Sync > FileOpenAdapter for Registration < T > {
85
108
type Arg = T ;
86
109
87
110
unsafe fn convert ( _inode : * mut bindings:: inode , file : * mut bindings:: file ) -> * const Self :: Arg {
88
111
// SAFETY: the caller must guarantee that `file` is valid.
89
112
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 ( ) }
91
118
}
92
119
}
93
120
94
121
// 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.
97
123
unsafe impl < T : Sync > Sync for Registration < T > { }
98
124
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
100
126
// `Send`, so is `Registration<T>`. `T` needs to be `Sync` because it's a requirement of
101
127
// `Registration<T>`.
102
128
unsafe impl < T : Send + Sync > Send for Registration < T > { }
@@ -105,7 +131,13 @@ impl<T: Sync> Drop for Registration<T> {
105
131
/// Removes the registration from the kernel if it has completed successfully before.
106
132
fn drop ( & mut self ) {
107
133
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 ( ) } ;
109
141
}
110
142
}
111
143
}
0 commit comments