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.

MFC after:	1 week
This commit is contained in:
Mateusz Guzik 2017-01-24 22:00:16 +00:00
parent 543b2f425d
commit 736ff8c396
2 changed files with 31 additions and 21 deletions

View File

@ -174,6 +174,9 @@ extern const int pmc_kernel_version;
/* PMC soft per cpu trapframe */ /* PMC soft per cpu trapframe */
extern struct trapframe pmc_tf[MAXCPU]; extern struct trapframe pmc_tf[MAXCPU];
/* Quick check if preparatory work is necessary */
#define PMC_HOOK_INSTALLED(cmd) __predict_false(pmc_hook != NULL)
/* Hook invocation; for use within the kernel */ /* Hook invocation; for use within the kernel */
#define PMC_CALL_HOOK(t, cmd, arg) \ #define PMC_CALL_HOOK(t, cmd, arg) \
do { \ do { \

View File

@ -526,6 +526,7 @@ sys_munmap(td, uap)
#ifdef HWPMC_HOOKS #ifdef HWPMC_HOOKS
struct pmckern_map_out pkm; struct pmckern_map_out pkm;
vm_map_entry_t entry; vm_map_entry_t entry;
bool pmc_handled;
#endif #endif
vm_offset_t addr; vm_offset_t addr;
vm_size_t size, pageoff; vm_size_t size, pageoff;
@ -551,20 +552,24 @@ sys_munmap(td, uap)
return (EINVAL); return (EINVAL);
vm_map_lock(map); vm_map_lock(map);
#ifdef HWPMC_HOOKS #ifdef HWPMC_HOOKS
/* pmc_handled = false;
* Inform hwpmc if the address range being unmapped contains if (PMC_HOOK_INSTALLED(PMC_FN_MUNMAP)) {
* an executable region. pmc_handled = true;
*/ /*
pkm.pm_address = (uintptr_t) NULL; * Inform hwpmc if the address range being unmapped contains
if (vm_map_lookup_entry(map, addr, &entry)) { * an executable region.
for (; */
entry != &map->header && entry->start < addr + size; pkm.pm_address = (uintptr_t) NULL;
entry = entry->next) { if (vm_map_lookup_entry(map, addr, &entry)) {
if (vm_map_check_protection(map, entry->start, for (;
entry->end, VM_PROT_EXECUTE) == TRUE) { entry != &map->header && entry->start < addr + size;
pkm.pm_address = (uintptr_t) addr; entry = entry->next) {
pkm.pm_size = (size_t) size; if (vm_map_check_protection(map, entry->start,
break; entry->end, VM_PROT_EXECUTE) == TRUE) {
pkm.pm_address = (uintptr_t) addr;
pkm.pm_size = (size_t) size;
break;
}
} }
} }
} }
@ -572,14 +577,16 @@ sys_munmap(td, uap)
vm_map_delete(map, addr, addr + size); vm_map_delete(map, addr, addr + size);
#ifdef HWPMC_HOOKS #ifdef HWPMC_HOOKS
/* downgrade the lock to prevent a LOR with the pmc-sx lock */ if (__predict_false(pmc_handled)) {
vm_map_lock_downgrade(map); /* downgrade the lock to prevent a LOR with the pmc-sx lock */
if (pkm.pm_address != (uintptr_t) NULL) vm_map_lock_downgrade(map);
PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); if (pkm.pm_address != (uintptr_t) NULL)
vm_map_unlock_read(map); PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm);
#else vm_map_unlock_read(map);
vm_map_unlock(map); } else
#endif #endif
vm_map_unlock(map);
/* vm_map_delete returns nothing but KERN_SUCCESS anyway */ /* vm_map_delete returns nothing but KERN_SUCCESS anyway */
return (0); return (0);
} }