diff options
author | alc <alc@FreeBSD.org> | 2003-10-15 08:00:45 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2003-10-15 08:00:45 +0000 |
commit | b722f9a630030db0a9e43bcb2bfdb37f9847d82a (patch) | |
tree | 7a7be83fb5ff1e2694f2a91ca043d5f282177f06 /sys | |
parent | 72dab909cc26aadb64e45338f150233dc134d10d (diff) | |
download | FreeBSD-src-b722f9a630030db0a9e43bcb2bfdb37f9847d82a.zip FreeBSD-src-b722f9a630030db0a9e43bcb2bfdb37f9847d82a.tar.gz |
- vm_fault_copy_entry() should not assume that the source object contains
every page. If the source entry was read-only, one or more wired pages
could be in backing objects.
- vm_fault_copy_entry() should not set the PG_WRITEABLE flag on the page
unless the destination entry is, in fact, writeable.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/vm/vm_fault.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 5d8dec3..a1abc44 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -1124,10 +1124,11 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry) vm_map_entry_t dst_entry; vm_map_entry_t src_entry; { - vm_object_t dst_object; + vm_object_t backing_object, dst_object, object; vm_object_t src_object; vm_ooffset_t dst_offset; vm_ooffset_t src_offset; + vm_pindex_t pindex; vm_prot_t prot; vm_offset_t vaddr; vm_page_t dst_m; @@ -1181,12 +1182,24 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry) * memory.) */ VM_OBJECT_LOCK(src_object); - src_m = vm_page_lookup(src_object, - OFF_TO_IDX(dst_offset + src_offset)); + object = src_object; + pindex = 0; + while ((src_m = vm_page_lookup(object, pindex + + OFF_TO_IDX(dst_offset + src_offset))) == NULL && + (src_entry->protection & VM_PROT_WRITE) == 0 && + (backing_object = object->backing_object) != NULL) { + /* + * Allow fallback to backing objects if we are reading. + */ + VM_OBJECT_LOCK(backing_object); + pindex += OFF_TO_IDX(object->backing_object_offset); + VM_OBJECT_UNLOCK(object); + object = backing_object; + } if (src_m == NULL) panic("vm_fault_copy_wired: page missing"); pmap_copy_page(src_m, dst_m); - VM_OBJECT_UNLOCK(src_object); + VM_OBJECT_UNLOCK(object); dst_m->valid = VM_PAGE_BITS_ALL; VM_OBJECT_UNLOCK(dst_object); @@ -1196,7 +1209,8 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry) pmap_enter(dst_map->pmap, vaddr, dst_m, prot, FALSE); VM_OBJECT_LOCK(dst_object); vm_page_lock_queues(); - vm_page_flag_set(dst_m, PG_WRITEABLE); + if ((prot & VM_PROT_WRITE) != 0) + vm_page_flag_set(dst_m, PG_WRITEABLE); /* * Mark it no longer busy, and put it on the active list. |