@@ -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,104 @@ 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 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