1*7937dca7SDanilo Krummrich // SPDX-License-Identifier: GPL-2.0 2*7937dca7SDanilo Krummrich 3*7937dca7SDanilo Krummrich use super::Vmalloc; 4*7937dca7SDanilo Krummrich use crate::page; 5*7937dca7SDanilo Krummrich use core::marker::PhantomData; 6*7937dca7SDanilo Krummrich use core::ptr::NonNull; 7*7937dca7SDanilo Krummrich 8*7937dca7SDanilo Krummrich /// An [`Iterator`] of [`page::BorrowedPage`] items owned by a [`Vmalloc`] allocation. 9*7937dca7SDanilo Krummrich /// 10*7937dca7SDanilo Krummrich /// # Guarantees 11*7937dca7SDanilo Krummrich /// 12*7937dca7SDanilo Krummrich /// The pages iterated by the [`Iterator`] appear in the order as they are mapped in the CPU's 13*7937dca7SDanilo Krummrich /// virtual address space ascendingly. 14*7937dca7SDanilo Krummrich /// 15*7937dca7SDanilo Krummrich /// # Invariants 16*7937dca7SDanilo Krummrich /// 17*7937dca7SDanilo Krummrich /// - `buf` is a valid and [`page::PAGE_SIZE`] aligned pointer into a [`Vmalloc`] allocation. 18*7937dca7SDanilo Krummrich /// - `size` is the number of bytes from `buf` until the end of the [`Vmalloc`] allocation `buf` 19*7937dca7SDanilo Krummrich /// points to. 20*7937dca7SDanilo Krummrich pub struct VmallocPageIter<'a> { 21*7937dca7SDanilo Krummrich /// The base address of the [`Vmalloc`] buffer. 22*7937dca7SDanilo Krummrich buf: NonNull<u8>, 23*7937dca7SDanilo Krummrich /// The size of the buffer pointed to by `buf` in bytes. 24*7937dca7SDanilo Krummrich size: usize, 25*7937dca7SDanilo Krummrich /// The current page index of the [`Iterator`]. 26*7937dca7SDanilo Krummrich index: usize, 27*7937dca7SDanilo Krummrich _p: PhantomData<page::BorrowedPage<'a>>, 28*7937dca7SDanilo Krummrich } 29*7937dca7SDanilo Krummrich 30*7937dca7SDanilo Krummrich impl<'a> Iterator for VmallocPageIter<'a> { 31*7937dca7SDanilo Krummrich type Item = page::BorrowedPage<'a>; 32*7937dca7SDanilo Krummrich 33*7937dca7SDanilo Krummrich fn next(&mut self) -> Option<Self::Item> { 34*7937dca7SDanilo Krummrich let offset = self.index.checked_mul(page::PAGE_SIZE)?; 35*7937dca7SDanilo Krummrich 36*7937dca7SDanilo Krummrich // Even though `self.size()` may be smaller than `Self::page_count() * page::PAGE_SIZE`, it 37*7937dca7SDanilo Krummrich // is always a number between `(Self::page_count() - 1) * page::PAGE_SIZE` and 38*7937dca7SDanilo Krummrich // `Self::page_count() * page::PAGE_SIZE`, hence the check below is sufficient. 39*7937dca7SDanilo Krummrich if offset < self.size() { 40*7937dca7SDanilo Krummrich self.index += 1; 41*7937dca7SDanilo Krummrich } else { 42*7937dca7SDanilo Krummrich return None; 43*7937dca7SDanilo Krummrich } 44*7937dca7SDanilo Krummrich 45*7937dca7SDanilo Krummrich // TODO: Use `NonNull::add()` instead, once the minimum supported compiler version is 46*7937dca7SDanilo Krummrich // bumped to 1.80 or later. 47*7937dca7SDanilo Krummrich // 48*7937dca7SDanilo Krummrich // SAFETY: `offset` is in the interval `[0, (self.page_count() - 1) * page::PAGE_SIZE]`, 49*7937dca7SDanilo Krummrich // hence the resulting pointer is guaranteed to be within the same allocation. 50*7937dca7SDanilo Krummrich let ptr = unsafe { self.buf.as_ptr().add(offset) }; 51*7937dca7SDanilo Krummrich 52*7937dca7SDanilo Krummrich // SAFETY: `ptr` is guaranteed to be non-null given that it is derived from `self.buf`. 53*7937dca7SDanilo Krummrich let ptr = unsafe { NonNull::new_unchecked(ptr) }; 54*7937dca7SDanilo Krummrich 55*7937dca7SDanilo Krummrich // SAFETY: 56*7937dca7SDanilo Krummrich // - `ptr` is a valid pointer to a `Vmalloc` allocation. 57*7937dca7SDanilo Krummrich // - `ptr` is valid for the duration of `'a`. 58*7937dca7SDanilo Krummrich Some(unsafe { Vmalloc::to_page(ptr) }) 59*7937dca7SDanilo Krummrich } 60*7937dca7SDanilo Krummrich 61*7937dca7SDanilo Krummrich fn size_hint(&self) -> (usize, Option<usize>) { 62*7937dca7SDanilo Krummrich let remaining = self.page_count().saturating_sub(self.index); 63*7937dca7SDanilo Krummrich 64*7937dca7SDanilo Krummrich (remaining, Some(remaining)) 65*7937dca7SDanilo Krummrich } 66*7937dca7SDanilo Krummrich } 67*7937dca7SDanilo Krummrich 68*7937dca7SDanilo Krummrich impl<'a> VmallocPageIter<'a> { 69*7937dca7SDanilo Krummrich /// Creates a new [`VmallocPageIter`] instance. 70*7937dca7SDanilo Krummrich /// 71*7937dca7SDanilo Krummrich /// # Safety 72*7937dca7SDanilo Krummrich /// 73*7937dca7SDanilo Krummrich /// - `buf` must be a [`page::PAGE_SIZE`] aligned pointer into a [`Vmalloc`] allocation. 74*7937dca7SDanilo Krummrich /// - `buf` must be valid for at least the lifetime of `'a`. 75*7937dca7SDanilo Krummrich /// - `size` must be the number of bytes from `buf` until the end of the [`Vmalloc`] allocation 76*7937dca7SDanilo Krummrich /// `buf` points to. 77*7937dca7SDanilo Krummrich pub unsafe fn new(buf: NonNull<u8>, size: usize) -> Self { 78*7937dca7SDanilo Krummrich // INVARIANT: By the safety requirements, `buf` is a valid and `page::PAGE_SIZE` aligned 79*7937dca7SDanilo Krummrich // pointer into a [`Vmalloc`] allocation. 80*7937dca7SDanilo Krummrich Self { 81*7937dca7SDanilo Krummrich buf, 82*7937dca7SDanilo Krummrich size, 83*7937dca7SDanilo Krummrich index: 0, 84*7937dca7SDanilo Krummrich _p: PhantomData, 85*7937dca7SDanilo Krummrich } 86*7937dca7SDanilo Krummrich } 87*7937dca7SDanilo Krummrich 88*7937dca7SDanilo Krummrich /// Returns the size of the backing [`Vmalloc`] allocation in bytes. 89*7937dca7SDanilo Krummrich /// 90*7937dca7SDanilo Krummrich /// Note that this is the size the [`Vmalloc`] allocation has been allocated with. Hence, this 91*7937dca7SDanilo Krummrich /// number may be smaller than `[`Self::page_count`] * [`page::PAGE_SIZE`]`. 92*7937dca7SDanilo Krummrich #[inline] 93*7937dca7SDanilo Krummrich pub fn size(&self) -> usize { 94*7937dca7SDanilo Krummrich self.size 95*7937dca7SDanilo Krummrich } 96*7937dca7SDanilo Krummrich 97*7937dca7SDanilo Krummrich /// Returns the number of pages owned by the backing [`Vmalloc`] allocation. 98*7937dca7SDanilo Krummrich #[inline] 99*7937dca7SDanilo Krummrich pub fn page_count(&self) -> usize { 100*7937dca7SDanilo Krummrich self.size().div_ceil(page::PAGE_SIZE) 101*7937dca7SDanilo Krummrich } 102*7937dca7SDanilo Krummrich } 103