fix(mremap): fix referencing

Before it was first add_ref'ed by `borrow_frame_enforce_rw_allocated`,
manually and then by `allocated_shared_one_page`.

Now it is only done by `borrow_frame_enforce_rw_allocated` and does not
get unref-ed as take() is called on the returned `RaiiFrame`.

Now the page is manually mapped and an `Allocated` type grant is
constructed (synonymous to `MAP_PRIVATE`). Before by using `allocated_shared_one_page`
an `AllocatedShared` provided grant was constructed (synonymous to
`MAP_SHARED`), which was wrong as the TCB would've not got CoW-ed
after fork(), making the Tcb malformed.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2024-12-11 16:29:17 +11:00
parent 08231eb4df
commit af36ae12b0
2 changed files with 31 additions and 19 deletions
+16
View File
@@ -1102,6 +1102,22 @@ pub struct GrantFileRef {
impl Grant {
// TODO: PageCount newtype, to avoid confusion between bytes and pages?
// `base` must be mapped by the caller.
pub fn allocated_one_page_nomap(base: Page, flags: PageFlags<RmmA>) -> Grant {
Grant {
base,
info: GrantInfo {
page_count: 1,
flags,
mapped: true,
provider: Provider::Allocated {
cow_file_ref: None,
phys_contiguous: false,
},
},
}
}
// TODO: is_pinned
pub fn allocated_shared_one_page(
frame: Frame,
+15 -19
View File
@@ -9,10 +9,9 @@ use crate::{
context::{
self,
file::{FileDescription, FileDescriptor, InternalFlags},
memory::{AddrSpace, PageSpan},
memory::{AddrSpace, GenericFlusher, Grant, PageSpan, TlbShootdownActions},
process,
},
memory::AddRefError,
paging::{Page, VirtualAddress, PAGE_SIZE},
scheme::{self, CallerCtx, FileHandle, KernelScheme, OpenResult},
syscall::{data::Stat, error::*, flag::*},
@@ -500,17 +499,9 @@ pub fn mremap(
if new_page_count != 1 {
return Err(Error::new(EOPNOTSUPP));
}
let raii_frame = addr_space.borrow_frame_enforce_rw_allocated(src_span.base)?;
let info = crate::memory::get_page_info(raii_frame.get()).ok_or(Error::new(EINVAL))?;
match info.add_ref(crate::memory::RefKind::Shared) {
Ok(()) => (),
Err(AddRefError::RcOverflow) => return Err(Error::new(ENOMEM)),
Err(AddRefError::CowToShared) => return Err(Error::new(EINVAL)),
Err(AddRefError::SharedToCow) => unreachable!(),
}
let base = addr_space.acquire_write().mmap(
&addr_space,
requested_dst_base,
@@ -518,14 +509,19 @@ pub fn mremap(
map_flags,
&mut Vec::new(),
|page, page_flags, mapper, flusher| {
crate::context::memory::Grant::allocated_shared_one_page(
raii_frame.take(),
page,
page_flags,
mapper,
flusher,
false,
)
let frame = raii_frame.take();
// XXX: add_ref(RefKind::Shared) is internally done by borrow_frame_enforce_rw_allocated(src_span.base).
// The page does not get unref-ed as we call take() on the `raii_frame`.
unsafe {
mapper
.map_phys(page.start_address(), frame.base(), page_flags)
.ok_or(Error::new(ENOMEM))?
.ignore();
flusher.queue(frame, None, TlbShootdownActions::NEW_MAPPING);
}
Ok(Grant::allocated_one_page_nomap(page, page_flags))
},
)?;