@@ -11,6 +11,7 @@ pub mod vec_ext;
1111/// Indicates an allocation error.
1212#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
1313pub struct AllocError ;
14+ use core:: { alloc:: Layout , ptr:: NonNull } ;
1415
1516/// Flags to be used when allocating memory.
1617///
@@ -86,3 +87,103 @@ pub mod flags {
8687 /// small allocations.
8788 pub const GFP_NOWAIT : Flags = Flags ( bindings:: GFP_NOWAIT ) ;
8889}
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 it's 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