1111use alloc:: boxed:: Box ;
1212use core:: convert:: TryInto ;
1313use core:: marker:: PhantomPinned ;
14- use core:: mem:: MaybeUninit ;
1514use core:: pin:: Pin ;
1615
1716use crate :: bindings;
@@ -20,10 +19,67 @@ use crate::error::{Error, Result};
2019use crate :: file_operations;
2120use crate :: types:: CStr ;
2221
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+
2379struct RegistrationInner < const N : usize > {
2480 dev : bindings:: dev_t ,
2581 used : usize ,
26- cdevs : [ MaybeUninit < bindings :: cdev > ; N ] ,
82+ cdevs : [ Option < Cdev > ; N ] ,
2783 _pin : PhantomPinned ,
2884}
2985
@@ -96,10 +152,11 @@ impl<const N: usize> Registration<{ N }> {
96152 if res != 0 {
97153 return Err ( Error :: from_kernel_errno ( res) ) ;
98154 }
155+ const NONE : Option < Cdev > = None ;
99156 this. inner = Some ( RegistrationInner {
100157 dev,
101158 used : 0 ,
102- cdevs : [ MaybeUninit :: < bindings :: cdev > :: uninit ( ) ; N ] ,
159+ cdevs : [ NONE ; N ] ,
103160 _pin : PhantomPinned ,
104161 } ) ;
105162 }
@@ -108,22 +165,13 @@ impl<const N: usize> Registration<{ N }> {
108165 if inner. used == N {
109166 return Err ( Error :: EINVAL ) ;
110167 }
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) ;
127175 inner. used += 1 ;
128176 Ok ( ( ) )
129177 }
@@ -149,12 +197,14 @@ unsafe impl<const N: usize> Sync for Registration<{ N }> {}
149197impl < const N : usize > Drop for Registration < { N } > {
150198 fn drop ( & mut self ) {
151199 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`].
154207 unsafe {
155- for i in 0 ..inner. used {
156- bindings:: cdev_del ( inner. cdevs [ i] . as_mut_ptr ( ) ) ;
157- }
158208 bindings:: unregister_chrdev_region ( inner. dev , N . try_into ( ) . unwrap ( ) ) ;
159209 }
160210 }
0 commit comments