1use super::{Alloc, Slab, SlabFlags, SlabHdr, Uma, UmaFlags, small_alloc};
2use crate::config::{PAGE_MASK, PAGE_SHIFT, PAGE_SIZE};
3use crate::lock::Mutex;
4use crate::mem::Strong;
5use crate::vm::{PageObj, Vm, kaddr_to_phys};
6use alloc::collections::vec_deque::VecDeque;
7use alloc::sync::Arc;
8use core::alloc::Layout;
9use core::cmp::{max, min};
10use core::num::NonZero;
11use core::pin::Pin;
12use core::ptr::NonNull;
13use core::sync::atomic::{AtomicU32, Ordering};
14
15pub struct UmaKeg {
17 vm: &'static Vm,
18 size: NonZero<usize>, rsize: usize, pgoff: usize, ppera: usize, ipers: usize, alloc: fn(&'static Vm, Alloc) -> (*mut u8, SlabFlags), init: Option<fn()>, max_pages: usize, recurse: AtomicU32, flags: UmaFlags, state: Mutex<KegState>,
29}
30
31impl UmaKeg {
32 pub(super) fn new(
42 vm: &'static Vm,
43 size: NonZero<usize>,
44 align: usize,
45 init: Option<fn()>,
46 mut flags: UmaFlags,
47 ) -> Arc<Self> {
48 if flags.has_any(UmaFlags::Vm) {
49 todo!()
50 }
51
52 if flags.has_any(UmaFlags::ZInit) {
53 todo!()
54 }
55
56 if flags.has_any(UmaFlags::Malloc) {
57 flags |= UmaFlags::VToSlab;
58 }
59
60 let hdr = Layout::new::<SlabHdr>();
62 let (mut hdr, off) = hdr.extend(Layout::new::<u8>()).unwrap();
63
64 hdr = hdr.pad_to_align();
65
66 let free_item = hdr.size() - off;
68 let available = PAGE_SIZE.get() - hdr.size();
69
70 let (rsize, ppera, ipers) = if flags.has_any(UmaFlags::CacheSpread) {
72 let rsize = size.get().next_multiple_of(align + 1);
74 let align = align + 1;
75 let rsize = if (rsize & align) == 0 {
76 rsize + align
78 } else {
79 rsize
80 };
81
82 let pages = (PAGE_SIZE.get() / align * rsize) >> PAGE_SHIFT;
84 let ppera = min(pages, (128 * 1024) / PAGE_SIZE);
85
86 let ipers = (ppera * PAGE_SIZE.get() + (rsize - size.get())) / rsize;
88
89 (rsize, ppera, ipers)
90 } else {
91 if (size.get() + free_item) > available {
93 if !flags.has_any(UmaFlags::Internal) {
95 flags |= UmaFlags::Offpage;
96
97 if !flags.has_any(UmaFlags::VToSlab) {
98 flags |= UmaFlags::Hash;
99 }
100 }
101
102 let mut ppera = size.get() >> PAGE_SHIFT;
104
105 if size.get() > (size.get() & !PAGE_MASK.get()) {
106 ppera += 1;
107 }
108
109 (size.get(), ppera, 1)
110 } else {
111 let rsize = max(size, Uma::SMALLEST_UNIT);
113 let rsize = rsize.get().next_multiple_of(align + 1);
114
115 let mut ipers = available / (rsize + free_item);
117
118 if !flags.has_any(UmaFlags::Internal | UmaFlags::CacheOnly)
120 && (available % (rsize + free_item)) >= Uma::MAX_WASTE.get()
121 && (PAGE_SIZE.get() / rsize) > ipers
122 {
123 ipers = PAGE_SIZE.get() / rsize;
124
125 if flags.has_any(UmaFlags::VToSlab) {
126 flags |= UmaFlags::Offpage;
127 } else {
128 flags |= UmaFlags::Offpage | UmaFlags::Hash;
129 }
130 }
131
132 (rsize, 1, ipers)
133 }
134 };
135
136 if flags.has_any(UmaFlags::Offpage) {
137 }
139
140 let alloc = if ppera == 1 {
142 small_alloc
144 } else {
145 Self::page_alloc
146 };
147
148 if flags.has_any(UmaFlags::MtxClass) {
149 todo!()
150 }
151
152 let mut pgoff = 0;
154
155 if !flags.has_any(UmaFlags::Offpage) {
156 let space = ppera * PAGE_SIZE.get();
157
158 pgoff = (space - hdr.size()) - ipers * free_item;
160
161 if space < pgoff + hdr.size() + ipers * free_item {
163 panic!("UMA slab won't fit");
164 }
165 }
166
167 if flags.has_any(UmaFlags::Hash) {
168 todo!()
169 }
170
171 Arc::new(Self {
174 vm,
175 size,
176 rsize,
177 pgoff,
178 ppera,
179 ipers,
180 alloc,
181 init,
182 max_pages: 0,
183 recurse: AtomicU32::new(0),
184 flags,
185 state: Mutex::new(KegState {
186 pages: 0,
187 free: 0,
188 partial_slabs: VecDeque::new(),
189 }),
190 })
191 }
192
193 pub fn size(&self) -> NonZero<usize> {
194 self.size
195 }
196
197 pub fn allocated_size(&self) -> usize {
198 self.rsize
199 }
200
201 pub fn item_per_slab(&self) -> usize {
202 self.ipers
203 }
204
205 pub fn recurse(&self) -> u32 {
206 self.recurse.load(Ordering::Relaxed)
208 }
209
210 pub fn flags(&self) -> UmaFlags {
211 self.flags
212 }
213
214 pub(super) fn state(&self) -> &Mutex<KegState> {
215 &self.state
216 }
217
218 fn page_alloc(_: &'static Vm, _: Alloc) -> (*mut u8, SlabFlags) {
225 todo!()
226 }
227
228 pub unsafe fn fetch_slab(self: &Arc<Self>, mut flags: Alloc) -> Option<Pin<Strong<Slab>>> {
238 let mut state = self.state.lock();
239
240 while state.free == 0 {
241 if flags.has_any(Alloc::NoVm) {
242 return None;
243 }
244
245 #[allow(clippy::while_immutable_condition)] while self.max_pages != 0 && self.max_pages <= state.pages {
247 todo!()
248 }
249
250 self.recurse.fetch_add(1, Ordering::Relaxed);
251 let slab = self.alloc_slab(&mut state, flags);
252 self.recurse.fetch_sub(1, Ordering::Relaxed);
253
254 if let Some(slab) = slab {
255 let slab = unsafe { Pin::into_inner_unchecked(slab) };
258
259 state.partial_slabs.push_front(Strong::as_ptr(&slab));
260
261 return Some(unsafe { Pin::new_unchecked(slab) });
262 }
263
264 flags |= Alloc::NoVm;
265 }
266
267 if let Some(v) = state.partial_slabs.front().copied() {
268 return Some(unsafe { Pin::new_unchecked(Strong::new(v.as_ptr())) });
269 }
270
271 todo!()
272 }
273
274 fn alloc_slab(
281 self: &Arc<Self>,
282 state: &mut KegState,
283 flags: Alloc,
284 ) -> Option<Pin<Strong<Slab>>> {
285 if self.flags.has_any(UmaFlags::Offpage) {
286 todo!()
287 } else {
288 let flags = if self.flags.has_any(UmaFlags::Malloc) {
290 flags & !Alloc::Zero
291 } else {
292 flags | Alloc::Zero
293 };
294
295 let (mem, slab_flags) = (self.alloc)(self.vm, flags);
297
298 if !mem.is_null() {
299 let hdr = unsafe { mem.byte_add(self.pgoff).cast::<SlabHdr>() };
302
303 unsafe { hdr.write(SlabHdr::new(self.clone(), slab_flags, mem, self.ipers)) };
308
309 let (_, off) = Layout::new::<SlabHdr>()
311 .extend(Layout::new::<u8>())
312 .unwrap();
313 let free = unsafe { hdr.byte_add(off).cast::<u8>() };
314
315 for i in 0..self.ipers {
316 let item = (i + 1).try_into().unwrap();
317
318 unsafe { free.add(i).write(item) };
319 }
320
321 if self.init.is_some() {
322 todo!()
323 }
324
325 if self.flags.has_any(UmaFlags::Hash) {
326 todo!()
327 }
328
329 state.pages += self.ppera;
330 state.free += self.ipers;
331
332 let slab = core::ptr::slice_from_raw_parts_mut(hdr, self.ipers) as *mut Slab;
335 let slab = unsafe { Pin::new_unchecked(Strong::new(slab)) };
336
337 if self.flags.has_any(UmaFlags::VToSlab) {
338 let mut next = mem as usize;
339
340 for _ in 0..self.ppera {
341 let p = unsafe { kaddr_to_phys(next) };
342 let p = self.vm.phys_to_page(p).unwrap(); let mut s = p.state.lock();
344
345 s.object = Some(PageObj::Slab(slab.clone()));
349
350 drop(s);
351
352 next += PAGE_SIZE.get();
353 }
354 }
355
356 return Some(slab);
357 }
358
359 todo!()
360 }
361 }
362}
363
364pub(super) struct KegState {
366 pub(super) pages: usize, pub(super) free: usize, pub(super) partial_slabs: VecDeque<NonNull<Slab>>, }
370
371unsafe impl Send for KegState {}