0.3.0: converge kernel onto upstream master
- Rebase all Red Bear kernel changes onto upstream master (4d5d36d4).
- Update version to 0.5.12+rb0.3.0 and add Red Bear author attribution.
- Switch redox_syscall direct dependency to local fork path (../syscall).
- Bump rust-toolchain.toml to nightly-2026-05-24.
- Regenerate Cargo.lock for +rb0.3.0 suffixes and path deps.
This commit is contained in:
+59
-143
@@ -1,19 +1,14 @@
|
||||
use alloc::{
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
|
||||
use arrayvec::ArrayVec;
|
||||
use core::{
|
||||
cmp,
|
||||
fmt::Debug,
|
||||
mem::ManuallyDrop,
|
||||
num::NonZeroUsize,
|
||||
ops::{Bound, Deref},
|
||||
ops::Bound,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
use rmm::{Arch as _, PageFlush};
|
||||
use smallvec::SmallVec;
|
||||
use syscall::{error::*, flag::MapFlags, GrantFlags, MunmapFlags};
|
||||
|
||||
use crate::{
|
||||
@@ -59,8 +54,6 @@ pub struct UnmapResult {
|
||||
pub size: usize,
|
||||
pub flags: MunmapFlags,
|
||||
}
|
||||
pub type UnmapVec = SmallVec<[UnmapResult; 16]>;
|
||||
|
||||
impl UnmapResult {
|
||||
pub fn unmap(mut self, token: &mut CleanLockToken) -> Result<()> {
|
||||
let Some(GrantFileRef {
|
||||
@@ -71,9 +64,6 @@ impl UnmapResult {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// TODO: This is not ideal, the lock must be held until try_close(), however that would break borrowing rules.
|
||||
// Proper unmap operation would be a recursive operation, since closing a file can trigger another unmap().
|
||||
// We should refactor Result of munmap() to handle unmap and closing files recursively.
|
||||
let (scheme_id, number) = {
|
||||
let desc = description.write(token.token());
|
||||
(desc.scheme, desc.number)
|
||||
@@ -322,7 +312,8 @@ impl AddrSpaceWrapper {
|
||||
requested_span: PageSpan,
|
||||
unpin: bool,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<UnmapVec> {
|
||||
) -> Result<Vec<UnmapResult>> {
|
||||
let mut token = token.token();
|
||||
let mut guard = self.acquire_write(token.downgrade());
|
||||
let guard = &mut *guard;
|
||||
|
||||
@@ -342,7 +333,7 @@ impl AddrSpaceWrapper {
|
||||
requested_dst_base: Option<Page>,
|
||||
new_page_count: usize,
|
||||
new_flags: MapFlags,
|
||||
mut notify_files_out: Option<&mut UnmapVec>,
|
||||
mut notify_files_out: Option<&mut Vec<UnmapResult>>,
|
||||
token: LockToken<L5>,
|
||||
) -> Result<Page> {
|
||||
let dst_lock = self;
|
||||
@@ -419,7 +410,7 @@ impl AddrSpaceWrapper {
|
||||
|
||||
if new_page_count < src_span.count {
|
||||
let unpin = false;
|
||||
let notify_files = AddrSpace::munmap_inner(
|
||||
let notify_files: Vec<UnmapResult> = AddrSpace::munmap_inner(
|
||||
src_grants,
|
||||
src_mapper,
|
||||
src_flusher,
|
||||
@@ -599,8 +590,8 @@ impl AddrSpace {
|
||||
this_flusher: &mut Flusher,
|
||||
mut requested_span: PageSpan,
|
||||
unpin: bool,
|
||||
) -> Result<UnmapVec> {
|
||||
let mut notify_files = UnmapVec::new();
|
||||
) -> Result<Vec<UnmapResult>> {
|
||||
let mut notify_files = Vec::new();
|
||||
|
||||
let next = |grants: &mut UserGrants, span: PageSpan| {
|
||||
grants
|
||||
@@ -671,9 +662,7 @@ impl AddrSpace {
|
||||
}
|
||||
|
||||
// Remove irrelevant region
|
||||
// TODO: Lock ordering violation
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let unmap_result = grant.unmap(this_mapper, this_flusher, &mut token);
|
||||
let unmap_result = grant.unmap(this_mapper, this_flusher);
|
||||
|
||||
// Notify scheme that holds grant
|
||||
if unmap_result.file_desc.is_some() {
|
||||
@@ -698,7 +687,7 @@ impl AddrSpace {
|
||||
requested_base_opt: Option<Page>,
|
||||
page_count: NonZeroUsize,
|
||||
flags: MapFlags,
|
||||
notify_files_out: Option<&mut UnmapVec>,
|
||||
notify_files_out: Option<&mut Vec<UnmapResult>>,
|
||||
map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut Flusher) -> Result<Grant>,
|
||||
) -> Result<Page> {
|
||||
assert_eq!(dst_lock.inner.as_mut_ptr(), self as *mut Self);
|
||||
@@ -772,40 +761,21 @@ impl AddrSpace {
|
||||
// longer arc-rwlock wrapped, it cannot be referenced `External`ly by borrowing grants,
|
||||
// so it should suffice to iterate over PageInfos and decrement and maybe deallocate
|
||||
// the underlying pages (and send some funmaps).
|
||||
let res = { grant.unmap(&mut self.table.utable, &mut NopFlusher, token) };
|
||||
let res = { grant.unmap(&mut self.table.utable, &mut NopFlusher) };
|
||||
|
||||
let _ = res.unmap(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AddrSpaceSwitchReadGuard {
|
||||
pub lock: RwLockReadGuard<'static, L5, AddrSpace>,
|
||||
}
|
||||
|
||||
impl AddrSpaceSwitchReadGuard {
|
||||
pub fn new(guard: RwLockReadGuard<'_, L5, AddrSpace>) -> Self {
|
||||
Self {
|
||||
lock: unsafe { core::mem::transmute(guard) },
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Deref for AddrSpaceSwitchReadGuard {
|
||||
type Target = RwLockReadGuard<'static, L5, AddrSpace>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.lock
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UserGrants {
|
||||
// Using a BTreeMap for its range method.
|
||||
inner: BTreeMap<Page, GrantInfo>,
|
||||
// Holes ordered by memory address for merging adjacent holes
|
||||
holes_by_addr: BTreeMap<VirtualAddress, usize>,
|
||||
// Holes ordered by size then start address for fast allocations
|
||||
holes_by_size: BTreeSet<(usize, VirtualAddress)>,
|
||||
// Using a BTreeMap for its range method.
|
||||
holes: BTreeMap<VirtualAddress, usize>,
|
||||
// TODO: Would an additional map ordered by (size,start) to allow for O(log n) allocations be
|
||||
// beneficial?
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -907,41 +877,10 @@ impl Debug for PageSpan {
|
||||
|
||||
impl UserGrants {
|
||||
pub fn new() -> Self {
|
||||
let mut holes_by_addr = BTreeMap::new();
|
||||
let mut holes_by_size = BTreeSet::new();
|
||||
|
||||
let initial_offset = VirtualAddress::new(0);
|
||||
let initial_size = crate::USER_END_OFFSET;
|
||||
|
||||
holes_by_addr.insert(initial_offset, initial_size);
|
||||
holes_by_size.insert((initial_size, initial_offset));
|
||||
|
||||
Self {
|
||||
inner: BTreeMap::new(),
|
||||
holes_by_addr,
|
||||
holes_by_size,
|
||||
}
|
||||
}
|
||||
/// Internal helper to keep the two hole maps in sync
|
||||
fn insert_hole(&mut self, offset: VirtualAddress, size: usize) {
|
||||
self.holes_by_addr.insert(offset, size);
|
||||
self.holes_by_size.insert((size, offset));
|
||||
}
|
||||
/// Internal helper to keep the two hole maps in sync
|
||||
fn remove_hole(&mut self, offset: &VirtualAddress) -> Option<usize> {
|
||||
if let Some(size) = self.holes_by_addr.remove(offset) {
|
||||
self.holes_by_size.remove(&(size, *offset));
|
||||
Some(size)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
/// Internal helper to keep the two hole maps in sync
|
||||
fn resize_hole(&mut self, offset: &VirtualAddress, new_size: usize) {
|
||||
if let Some(size) = self.holes_by_addr.get_mut(offset) {
|
||||
self.holes_by_size.remove(&(*size, *offset));
|
||||
*size = new_size;
|
||||
self.holes_by_size.insert((new_size, *offset));
|
||||
holes: core::iter::once((VirtualAddress::new(0), crate::USER_END_OFFSET))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,16 +943,18 @@ impl UserGrants {
|
||||
// TODO: Allow explicitly allocating guard pages? Perhaps using mprotect or mmap with
|
||||
// PROT_NONE?
|
||||
|
||||
let req_size = page_count * PAGE_SIZE;
|
||||
let (_, hole_start) = self
|
||||
.holes_by_size
|
||||
.range((req_size, VirtualAddress::new(0))..)
|
||||
.find(|&&(hole_size, hole_offset)| {
|
||||
// A hole might be large enough, but the usable
|
||||
// portion above `min` address might be too small.
|
||||
let usable_start = cmp::max(hole_offset.data(), min);
|
||||
let hole_end = hole_offset.data() + hole_size;
|
||||
usable_start + req_size <= hole_end
|
||||
let (hole_start, _hole_size) = self
|
||||
.holes
|
||||
.iter()
|
||||
.skip_while(|(hole_offset, hole_size)| hole_offset.data() + **hole_size <= min)
|
||||
.find(|(hole_offset, hole_size)| {
|
||||
let avail_size =
|
||||
if hole_offset.data() <= min && min <= hole_offset.data() + **hole_size {
|
||||
**hole_size - (min - hole_offset.data())
|
||||
} else {
|
||||
**hole_size
|
||||
};
|
||||
page_count * PAGE_SIZE <= avail_size
|
||||
})?;
|
||||
// Create new region
|
||||
Some(PageSpan::new(
|
||||
@@ -1029,14 +970,10 @@ impl UserGrants {
|
||||
let size = page_count * PAGE_SIZE;
|
||||
let end_address = base.start_address().add(size);
|
||||
|
||||
let previous_hole = self
|
||||
.holes_by_addr
|
||||
.range(..start_address)
|
||||
.next_back()
|
||||
.map(|(&k, &v)| (k, v));
|
||||
let previous_hole = self.holes.range_mut(..start_address).next_back();
|
||||
|
||||
if let Some((hole_offset, hole_size)) = previous_hole {
|
||||
let prev_hole_end = hole_offset.data() + hole_size;
|
||||
let prev_hole_end = hole_offset.data() + *hole_size;
|
||||
|
||||
// Note that prev_hole_end cannot exactly equal start_address, since that would imply
|
||||
// there is another grant at that position already, as it would otherwise have been
|
||||
@@ -1046,49 +983,46 @@ impl UserGrants {
|
||||
// hole_offset must be below (but never equal to) the start address due to the
|
||||
// `..start_address()` limit; hence, all we have to do is to shrink the
|
||||
// previous offset.
|
||||
self.resize_hole(&hole_offset, start_address.data() - hole_offset.data());
|
||||
*hole_size = start_address.data() - hole_offset.data();
|
||||
}
|
||||
if prev_hole_end > end_address.data() {
|
||||
// The grant is splitting this hole in two, so insert the new one at the end.
|
||||
self.insert_hole(end_address, prev_hole_end - end_address.data());
|
||||
self.holes
|
||||
.insert(end_address, prev_hole_end - end_address.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Next hole
|
||||
if let Some(hole_size) = self.remove_hole(&start_address) {
|
||||
if let Some(hole_size) = self.holes.remove(&start_address) {
|
||||
let remainder = hole_size - size;
|
||||
if remainder > 0 {
|
||||
self.insert_hole(end_address, remainder);
|
||||
self.holes.insert(end_address, remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unreserve(&mut self, base: Page, page_count: usize) {
|
||||
fn unreserve(holes: &mut BTreeMap<VirtualAddress, usize>, base: Page, page_count: usize) {
|
||||
// TODO
|
||||
let start_address = base.start_address();
|
||||
let size = page_count * PAGE_SIZE;
|
||||
let end_address = base.start_address().add(size);
|
||||
|
||||
// The size of any possible hole directly after the to-be-freed region.
|
||||
let exactly_after_size = self.remove_hole(&end_address);
|
||||
let exactly_after_size = holes.remove(&end_address);
|
||||
|
||||
// There was a range that began exactly prior to the to-be-freed region, so simply
|
||||
// increment the size such that it occupies the grant too. If in addition there was a grant
|
||||
// directly after the grant, include it too in the size.
|
||||
if let Some((hole_offset, _hole_size)) = self
|
||||
.holes_by_addr
|
||||
.range(..start_address)
|
||||
if let Some((hole_offset, hole_size)) = holes
|
||||
.range_mut(..start_address)
|
||||
.next_back()
|
||||
.filter(|(offset, size)| offset.data() + **size == start_address.data())
|
||||
.map(|(&offset, &size)| (offset, size))
|
||||
{
|
||||
self.resize_hole(
|
||||
&hole_offset,
|
||||
end_address.data() - hole_offset.data() + exactly_after_size.unwrap_or(0),
|
||||
);
|
||||
*hole_size = end_address.data() - hole_offset.data() + exactly_after_size.unwrap_or(0);
|
||||
} else {
|
||||
// There was no free region directly before the to-be-freed region, however will
|
||||
// now unconditionally insert a new free region where the grant was, and add that extra
|
||||
// size if there was something after it.
|
||||
self.insert_hole(start_address, size + exactly_after_size.unwrap_or(0));
|
||||
holes.insert(start_address, size + exactly_after_size.unwrap_or(0));
|
||||
}
|
||||
}
|
||||
pub fn insert(&mut self, mut grant: Grant) {
|
||||
@@ -1140,7 +1074,7 @@ impl UserGrants {
|
||||
|
||||
if (base..base.next_by(info.page_count())).contains(&page) {
|
||||
let (base, info) = cursor.remove_prev().unwrap();
|
||||
self.unreserve(base, info.page_count());
|
||||
Self::unreserve(&mut self.holes, base, info.page_count());
|
||||
Some(Grant { base, info })
|
||||
} else {
|
||||
None
|
||||
@@ -1469,15 +1403,15 @@ impl Grant {
|
||||
for dst_page in span.pages() {
|
||||
let src_page = src.src_base.next_by(dst_page.offset_from(span.base));
|
||||
|
||||
let (frame, page_flags, is_cow) = match src.mode {
|
||||
let (frame, is_cow) = match src.mode {
|
||||
MmapMode::Shared => {
|
||||
// TODO: Error code for "scheme responded with unmapped page"?
|
||||
let (frame, page_flags) = match src_addrspace
|
||||
let frame = match src_addrspace
|
||||
.table
|
||||
.utable
|
||||
.translate(src_page.start_address())
|
||||
{
|
||||
Some((phys, page_flags)) => (Frame::containing(phys), page_flags),
|
||||
Some((phys, _)) => Frame::containing(phys),
|
||||
// TODO: ensure the correct context is hardblocked, if necessary
|
||||
None => {
|
||||
let (frame, _, new_guard) = correct_inner(
|
||||
@@ -1488,26 +1422,20 @@ impl Grant {
|
||||
0,
|
||||
)
|
||||
.map_err(|_| Error::new(EIO))?;
|
||||
let page_flags = new_guard
|
||||
.table
|
||||
.utable
|
||||
.translate(src_page.start_address())
|
||||
.unwrap()
|
||||
.1;
|
||||
guard = new_guard;
|
||||
(frame, page_flags)
|
||||
frame
|
||||
}
|
||||
};
|
||||
|
||||
(frame, page_flags, false)
|
||||
(frame, false)
|
||||
}
|
||||
MmapMode::Cow => unsafe {
|
||||
let (frame, page_flags) = match guard
|
||||
let frame = match guard
|
||||
.table
|
||||
.utable
|
||||
.remap_with(src_page.start_address(), |flags| flags.write(false))
|
||||
{
|
||||
Some((page_flags, phys, _)) => (Frame::containing(phys), page_flags),
|
||||
Some((_, phys, _)) => Frame::containing(phys),
|
||||
// TODO: ensure the correct context is hardblocked, if necessary
|
||||
None => {
|
||||
let (frame, _, new_guard) = correct_inner(
|
||||
@@ -1518,19 +1446,12 @@ impl Grant {
|
||||
0,
|
||||
)
|
||||
.map_err(|_| Error::new(EIO))?;
|
||||
// FIXME correct_inner should read the page flags instead
|
||||
let page_flags = new_guard
|
||||
.table
|
||||
.utable
|
||||
.translate(src_page.start_address())
|
||||
.unwrap()
|
||||
.1;
|
||||
guard = new_guard;
|
||||
(frame, page_flags)
|
||||
frame
|
||||
}
|
||||
};
|
||||
|
||||
(frame, page_flags, true)
|
||||
(frame, true)
|
||||
},
|
||||
};
|
||||
src_addrspace = &mut *guard;
|
||||
@@ -1590,14 +1511,7 @@ impl Grant {
|
||||
.map_phys(
|
||||
dst_page.start_address(),
|
||||
frame.base(),
|
||||
new_flags
|
||||
.write(new_flags.has_write() && !is_cow)
|
||||
// FIXME make sure this stays in sync with the MemoryType flags
|
||||
.uncacheable(page_flags.has_flag(RmmA::ENTRY_FLAG_UNCACHEABLE))
|
||||
.device_memory(page_flags.has_flag(RmmA::ENTRY_FLAG_DEVICE_MEMORY))
|
||||
.write_combining(
|
||||
page_flags.has_flag(RmmA::ENTRY_FLAG_WRITE_COMBINING),
|
||||
),
|
||||
new_flags.write(new_flags.has_write() && !is_cow),
|
||||
)
|
||||
.unwrap();
|
||||
flush.ignore();
|
||||
@@ -1991,7 +1905,6 @@ impl Grant {
|
||||
mut self,
|
||||
mapper: &mut PageMapper,
|
||||
flusher: &mut impl GenericFlusher,
|
||||
token: &mut CleanLockToken,
|
||||
) -> UnmapResult {
|
||||
assert!(self.info.mapped);
|
||||
assert!(!self.info.is_pinned());
|
||||
@@ -2002,6 +1915,9 @@ impl Grant {
|
||||
..
|
||||
} = self.info.provider
|
||||
{
|
||||
// TODO: Lock ordering violation
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let mut token = token.token();
|
||||
let mut guard = address_space.acquire_write(token.downgrade());
|
||||
|
||||
for (_, grant) in guard
|
||||
@@ -2843,7 +2759,7 @@ pub struct BorrowedFmapSource<'a> {
|
||||
pub addr_space_guard: RwLockWriteGuard<'a, L5, AddrSpace>,
|
||||
}
|
||||
|
||||
pub fn handle_notify_files(notify_files: UnmapVec, token: &mut CleanLockToken) {
|
||||
pub fn handle_notify_files(notify_files: Vec<UnmapResult>, token: &mut CleanLockToken) {
|
||||
for file in notify_files {
|
||||
let _ = file.unmap(token);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user