mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
mm: properly fork shared file mappings
mm_fork_context() currently maps shared chdev mappings 1:1 when forking a range. The issue with this approach is that chdev mappings are not guaranteed to be backed by physical memory, and thus cannot safely be refcounted. This can lead to issues on devices with more complex buffer lifetimes. To allow for internal book-keeping, do not map shared chdev memory on fork and instead allow it to go through the entire fault-in process again.
This commit is contained in:
+17
-9
@@ -590,21 +590,27 @@ mm_context_t *mm_fork_context(mm_context_t *old_context) {
|
|||||||
|
|
||||||
bool writeable = arch_mmu_iswritable(old_context->pagetable, vaddr);
|
bool writeable = arch_mmu_iswritable(old_context->pagetable, vaddr);
|
||||||
bool private = !(range->flags & MM_RANGE_FLAGS_SHARED);
|
bool private = !(range->flags & MM_RANGE_FLAGS_SHARED);
|
||||||
if ((range->flags & MM_RANGE_FLAGS_FILE) && range->vnode->type == V_TYPE_CHDEV && !private) {
|
// the semantics of device mappings in general are:
|
||||||
// TODO: implement fork semantics for device mappings properly.
|
// - a device mapping always gets *fully* mapped on VOP_MMAP
|
||||||
if (arch_mmu_map(new_context->pagetable, phys, vaddr, new_range->mmuflags) == false)
|
// - if a device mapping is private, it gets a valid
|
||||||
goto error;
|
// physical page and goes through the normal fork path.
|
||||||
|
// - if a device mapping is shared, it does not have a valid
|
||||||
|
// physical page and must have VOP_MMAP called for it again.
|
||||||
|
// defer that until its actually accessed in a new page fault
|
||||||
|
if ((range->flags & MM_RANGE_FLAGS_FILE) &&
|
||||||
|
range->vnode->type == V_TYPE_CHDEV && !private)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
page_t *page = mm_get_page(phys);
|
page_t *page = mm_get_page(phys);
|
||||||
if (mm_is_page_locked(page) && writeable && private) {
|
if (mm_is_page_locked(page) && writeable && private) {
|
||||||
// the page is a private locked page, eagerly copy it to ensure fork/futex correctness
|
// the page is a private locked page, eagerly copy it
|
||||||
|
// to ensure fork/futex correctness
|
||||||
void *new_phys = mm_alloc_page(MEMORY_SECTION_DEFAULT);
|
void *new_phys = mm_alloc_page(MEMORY_SECTION_DEFAULT);
|
||||||
if (new_phys == NULL)
|
if (new_phys == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (arch_mmu_map(new_context->pagetable, new_phys, vaddr, new_range->mmuflags) == false) {
|
if (arch_mmu_map(new_context->pagetable, new_phys, vaddr,
|
||||||
|
new_range->mmuflags) == false) {
|
||||||
mm_release_page(new_phys);
|
mm_release_page(new_phys);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -612,12 +618,14 @@ mm_context_t *mm_fork_context(mm_context_t *old_context) {
|
|||||||
memcpy(MAKE_HHDM(new_phys), MAKE_HHDM(phys), PAGE_SIZE);
|
memcpy(MAKE_HHDM(new_phys), MAKE_HHDM(phys), PAGE_SIZE);
|
||||||
} else {
|
} else {
|
||||||
// go through the normal CoW path
|
// go through the normal CoW path
|
||||||
if (arch_mmu_map(new_context->pagetable, phys, vaddr, new_range->mmuflags & ~ARCH_MMU_FLAGS_WRITE) == false)
|
if (arch_mmu_map(new_context->pagetable, phys, vaddr,
|
||||||
|
new_range->mmuflags & ~ARCH_MMU_FLAGS_WRITE) == false)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
mm_hold_page(phys);
|
mm_hold_page(phys);
|
||||||
|
|
||||||
arch_mmu_remap(old_context->pagetable, phys, vaddr, new_range->mmuflags & ~ARCH_MMU_FLAGS_WRITE);
|
arch_mmu_remap(old_context->pagetable, phys, vaddr,
|
||||||
|
new_range->mmuflags & ~ARCH_MMU_FLAGS_WRITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user