diff options
| author | Mark Johnston <markj@FreeBSD.org> | 2026-03-27 00:25:31 +0000 |
|---|---|---|
| committer | Mark Johnston <markj@FreeBSD.org> | 2026-03-27 00:25:31 +0000 |
| commit | f404109e90eee7f67ddaae3f52286d524a190fa0 (patch) | |
| tree | fa4d19db51df1e7b02ea4f9246b4002c9c559552 /sys/vm | |
| parent | 8f3227f527567aef53da845ab78da8e16d9051c1 (diff) | |
Diffstat (limited to 'sys/vm')
| -rw-r--r-- | sys/vm/vm_fault.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 88438320a17a..125311912c20 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -645,6 +645,8 @@ vm_fault_populate(struct faultstate *fs) pager_last = map_last; } for (pidx = pager_first; pidx <= pager_last; pidx += npages) { + bool writeable; + m = vm_page_lookup(fs->first_object, pidx); vaddr = fs->entry->start + IDX_TO_OFF(pidx) - fs->entry->offset; KASSERT(m != NULL && m->pindex == pidx, @@ -655,14 +657,28 @@ vm_fault_populate(struct faultstate *fs) !pmap_ps_enabled(fs->map->pmap))) psind--; + writeable = (fs->prot & VM_PROT_WRITE) != 0; npages = atop(pagesizes[psind]); for (i = 0; i < npages; i++) { vm_fault_populate_check_page(&m[i]); vm_fault_dirty(fs, &m[i]); + + /* + * If this is a writeable superpage mapping, all + * constituent pages and the new mapping should be + * dirty, otherwise the mapping should be read-only. + */ + if (writeable && psind > 0 && + (m[i].oflags & VPO_UNMANAGED) == 0 && + m[i].dirty != VM_PAGE_BITS_ALL) + writeable = false; } + if (psind > 0 && writeable) + fs->fault_type |= VM_PROT_WRITE; VM_OBJECT_WUNLOCK(fs->first_object); - rv = pmap_enter(fs->map->pmap, vaddr, m, fs->prot, fs->fault_type | - (fs->wired ? PMAP_ENTER_WIRED : 0), psind); + rv = pmap_enter(fs->map->pmap, vaddr, m, + fs->prot & ~(writeable ? 0 : VM_PROT_WRITE), + fs->fault_type | (fs->wired ? PMAP_ENTER_WIRED : 0), psind); /* * pmap_enter() may fail for a superpage mapping if additional |
