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,69 @@ use crate::error::{Error, KernelResult};
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
+ ) -> KernelResult < 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 ) -> KernelResult < ( ) > {
57
+ // SAFETY: by the type invariants:
58
+ // - [`self.0`] is valid and non-null.
59
+ // - [`(*self.0).ops`] is valid, non-null, and has a static lifetime.
60
+ // - [`(*self.0).owner`] is valid and, if non-null, has module lifetime.
61
+ // This guarantees that [`(*self.0).ops`] and [`(*self.0).owner`] (if non-null)
62
+ // will live at least as long as [`self.0`].
63
+ // dev and count are scalars.
64
+ let rc = unsafe { bindings:: cdev_add ( self . 0 , dev, count) } ;
65
+ if rc != 0 {
66
+ return Err ( Error :: from_kernel_errno ( rc) ) ;
67
+ }
68
+ Ok ( ( ) )
69
+ }
70
+ }
71
+
72
+ impl Drop for Cdev {
73
+ fn drop ( & mut self ) {
74
+ // SAFETY: [`self.0`] is valid and non-null by the type invariants.
75
+ unsafe {
76
+ bindings:: cdev_del ( self . 0 ) ;
77
+ }
78
+ }
79
+ }
80
+
23
81
struct RegistrationInner < const N : usize > {
24
82
dev : bindings:: dev_t ,
25
83
used : usize ,
26
- cdevs : [ MaybeUninit < bindings :: cdev > ; N ] ,
84
+ cdevs : [ Option < Cdev > ; N ] ,
27
85
_pin : PhantomPinned ,
28
86
}
29
87
@@ -96,10 +154,11 @@ impl<const N: usize> Registration<{ N }> {
96
154
if res != 0 {
97
155
return Err ( Error :: from_kernel_errno ( res) ) ;
98
156
}
157
+ const NONE : Option < Cdev > = None ;
99
158
this. inner = Some ( RegistrationInner {
100
159
dev,
101
160
used : 0 ,
102
- cdevs : [ MaybeUninit :: < bindings :: cdev > :: uninit ( ) ; N ] ,
161
+ cdevs : [ NONE ; N ] ,
103
162
_pin : PhantomPinned ,
104
163
} ) ;
105
164
}
@@ -108,22 +167,13 @@ impl<const N: usize> Registration<{ N }> {
108
167
if inner. used == N {
109
168
return Err ( Error :: EINVAL ) ;
110
169
}
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
- }
170
+
171
+ // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
172
+ // registration.
173
+ let fops = unsafe { file_operations:: FileOperationsVtable :: < Self , T > :: build ( ) } ;
174
+ let mut cdev = Cdev :: alloc ( fops, & this. this_module ) ?;
175
+ cdev. add ( inner. dev + inner. used as bindings:: dev_t , 1 ) ?;
176
+ inner. cdevs [ inner. used ] . replace ( cdev) ;
127
177
inner. used += 1 ;
128
178
Ok ( ( ) )
129
179
}
@@ -149,12 +199,9 @@ unsafe impl<const N: usize> Sync for Registration<{ N }> {}
149
199
impl < const N : usize > Drop for Registration < { N } > {
150
200
fn drop ( & mut self ) {
151
201
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` .
202
+ // SAFETY: TODO needs explanation why unregister_chrdev_region
203
+ // is safe here .
154
204
unsafe {
155
- for i in 0 ..inner. used {
156
- bindings:: cdev_del ( inner. cdevs [ i] . as_mut_ptr ( ) ) ;
157
- }
158
205
bindings:: unregister_chrdev_region ( inner. dev , N . try_into ( ) . unwrap ( ) ) ;
159
206
}
160
207
}
0 commit comments