diff options
author | mjg <mjg@FreeBSD.org> | 2017-03-14 20:43:04 +0000 |
---|---|---|
committer | mjg <mjg@FreeBSD.org> | 2017-03-14 20:43:04 +0000 |
commit | 3edf8a9d08485cf11c17af11e7852d41f8edea23 (patch) | |
tree | 3a52f54c3221a41c2827b86fcf9b8cfa4136dae9 /sys/vm | |
parent | 57f28a25af7dd32fc8adea80c5ebb2b237cc86a6 (diff) | |
download | FreeBSD-src-3edf8a9d08485cf11c17af11e7852d41f8edea23.zip FreeBSD-src-3edf8a9d08485cf11c17af11e7852d41f8edea23.tar.gz |
MFC r312724,r312901,r312902:
hwpmc: partially depessimize munmap handling if the module is not loaded
HWPMC_HOOKS is enabled in GENERIC and triggers some work avoidable in the
common (module not loaded) case.
In particular this avoids permission checks + lock downgrade
singlethreaded and in cases were an executable mapping is found the pmc
sx lock is no longer bounced.
Note this is a band aid.
==
hwpmc: partially depessimize mmap handling if the module is not loaded
In particular this means the pmc sx lock is no longer taken when an
executable mapping succeeds.
==
hwpmc: annotate pmc_hook and pmc_intr as __read_mostly
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vm_mmap.c | 49 |
1 files changed, 28 insertions, 21 deletions
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index ada71f0..db0a3bd 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -500,6 +500,7 @@ kern_munmap(struct thread *td, uintptr_t addr0, size_t size) #ifdef HWPMC_HOOKS struct pmckern_map_out pkm; vm_map_entry_t entry; + bool pmc_handled; #endif vm_offset_t addr; vm_size_t pageoff; @@ -524,20 +525,24 @@ kern_munmap(struct thread *td, uintptr_t addr0, size_t size) return (EINVAL); vm_map_lock(map); #ifdef HWPMC_HOOKS - /* - * Inform hwpmc if the address range being unmapped contains - * an executable region. - */ - pkm.pm_address = (uintptr_t) NULL; - if (vm_map_lookup_entry(map, addr, &entry)) { - for (; - entry != &map->header && entry->start < addr + size; - entry = entry->next) { - if (vm_map_check_protection(map, entry->start, - entry->end, VM_PROT_EXECUTE) == TRUE) { - pkm.pm_address = (uintptr_t) addr; - pkm.pm_size = (size_t) size; - break; + pmc_handled = false; + if (PMC_HOOK_INSTALLED(PMC_FN_MUNMAP)) { + pmc_handled = true; + /* + * Inform hwpmc if the address range being unmapped contains + * an executable region. + */ + pkm.pm_address = (uintptr_t) NULL; + if (vm_map_lookup_entry(map, addr, &entry)) { + for (; + entry != &map->header && entry->start < addr + size; + entry = entry->next) { + if (vm_map_check_protection(map, entry->start, + entry->end, VM_PROT_EXECUTE) == TRUE) { + pkm.pm_address = (uintptr_t) addr; + pkm.pm_size = (size_t) size; + break; + } } } } @@ -545,14 +550,16 @@ kern_munmap(struct thread *td, uintptr_t addr0, size_t size) vm_map_delete(map, addr, addr + size); #ifdef HWPMC_HOOKS - /* downgrade the lock to prevent a LOR with the pmc-sx lock */ - vm_map_lock_downgrade(map); - if (pkm.pm_address != (uintptr_t) NULL) - PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); - vm_map_unlock_read(map); -#else - vm_map_unlock(map); + if (__predict_false(pmc_handled)) { + /* downgrade the lock to prevent a LOR with the pmc-sx lock */ + vm_map_lock_downgrade(map); + if (pkm.pm_address != (uintptr_t) NULL) + PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); + vm_map_unlock_read(map); + } else #endif + vm_map_unlock(map); + /* vm_map_delete returns nothing but KERN_SUCCESS anyway */ return (0); } |