diff options
author | kib <kib@FreeBSD.org> | 2009-04-10 10:16:03 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-04-10 10:16:03 +0000 |
commit | 81638d98846e99a6bfcf7398057a650533aa1390 (patch) | |
tree | d2a9dfe34e82f1ea1ab3cbe791593b31fbee1dd2 /sys/vm/vm_map.c | |
parent | 5a12c5d70e83806a92145c478867d74073203a09 (diff) | |
download | FreeBSD-src-81638d98846e99a6bfcf7398057a650533aa1390.zip FreeBSD-src-81638d98846e99a6bfcf7398057a650533aa1390.tar.gz |
When vm_map_wire(9) is allowed to skip holes in the wired region, skip
the mappings without any of read and execution rights, in particular,
the PROT_NONE entries. This makes mlockall(2) work for the process
address space that has such mappings.
Since protection mode of the entry may change between setting
MAP_ENTRY_IN_TRANSITION and final pass over the region that records
the wire status of the entries, allocate new map entry flag
MAP_ENTRY_WIRE_SKIPPED to mark the skipped PROT_NONE entries.
Reported and tested by: Hans Ottevanger <fbsdhackers beasties demon nl>
Reviewed by: alc
MFC after: 3 weeks
Diffstat (limited to 'sys/vm/vm_map.c')
-rw-r--r-- | sys/vm/vm_map.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index f395be8..718c890 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2217,6 +2217,16 @@ vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end, * */ if (entry->wired_count == 0) { + if ((entry->protection & (VM_PROT_READ|VM_PROT_EXECUTE)) + == 0) { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { + end = entry->end; + rv = KERN_INVALID_ADDRESS; + goto done; + } + entry->eflags |= MAP_ENTRY_WIRE_SKIPPED; + goto next_entry; + } entry->wired_count++; saved_start = entry->start; saved_end = entry->end; @@ -2274,6 +2284,7 @@ vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end, * Check the map for holes in the specified region. * If VM_MAP_WIRE_HOLESOK was specified, skip this check. */ + next_entry: if (((flags & VM_MAP_WIRE_HOLESOK) == 0) && (entry->end < end && (entry->next == &map->header || entry->next->start > entry->end))) { @@ -2295,6 +2306,8 @@ done: } entry = first_entry; while (entry != &map->header && entry->start < end) { + if ((entry->eflags & MAP_ENTRY_WIRE_SKIPPED) != 0) + goto next_entry_done; if (rv == KERN_SUCCESS) { if (user_wire) entry->eflags |= MAP_ENTRY_USER_WIRED; @@ -2317,9 +2330,10 @@ done: entry->object.vm_object->type == OBJT_DEVICE); } } + next_entry_done: KASSERT(entry->eflags & MAP_ENTRY_IN_TRANSITION, ("vm_map_wire: in-transition flag missing")); - entry->eflags &= ~MAP_ENTRY_IN_TRANSITION; + entry->eflags &= ~(MAP_ENTRY_IN_TRANSITION|MAP_ENTRY_WIRE_SKIPPED); if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; need_wakeup = TRUE; |