mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-05-05 09:57:21 +02:00
161dd7b51e
Currently, we need to go through raw pointers and then re-create the `NonNull` from the result of offsetting the raw pointer. `feature(non_null_convenience)` [1] has been stabilized in Rust 1.80.0 [2], which is older than our new minimum Rust version (Rust 1.85.0). Thus, now that we bump the Rust minimum version, simplify using `NonNull::add()` and clean the TODO note. Link: https://github.com/rust-lang/rust/issues/117691 [1] Link: https://github.com/rust-lang/rust/pull/124498 [2] Reviewed-by: Tamir Duberstein <tamird@kernel.org> Reviewed-by: Gary Guo <gary@garyguo.net> Acked-by: Danilo Krummrich <dakr@kernel.org> Link: https://patch.msgid.link/20260405235309.418950-15-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
97 lines
3.3 KiB
Rust
97 lines
3.3 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
use super::Vmalloc;
|
|
use crate::page;
|
|
use core::marker::PhantomData;
|
|
use core::ptr::NonNull;
|
|
|
|
/// An [`Iterator`] of [`page::BorrowedPage`] items owned by a [`Vmalloc`] allocation.
|
|
///
|
|
/// # Guarantees
|
|
///
|
|
/// The pages iterated by the [`Iterator`] appear in the order as they are mapped in the CPU's
|
|
/// virtual address space ascendingly.
|
|
///
|
|
/// # Invariants
|
|
///
|
|
/// - `buf` is a valid and [`page::PAGE_SIZE`] aligned pointer into a [`Vmalloc`] allocation.
|
|
/// - `size` is the number of bytes from `buf` until the end of the [`Vmalloc`] allocation `buf`
|
|
/// points to.
|
|
pub struct VmallocPageIter<'a> {
|
|
/// The base address of the [`Vmalloc`] buffer.
|
|
buf: NonNull<u8>,
|
|
/// The size of the buffer pointed to by `buf` in bytes.
|
|
size: usize,
|
|
/// The current page index of the [`Iterator`].
|
|
index: usize,
|
|
_p: PhantomData<page::BorrowedPage<'a>>,
|
|
}
|
|
|
|
impl<'a> Iterator for VmallocPageIter<'a> {
|
|
type Item = page::BorrowedPage<'a>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let offset = self.index.checked_mul(page::PAGE_SIZE)?;
|
|
|
|
// Even though `self.size()` may be smaller than `Self::page_count() * page::PAGE_SIZE`, it
|
|
// is always a number between `(Self::page_count() - 1) * page::PAGE_SIZE` and
|
|
// `Self::page_count() * page::PAGE_SIZE`, hence the check below is sufficient.
|
|
if offset < self.size() {
|
|
self.index += 1;
|
|
} else {
|
|
return None;
|
|
}
|
|
|
|
// SAFETY: `offset` is in the interval `[0, (self.page_count() - 1) * page::PAGE_SIZE]`,
|
|
// hence the resulting pointer is guaranteed to be within the same allocation.
|
|
let ptr = unsafe { self.buf.add(offset) };
|
|
|
|
// SAFETY:
|
|
// - `ptr` is a valid pointer to a `Vmalloc` allocation.
|
|
// - `ptr` is valid for the duration of `'a`.
|
|
Some(unsafe { Vmalloc::to_page(ptr) })
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
let remaining = self.page_count().saturating_sub(self.index);
|
|
|
|
(remaining, Some(remaining))
|
|
}
|
|
}
|
|
|
|
impl<'a> VmallocPageIter<'a> {
|
|
/// Creates a new [`VmallocPageIter`] instance.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - `buf` must be a [`page::PAGE_SIZE`] aligned pointer into a [`Vmalloc`] allocation.
|
|
/// - `buf` must be valid for at least the lifetime of `'a`.
|
|
/// - `size` must be the number of bytes from `buf` until the end of the [`Vmalloc`] allocation
|
|
/// `buf` points to.
|
|
pub unsafe fn new(buf: NonNull<u8>, size: usize) -> Self {
|
|
// INVARIANT: By the safety requirements, `buf` is a valid and `page::PAGE_SIZE` aligned
|
|
// pointer into a [`Vmalloc`] allocation.
|
|
Self {
|
|
buf,
|
|
size,
|
|
index: 0,
|
|
_p: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Returns the size of the backing [`Vmalloc`] allocation in bytes.
|
|
///
|
|
/// Note that this is the size the [`Vmalloc`] allocation has been allocated with. Hence, this
|
|
/// number may be smaller than `[`Self::page_count`] * [`page::PAGE_SIZE`]`.
|
|
#[inline]
|
|
pub fn size(&self) -> usize {
|
|
self.size
|
|
}
|
|
|
|
/// Returns the number of pages owned by the backing [`Vmalloc`] allocation.
|
|
#[inline]
|
|
pub fn page_count(&self) -> usize {
|
|
self.size().div_ceil(page::PAGE_SIZE)
|
|
}
|
|
}
|