@@ -11,6 +11,7 @@ pub mod vec_ext;
11
11
/// Indicates an allocation error.
12
12
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
13
13
pub struct AllocError ;
14
+ use core:: { alloc:: Layout , ptr:: NonNull } ;
14
15
15
16
/// Flags to be used when allocating memory.
16
17
///
@@ -86,3 +87,104 @@ pub mod flags {
86
87
/// small allocations.
87
88
pub const GFP_NOWAIT : Flags = Flags ( bindings:: GFP_NOWAIT ) ;
88
89
}
90
+
91
+ /// The kernel's [`Allocator`] trait.
92
+ ///
93
+ /// An implementation of [`Allocator`] can allocate, re-allocate and free memory buffer described
94
+ /// via [`Layout`].
95
+ ///
96
+ /// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on
97
+ /// an object instance.
98
+ ///
99
+ /// In order to be able to support `#[derive(SmartPointer)]` later on, we need to avoid a design
100
+ /// that requires an `Allocator` to be instantiated, hence its functions must not contain any kind
101
+ /// of `self` parameter.
102
+ ///
103
+ /// # Safety
104
+ ///
105
+ /// A memory allocation returned from an allocator must remain valid until it is explicitly freed.
106
+ ///
107
+ /// Any pointer to a valid memory allocation must be valid to be passed to any other [`Allocator`]
108
+ /// function of the same type.
109
+ ///
110
+ /// Implementers must ensure that all trait functions abide by the guarantees documented in the
111
+ /// `# Guarantees` sections.
112
+ pub unsafe trait Allocator {
113
+ /// Allocate memory based on `layout` and `flags`.
114
+ ///
115
+ /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
116
+ /// constraints (i.e. minimum size and alignment as specified by `layout`).
117
+ ///
118
+ /// This function is equivalent to `realloc` when called with `None`.
119
+ ///
120
+ /// # Guarantees
121
+ ///
122
+ /// When the return value is `Ok(ptr)`, then `ptr` is
123
+ /// - valid for reads and writes for `layout.size()` bytes, until it is passed to
124
+ /// [`Allocator::free`] or [`Allocator::realloc`],
125
+ /// - aligned to `layout.align()`,
126
+ ///
127
+ /// Additionally, `Flags` are honored as documented in
128
+ /// <https://docs.kernel.org/core-api/mm-api.html#mm-api-gfp-flags>.
129
+ fn alloc ( layout : Layout , flags : Flags ) -> Result < NonNull < [ u8 ] > , AllocError > {
130
+ // SAFETY: Passing `None` to `realloc` is valid by it's safety requirements and asks for a
131
+ // new memory allocation.
132
+ unsafe { Self :: realloc ( None , layout, flags) }
133
+ }
134
+
135
+ /// Re-allocate an existing memory allocation to satisfy the requested `layout`.
136
+ ///
137
+ /// If the requested size is zero, `realloc` behaves equivalent to `free`.
138
+ ///
139
+ /// If the requested size is larger than the size of the existing allocation, a successful call
140
+ /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
141
+ /// may also be larger.
142
+ ///
143
+ /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
144
+ /// may not shrink the buffer; this is implementation specific to the allocator.
145
+ ///
146
+ /// On allocation failure, the existing buffer, if any, remains valid.
147
+ ///
148
+ /// The buffer is represented as `NonNull<[u8]>`.
149
+ ///
150
+ /// # Safety
151
+ ///
152
+ /// If `ptr == Some(p)`, then `p` must point to an existing and valid memory allocation created
153
+ /// by this allocator. The alignment encoded in `layout` must be smaller than or equal to the
154
+ /// alignment requested in the previous `alloc` or `realloc` call of the same allocation.
155
+ ///
156
+ /// Additionally, `ptr` is allowed to be `None`; in this case a new memory allocation is
157
+ /// created.
158
+ ///
159
+ /// # Guarantees
160
+ ///
161
+ /// This function has the same guarantees as [`Allocator::alloc`]. When `ptr == Some(p)`, then
162
+ /// it additionally guarantees that:
163
+ /// - the contents of the memory pointed to by `p` are preserved up to the lesser of the new
164
+ /// and old size,
165
+ /// and old size, i.e.
166
+ /// `ret_ptr[0..min(layout.size(), old_size)] == p[0..min(layout.size(), old_size)]`, where
167
+ /// `old_size` is the size of the allocation that `p` points at.
168
+
169
+ /// - when the return value is `Err(AllocError)`, then `p` is still valid.
170
+ unsafe fn realloc (
171
+ ptr : Option < NonNull < u8 > > ,
172
+ layout : Layout ,
173
+ flags : Flags ,
174
+ ) -> Result < NonNull < [ u8 ] > , AllocError > ;
175
+
176
+ /// Free an existing memory allocation.
177
+ ///
178
+ /// # Safety
179
+ ///
180
+ /// `ptr` must point to an existing and valid memory allocation created by this `Allocator` and
181
+ /// must not be a dangling pointer.
182
+ ///
183
+ /// The memory allocation at `ptr` must never again be read from or written to.
184
+ unsafe fn free ( ptr : NonNull < u8 > ) {
185
+ // SAFETY: The caller guarantees that `ptr` points at a valid allocation created by this
186
+ // allocator. We are passing a `Layout` with the smallest possible alignment, so it is
187
+ // smaller than or equal to the alignment previously used with this allocation.
188
+ let _ = unsafe { Self :: realloc ( Some ( ptr) , Layout :: new :: < ( ) > ( ) , Flags ( 0 ) ) } ;
189
+ }
190
+ }
0 commit comments