Support transferring grants again.

This commit is contained in:
4lDO2
2023-07-03 13:07:54 +02:00
parent 55f1829e77
commit b24cf821c2
2 changed files with 54 additions and 35 deletions
+48 -7
View File
@@ -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
View File
@@ -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())