summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_fault.c
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2003-10-15 08:00:45 +0000
committeralc <alc@FreeBSD.org>2003-10-15 08:00:45 +0000
commitb722f9a630030db0a9e43bcb2bfdb37f9847d82a (patch)
tree7a7be83fb5ff1e2694f2a91ca043d5f282177f06 /sys/vm/vm_fault.c
parent72dab909cc26aadb64e45338f150233dc134d10d (diff)
downloadFreeBSD-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/vm/vm_fault.c')
-rw-r--r--sys/vm/vm_fault.c24
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.
OpenPOWER on IntegriCloud