11
11
use alloc:: boxed:: Box ;
12
12
use core:: convert:: TryInto ;
13
13
use core:: marker:: PhantomPinned ;
14
- use core:: mem:: MaybeUninit ;
15
14
use core:: pin:: Pin ;
16
15
17
16
use crate :: bindings;
@@ -20,10 +19,67 @@ use crate::error::{Error, Result};
20
19
use crate :: file_operations;
21
20
use crate :: types:: CStr ;
22
21
22
+ /// Character device.
23
+ ///
24
+ /// # Invariants
25
+ ///
26
+ /// - [`self.0`] is valid and non-null.
27
+ /// - [`(*self.0).ops`] is valid, non-null and has static lifetime.
28
+ /// - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
29
+ struct Cdev ( * mut bindings:: cdev ) ;
30
+
31
+ impl Cdev {
32
+ fn alloc (
33
+ fops : & ' static bindings:: file_operations ,
34
+ module : & ' static crate :: ThisModule ,
35
+ ) -> Result < Self > {
36
+ // SAFETY: FFI call.
37
+ let cdev = unsafe { bindings:: cdev_alloc ( ) } ;
38
+ if cdev. is_null ( ) {
39
+ return Err ( Error :: ENOMEM ) ;
40
+ }
41
+ // SAFETY: `cdev` is valid and non-null since `cdev_alloc()`
42
+ // returned a valid pointer which was null-checked.
43
+ unsafe {
44
+ ( * cdev) . ops = fops;
45
+ ( * cdev) . owner = module. 0 ;
46
+ }
47
+ // INVARIANTS:
48
+ // - [`self.0`] is valid and non-null.
49
+ // - [`(*self.0).ops`] is valid, non-null and has static lifetime,
50
+ // because it was coerced from a reference with static lifetime.
51
+ // - [`(*self.0).owner`] is valid and, if non-null, has module lifetime,
52
+ // guaranteed by the [`ThisModule`] invariant.
53
+ Ok ( Self ( cdev) )
54
+ }
55
+
56
+ fn add ( & mut self , dev : bindings:: dev_t , count : c_types:: c_uint ) -> Result {
57
+ // SAFETY: according to the type invariants:
58
+ // - [`self.0`] can be safely passed to [`bindings::cdev_add`].
59
+ // - [`(*self.0).ops`] will live at least as long as [`self.0`].
60
+ // - [`(*self.0).owner`] will live at least as long as the
61
+ // module, which is an implicit requirement.
62
+ let rc = unsafe { bindings:: cdev_add ( self . 0 , dev, count) } ;
63
+ if rc != 0 {
64
+ return Err ( Error :: from_kernel_errno ( rc) ) ;
65
+ }
66
+ Ok ( ( ) )
67
+ }
68
+ }
69
+
70
+ impl Drop for Cdev {
71
+ fn drop ( & mut self ) {
72
+ // SAFETY: [`self.0`] is valid and non-null by the type invariants.
73
+ unsafe {
74
+ bindings:: cdev_del ( self . 0 ) ;
75
+ }
76
+ }
77
+ }
78
+
23
79
struct RegistrationInner < const N : usize > {
24
80
dev : bindings:: dev_t ,
25
81
used : usize ,
26
- cdevs : [ MaybeUninit < bindings :: cdev > ; N ] ,
82
+ cdevs : [ Option < Cdev > ; N ] ,
27
83
_pin : PhantomPinned ,
28
84
}
29
85
@@ -96,10 +152,11 @@ impl<const N: usize> Registration<{ N }> {
96
152
if res != 0 {
97
153
return Err ( Error :: from_kernel_errno ( res) ) ;
98
154
}
155
+ const NONE : Option < Cdev > = None ;
99
156
this. inner = Some ( RegistrationInner {
100
157
dev,
101
158
used : 0 ,
102
- cdevs : [ MaybeUninit :: < bindings :: cdev > :: uninit ( ) ; N ] ,
159
+ cdevs : [ NONE ; N ] ,
103
160
_pin : PhantomPinned ,
104
161
} ) ;
105
162
}
@@ -108,22 +165,13 @@ impl<const N: usize> Registration<{ N }> {
108
165
if inner. used == N {
109
166
return Err ( Error :: EINVAL ) ;
110
167
}
111
- let cdev = inner. cdevs [ inner. used ] . as_mut_ptr ( ) ;
112
- // SAFETY: Calling unsafe functions and manipulating `MaybeUninit`
113
- // pointer.
114
- unsafe {
115
- bindings:: cdev_init (
116
- cdev,
117
- // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
118
- // registration.
119
- file_operations:: FileOperationsVtable :: < Self , T > :: build ( ) ,
120
- ) ;
121
- ( * cdev) . owner = this. this_module . 0 ;
122
- let rc = bindings:: cdev_add ( cdev, inner. dev + inner. used as bindings:: dev_t , 1 ) ;
123
- if rc != 0 {
124
- return Err ( Error :: from_kernel_errno ( rc) ) ;
125
- }
126
- }
168
+
169
+ // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
170
+ // registration.
171
+ let fops = unsafe { file_operations:: FileOperationsVtable :: < Self , T > :: build ( ) } ;
172
+ let mut cdev = Cdev :: alloc ( fops, & this. this_module ) ?;
173
+ cdev. add ( inner. dev + inner. used as bindings:: dev_t , 1 ) ?;
174
+ inner. cdevs [ inner. used ] . replace ( cdev) ;
127
175
inner. used += 1 ;
128
176
Ok ( ( ) )
129
177
}
@@ -149,12 +197,14 @@ unsafe impl<const N: usize> Sync for Registration<{ N }> {}
149
197
impl < const N : usize > Drop for Registration < { N } > {
150
198
fn drop ( & mut self ) {
151
199
if let Some ( inner) = self . inner . as_mut ( ) {
152
- // SAFETY: Calling unsafe functions, `0..inner.used` of
153
- // `inner.cdevs` are initialized in `Registration::register`.
200
+ // Replicate kernel C behaviour: drop [`Cdev`]s before calling
201
+ // [`bindings::unregister_chrdev_region`].
202
+ for i in 0 ..inner. used {
203
+ inner. cdevs [ i] . take ( ) ;
204
+ }
205
+ // SAFETY: [`self.inner`] is Some, so [`inner.dev`] was previously
206
+ // created using [`bindings::alloc_chrdev_region`].
154
207
unsafe {
155
- for i in 0 ..inner. used {
156
- bindings:: cdev_del ( inner. cdevs [ i] . as_mut_ptr ( ) ) ;
157
- }
158
208
bindings:: unregister_chrdev_region ( inner. dev , N . try_into ( ) . unwrap ( ) ) ;
159
209
}
160
210
}
0 commit comments