@@ -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,103 @@ 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 buffers 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 its safety requirements and asks for a
131
+ // new memory allocation.
132
+ unsafe { Self :: realloc ( None , layout, Layout :: new :: < ( ) > ( ) , 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
153
+ /// created by this [`Allocator`]; if `old_layout` is zero-sized `p` does not need to be a
154
+ /// pointer returned by this [`Allocator`].
155
+ /// - `ptr` is allowed to be `None`; in this case a new memory allocation is created and
156
+ /// `old_layout` is ignored.
157
+ /// - `old_layout` must match the `Layout` the allocation has been created with.
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, i.e. `ret_ptr[0..min(layout.size(), old_layout.size())] ==
165
+ /// p[0..min(layout.size(), old_layout.size())]`.
166
+ /// - when the return value is `Err(AllocError)`, then `ptr` is still valid.
167
+ unsafe fn realloc (
168
+ ptr : Option < NonNull < u8 > > ,
169
+ layout : Layout ,
170
+ old_layout : Layout ,
171
+ flags : Flags ,
172
+ ) -> Result < NonNull < [ u8 ] > , AllocError > ;
173
+
174
+ /// Free an existing memory allocation.
175
+ ///
176
+ /// # Safety
177
+ ///
178
+ /// - `ptr` must point to an existing and valid memory allocation created by this [`Allocator`];
179
+ /// if `old_layout` is zero-sized `p` does not need to be a pointer returned by this
180
+ /// [`Allocator`].
181
+ /// - `layout` must match the `Layout` the allocation has been created with.
182
+ /// - The memory allocation at `ptr` must never again be read from or written to.
183
+ unsafe fn free ( ptr : NonNull < u8 > , layout : Layout ) {
184
+ // SAFETY: The caller guarantees that `ptr` points at a valid allocation created by this
185
+ // allocator. We are passing a `Layout` with the smallest possible alignment, so it is
186
+ // smaller than or equal to the alignment previously used with this allocation.
187
+ let _ = unsafe { Self :: realloc ( Some ( ptr) , Layout :: new :: < ( ) > ( ) , layout, Flags ( 0 ) ) } ;
188
+ }
189
+ }
0 commit comments