Support transferring grants again.
This commit is contained in:
+48
-7
@@ -277,6 +277,34 @@ impl AddrSpace {
|
||||
|
||||
Ok(selected_span.base)
|
||||
}
|
||||
pub fn r#move(dst: &mut AddrSpace, src: &mut AddrSpace, src_span: PageSpan, requested_dst_base: Option<Page>, new_flags: MapFlags) -> Result<Page> {
|
||||
let nz_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let grant_base = {
|
||||
let mut conflicts_iter = src.grants.conflicts(src_span);
|
||||
|
||||
let (grant_base, grant_info) = conflicts_iter.next().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
if conflicts_iter.next().is_some() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
if grant_info.is_pinned() {
|
||||
return Err(Error::new(EBUSY));
|
||||
}
|
||||
|
||||
grant_base
|
||||
};
|
||||
|
||||
let grant = src.grants.remove(grant_base).expect("grant cannot disappear");
|
||||
let (before, middle, after) = grant.extract(src_span).expect("called intersect(), must succeed");
|
||||
|
||||
if let Some(before) = before { src.grants.insert(before); }
|
||||
if let Some(after) = after { src.grants.insert(after); }
|
||||
|
||||
let src_flusher = PageFlushAll::new();
|
||||
|
||||
dst.mmap(requested_dst_base, nz_count, new_flags, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, &mut src.table.utable, dst_mapper, src_flusher, dst_flusher))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -812,14 +840,27 @@ impl Grant {
|
||||
},
|
||||
})
|
||||
}
|
||||
pub fn transfer(mut src_grant: Grant, dst_base: Page, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, src_flusher: impl Flusher<RmmA>, dst_flusher: impl Flusher<RmmA>) -> Result<Grant> {
|
||||
todo!()
|
||||
/*
|
||||
assert!(core::mem::replace(&mut src_grant.info.mapped, false));
|
||||
let desc_opt = src_grant.info.desc_opt.take();
|
||||
/// Move a grant between two address spaces.
|
||||
pub fn transfer(mut self, dst_base: Page, flags: PageFlags<RmmA>, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, mut src_flusher: impl Flusher<RmmA>, mut dst_flusher: impl Flusher<RmmA>) -> Result<Grant> {
|
||||
assert!(!self.info.is_pinned());
|
||||
|
||||
Self::copy_inner(src_grant.base, dst_base, src_grant.info.page_count, src_grant.info.flags(), desc_opt, src_mapper, dst_mapper, src_flusher, dst_flusher, src_grant.info.owned, true).map_err(Into::into)
|
||||
*/
|
||||
for src_page in self.span().pages() {
|
||||
let dst_page = dst_base.next_by(src_page.offset_from(self.base));
|
||||
|
||||
let unmap_parents = true;
|
||||
|
||||
// TODO: Validate flags?
|
||||
let Some((phys, _flags, flush)) = (unsafe { src_mapper.unmap_phys(src_page.start_address(), unmap_parents) }) else {
|
||||
continue;
|
||||
};
|
||||
src_flusher.consume(flush);
|
||||
|
||||
// TODO: Preallocate to handle OOM?
|
||||
let flush = unsafe { dst_mapper.map_phys(dst_page.start_address(), phys, flags).expect("TODO: OOM") };
|
||||
dst_flusher.consume(flush);
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn remap(&mut self, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>, flags: PageFlags<RmmA>) {
|
||||
|
||||
+6
-28
@@ -682,42 +682,20 @@ impl KernelScheme for ProcScheme {
|
||||
}
|
||||
|
||||
let (requested_dst_page, page_count) = crate::syscall::validate_region(map.address, map.size)?;
|
||||
let (src_page, _) = crate::syscall::validate_region(map.offset, map.size)?;
|
||||
let src_span = PageSpan::validate_nonempty(VirtualAddress::new(map.offset), map.size).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let requested_dst_page = (map.address != 0).then_some(requested_dst_page);
|
||||
let requested_dst_base = (map.address != 0).then_some(requested_dst_page);
|
||||
|
||||
let mut src_addr_space = addrspace.write();
|
||||
let src_addr_space = &mut *src_addr_space;
|
||||
let mut dst_addr_space = dst_addr_space.write();
|
||||
|
||||
let src_grant_span = {
|
||||
let src_span = PageSpan::new(src_page, page_count);
|
||||
let mut conflicts = src_addr_space.grants.conflicts(src_span);
|
||||
let (first_base, first_info) = conflicts.next().ok_or(Error::new(EINVAL))?;
|
||||
if conflicts.next().is_some() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
if !first_info.can_have_flags(map.flags) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
PageSpan::new(first_base, first_info.page_count()).intersection(src_span)
|
||||
};
|
||||
|
||||
let src_mapper = &mut src_addr_space.table.utable;
|
||||
let src_page_count = NonZeroUsize::new(src_grant_span.count).ok_or(Error::new(EINVAL))?;
|
||||
let src_page_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
// TODO: Validate flags
|
||||
let result_base = if consume {
|
||||
let grant = src_addr_space.grants.remove(src_grant_span.base).expect("grant cannot disappear");
|
||||
let (before, middle, after) = grant.extract(src_grant_span).expect("called intersect(), must succeed");
|
||||
|
||||
if let Some(before) = before { src_addr_space.grants.insert(before); }
|
||||
if let Some(after) = after { src_addr_space.grants.insert(after); }
|
||||
|
||||
dst_addr_space.mmap(requested_dst_page, src_page_count, map.flags, |dst_page, _flags, dst_mapper, dst_flusher| Grant::transfer(middle, dst_page, src_mapper, dst_mapper, InactiveFlusher::new(), dst_flusher))?
|
||||
AddrSpace::r#move(&mut *dst_addr_space, &mut *src_addr_space, src_span, requested_dst_base, map.flags)?
|
||||
} else {
|
||||
dst_addr_space.mmap(requested_dst_page, src_page_count, map.flags, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), src_addr_space, src_grant_span.base, dst_page, src_grant_span.count, flags, dst_mapper, flusher, true, true, false)?))?
|
||||
dst_addr_space.mmap(requested_dst_base, src_page_count, map.flags, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), &*src_addr_space, src_span.base, dst_page, src_span.count, flags, dst_mapper, flusher, true, true, false)?))?
|
||||
};
|
||||
|
||||
Ok(result_base.start_address().data())
|
||||
|
||||
Reference in New Issue
Block a user