feat(kernel): per-process budgets (pages, endpoints, notifs, regions) carved from creator, returned on death; init owns pool
This commit is contained in:
@@ -91,22 +91,13 @@ impl<P: Platform> Kernel<P> {
|
||||
}
|
||||
|
||||
fn quota_mut(&mut self, pid: ProcessId) -> Result<&mut Quota, KernelError> {
|
||||
self.quotas
|
||||
.get_mut(pid.raw() as usize)
|
||||
.ok_or(KernelError::InvalidProcess(pid))
|
||||
self.budget_mut(pid).map(|b| &mut b.pages)
|
||||
}
|
||||
|
||||
pub fn page_usage(&self, pid: ProcessId) -> usize {
|
||||
self.quotas.get(pid.raw() as usize).map_or(0, Quota::used)
|
||||
}
|
||||
|
||||
pub fn set_page_limit(&mut self, pid: ProcessId, limit: usize) -> Result<(), KernelError> {
|
||||
self.processes.get(pid)?;
|
||||
if self.quota_mut(pid)?.set_limit(limit) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(KernelError::OutOfMemory)
|
||||
}
|
||||
self.budgets
|
||||
.get(pid.raw() as usize)
|
||||
.map_or(0, |b| b.pages.used())
|
||||
}
|
||||
|
||||
pub fn free_page_count(&self) -> usize {
|
||||
@@ -121,10 +112,11 @@ impl<P: Platform> Kernel<P> {
|
||||
pa: PhysicalAddress,
|
||||
perms: PagePerms,
|
||||
) -> Result<(), KernelError> {
|
||||
let quota = self
|
||||
.quotas
|
||||
let quota = &mut self
|
||||
.budgets
|
||||
.get_mut(pid.raw() as usize)
|
||||
.ok_or(KernelError::InvalidProcess(pid))?;
|
||||
.ok_or(KernelError::InvalidProcess(pid))?
|
||||
.pages;
|
||||
let mut source = ChargedFrames {
|
||||
frames: &mut self.frames,
|
||||
quota,
|
||||
@@ -136,11 +128,11 @@ impl<P: Platform> Kernel<P> {
|
||||
}
|
||||
|
||||
pub(crate) fn create_address_space(&mut self, pid: ProcessId) -> Result<(), KernelError> {
|
||||
let quota = self
|
||||
.quotas
|
||||
let quota = &mut self
|
||||
.budgets
|
||||
.get_mut(pid.raw() as usize)
|
||||
.ok_or(KernelError::InvalidProcess(pid))?;
|
||||
*quota = Quota::default();
|
||||
.ok_or(KernelError::InvalidProcess(pid))?
|
||||
.pages;
|
||||
let mut source = ChargedFrames {
|
||||
frames: &mut self.frames,
|
||||
quota,
|
||||
@@ -152,9 +144,6 @@ impl<P: Platform> Kernel<P> {
|
||||
.map_err(map_error);
|
||||
if created.is_err() {
|
||||
self.frames.free_owned_by(pid);
|
||||
if let Some(q) = self.quotas.get_mut(pid.raw() as usize) {
|
||||
*q = Quota::default();
|
||||
}
|
||||
}
|
||||
created
|
||||
}
|
||||
@@ -188,8 +177,8 @@ impl<P: Platform> Kernel<P> {
|
||||
if let Some((pa, _)) = self.user_frame(pid, va) {
|
||||
self.platform.unmap_page(pid, va);
|
||||
self.frames.free(pa);
|
||||
if let Some(q) = self.quotas.get_mut(pid.raw() as usize) {
|
||||
q.uncharge(1);
|
||||
if let Some(b) = self.budgets.get_mut(pid.raw() as usize) {
|
||||
b.pages.uncharge(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,9 +189,6 @@ impl<P: Platform> Kernel<P> {
|
||||
self.teardown_regions(pid);
|
||||
self.platform.destroy_address_space(pid);
|
||||
self.frames.free_owned_by(pid);
|
||||
if let Some(q) = self.quotas.get_mut(pid.raw() as usize) {
|
||||
*q = Quota::default();
|
||||
}
|
||||
if let Some(c) = self.heap_cursors.get_mut(pid.raw() as usize) {
|
||||
*c = 0;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ impl<P: Platform> Kernel<P> {
|
||||
self.processes.get(owner)?;
|
||||
let id = self.regions.next_free_id().ok_or(KernelError::NoFreeSlot)?;
|
||||
let count = pages.value() as usize;
|
||||
self.charge_object(owner, crate::budget::REGIONS)?;
|
||||
if !self.quota_mut(owner)?.charge(count) {
|
||||
self.uncharge_object(owner, crate::budget::REGIONS);
|
||||
return Err(KernelError::OutOfMemory);
|
||||
}
|
||||
let Some(base) = self
|
||||
@@ -36,6 +38,7 @@ impl<P: Platform> Kernel<P> {
|
||||
.alloc_contiguous(count, |_| FrameUse::Region { region: id })
|
||||
else {
|
||||
self.quota_mut(owner)?.uncharge(count);
|
||||
self.uncharge_object(owner, crate::budget::REGIONS);
|
||||
return Err(KernelError::OutOfMemory);
|
||||
};
|
||||
for i in 0..count {
|
||||
@@ -76,9 +79,11 @@ impl<P: Platform> Kernel<P> {
|
||||
if overlaps {
|
||||
return Err(KernelError::AddressInUse);
|
||||
}
|
||||
self.charge_object(owner, crate::budget::REGIONS)?;
|
||||
self.regions
|
||||
.insert(Region::new(owner, RegionBacking::Device, base, pages))
|
||||
.ok_or(KernelError::NoFreeSlot)
|
||||
.inspect_err(|_| self.uncharge_object(owner, crate::budget::REGIONS))
|
||||
}
|
||||
|
||||
pub fn region_base(&self, id: RegionId) -> Option<PhysicalAddress> {
|
||||
|
||||
Reference in New Issue
Block a user