@@ -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,114 @@ 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+ //
113+ // Note that `Allocator::{realloc,free}` don't have an `old_layout` argument (like stdlib's
114+ // corresponding `Allocator` trait functions have), since the implemented (kernel) allocators
115+ // neither need nor honor such an argument. Thus, it would be misleading to make this API require it
116+ // anyways.
117+ //
118+ // More generally, this trait isn't intended for implementers to encode a lot of semantics, but
119+ // rather provide a thin generalization layer for the kernel's allocators.
120+ //
121+ // Depending on future requirements, the requirements for this trait may change as well and
122+ // implementing allocators that need to encode more semantics may become desirable.
123+ pub unsafe trait Allocator {
124+ /// Allocate memory based on `layout` and `flags`.
125+ ///
126+ /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
127+ /// constraints (i.e. minimum size and alignment as specified by `layout`).
128+ ///
129+ /// This function is equivalent to `realloc` when called with `None`.
130+ ///
131+ /// # Guarantees
132+ ///
133+ /// When the return value is `Ok(ptr)`, then `ptr` is
134+ /// - valid for reads and writes for `layout.size()` bytes, until it is passed to
135+ /// [`Allocator::free`] or [`Allocator::realloc`],
136+ /// - aligned to `layout.align()`,
137+ ///
138+ /// Additionally, `Flags` are honored as documented in
139+ /// <https://docs.kernel.org/core-api/mm-api.html#mm-api-gfp-flags>.
140+ fn alloc ( layout : Layout , flags : Flags ) -> Result < NonNull < [ u8 ] > , AllocError > {
141+ // SAFETY: Passing `None` to `realloc` is valid by it's safety requirements and asks for a
142+ // new memory allocation.
143+ unsafe { Self :: realloc ( None , layout, flags) }
144+ }
145+
146+ /// Re-allocate an existing memory allocation to satisfy the requested `layout`.
147+ ///
148+ /// If the requested size is zero, `realloc` behaves equivalent to `free`.
149+ ///
150+ /// If the requested size is larger than the size of the existing allocation, a successful call
151+ /// to `realloc` guarantees that the new or grown buffer has at least `Layout::size` bytes, but
152+ /// may also be larger.
153+ ///
154+ /// If the requested size is smaller than the size of the existing allocation, `realloc` may or
155+ /// may not shrink the buffer; this is implementation specific to the allocator.
156+ ///
157+ /// On allocation failure, the existing buffer, if any, remains valid.
158+ ///
159+ /// The buffer is represented as `NonNull<[u8]>`.
160+ ///
161+ /// # Safety
162+ ///
163+ /// If `ptr == Some(p)`, then `p` must point to an existing and valid memory allocation created
164+ /// by this allocator. The alignment encoded in `layout` must be smaller than or equal to the
165+ /// alignment requested in the previous `alloc` or `realloc` call of the same allocation.
166+ ///
167+ /// Additionally, `ptr` is allowed to be `None`; in this case a new memory allocation is
168+ /// created.
169+ ///
170+ /// # Guarantees
171+ ///
172+ /// This function has the same guarantees as [`Allocator::alloc`]. When `ptr == Some(p)`, then
173+ /// it additionally guarantees that:
174+ /// - the contents of the memory pointed to by `p` are preserved up to the lesser of the new
175+ /// and old size,
176+ /// and old size, i.e.
177+ /// `ret_ptr[0..min(layout.size(), old_size)] == p[0..min(layout.size(), old_size)]`, where
178+ /// `old_size` is the size of the allocation that `p` points at.
179+ /// - when the return value is `Err(AllocError)`, then `p` is still valid.
180+ unsafe fn realloc (
181+ ptr : Option < NonNull < u8 > > ,
182+ layout : Layout ,
183+ flags : Flags ,
184+ ) -> Result < NonNull < [ u8 ] > , AllocError > ;
185+
186+ /// Free an existing memory allocation.
187+ ///
188+ /// # Safety
189+ ///
190+ /// `ptr` must point to an existing and valid memory allocation created by this `Allocator` and
191+ /// must not be a dangling pointer.
192+ ///
193+ /// The memory allocation at `ptr` must never again be read from or written to.
194+ unsafe fn free ( ptr : NonNull < u8 > ) {
195+ // SAFETY: The caller guarantees that `ptr` points at a valid allocation created by this
196+ // allocator. We are passing a `Layout` with the smallest possible alignment, so it is
197+ // smaller than or equal to the alignment previously used with this allocation.
198+ let _ = unsafe { Self :: realloc ( Some ( ptr) , Layout :: new :: < ( ) > ( ) , Flags ( 0 ) ) } ;
199+ }
200+ }
0 commit comments